|
@@ -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;
|