[U-Boot] [PATCHV5 3/6] ARMv8/layerscape: Add FSL PPA support

York Sun york.sun at nxp.com
Wed Jun 8 02:51:02 CEST 2016


On 06/04/2016 11:40 PM, Zhiqiang Hou wrote:
> From: Hou Zhiqiang <Zhiqiang.Hou at 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.Hou at 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 at 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


Zhiqiang,

I am not convinced this function can be used to prove ppa is up and running, as
you used in your 4th patch in this set. See more comment there.

This function can return a psci version number based on the image. Is it
possible to make a PSCI call to return the version of running image?

York



More information about the U-Boot mailing list