X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=arch%2Farm%2Fcpu%2Farmv8%2Fsec_firmware.c;h=927eae4f741d8d806926567a97f859eeb995330d;hb=da63df97ea100053ea34cc022a1660f760ec32b4;hp=4afa3ad8b1dcefc6deb6115b464998fd897c9b72;hpb=7f4ed7cb78c324a7e8b71356f88220cf3efda367;p=oweals%2Fu-boot.git diff --git a/arch/arm/cpu/armv8/sec_firmware.c b/arch/arm/cpu/armv8/sec_firmware.c index 4afa3ad8b1..927eae4f74 100644 --- a/arch/arm/cpu/armv8/sec_firmware.c +++ b/arch/arm/cpu/armv8/sec_firmware.c @@ -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); @@ -224,29 +303,87 @@ __weak bool sec_firmware_is_valid(const void *sec_firmware_img) */ unsigned int sec_firmware_support_psci_version(void) { - if (sec_firmware_addr & SEC_FIRMWARE_RUNNING) + if (current_el() == SEC_FIRMWARE_TARGET_EL) return _sec_firmware_support_psci_version(); return PSCI_INVALID_VER; } #endif +/* + * Check with sec_firmware if it supports random number generation + * via HW RNG + * + * The return value will be true if it is supported + */ +bool sec_firmware_support_hwrng(void) +{ + uint8_t rand[8]; + if (sec_firmware_addr & SEC_FIRMWARE_RUNNING) { + if (!sec_firmware_get_random(rand, 8)) + return true; + } + + return false; +} + +/* + * sec_firmware_get_random - Get a random number from SEC Firmware + * @rand: random number buffer to be filled + * @bytes: Number of bytes of random number to be supported + * @eret: -1 in case of error, 0 for success + */ +int sec_firmware_get_random(uint8_t *rand, int bytes) +{ + unsigned long long num; + struct pt_regs regs; + int param1; + + if (!bytes || bytes > 8) { + printf("Max Random bytes genration supported is 8\n"); + return -1; + } +#define SIP_RNG_64 0xC200FF11 + regs.regs[0] = SIP_RNG_64; + + if (bytes <= 4) + param1 = 0; + else + param1 = 1; + regs.regs[1] = param1; + + smc_call(®s); + + if (regs.regs[0]) + return -1; + + num = regs.regs[1]; + memcpy(rand, &num, bytes); + + return 0; +} + /* * sec_firmware_init - Initialize the SEC Firmware * @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; @@ -278,3 +415,49 @@ int sec_firmware_init(const void *sec_firmware_img, return 0; } + +/* + * fdt_fix_kaslr - Add kalsr-seed node in Device tree + * @fdt: Device tree + * @eret: 0 in case of error, 1 for success + */ +int fdt_fixup_kaslr(void *fdt) +{ + int nodeoffset; + int err, ret = 0; + u8 rand[8]; + +#if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT) + /* Check if random seed generation is supported */ + if (sec_firmware_support_hwrng() == false) + return 0; + + ret = sec_firmware_get_random(rand, 8); + if (ret < 0) { + printf("WARNING: No random number to set kaslr-seed\n"); + return 0; + } + + err = fdt_check_header(fdt); + if (err < 0) { + printf("fdt_chosen: %s\n", fdt_strerror(err)); + return 0; + } + + /* find or create "/chosen" node. */ + nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); + if (nodeoffset < 0) + return 0; + + err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand, + sizeof(rand)); + if (err < 0) { + printf("WARNING: can't set kaslr-seed %s.\n", + fdt_strerror(err)); + return 0; + } + ret = 1; +#endif + + return ret; +}