armv8: sec_firmware: Add support for loadables in FIT
authorSumit Garg <sumit.garg@nxp.com>
Fri, 1 Sep 2017 08:25:01 +0000 (13:55 +0530)
committerYork Sun <york.sun@nxp.com>
Fri, 27 Oct 2017 15:47:14 +0000 (08:47 -0700)
Enable support for loadables in SEC firmware FIT image. Currently
support is added for single loadable image.

Brief description of implementation:
  Add two more address pointers (loadable_h, loadable_l) as arguments to
  sec_firmware_init() api.
  Create new api: sec_firmware_checks_copy_loadable() to check if loadables
  node is present in SEC firmware FIT image. If present, verify loadable
  image and copies it to secure DDR memory.
  Populate address pointers with secure DDR memory addresses where loadable
  is copied.

Example use-case could be trusted OS (tee.bin) as loadables node in SEC
firmware FIT image.

Signed-off-by: Sumit Garg <sumit.garg@nxp.com>
Reviewed-by: York Sun <york.sun@nxp.com>
arch/arm/cpu/armv8/fsl-layerscape/ppa.c
arch/arm/cpu/armv8/sec_firmware.c
arch/arm/include/asm/armv8/sec_firmware.h

index bbf8bba1120d301c2f559ab178bb23598412af0f..cddcee964afd0560a3d78be1b8d2467db206d675 100644 (file)
@@ -35,6 +35,7 @@ int ppa_init(void)
        unsigned int el = current_el();
        void *ppa_fit_addr;
        u32 *boot_loc_ptr_l, *boot_loc_ptr_h;
+       u32 *loadable_l, *loadable_h;
        int ret;
 
 #ifdef CONFIG_CHAIN_OF_TRUST
@@ -240,9 +241,9 @@ int ppa_init(void)
                                           PPA_KEY_HASH,
                                           &ppa_img_addr);
                if (ret != 0)
-                       printf("PPA validation failed\n");
+                       printf("SEC firmware(s) validation failed\n");
                else
-                       printf("PPA validation Successful\n");
+                       printf("SEC firmware(s) validation Successful\n");
        }
 #if defined(CONFIG_SYS_LS_PPA_FW_IN_MMC) || \
        defined(CONFIG_SYS_LS_PPA_FW_IN_NAND)
@@ -254,15 +255,24 @@ int ppa_init(void)
        struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
        boot_loc_ptr_l = &gur->bootlocptrl;
        boot_loc_ptr_h = &gur->bootlocptrh;
+
+       /* Assign addresses to loadable ptrs */
+       loadable_l = &gur->scratchrw[4];
+       loadable_h = &gur->scratchrw[5];
 #elif defined(CONFIG_FSL_LSCH2)
        struct ccsr_scfg __iomem *scfg = (void *)(CONFIG_SYS_FSL_SCFG_ADDR);
        boot_loc_ptr_l = &scfg->scratchrw[1];
        boot_loc_ptr_h = &scfg->scratchrw[0];
+
+       /* Assign addresses to loadable ptrs */
+       loadable_l = &scfg->scratchrw[2];
+       loadable_h = &scfg->scratchrw[3];
 #endif
 
        debug("fsl-ppa: boot_loc_ptr_l = 0x%p, boot_loc_ptr_h =0x%p\n",
              boot_loc_ptr_l, boot_loc_ptr_h);
-       ret = sec_firmware_init(ppa_fit_addr, boot_loc_ptr_l, boot_loc_ptr_h);
+       ret = sec_firmware_init(ppa_fit_addr, boot_loc_ptr_l, boot_loc_ptr_h,
+                               loadable_l, loadable_h);
 
 #if defined(CONFIG_SYS_LS_PPA_FW_IN_MMC) || \
        defined(CONFIG_SYS_LS_PPA_FW_IN_NAND)
index 0e7483437a9bbc9b00952308ec0b8f089c215f1a..927eae4f741d8d806926567a97f859eeb995330d 100644 (file)
@@ -105,6 +105,74 @@ static int sec_firmware_parse_image(const void *sec_firmware_img,
        return 0;
 }
 
+/*
+ * SEC Firmware FIT image parser to check if any loadable is
+ * present. If present, verify integrity of the loadable and
+ * copy loadable to address provided in (loadable_h, loadable_l).
+ *
+ * Returns 0 on success and a negative errno on error task fail.
+ */
+static int sec_firmware_check_copy_loadable(const void *sec_firmware_img,
+                                           u32 *loadable_l, u32 *loadable_h)
+{
+       phys_addr_t sec_firmware_loadable_addr = 0;
+       int conf_node_off, ld_node_off;
+       char *conf_node_name = NULL;
+       const void *data;
+       size_t size;
+       ulong load;
+
+       conf_node_name = SEC_FIRMEWARE_FIT_CNF_NAME;
+
+       conf_node_off = fit_conf_get_node(sec_firmware_img, conf_node_name);
+       if (conf_node_off < 0) {
+               printf("SEC Firmware: %s: no such config\n", conf_node_name);
+       return -ENOENT;
+       }
+
+       ld_node_off = fit_conf_get_prop_node(sec_firmware_img, conf_node_off,
+                                            FIT_LOADABLE_PROP);
+       if (ld_node_off >= 0) {
+               printf("SEC Firmware: '%s' present in config\n",
+                      FIT_LOADABLE_PROP);
+
+               /* Verify secure firmware image */
+               if (!(fit_image_verify(sec_firmware_img, ld_node_off))) {
+                       printf("SEC Loadable: Bad loadable image (bad CRC)\n");
+                       return -EINVAL;
+               }
+
+               if (fit_image_get_data(sec_firmware_img, ld_node_off,
+                                      &data, &size)) {
+                       printf("SEC Loadable: Can't get subimage data/size");
+                       return -ENOENT;
+               }
+
+               /* Get load address, treated as load offset to secure memory */
+               if (fit_image_get_load(sec_firmware_img, ld_node_off, &load)) {
+                       printf("SEC Loadable: Can't get subimage load");
+                       return -ENOENT;
+               }
+
+               /* Compute load address for loadable in secure memory */
+               sec_firmware_loadable_addr = (sec_firmware_addr -
+                                               gd->arch.tlb_size) + load;
+
+               /* Copy loadable to secure memory and flush dcache */
+               debug("%s copied to address 0x%p\n",
+                     FIT_LOADABLE_PROP, (void *)sec_firmware_loadable_addr);
+               memcpy((void *)sec_firmware_loadable_addr, data, size);
+               flush_dcache_range(sec_firmware_loadable_addr,
+                                  sec_firmware_loadable_addr + size);
+       }
+
+       /* Populate address ptrs for loadable image with loadbale addr */
+       out_le32(loadable_l, (sec_firmware_loadable_addr & WORD_MASK));
+       out_le32(loadable_h, (sec_firmware_loadable_addr >> WORD_SHIFT));
+
+       return 0;
+}
+
 static int sec_firmware_copy_image(const char *title,
                         u64 image_addr, u32 image_size, u64 sec_firmware)
 {
@@ -117,9 +185,11 @@ static int sec_firmware_copy_image(const char *title,
 
 /*
  * This function will parse the SEC Firmware image, and then load it
- * to secure memory.
+ * to secure memory. Also load any loadable if present along with SEC
+ * Firmware image.
  */
-static int sec_firmware_load_image(const void *sec_firmware_img)
+static int sec_firmware_load_image(const void *sec_firmware_img,
+                                  u32 *loadable_l, u32 *loadable_h)
 {
        const void *raw_image_addr;
        size_t raw_image_size = 0;
@@ -172,6 +242,15 @@ static int sec_firmware_load_image(const void *sec_firmware_img)
        if (ret)
                goto out;
 
+       /*
+        * Check if any loadable are present along with firmware image, if
+        * present load them.
+        */
+       ret = sec_firmware_check_copy_loadable(sec_firmware_img, loadable_l,
+                                              loadable_h);
+       if (ret)
+               goto out;
+
        sec_firmware_addr |= SEC_FIRMWARE_LOADED;
        debug("SEC Firmware: Entry point: 0x%llx\n",
              sec_firmware_addr & SEC_FIRMWARE_ADDR_MASK);
@@ -289,17 +368,22 @@ int sec_firmware_get_random(uint8_t *rand, int bytes)
  * @sec_firmware_img:  the SEC Firmware image address
  * @eret_hold_l:       the address to hold exception return address low
  * @eret_hold_h:       the address to hold exception return address high
+ * @loadable_l:                the address to hold loadable address low
+ * @loadable_h:                the address to hold loadable address high
  */
 int sec_firmware_init(const void *sec_firmware_img,
                        u32 *eret_hold_l,
-                       u32 *eret_hold_h)
+                       u32 *eret_hold_h,
+                       u32 *loadable_l,
+                       u32 *loadable_h)
 {
        int ret;
 
        if (!sec_firmware_is_valid(sec_firmware_img))
                return -EINVAL;
 
-       ret = sec_firmware_load_image(sec_firmware_img);
+       ret = sec_firmware_load_image(sec_firmware_img, loadable_l,
+                                     loadable_h);
        if (ret) {
                printf("SEC Firmware: Failed to load image\n");
                return ret;
index 6d42a7111f2a37f382760d3cf2bd52689f027976..2ba1847a2ed79d6fc1970fc7cf303b552cd63ae1 100644 (file)
@@ -9,8 +9,10 @@
 
 #define PSCI_INVALID_VER               0xffffffff
 #define SEC_JR3_OFFSET                 0x40000
+#define WORD_MASK                      0xffffffff
+#define WORD_SHIFT                     32
 
-int sec_firmware_init(const void *, u32 *, u32 *);
+int sec_firmware_init(const void *, u32 *, u32 *, u32 *, u32 *);
 int _sec_firmware_entry(const void *, u32 *, u32 *);
 bool sec_firmware_is_valid(const void *);
 bool sec_firmware_support_hwrng(void);