From: Mikael Olsson Date: Fri, 13 Jan 2023 08:56:41 +0000 (+0100) Subject: feat(ethos-n): add NPU firmware validation X-Git-Tag: baikal/aarch64/sdk5.10~1^2~111^2~9 X-Git-Url: https://git.baikalelectronics.ru/?a=commitdiff_plain;h=313b776f851ed184abb265df2b6269fe78f48ecd;p=arm-tf.git feat(ethos-n): add NPU firmware validation When the Arm(R) Ethos(TM)-N NPU driver is built with TZMP1 support, it will now validate the NPU firmware binary that BL2 is expected to load into the protected memory location specified by ARM_ETHOSN_NPU_IMAGE_BASE. Juno has been updated with a new BL31 memory mapping to allow the SiP service to read the protected memory that contains the NPU firmware binary. Signed-off-by: Mikael Olsson Change-Id: I633256ab7dd4f8f5a6f864c8c98a66bf9dfc37f3 --- diff --git a/drivers/arm/ethosn/ethosn_big_fw.c b/drivers/arm/ethosn/ethosn_big_fw.c new file mode 100644 index 000000000..9bb33eac8 --- /dev/null +++ b/drivers/arm/ethosn/ethosn_big_fw.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "ethosn_big_fw.h" + +/* Magic (FourCC) number to identify the big firmware binary */ +#define ETHOSN_BIG_FW_MAGIC ('E' | ('N' << 8) | ('F' << 16) | ('W' << 24)) + +/* Supported big firmware version */ +#define ETHOSN_BIG_FW_VERSION_MAJOR 9 + +#define ETHOSN_ARCH_VER_MAJOR_MASK U(0xF000) +#define ETHOSN_ARCH_VER_MAJOR_SHIFT U(0xC) +#define ETHOSN_ARCH_VER_MINOR_MASK U(0xF00) +#define ETHOSN_ARCH_VER_MINOR_SHIFT U(0x8) +#define ETHOSN_ARCH_VER_REV_MASK U(0xFF) + +/* Convert Arm(R) Ethos(TM)-N NPU architecture version to big firmware format */ +#define ETHOSN_BIG_FW_FORMAT_ARCH_VER(arch_ver) \ + (arch_ver & ETHOSN_ARCH_VER_MAJOR_MASK) << ETHOSN_ARCH_VER_MAJOR_SHIFT | \ + (arch_ver & ETHOSN_ARCH_VER_MINOR_MASK) << ETHOSN_ARCH_VER_MINOR_SHIFT | \ + (arch_ver & ETHOSN_ARCH_VER_REV_MASK) + + +bool ethosn_big_fw_verify_header(const struct ethosn_big_fw *big_fw, + uint32_t npu_arch_ver) +{ + const uint32_t arch_ver = ETHOSN_BIG_FW_FORMAT_ARCH_VER(npu_arch_ver); + + if (big_fw->fw_magic != ETHOSN_BIG_FW_MAGIC) { + ERROR("ETHOSN: Unable to find firmware. Invalid magic value: 0x%02x\n", + big_fw->fw_magic); + + return false; + } + + if (big_fw->fw_ver_major != ETHOSN_BIG_FW_VERSION_MAJOR) { + ERROR("ETHOSN: Unsupported firmware version: %u.%u.%u. Expected Version %u.x.x.\n", + big_fw->fw_ver_major, big_fw->fw_ver_minor, + big_fw->fw_ver_patch, ETHOSN_BIG_FW_VERSION_MAJOR); + + return false; + } + + if (big_fw->arch_min > arch_ver || arch_ver > big_fw->arch_max) { + ERROR("ETHOSN: Firmware is not compatbile with architecture version: 0x%02x\n", + npu_arch_ver); + return false; + } + + return true; +} diff --git a/drivers/arm/ethosn/ethosn_big_fw.h b/drivers/arm/ethosn/ethosn_big_fw.h new file mode 100644 index 000000000..a3213229f --- /dev/null +++ b/drivers/arm/ethosn/ethosn_big_fw.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +/* + * Big FW binary structure. + * Must be kept in sync with the Arm(R) Ethos(TM)-N NPU firmware binary layout. + */ +struct ethosn_big_fw { + uint32_t fw_magic; + uint32_t fw_ver_major; + uint32_t fw_ver_minor; + uint32_t fw_ver_patch; + uint32_t arch_min; + uint32_t arch_max; + uint32_t offset; + uint32_t size; + uint32_t code_offset; + uint32_t code_size; + uint32_t ple_offset; + uint32_t ple_size; + uint32_t vector_table_offset; + uint32_t vector_table_size; + uint32_t unpriv_stack_offset; + uint32_t unpriv_stack_size; + uint32_t priv_stack_offset; + uint32_t priv_stack_size; +} __packed; + +bool ethosn_big_fw_verify_header(const struct ethosn_big_fw *big_fw, + uint32_t npu_arch_ver); diff --git a/drivers/arm/ethosn/ethosn_smc.c b/drivers/arm/ethosn/ethosn_smc.c index 6b1ab85dc..e314577a3 100644 --- a/drivers/arm/ethosn/ethosn_smc.c +++ b/drivers/arm/ethosn/ethosn_smc.c @@ -17,6 +17,10 @@ #include +#if ARM_ETHOSN_NPU_TZMP1 +#include "ethosn_big_fw.h" +#endif + /* * Number of Arm(R) Ethos(TM)-N NPU (NPU) devices available */ @@ -56,10 +60,18 @@ #define SEC_MMUSID_REG_BASE U(0x3008) #define SEC_MMUSID_OFFSET U(0x1000) +#define SEC_NPU_ID_REG U(0xF000) +#define SEC_NPU_ID_ARCH_VER_SHIFT U(0X10) + #define INPUT_STREAM_INDEX U(0x6) #define INTERMEDIATE_STREAM_INDEX U(0x7) #define OUTPUT_STREAM_INDEX U(0x8) +#if ARM_ETHOSN_NPU_TZMP1 +CASSERT(ARM_ETHOSN_NPU_FW_IMAGE_BASE > 0U, assert_ethosn_invalid_fw_image_base); +static const struct ethosn_big_fw *big_fw; +#endif + static bool ethosn_get_device_and_core(uintptr_t core_addr, const struct ethosn_device_t **dev_match, const struct ethosn_core_t **core_match) @@ -86,6 +98,14 @@ static bool ethosn_get_device_and_core(uintptr_t core_addr, } #if ARM_ETHOSN_NPU_TZMP1 +static uint32_t ethosn_core_read_arch_version(uintptr_t core_addr) +{ + uint32_t npu_id = mmio_read_32(ETHOSN_CORE_SEC_REG(core_addr, + SEC_NPU_ID_REG)); + + return (npu_id >> SEC_NPU_ID_ARCH_VER_SHIFT); +} + static void ethosn_configure_stream_nsaid(const struct ethosn_core_t *core, bool is_protected) { @@ -289,10 +309,39 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid, int ethosn_smc_setup(void) { +#if ARM_ETHOSN_NPU_TZMP1 + struct ethosn_device_t *dev; + uint32_t arch_ver; +#endif + if (ETHOSN_NUM_DEVICES == 0U) { ERROR("ETHOSN: No NPU found\n"); return ETHOSN_FAILURE; } +#if ARM_ETHOSN_NPU_TZMP1 + + /* Only one NPU core is supported in the TZMP1 setup */ + if ((ETHOSN_NUM_DEVICES != 1U) || + (ETHOSN_GET_DEVICE(0U)->num_cores != 1U)) { + ERROR("ETHOSN: TZMP1 doesn't support multiple NPU cores\n"); + return ETHOSN_FAILURE; + } + + dev = ETHOSN_GET_DEVICE(0U); + arch_ver = ethosn_core_read_arch_version(dev->cores[0U].addr); + big_fw = (struct ethosn_big_fw *)ARM_ETHOSN_NPU_FW_IMAGE_BASE; + + if (!ethosn_big_fw_verify_header(big_fw, arch_ver)) { + return ETHOSN_FAILURE; + } + + NOTICE("ETHOSN: TZMP1 setup succeeded with firmware version %u.%u.%u\n", + big_fw->fw_ver_major, big_fw->fw_ver_minor, + big_fw->fw_ver_patch); +#else + NOTICE("ETHOSN: Setup succeeded\n"); +#endif + return 0; } diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h index ef37104e9..5eaec698d 100644 --- a/plat/arm/board/juno/include/platform_def.h +++ b/plat/arm/board/juno/include/platform_def.h @@ -66,6 +66,11 @@ MT_MEMORY | MT_RO | MT_NS) #ifdef JUNO_ETHOSN_TZMP1 +#define JUNO_ETHOSN_PROT_FW_RO MAP_REGION_FLAT( \ + JUNO_ETHOSN_FW_TZC_PROT_DRAM2_BASE, \ + JUNO_ETHOSN_FW_TZC_PROT_DRAM2_SIZE, \ + MT_RO_DATA | MT_SECURE) + #define JUNO_ETHOSN_PROT_FW_RW MAP_REGION_FLAT( \ JUNO_ETHOSN_FW_TZC_PROT_DRAM2_BASE, \ JUNO_ETHOSN_FW_TZC_PROT_DRAM2_SIZE, \ @@ -126,8 +131,8 @@ #endif #ifdef IMAGE_BL31 -# define PLAT_ARM_MMAP_ENTRIES 7 -# define MAX_XLAT_TABLES 5 +# define PLAT_ARM_MMAP_ENTRIES 8 +# define MAX_XLAT_TABLES 6 #endif #ifdef IMAGE_BL32 diff --git a/plat/arm/board/juno/juno_common.c b/plat/arm/board/juno/juno_common.c index 584b2ed72..02614da4a 100644 --- a/plat/arm/board/juno/juno_common.c +++ b/plat/arm/board/juno/juno_common.c @@ -79,6 +79,9 @@ const mmap_region_t plat_arm_mmap[] = { #endif SOC_CSS_MAP_DEVICE, ARM_DTB_DRAM_NS, +#ifdef JUNO_ETHOSN_TZMP1 + JUNO_ETHOSN_PROT_FW_RO, +#endif {0} }; #endif diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk index e424ec07c..fca6f4f95 100644 --- a/plat/arm/common/arm_common.mk +++ b/plat/arm/common/arm_common.mk @@ -359,6 +359,9 @@ ifeq (${ARM_ETHOSN_NPU_DRIVER},1) ARM_SVC_HANDLER_SRCS += plat/arm/common/fconf/fconf_ethosn_getter.c \ drivers/delay_timer/delay_timer.c \ drivers/arm/ethosn/ethosn_smc.c +ifeq (${ARM_ETHOSN_NPU_TZMP1},1) +ARM_SVC_HANDLER_SRCS += drivers/arm/ethosn/ethosn_big_fw.c +endif endif ifeq (${ARCH}, aarch64)