From patchwork Wed Apr 12 21:15:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jordan Crouse X-Patchwork-Id: 9678401 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A789E60383 for ; Wed, 12 Apr 2017 21:15:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 98AED28648 for ; Wed, 12 Apr 2017 21:15:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8D6B028649; Wed, 12 Apr 2017 21:15:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 2B3812864D for ; Wed, 12 Apr 2017 21:15:31 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 803356E737; Wed, 12 Apr 2017 21:15:27 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from smtp.codeaurora.org (smtp.codeaurora.org [198.145.29.96]) by gabe.freedesktop.org (Postfix) with ESMTPS id CB2A76E267; Wed, 12 Apr 2017 21:15:25 +0000 (UTC) Received: by smtp.codeaurora.org (Postfix, from userid 1000) id B6D1260848; Wed, 12 Apr 2017 21:15:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1492031725; bh=zzGrRmFLj9NVt3P68VroxwObz7K3mAkfz1oASxn4QPU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LYfpKyc7Y9ZpLNXfknsJKqRx4zd2C10HNeE5SVzUoy3f8ybGLkdxf/zbSTriPMHkU nQ/sirrkhZePE5BkzuO4gOWavcv/pvEX7oL9R1QRb1loZ2xerzbhlyKs9+0WryNgAq BRBqD/a0fs5Bq+kFbLrtR1mgu9CtKBbHGGmxPSVQ= Received: from jcrouse-lnx.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: jcrouse@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id CCB3D607E6; Wed, 12 Apr 2017 21:15:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1492031725; bh=zzGrRmFLj9NVt3P68VroxwObz7K3mAkfz1oASxn4QPU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LYfpKyc7Y9ZpLNXfknsJKqRx4zd2C10HNeE5SVzUoy3f8ybGLkdxf/zbSTriPMHkU nQ/sirrkhZePE5BkzuO4gOWavcv/pvEX7oL9R1QRb1loZ2xerzbhlyKs9+0WryNgAq BRBqD/a0fs5Bq+kFbLrtR1mgu9CtKBbHGGmxPSVQ= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org CCB3D607E6 Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=jcrouse@codeaurora.org From: Jordan Crouse To: freedreno@lists.freedesktop.org, dri-devel@lists.freedesktop.org, bjorn.andersson@linaro.org Subject: [PATCH 1/6] drm/msm: Add a quick and dirty PIL loader Date: Wed, 12 Apr 2017 15:15:13 -0600 Message-Id: <1492031718-28477-2-git-send-email-jcrouse@codeaurora.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1492031718-28477-1-git-send-email-jcrouse@codeaurora.org> References: <1492031718-28477-1-git-send-email-jcrouse@codeaurora.org> Cc: linux-arm-msm@vger.kernel.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP In order to switch the GPU out of secure mode on most systems we need to load a zap shader into memory and get it authenticated and into the secure world. All the bits and pieces to do the load are scattered throughout the kernel, but we need to bring everything together. Add a semi-custom loader that will read a MDT file and get it loaded and authenticated through SCM. Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 166 ++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 31a9bce..6c55d24 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -11,6 +11,12 @@ * */ +#include +#include +#include +#include +#include +#include #include "msm_gem.h" #include "msm_mmu.h" #include "a5xx_gpu.h" @@ -18,6 +24,166 @@ extern bool hang_debug; static void a5xx_dump(struct msm_gpu *gpu); +static inline bool _check_segment(const struct elf32_phdr *phdr) +{ + return ((phdr->p_type == PT_LOAD) && + ((phdr->p_flags & (7 << 24)) != (2 << 24)) && + phdr->p_memsz); +} + +static int __pil_tz_load_image(struct platform_device *pdev, + const struct firmware *mdt, const char *fwname, + void *fwptr, size_t fw_size, unsigned long fw_min_addr) +{ + char str[64] = { 0 }; + const struct elf32_hdr *ehdr = (struct elf32_hdr *) mdt->data; + const struct elf32_phdr *phdrs = (struct elf32_phdr *) (ehdr + 1); + const struct firmware *fw; + int i, ret = 0; + + for (i = 0; i < ehdr->e_phnum; i++) { + const struct elf32_phdr *phdr = &phdrs[i]; + size_t offset; + + /* Make sure the segment is loadable */ + if (!_check_segment(phdr)) + continue; + + /* Get the offset of the segment within the region */ + offset = (phdr->p_paddr - fw_min_addr); + + /* Request the file containing the segment */ + snprintf(str, sizeof(str) - 1, "%s.b%02d", fwname, i); + + ret = request_firmware(&fw, str, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Failed to load segment %s\n", str); + break; + } + + if (offset + fw->size > fw_size) { + dev_err(&pdev->dev, "Segment %s is too big\n", str); + ret = -EINVAL; + release_firmware(fw); + break; + } + + /* Copy the segment into place */ + memcpy(fwptr + offset, fw->data, fw->size); + release_firmware(fw); + } + + return ret; +} + +static int _pil_tz_load_image(struct platform_device *pdev) +{ + char str[64] = { 0 }; + const char *fwname; + const struct elf32_hdr *ehdr; + const struct elf32_phdr *phdrs; + const struct firmware *mdt; + phys_addr_t fw_min_addr, fw_max_addr; + dma_addr_t fw_phys; + size_t fw_size; + u32 pas_id; + void *ptr; + int i, ret; + + if (pdev == NULL) + return -ENODEV; + + if (!qcom_scm_is_available()) { + dev_err(&pdev->dev, "SCM is not available\n"); + return -EINVAL; + } + + ret = of_reserved_mem_device_init(&pdev->dev); + + if (ret) { + dev_err(&pdev->dev, "Unable to set up the reserved memory\n"); + return ret; + } + + /* Get the firmware and PAS id from the device node */ + if (of_property_read_string(pdev->dev.of_node, "qcom,firmware", + &fwname)) { + dev_err(&pdev->dev, "Could not read a firmware name\n"); + return -EINVAL; + } + + if (of_property_read_u32(pdev->dev.of_node, "qcom,pas-id", &pas_id)) { + dev_err(&pdev->dev, "Could not read the pas ID\n"); + return -EINVAL; + } + + snprintf(str, sizeof(str) - 1, "%s.mdt", fwname); + + /* Request the MDT file for the firmware */ + ret = request_firmware(&mdt, str, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Unable to load %s\n", str); + return ret; + } + + ehdr = (struct elf32_hdr *) mdt->data; + phdrs = (struct elf32_phdr *) (ehdr + 1); + + /* Get the extents of the firmware image */ + + fw_min_addr = (phys_addr_t) ULLONG_MAX; + fw_max_addr = 0; + + for (i = 0; i < ehdr->e_phnum; i++) { + const struct elf32_phdr *phdr = &phdrs[i]; + + if (!_check_segment(phdr)) + continue; + + fw_min_addr = min_t(phys_addr_t, fw_min_addr, phdr->p_paddr); + fw_max_addr = max_t(phys_addr_t, fw_max_addr, + PAGE_ALIGN(phdr->p_paddr + phdr->p_memsz)); + } + + if (fw_min_addr == (phys_addr_t) ULLONG_MAX && fw_max_addr == 0) + goto out; + + fw_size = (size_t) (fw_max_addr - fw_min_addr); + + /* Verify the MDT header */ + ret = qcom_scm_pas_init_image(pas_id, mdt->data, mdt->size); + if (ret) { + dev_err(&pdev->dev, "Invalid firmware metadata\n"); + goto out; + } + + /* allocate some memory */ + ptr = dma_alloc_coherent(&pdev->dev, fw_size, &fw_phys, GFP_KERNEL); + if (ptr == NULL) + goto out; + + /* Set up the newly allocated memory region */ + ret = qcom_scm_pas_mem_setup(pas_id, fw_phys, fw_size); + if (ret) { + dev_err(&pdev->dev, "Unable to set up firmware memory\n"); + goto out; + } + + ret = __pil_tz_load_image(pdev, mdt, fwname, ptr, fw_size, fw_min_addr); + if (!ret) { + ret = qcom_scm_pas_auth_and_reset(pas_id); + if (ret) + dev_err(&pdev->dev, "Unable to authorize the image\n"); + } + +out: + if (ret && ptr) + dma_free_coherent(&pdev->dev, fw_size, ptr, fw_phys); + + release_firmware(mdt); + return ret; +} + static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx) {