Re: [Freedreno] [PATCH 11/12] drm/msm: Add a quick and dirty PIL loader

2016-12-06 Thread Jordan Crouse
On Mon, Dec 05, 2016 at 11:57:43AM -0800, Bjorn Andersson wrote:
> > + if (of_property_read_u32(pdev->dev.of_node, "qcom,pas-id", _id)) {
> 
> This is constant, so define it in the driver.

Little bit concerned it might not always be constant but I suppose we can cross
that bridge when we get to it.

> Regards,
> Bjorn

Jordan
-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH 11/12] drm/msm: Add a quick and dirty PIL loader

2016-11-28 Thread Jordan Crouse
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 3824bc4..eefe197 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -11,12 +11,178 @@
  *
  */
 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 #include "msm_gem.h"
 #include "a5xx_gpu.h"
 
 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 = [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(, str, >dev);
+   if (ret) {
+   dev_err(>dev, "Failed to load segment %s\n", str);
+   break;
+   }
+
+   if (offset + fw->size > fw_size) {
+   dev_err(>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(>dev, "SCM is not available\n");
+   return -EINVAL;
+   }
+
+   ret = of_reserved_mem_device_init(>dev);
+
+   if (ret) {
+   dev_err(>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",
+   )) {
+   dev_err(>dev, "Could not read a firmware name\n");
+   return -EINVAL;
+   }
+
+   if (of_property_read_u32(pdev->dev.of_node, "qcom,pas-id", _id)) {
+   dev_err(>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(, str, >dev);
+   if (ret) {
+   dev_err(>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 = [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 &&