From: Hou Zhiqiang <zhiqiang....@nxp.com> The FSL Primary Protected Application (PPA) is a software component loaded during boot which runs in TrustZone and remains resident after boot.
Signed-off-by: Hou Zhiqiang <zhiqiang....@nxp.com> --- V5: - Added API sec_firmware_init() implementation. V4: - Moved secure firmware validation API to this patch. - Moved secure firmware getting supported PSCI version API to this patch. V3: - Refactor the code. - Add PPA firmware version info output. arch/arm/cpu/armv8/fsl-layerscape/Makefile | 1 + arch/arm/cpu/armv8/fsl-layerscape/ppa.c | 311 +++++++++++++++++++++++++ arch/arm/cpu/armv8/fsl-layerscape/ppa_entry.S | 53 +++++ arch/arm/include/asm/arch-fsl-layerscape/ppa.h | 14 ++ arch/arm/include/asm/armv8/sec_firmware.h | 4 + 5 files changed, 383 insertions(+) create mode 100644 arch/arm/cpu/armv8/fsl-layerscape/ppa.c create mode 100644 arch/arm/cpu/armv8/fsl-layerscape/ppa_entry.S create mode 100644 arch/arm/include/asm/arch-fsl-layerscape/ppa.h diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Makefile b/arch/arm/cpu/armv8/fsl-layerscape/Makefile index 5f86ef9..1535fee 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Makefile +++ b/arch/arm/cpu/armv8/fsl-layerscape/Makefile @@ -10,6 +10,7 @@ obj-y += soc.o obj-$(CONFIG_MP) += mp.o obj-$(CONFIG_OF_LIBFDT) += fdt.o obj-$(CONFIG_SPL) += spl.o +obj-$(CONFIG_FSL_LS_PPA) += ppa.o ppa_entry.o ifneq ($(CONFIG_FSL_LSCH3),) obj-y += fsl_lsch3_speed.o diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ppa.c b/arch/arm/cpu/armv8/fsl-layerscape/ppa.c new file mode 100644 index 0000000..6a75960 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/ppa.c @@ -0,0 +1,311 @@ +/* + * Copyright 2016 NXP Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <config.h> +#include <errno.h> +#include <malloc.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/types.h> +#include <asm/macro.h> +#include <asm/arch/soc.h> +#ifdef CONFIG_FSL_LSCH3 +#include <asm/arch/immap_lsch3.h> +#elif defined(CONFIG_FSL_LSCH2) +#include <asm/arch/immap_lsch2.h> +#endif +#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#include <asm/armv8/sec_firmware.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +extern void c_runtime_cpu_setup(void); + +#define LS_PPA_FIT_FIRMWARE_IMAGE "firmware" +#define LS_PPA_FIT_CNF_NAME "config@1" +#define PPA_MEM_SIZE_ENV_VAR "ppamemsize" + +/* + * Return the actual size of the PPA private DRAM block. + */ +unsigned long ppa_get_dram_block_size(void) +{ + unsigned long dram_block_size = CONFIG_SYS_LS_PPA_DRAM_BLOCK_MIN_SIZE; + + char *dram_block_size_env_var = getenv(PPA_MEM_SIZE_ENV_VAR); + + if (dram_block_size_env_var) { + dram_block_size = simple_strtoul(dram_block_size_env_var, NULL, + 10); + + if (dram_block_size < CONFIG_SYS_LS_PPA_DRAM_BLOCK_MIN_SIZE) { + printf("fsl-ppa: WARNING: Invalid value for \'" + PPA_MEM_SIZE_ENV_VAR + "\' environment variable: %lu\n", + dram_block_size); + + dram_block_size = CONFIG_SYS_LS_PPA_DRAM_BLOCK_MIN_SIZE; + } + } + + return dram_block_size; +} + +static bool ppa_firmware_is_valid(void *ppa_addr) +{ + void *fit_hdr; + + fit_hdr = ppa_addr; + + if (fdt_check_header(fit_hdr)) { + printf("fsl-ppa: Bad firmware image (not a FIT image)\n"); + return false; + } + + if (!fit_check_format(fit_hdr)) { + printf("fsl-ppa: Bad firmware image (bad FIT header)\n"); + return false; + } + + return true; +} + +static int ppa_firmware_get_data(void *ppa_addr, + const void **data, size_t *size) +{ + void *fit_hdr; + int conf_node_off, fw_node_off; + char *conf_node_name = NULL; + char *desc; + int ret; + + fit_hdr = ppa_addr; + conf_node_name = LS_PPA_FIT_CNF_NAME; + + conf_node_off = fit_conf_get_node(fit_hdr, conf_node_name); + if (conf_node_off < 0) { + printf("fsl-ppa: %s: no such config\n", conf_node_name); + return -ENOENT; + } + + fw_node_off = fit_conf_get_prop_node(fit_hdr, conf_node_off, + LS_PPA_FIT_FIRMWARE_IMAGE); + if (fw_node_off < 0) { + printf("fsl-ppa: No '%s' in config\n", + LS_PPA_FIT_FIRMWARE_IMAGE); + return -ENOLINK; + } + + /* Verify PPA firmware image */ + if (!(fit_image_verify(fit_hdr, fw_node_off))) { + printf("fsl-ppa: Bad firmware image (bad CRC)\n"); + return -EINVAL; + } + + if (fit_image_get_data(fit_hdr, fw_node_off, data, size)) { + printf("fsl-ppa: Can't get %s subimage data/size", + LS_PPA_FIT_FIRMWARE_IMAGE); + return -ENOENT; + } + + ret = fit_get_desc(fit_hdr, fw_node_off, &desc); + if (ret) + printf("PPA Firmware unavailable\n"); + else + printf("%s\n", desc); + + return 0; +} + +/* + * PPA firmware FIT image parser checks if the image is in FIT + * format, verifies integrity of the image and calculates raw + * image address and size values. + * + * Returns 0 on success and a negative errno on error task fail. + */ +static int ppa_parse_firmware_fit_image(const void **raw_image_addr, + size_t *raw_image_size) +{ + void *ppa_addr; + int ret; + +#ifdef CONFIG_SYS_LS_PPA_FW_IN_NOR + ppa_addr = (void *)CONFIG_SYS_LS_PPA_FW_ADDR; +#else +#error "No CONFIG_SYS_LS_PPA_FW_IN_xxx defined" +#endif + + if (!ppa_firmware_is_valid(ppa_addr)) + return -1; + + ret = ppa_firmware_get_data(ppa_addr, raw_image_addr, raw_image_size); + if (ret) + return ret; + + debug("fsl-ppa: raw_image_addr = 0x%p, raw_image_size = 0x%lx\n", + *raw_image_addr, *raw_image_size); + + return 0; +} + +static int ppa_copy_image(const char *title, + u64 image_addr, u32 image_size, u64 ppa_ram_addr) +{ + debug("%s copied to address 0x%p\n", title, (void *)ppa_ram_addr); + memcpy((void *)ppa_ram_addr, (void *)image_addr, image_size); + flush_dcache_range(ppa_ram_addr, ppa_ram_addr + image_size); + + return 0; +} + +static int ppa_init_pre(u64 *entry) +{ + u64 ppa_ram_addr; + const void *raw_image_addr; + size_t raw_image_size = 0; + size_t ppa_ram_size = ppa_get_dram_block_size(); + int ret; + + debug("fsl-ppa: ppa size(0x%lx)\n", ppa_ram_size); + + /* + * The Excetpion Level must be EL3 to prepare and initialize the PPA. + */ + if (current_el() != 3) { + ret = -EACCES; + goto out; + } + +#ifdef CONFIG_SYS_MEM_RESERVE_SECURE + /* + * The PPA must be stored in secure memory. + * Append PPA to secure mmu table. + */ + if (!(gd->secure_ram & MEM_RESERVE_SECURE_MAINTAINED)) { + ret = -ENXIO; + goto out; + } + + ppa_ram_addr = (gd->secure_ram & MEM_RESERVE_SECURE_ADDR_MASK) + + gd->arch.tlb_size; +#else +#error "The CONFIG_SYS_MEM_RESERVE_SECURE must be defined when enabled PPA" +#endif + + /* Align PPA base address to 4K */ + ppa_ram_addr = (ppa_ram_addr + 0xfff) & ~0xfff; + debug("fsl-ppa: PPA load address (0x%llx)\n", ppa_ram_addr); + + ret = ppa_parse_firmware_fit_image(&raw_image_addr, &raw_image_size); + if (ret < 0) + goto out; + + if (ppa_ram_size < raw_image_size) { + ret = -ENOSPC; + goto out; + } + + /* TODO: + * Check if the end addr of PPA has been extend the secure memory. + */ + + ppa_copy_image("PPA firmware", (u64)raw_image_addr, + raw_image_size, ppa_ram_addr); + + debug("fsl-ppa: PPA entry: 0x%llx\n", ppa_ram_addr); + *entry = ppa_ram_addr; + + return 0; + +out: + printf("fsl-ppa: error (%d)\n", ret); + *entry = 0; + + return ret; +} + +static int ppa_init_entry(void *ppa_entry) +{ + int ret; + u32 *boot_loc_ptr_l, *boot_loc_ptr_h; + +#ifdef CONFIG_FSL_LSCH3 + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + boot_loc_ptr_l = &gur->bootlocptrl; + boot_loc_ptr_h = &gur->bootlocptrh; +#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]; +#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 = ppa_init(ppa_entry, boot_loc_ptr_l, boot_loc_ptr_h); + if (ret < 0) + return ret; + + debug("fsl-ppa: Return from PPA: current_el = %d\n", current_el()); + + /* The PE will be turned into EL2 when run out of PPA. */ + if (current_el() != 2) + return -EACCES; + + /* + * First, set vector for EL2. + */ + c_runtime_cpu_setup(); + + /* Enable caches and MMU for EL2. */ + enable_caches(); + + return 0; +} + +bool sec_firmware_is_valid(void) +{ + void *ppa_addr; + +#ifdef CONFIG_SYS_LS_PPA_FW_IN_NOR + ppa_addr = (void *)CONFIG_SYS_LS_PPA_FW_ADDR; +#else +#error "No CONFIG_SYS_LS_PPA_FW_IN_xxx defined" +#endif + + return ppa_firmware_is_valid(ppa_addr); +} + +#ifdef CONFIG_ARMV8_PSCI +unsigned int sec_firmware_support_psci_version(void) +{ + unsigned int psci_ver = 0; + + if (sec_firmware_is_valid()) + psci_ver = ppa_support_psci_version(); + + return psci_ver; +} +#endif + +int sec_firmware_init(void) +{ + u64 ppa_entry; + int ret; + + ret = ppa_init_pre(&ppa_entry); + + if (!ret && ppa_entry) { + ret = ppa_init_entry((void *)ppa_entry); + if (ret) + printf("fsl-ppa: failed to initialze PPA\n"); + } else { + printf("fsl-ppa: failed to get the PPA entry\n"); + } + + return ret; +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ppa_entry.S b/arch/arm/cpu/armv8/fsl-layerscape/ppa_entry.S new file mode 100644 index 0000000..a17869f --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/ppa_entry.S @@ -0,0 +1,53 @@ +/* + * Copyright 2016 NXP Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <linux/linkage.h> +#include <asm/system.h> +#include <asm/macro.h> + +ENTRY(ppa_init) + /* + * x0: PPA entry point + * x1: Boot Location Pointer Low + * x2: Boot Location Pointer High + */ + + /* Save stack pointer for EL2 */ + mov x3, sp + msr sp_el2, x3 + + /* Set boot loc pointer */ + adr x4, 1f + mov x3, x4 +#if defined(CONFIG_FSL_LSCH2) + rev w3, w3 +#endif + str w3, [x1] + lsr x3, x4, #32 +#if defined(CONFIG_FSL_LSCH2) + rev w3, w3 +#endif + str w3, [x2] + +/* Call PPA monitor */ + br x0 + +1: + mov x0, #0 + ret +ENDPROC(ppa_init) + +#ifdef CONFIG_ARMV8_PSCI +ENTRY(ppa_support_psci_version) + mov x0, 0x84000000 + mov x1, 0x0 + mov x2, 0x0 + mov x3, 0x0 + smc #0 + ret +ENDPROC(ppa_support_psci_version) +#endif diff --git a/arch/arm/include/asm/arch-fsl-layerscape/ppa.h b/arch/arm/include/asm/arch-fsl-layerscape/ppa.h new file mode 100644 index 0000000..041f858 --- /dev/null +++ b/arch/arm/include/asm/arch-fsl-layerscape/ppa.h @@ -0,0 +1,14 @@ +/* + * Copyright 2016 NXP Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FSL_PPA_H_ +#define __FSL_PPA_H_ + +int ppa_init(void *, u32*, u32*); +unsigned long ppa_get_dram_block_size(void); +unsigned int ppa_support_psci_version(void); + +#endif diff --git a/arch/arm/include/asm/armv8/sec_firmware.h b/arch/arm/include/asm/armv8/sec_firmware.h index e2591aa..29f2c38 100644 --- a/arch/arm/include/asm/armv8/sec_firmware.h +++ b/arch/arm/include/asm/armv8/sec_firmware.h @@ -7,6 +7,10 @@ #ifndef __SEC_FIRMWARE_H_ #define __SEC_FIRMWARE_H_ +#ifdef CONFIG_FSL_LS_PPA +#include <asm/arch/ppa.h> +#endif + int sec_firmware_init(void); bool sec_firmware_is_valid(void); #ifdef CONFIG_ARMV8_PSCI -- 2.1.0.27.g96db324 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot