From 9ae5f67306b380c626a74782eff9e98b7f7996ee Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Mon, 13 May 2024 10:25:40 +0100 Subject: [PATCH 1/8] feat(spm): use xfer list with Hob list in SPM_MM According to Platform Initialization (PI) Specification [1] and Discussion on edk2 mailing list [2], StandaloneMm shouldn't create Hob but it should be passed from TF-A. IOW, TF-A should pass boot information via PHIT Hob to initialise StandaloneMm properly. This patch applies using transfer list with PHIT Hob list [3] for delivering boot information to StandaloneMm. Link: https://uefi.org/sites/default/files/resources/PI_Spec_1_6.pdf [1] Link: https://edk2.groups.io/g/devel/topic/103675962#114283 [2] Link: https://github.com/FirmwareHandoff/firmware_handoff [3] Signed-off-by: Levi Yun Change-Id: I3df71a7679abf9859612afc8a5be7b2381007311 --- services/std_svc/spm/spm_mm/spm_mm_setup.c | 134 ++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/services/std_svc/spm/spm_mm/spm_mm_setup.c b/services/std_svc/spm/spm_mm/spm_mm_setup.c index de054597c..66ce84c0a 100644 --- a/services/std_svc/spm/spm_mm/spm_mm_setup.c +++ b/services/std_svc/spm/spm_mm/spm_mm_setup.c @@ -13,6 +13,15 @@ #include #include #include +#if HOB_LIST +#include +#include +#include +#include +#endif +#if TRANSFER_LIST +#include +#endif #include #include #include @@ -23,6 +32,92 @@ #include "spm_mm_private.h" #include "spm_shim_private.h" +#if HOB_LIST && TRANSFER_LIST +static struct efi_hob_handoff_info_table *build_sp_boot_hob_list( + const spm_mm_boot_info_t *sp_boot_info, uint16_t *hob_table_size) +{ + int ret; + struct efi_hob_handoff_info_table *hob_table; + struct efi_guid ns_buf_guid = MM_NS_BUFFER_GUID; + struct efi_guid mmram_resv_guid = MM_PEI_MMRAM_MEMORY_RESERVE_GUID; + struct efi_mmram_descriptor *mmram_desc_data; + uint16_t mmram_resv_data_size; + struct efi_mmram_hob_descriptor_block *mmram_hob_desc_data; + uint64_t hob_table_offset; + + hob_table_offset = sizeof(struct transfer_list_header) + + sizeof(struct transfer_list_entry); + + *hob_table_size = 0U; + + hob_table = create_hob_list(sp_boot_info->sp_mem_base, + sp_boot_info->sp_mem_limit - sp_boot_info->sp_mem_base, + sp_boot_info->sp_shared_buf_base + hob_table_offset, + sp_boot_info->sp_shared_buf_size); + if (hob_table == NULL) { + return NULL; + } + + ret = create_fv_hob(hob_table, sp_boot_info->sp_image_base, + sp_boot_info->sp_image_size); + if (ret) { + return NULL; + } + + ret = create_guid_hob(hob_table, &ns_buf_guid, + sizeof(struct efi_mmram_descriptor), (void **) &mmram_desc_data); + if (ret) { + return NULL; + } + + mmram_desc_data->physical_start = sp_boot_info->sp_ns_comm_buf_base; + mmram_desc_data->physical_size = sp_boot_info->sp_ns_comm_buf_size; + mmram_desc_data->cpu_start = sp_boot_info->sp_ns_comm_buf_base; + mmram_desc_data->region_state = EFI_CACHEABLE | EFI_ALLOCATED; + + mmram_resv_data_size = sizeof(struct efi_mmram_hob_descriptor_block) + + sizeof(struct efi_mmram_descriptor) * sp_boot_info->num_sp_mem_regions; + + ret = create_guid_hob(hob_table, &mmram_resv_guid, + mmram_resv_data_size, (void **) &mmram_hob_desc_data); + if (ret) { + return NULL; + } + + *hob_table_size = hob_table->efi_free_memory_bottom - + (efi_physical_address_t) hob_table; + + mmram_hob_desc_data->number_of_mm_reserved_regions = 4U; + mmram_desc_data = &mmram_hob_desc_data->descriptor[0]; + + /* First, should be image mm range. */ + mmram_desc_data[0].physical_start = sp_boot_info->sp_image_base; + mmram_desc_data[0].physical_size = sp_boot_info->sp_image_size; + mmram_desc_data[0].cpu_start = sp_boot_info->sp_image_base; + mmram_desc_data[0].region_state = EFI_CACHEABLE | EFI_ALLOCATED; + + /* Second, should be shared buffer mm range. */ + mmram_desc_data[1].physical_start = sp_boot_info->sp_shared_buf_base; + mmram_desc_data[1].physical_size = sp_boot_info->sp_shared_buf_size; + mmram_desc_data[1].cpu_start = sp_boot_info->sp_shared_buf_base; + mmram_desc_data[1].region_state = EFI_CACHEABLE | EFI_ALLOCATED; + + /* Ns Buffer mm range */ + mmram_desc_data[2].physical_start = sp_boot_info->sp_ns_comm_buf_base; + mmram_desc_data[2].physical_size = sp_boot_info->sp_ns_comm_buf_size; + mmram_desc_data[2].cpu_start = sp_boot_info->sp_ns_comm_buf_base; + mmram_desc_data[2].region_state = EFI_CACHEABLE | EFI_ALLOCATED; + + /* Heap mm range */ + mmram_desc_data[3].physical_start = sp_boot_info->sp_heap_base; + mmram_desc_data[3].physical_size = sp_boot_info->sp_heap_size; + mmram_desc_data[3].cpu_start = sp_boot_info->sp_heap_base; + mmram_desc_data[3].region_state = EFI_CACHEABLE; + + return hob_table; +} +#endif + /* Setup context of the Secure Partition */ void spm_sp_setup(sp_context_t *sp_ctx) { @@ -32,6 +127,15 @@ void spm_sp_setup(sp_context_t *sp_ctx) const spm_mm_boot_info_t *sp_boot_info = plat_get_secure_partition_boot_info(NULL); +#if HOB_LIST && TRANSFER_LIST + struct efi_hob_handoff_info_table *hob_table; + struct transfer_list_header *sp_boot_tl; + struct transfer_list_entry *sp_boot_te; + uint16_t hob_table_size; +#endif + + assert(sp_boot_info != NULL); + /* * Initialize CPU context * ---------------------- @@ -195,7 +299,35 @@ void spm_sp_setup(sp_context_t *sp_ctx) * Prepare information in buffer shared between EL3 and S-EL0 * ---------------------------------------------------------- */ +#if HOB_LIST && TRANSFER_LIST + sp_boot_tl = transfer_list_init((void *) sp_boot_info->sp_shared_buf_base, + sp_boot_info->sp_shared_buf_size); + assert(sp_boot_tl != NULL); + hob_table = build_sp_boot_hob_list(sp_boot_info, &hob_table_size); + assert(hob_table != NULL); + + transfer_list_update_checksum(sp_boot_tl); + + sp_boot_te = transfer_list_add(sp_boot_tl, TL_TAG_HOB_LIST, + hob_table_size, hob_table); + if (sp_boot_te == NULL) { + ERROR("Failed to add HOB list to xfer list\n"); + } + + transfer_list_set_handoff_args(sp_boot_tl, &ep_info); + + transfer_list_dump(sp_boot_tl); + + write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X0, + ep_info.args.arg0); + write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X1, + ep_info.args.arg1); + write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X2, + ep_info.args.arg2); + write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X3, + ep_info.args.arg3); +#else void *shared_buf_ptr = (void *) sp_boot_info->sp_shared_buf_base; /* Copy the boot information into the shared buffer with the SP. */ @@ -205,7 +337,6 @@ void spm_sp_setup(sp_context_t *sp_ctx) assert(sp_boot_info->sp_shared_buf_base <= (UINTPTR_MAX - sp_boot_info->sp_shared_buf_size + 1)); - assert(sp_boot_info != NULL); memcpy((void *) shared_buf_ptr, (const void *) sp_boot_info, sizeof(spm_mm_boot_info_t)); @@ -256,4 +387,5 @@ void spm_sp_setup(sp_context_t *sp_ctx) if (plat_my_core_pos() == sp_mp_info[index].linear_id) sp_mp_info[index].flags |= MP_INFO_FLAG_PRIMARY_CPU; } +#endif } From 8416e7917f9c82336e900659d35038942418582f Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Wed, 24 Jul 2024 18:03:58 +0100 Subject: [PATCH 2/8] feat(fvp): add StandaloneMm manifest in fvp Support StandaloneMm running with FF-A as S-EL0 SP when TF-A is built with EL3 SPMC partition manager. For this 1. add manifest file describing StandaloneMm partition. 2. add number of page mapping area. 3. StandaloneMm should use SRAM with 512K. while enabling, StandaloneMm, BL1 image requires more size: aarch64-none-elf/bin/ld: BL31 image has exceeded its limit. aarch64-none-elf/bin/ld: region `RAM' overflowed by 16384 bytes So, when using SRAM size with 512K configuration, increase size limit of BL1 binary. Signed-off-by: Levi Yun Change-Id: Idaa1db510340ebb812cfd13588610b2eea941918 --- plat/arm/board/fvp/fdts/fvp_stmm_manifest.dts | 146 ++++++++++++++++++ plat/arm/board/fvp/include/platform_def.h | 5 +- 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 plat/arm/board/fvp/fdts/fvp_stmm_manifest.dts diff --git a/plat/arm/board/fvp/fdts/fvp_stmm_manifest.dts b/plat/arm/board/fvp/fdts/fvp_stmm_manifest.dts new file mode 100644 index 000000000..df6810f56 --- /dev/null +++ b/plat/arm/board/fvp/fdts/fvp_stmm_manifest.dts @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/dts-v1/; + +#include + +/ { +#define MODE_SEL0 (0x1) +#define MODE_SEL1 (0x2) + +#define SECURE_RO 0x1 +#define SECURE_RW 0x3 +#define SECURE_EXECUTE_RO 0x5 +#define SECURE_EXECUTE_RW 0x7 +#define NON_SECURE_RO 0x9 +#define NON_SECURE_RW 0xB +#define NON_SECURE_EXECUTE_RO 0xD +#define NON_SECURE_EXECUTE_RW 0xF + /* + * FF-A compatible Secure Partition Manager parses the + * config file and fetch the following booting arguments to + * pass on to the StandAloneMM(StMM) Secure Partition. + */ + compatible = "arm,ffa-manifest-1.0"; + + description = "FVP Base StandaloneMm"; + ffa-version = <0x00010002>; /* 31:16 - Major, 15:0 - Minor */ + uuid = <0xdcae8d37 0x46446bf0 0xab401483 0xa3873c93>; + id = <0x8001>; + execution-ctx-count = ; + exception-level = ; /* SEL0*/ + execution-state = <0>; /* AArch64*/ + load-address = <0x0 0xff200000>; + image-size = <0x0 0x00300000>; + xlat-granule = <0>; /* 4KiB */ + boot-order = <0>; + messaging-method = <0x603>; /* Direct req/resp/req2/resp2 supported. */ + gp-register-num = <0>; + + device-regions { + compatible = "arm,ffa-manifest-device-regions"; + + /** + * System registers, rtc, uart and etc regions for access from S-EL0. + */ + io_fpga { + base-address = <0x0 0x1C000000>; + pages-count = <0x3000>; + attributes = ; + }; + + system_reg_el0 { + base-address = <0x0 0x1C010000>; + pages-count = <0x10>; + attributes = ; + }; + + /** + * ARM CSS SoC Peripherals area. + * Similar to SOC_CSS_MAP_DEVICE. + */ + soc_components { + base-address = <0x0 0x20000000>; + pages-count = <0xc200>; + attributes = ; + }; + + /** + * NOR0 Flash region, used for Firmware Image Update. + */ + nor_flash0 { + base-address = <0x0 0x08000000>; + pages-count = <0x4000>; + attributes = ; + }; + + /** + * NOR1 Flash region, used for Secure booting. + */ + nor_flash1 { + base-address = <0x0 0x0c000000>; + pages-count = <0x4000>; + attributes = ; + }; + }; + + memory-regions { + compatible = "arm,ffa-manifest-memory-regions"; + + /* + * SPM Payload memory. Mapped as code region for S-EL0 + * Similar to ARM_SP_IMAGE_MMAP. + */ + stmm_region { + description = "image"; + base-address = <0x0 0xff200000>; + pages-count = <0x300>; + /* StMM will remap the regions during runtime */ + attributes = ; + }; + + /* + * Memory shared between EL3 and S-EL0. + * Similar to ARM_SPM_BUF_EL0_MMAP. + */ + rx-tx-buffers { + description = "shared-buff"; + base-address = <0x0 0xff500000>; + pages-count = <0x100>; + attributes = ; + }; + + /* + * Memory shared between Normal world and S-EL0. + * Similar to ARM_SP_IMAGE_NS_BUF_MMAP. + */ + ns_comm_buffer { + /* + * Description is needed for StMM to identify + * ns-communication buffer. + */ + description = "ns-comm"; + base-address = <0x0 0xff600000>; + pages-count = <0x10>; + attributes = ; + }; + + /* + * Heap used by SP to allocate memory for DMA. + */ + heap { + /* + * Description is needed for StMM to identify + * heap buffer. + */ + description = "heap"; + base-address = <0x0 0xFF610000>; + pages-count = <0x7F0>; + attributes = ; + }; + }; +}; diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h index e0c9725ce..df4be8f7c 100644 --- a/plat/arm/board/fvp/include/platform_def.h +++ b/plat/arm/board/fvp/include/platform_def.h @@ -170,6 +170,8 @@ # elif SPMC_AT_EL3 # define PLAT_ARM_MMAP_ENTRIES 13 # define MAX_XLAT_TABLES 11 +# define PLAT_SP_IMAGE_MMAP_REGIONS 30 +# define PLAT_SP_IMAGE_MAX_XLAT_TABLES 10 # else # define PLAT_ARM_MMAP_ENTRIES 9 # if USE_DEBUGFS @@ -220,7 +222,8 @@ defined(IMAGE_BL2) && MEASURED_BOOT * In case of PSA Crypto API, few algorithms like ECDSA needs bigger BL1 RW * area. */ -#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA || PSA_CRYPTO +#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA || PSA_CRYPTO || \ +FVP_TRUSTED_SRAM_SIZE == 512 #define PLAT_ARM_MAX_BL1_RW_SIZE UL(0xC000) #else #define PLAT_ARM_MAX_BL1_RW_SIZE UL(0xB000) From 06cec933def225ef64d81983829c349f47b89319 Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Thu, 8 Aug 2024 13:13:23 +0100 Subject: [PATCH 3/8] fix(fvp): exclude extend memory map TZC regions The commit 192287523350 ("fix(spm-mm): carve out NS buffer TZC400 region") removes overlaps of ns shared buffer in secure memory region. Unfortunately, this separation increases 1 region and over maximum number of TZC programmable regions when they include extended memory map regions (DRAM3 to DRAM6). This causes boot failure of StandaloneMm with spmc_el3 && sp_el0 with ASSERT: drivers/arm/tzc/tzc400.c:256. To fix this, like SPM_MM, exclude setting extended memory map regions when it uses SPMC_AT_EL3 && SPC_AT_EL3_SEL0_SP. Signed-off-by: Levi Yun Change-Id: I2d40bea066ca030050dfe951218cd17171010676 --- plat/arm/board/fvp/fvp_security.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plat/arm/board/fvp/fvp_security.c b/plat/arm/board/fvp/fvp_security.c index 573d92efb..5b970346f 100644 --- a/plat/arm/board/fvp/fvp_security.c +++ b/plat/arm/board/fvp/fvp_security.c @@ -24,7 +24,7 @@ void plat_arm_security_setup(void) const arm_tzc_regions_info_t fvp_tzc_regions[] = { ARM_TZC_REGIONS_DEF, -#if !SPM_MM && !ENABLE_RME +#if !SPM_MM && !ENABLE_RME && !(SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP) {FVP_DRAM3_BASE, FVP_DRAM3_END, ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS}, {FVP_DRAM4_BASE, FVP_DRAM4_END, From 357f28db6bcca7856a8cdbedfe6ce4668b06b48c Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Tue, 27 Aug 2024 15:31:55 +0100 Subject: [PATCH 4/8] feat(synquacer): add support Hob creation When StandaloneMm used with SPM_MM, TF-A should create PHIT Hob to boot it. This patch supports Hob creation for StandaloneMm in synquacer platform. Signed-off-by: Levi Yun Change-Id: Ifa3ae1f0aa37f389aabb14f48be307502ae6fc2c --- plat/socionext/synquacer/platform.mk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plat/socionext/synquacer/platform.mk b/plat/socionext/synquacer/platform.mk index e4ae87bd4..7a5a03cdc 100644 --- a/plat/socionext/synquacer/platform.mk +++ b/plat/socionext/synquacer/platform.mk @@ -25,6 +25,14 @@ endif # Libraries include lib/xlat_tables_v2/xlat_tables.mk +ifeq (${TRANSFER_LIST}, 1) +include lib/transfer_list/transfer_list.mk +endif + +ifeq (${HOB_LIST}, 1) +include lib/hob/hob.mk +endif + PLAT_PATH := plat/socionext/synquacer PLAT_INCLUDES := -I$(PLAT_PATH)/include \ -I$(PLAT_PATH)/drivers/scpi \ From 4053a647f6eca71e5a34bc52303a049e3324ca90 Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Thu, 8 Feb 2024 13:14:42 +0000 Subject: [PATCH 5/8] feat(el3-spmc): support Hob list to boot S-EL0 SP The EDKII/StandaloneMm module runs as a S-EL0 partition on top of the EL3 FF-A SPMC. In the past the StandaloneMm partition received its boot information through the use of a device tree (DT) passed through the FF-A boot protocol. The StandaloneMm itself converted the DT into a HOB. To better match the UEFI PI spec, the EL3 SPMC must now produce the HOB including the PHIT (Phase Handoff Information Table) as first item in the HOB list. The SPMC then passes the HOB through the FF-A boot protocol for the StandaloneMm consumption. This discards the use of a DT between the SPMC and the StandaloneMm partition. Signed-off-by: Levi Yun Change-Id: I22fb02c710169bd5a5ba1d1f60dce977a5a59ab6 --- services/std_svc/spm/el3_spmc/spmc_main.c | 33 ++- services/std_svc/spm/el3_spmc/spmc_setup.c | 271 +++++++++++++++++++-- 2 files changed, 259 insertions(+), 45 deletions(-) diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c index c6ec30c3d..d7879afe6 100644 --- a/services/std_svc/spm/el3_spmc/spmc_main.c +++ b/services/std_svc/spm/el3_spmc/spmc_main.c @@ -2077,39 +2077,34 @@ static int find_and_prepare_sp_context(void) return ret; } - /* Check that the runtime EL in the manifest was correct. */ - if (sp->runtime_el != S_EL0 && sp->runtime_el != S_EL1) { - ERROR("Unexpected runtime EL: %d\n", sp->runtime_el); - return -EINVAL; - } - /* Perform any common initialisation. */ spmc_sp_common_setup(sp, next_image_ep_info, boot_info_reg); /* Perform any initialisation specific to S-EL1 SPs. */ if (sp->runtime_el == S_EL1) { spmc_el1_sp_setup(sp, next_image_ep_info); + spmc_sp_common_ep_commit(sp, next_image_ep_info); } - #if SPMC_AT_EL3_SEL0_SP - /* Setup spsr in endpoint info for common context management routine. */ - if (sp->runtime_el == S_EL0) { + /* Perform any initialisation specific to S-EL0 SPs. */ + else if (sp->runtime_el == S_EL0) { + /* Setup spsr in endpoint info for common context management routine. */ spmc_el0_sp_spsr_setup(next_image_ep_info); - } -#endif /* SPMC_AT_EL3_SEL0_SP */ - /* Initialize the SP context with the required ep info. */ - spmc_sp_common_ep_commit(sp, next_image_ep_info); + spmc_sp_common_ep_commit(sp, next_image_ep_info); -#if SPMC_AT_EL3_SEL0_SP - /* - * Perform any initialisation specific to S-EL0 not set by common - * context management routine. - */ - if (sp->runtime_el == S_EL0) { + /* + * Perform any initialisation specific to S-EL0 not set by common + * context management routine. + */ spmc_el0_sp_setup(sp, boot_info_reg, sp_manifest); } #endif /* SPMC_AT_EL3_SEL0_SP */ + else { + ERROR("Unexpected runtime EL: %u\n", sp->runtime_el); + return -EINVAL; + } + return 0; } diff --git a/services/std_svc/spm/el3_spmc/spmc_setup.c b/services/std_svc/spm/el3_spmc/spmc_setup.c index f7357f1fb..d42115d7c 100644 --- a/services/std_svc/spm/el3_spmc/spmc_setup.c +++ b/services/std_svc/spm/el3_spmc/spmc_setup.c @@ -5,14 +5,22 @@ */ #include +#include #include #include #include #include #include + #include #include +#if HOB_LIST +#include +#include +#include +#include +#endif #include #include #include @@ -51,6 +59,199 @@ enum sp_memory_region_type { SP_MEM_REGION_NOT_SPECIFIED }; + +#if HOB_LIST +static int get_memory_region_info(void *sp_manifest, int mem_region_node, + const char *name, uint32_t granularity, + uint64_t *base_address, uint32_t *size) +{ + char *property; + int node, ret; + + if (name != NULL) { + node = fdt_subnode_offset_namelen(sp_manifest, mem_region_node, + name, strlen(name)); + if (node < 0) { + ERROR("Not found '%s' region in memory regions configuration for SP.\n", + name); + return -ENOENT; + } + } else { + node = mem_region_node; + } + + property = "base-address"; + ret = fdt_read_uint64(sp_manifest, node, property, base_address); + if (ret < 0) { + ERROR("Not found property(%s) in memory region(%s).\n", + property, name); + return -ENOENT; + } + + property = "pages-count"; + ret = fdt_read_uint32(sp_manifest, node, property, size); + if (ret < 0) { + ERROR("Not found property(%s) in memory region(%s).\n", + property, name); + return -ENOENT; + } + + *size = ((*size) << (PAGE_SIZE_SHIFT + (granularity << 1))); + + return 0; +} + +static struct efi_hob_handoff_info_table *build_sp_boot_hob_list( + void *sp_manifest, uintptr_t hob_table_start, size_t *hob_table_size) +{ + struct efi_hob_handoff_info_table *hob_table; + uintptr_t base_address; + int mem_region_node; + int32_t node, ret; + const char *name; + uint32_t granularity, size; + uint32_t mem_region_num; + struct efi_guid ns_buf_guid = MM_NS_BUFFER_GUID; + struct efi_guid mmram_resv_guid = MM_PEI_MMRAM_MEMORY_RESERVE_GUID; + struct efi_mmram_descriptor *mmram_desc_data; + struct efi_mmram_hob_descriptor_block *mmram_hob_desc_data; + + if (sp_manifest == NULL || hob_table_size == NULL || *hob_table_size == 0) { + return NULL; + } + + node = fdt_path_offset(sp_manifest, "/"); + if (node < 0) { + ERROR("Failed to get root in sp_manifest.\n"); + return NULL; + } + + ret = fdt_read_uint32(sp_manifest, node, "xlat-granule", &granularity); + if (ret < 0) { + ERROR("Not found property(xlat-granule) in sp_manifest.\n"); + return NULL; + } + + if (granularity > 0x02) { + ERROR("Invalid granularity value: 0x%x\n", granularity); + return NULL; + } + + mem_region_node = fdt_subnode_offset_namelen(sp_manifest, 0, "memory-regions", + sizeof("memory-regions") - 1); + if (node < 0) { + ERROR("Not found memory-region configuration for SP.\n"); + return NULL; + } + + INFO("Generating PHIT_HOB...\n"); + + hob_table = create_hob_list(BL32_BASE, BL32_LIMIT, + hob_table_start, *hob_table_size); + if (hob_table == NULL) { + ERROR("Failed to create Hob Table.\n"); + return NULL; + } + + /* + * Create fv hob. + */ + ret = get_memory_region_info(sp_manifest, mem_region_node, + "stmm_region", granularity, &base_address, &size); + if (ret < 0) { + return NULL; + } + + if (base_address != BL32_BASE && + base_address + size > BL32_LIMIT) { + ERROR("Image is ouf of bound(0x%lx/0x%x), should be in (0x%llx/0x%llx)\n", + base_address, size, BL32_BASE, BL32_LIMIT - BL32_BASE); + return NULL; + } + + ret = create_fv_hob(hob_table, base_address, size); + if (ret < 0) { + ERROR("Failed to create fv hob... ret:%d\n", ret); + return NULL; + } + + INFO("Success to create FV hob(0x%lx/0x%x).\n", base_address, size); + + /* + * Create Ns Buffer hob. + */ + ret = get_memory_region_info(sp_manifest, mem_region_node, + "ns_comm_buffer", granularity, &base_address, &size); + if (ret < 0) { + return NULL; + } + + ret = create_guid_hob(hob_table, &ns_buf_guid, + sizeof(struct efi_mmram_descriptor), (void **) &mmram_desc_data); + if (ret < 0) { + ERROR("Failed to create ns buffer hob\n"); + return NULL; + } + + mmram_desc_data->physical_start = base_address; + mmram_desc_data->physical_size = size; + mmram_desc_data->cpu_start = base_address; + mmram_desc_data->region_state = EFI_CACHEABLE | EFI_ALLOCATED; + + /* + * Create mmram_resv hob. + */ + for (node = fdt_first_subnode(sp_manifest, mem_region_node), mem_region_num = 0; + node >= 0; + node = fdt_next_subnode(sp_manifest, node), mem_region_num++) { + ret = get_memory_region_info(sp_manifest, node, NULL, granularity, + &base_address, &size); + if (ret < 0) { + name = fdt_get_name(sp_manifest, node, NULL); + ERROR("Invalid memory region(%s) found!\n", name); + return NULL; + } + } + + ret = create_guid_hob(hob_table, &mmram_resv_guid, + (sizeof(struct efi_mmram_hob_descriptor_block) + + (sizeof(struct efi_mmram_descriptor) * mem_region_num)), + (void **) &mmram_hob_desc_data); + if (ret < 0) { + ERROR("Failed to create mmram_resv hob. ret: %d\n", ret); + return NULL; + } + + mmram_hob_desc_data->number_of_mm_reserved_regions = mem_region_num; + + for (node = fdt_first_subnode(sp_manifest, mem_region_node), mem_region_num = 0; + node >= 0; + node = fdt_next_subnode(sp_manifest, node), mem_region_num++) { + get_memory_region_info(sp_manifest, node, NULL, granularity, + &base_address, &size); + name = fdt_get_name(sp_manifest, node, NULL); + + mmram_desc_data = &mmram_hob_desc_data->descriptor[mem_region_num]; + mmram_desc_data->physical_start = base_address; + mmram_desc_data->physical_size = size; + mmram_desc_data->cpu_start = base_address; + + if (!strcmp(name, "heap")) { + mmram_desc_data->region_state = EFI_CACHEABLE; + } else { + mmram_desc_data->region_state = EFI_CACHEABLE | EFI_ALLOCATED; + } + } + + *hob_table_size = hob_table->efi_free_memory_bottom - + (efi_physical_address_t) hob_table; + + return hob_table; +} +#endif + + + /* * This function creates a initialization descriptor in the memory reserved * for passing boot information to an SP. It then copies the partition manifest @@ -62,14 +263,13 @@ static void spmc_create_boot_info(entry_point_info_t *ep_info, { struct ffa_boot_info_header *boot_header; struct ffa_boot_info_desc *boot_descriptor; - uintptr_t manifest_addr; + uintptr_t content_addr; /* * Calculate the maximum size of the manifest that can be accommodated * in the boot information memory region. */ - const unsigned int - max_manifest_sz = sizeof(ffa_boot_info_mem) - + size_t max_sz = sizeof(ffa_boot_info_mem) - (sizeof(struct ffa_boot_info_header) + sizeof(struct ffa_boot_info_desc)); @@ -83,17 +283,6 @@ static void spmc_create_boot_info(entry_point_info_t *ep_info, return; } - /* - * Check if the manifest will fit into the boot info memory region else - * bail. - */ - if (ep_info->args.arg1 > max_manifest_sz) { - WARN("Unable to copy manifest into boot information. "); - WARN("Max sz = %u bytes. Manifest sz = %lu bytes\n", - max_manifest_sz, ep_info->args.arg1); - return; - } - /* Zero the memory region before populating. */ memset(ffa_boot_info_mem, 0, PAGE_SIZE); @@ -125,29 +314,58 @@ static void spmc_create_boot_info(entry_point_info_t *ep_info, /* Set the count. Currently 1 since only the manifest is specified. */ boot_header->count_boot_info_desc = 1; + boot_descriptor->flags = + FFA_BOOT_INFO_FLAG_NAME(FFA_BOOT_INFO_FLAG_NAME_UUID) | + FFA_BOOT_INFO_FLAG_CONTENT(FFA_BOOT_INFO_FLAG_CONTENT_ADR); + + content_addr = (uintptr_t) (ffa_boot_info_mem + + boot_header->offset_boot_info_desc + + boot_header->size_boot_info_desc); + +#if HOB_LIST + /* Populate the boot information descriptor for the hob_list. */ + boot_descriptor->type = + FFA_BOOT_INFO_TYPE(FFA_BOOT_INFO_TYPE_STD) | + FFA_BOOT_INFO_TYPE_ID(FFA_BOOT_INFO_TYPE_ID_HOB); + + content_addr = (uintptr_t) build_sp_boot_hob_list( + (void *) ep_info->args.arg0, content_addr, &max_sz); + if (content_addr == (uintptr_t) NULL) { + WARN("Unable to create phit hob properly."); + return; + } + + boot_descriptor->size_boot_info = max_sz; + boot_descriptor->content = content_addr; +#else + /* + * Check if the manifest will fit into the boot info memory region else + * bail. + */ + if (ep_info->args.arg1 > max_sz) { + WARN("Unable to copy manifest into boot information. "); + WARN("Max sz = %lu bytes. Manifest sz = %lu bytes\n", + max_sz, ep_info->args.arg1); + return; + } + /* Populate the boot information descriptor for the manifest. */ boot_descriptor->type = FFA_BOOT_INFO_TYPE(FFA_BOOT_INFO_TYPE_STD) | FFA_BOOT_INFO_TYPE_ID(FFA_BOOT_INFO_TYPE_ID_FDT); - boot_descriptor->flags = - FFA_BOOT_INFO_FLAG_NAME(FFA_BOOT_INFO_FLAG_NAME_UUID) | - FFA_BOOT_INFO_FLAG_CONTENT(FFA_BOOT_INFO_FLAG_CONTENT_ADR); - /* * Copy the manifest into boot info region after the boot information * descriptor. */ boot_descriptor->size_boot_info = (uint32_t) ep_info->args.arg1; - manifest_addr = (uintptr_t) (ffa_boot_info_mem + - boot_header->offset_boot_info_desc + - boot_header->size_boot_info_desc); - memcpy((void *) manifest_addr, (void *) ep_info->args.arg0, + memcpy((void *) content_addr, (void *) ep_info->args.arg0, boot_descriptor->size_boot_info); - boot_descriptor->content = manifest_addr; + boot_descriptor->content = content_addr; +#endif /* Calculate the size of the total boot info blob. */ boot_header->size_boot_info_blob = boot_header->offset_boot_info_desc + @@ -158,7 +376,7 @@ static void spmc_create_boot_info(entry_point_info_t *ep_info, INFO("SP boot info @ 0x%lx, size: %u bytes.\n", (uintptr_t) ffa_boot_info_mem, boot_header->size_boot_info_blob); - INFO("SP manifest @ 0x%lx, size: %u bytes.\n", + INFO("SP content @ 0x%lx, size: %u bytes.\n", boot_descriptor->content, boot_descriptor->size_boot_info); } @@ -194,6 +412,7 @@ static void read_optional_string(void *manifest, int32_t offset, out[0] = '\0'; } else { memcpy(out, prop, MIN(lenp, (int)len)); + out[MIN(lenp, (int)len) - 1] = '\0'; } } @@ -292,10 +511,11 @@ static void populate_sp_regions(struct secure_partition_desc *sp, sp_mem_regions.base_va = base_address; sp_mem_regions.size = size; - INFO("Adding PA: 0x%llx VA: 0x%lx Size: 0x%lx attr:0x%x\n", + INFO("Adding PA: 0x%llx VA: 0x%lx Size: 0x%lx mem_attr: 0x%x, attr:0x%x\n", sp_mem_regions.base_pa, sp_mem_regions.base_va, sp_mem_regions.size, + mem_attr, sp_mem_regions.attr); if (type == SP_MEM_REGION_DEVICE) { @@ -464,7 +684,6 @@ void spmc_el0_sp_setup(struct secure_partition_desc *sp, } spmc_el0_sp_setup_system_registers(sp, ctx); - } #endif /* SPMC_AT_EL3_SEL0_SP */ From ddf72e6a36bd6ef0958af5cfd638926861fe5c21 Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Wed, 7 Aug 2024 16:54:17 +0100 Subject: [PATCH 6/8] feat(ff-a): add FFA_MEM_PERM_GET/SET_SMC64 FF-A memory management protocol v1.1 specifies not only FFA_MEM_PERM_GET_SMC32/FFA_MEM_PERM_SET_SMC32 but also FFA_MEM_PERM_GET_SMC64/FFA_MEM_PERM_SET_SMC64. Change former FFA_MEM_PERM_GET/SET definitions to separate operations and add handler for FFA_MEM_PERM_GET/SET_SMC64 in spmc_smc_handler(). Signed-off-by: Levi Yun Change-Id: I175063654703db26c1ffc3cfd7fa428b94d2bfc9 --- include/services/ffa_svc.h | 6 ++++-- services/std_svc/spm/el3_spmc/spmc_main.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h index 01dbea979..563e0d108 100644 --- a/include/services/ffa_svc.h +++ b/include/services/ffa_svc.h @@ -173,8 +173,8 @@ #define FFA_SPM_ID_GET FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET) #define FFA_NORMAL_WORLD_RESUME FFA_FID(SMC_32, FFA_FNUM_NORMAL_WORLD_RESUME) #define FFA_EL3_INTR_HANDLE FFA_FID(SMC_32, FFA_FNUM_EL3_INTR_HANDLE) -#define FFA_MEM_PERM_GET FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_GET) -#define FFA_MEM_PERM_SET FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_SET) +#define FFA_MEM_PERM_GET_SMC32 FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_GET) +#define FFA_MEM_PERM_SET_SMC32 FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_SET) #define FFA_CONSOLE_LOG_SMC32 FFA_FID(SMC_32, FFA_FNUM_CONSOLE_LOG) /* FFA SMC64 FIDs */ @@ -201,6 +201,8 @@ FFA_FID(SMC_64, FFA_FNUM_MSG_SEND_DIRECT_REQ2) #define FFA_MSG_SEND_DIRECT_RESP2_SMC64 \ FFA_FID(SMC_64, FFA_FNUM_MSG_SEND_DIRECT_RESP2) +#define FFA_MEM_PERM_GET_SMC64 FFA_FID(SMC_64, FFA_FNUM_MEM_PERM_GET) +#define FFA_MEM_PERM_SET_SMC64 FFA_FID(SMC_64, FFA_FNUM_MEM_PERM_SET) /* * FF-A partition properties values. diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c index d7879afe6..f434acd05 100644 --- a/services/std_svc/spm/el3_spmc/spmc_main.c +++ b/services/std_svc/spm/el3_spmc/spmc_main.c @@ -2421,11 +2421,13 @@ uint64_t spmc_smc_handler(uint32_t smc_fid, return spmc_ffa_console_log(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); - case FFA_MEM_PERM_GET: + case FFA_MEM_PERM_GET_SMC32: + case FFA_MEM_PERM_GET_SMC64: return ffa_mem_perm_get_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); - case FFA_MEM_PERM_SET: + case FFA_MEM_PERM_SET_SMC32: + case FFA_MEM_PERM_SET_SMC64: return ffa_mem_perm_set_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); From 09a580b7961827501f94dd3dafbc27c7c5b69237 Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Wed, 7 Aug 2024 18:06:28 +0100 Subject: [PATCH 7/8] feat(ff-a): support FFA_MSG_SEND_DIRECT_REQ2/RESP2 StandaloneMm which is S-EL0 partition uses FFA_MSG_SEND_DIRECT_REQ2/RESP2 to handle multiple services. For this, add support for FFA_MSG_SEND_DIRECT_REQ2/RESP2 in el3_spmc restrictly up to use 8 registers. although FF-A v1.2 defines FFA_MSG_SEND_DIRECT_REQ2/RESP2 with ability to pass/return up to 18 registers. Signed-off-by: Levi Yun Change-Id: I8ab1c332d269d9d131330bb2debd10d75bdba1ee --- include/services/ffa_svc.h | 2 + services/std_svc/spm/el3_spmc/spmc.h | 3 + services/std_svc/spm/el3_spmc/spmc_main.c | 67 +++++++++++++++++++++-- services/std_svc/spm/el3_spmc/spmc_pm.c | 2 + 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h index 563e0d108..f5a9a2dc0 100644 --- a/include/services/ffa_svc.h +++ b/include/services/ffa_svc.h @@ -210,6 +210,8 @@ #define FFA_PARTITION_DIRECT_REQ_RECV U(1 << 0) #define FFA_PARTITION_DIRECT_REQ_SEND U(1 << 1) #define FFA_PARTITION_INDIRECT_MSG U(1 << 2) +#define FFA_PARTITION_DIRECT_REQ2_RECV U(1 << 9) +#define FFA_PARTITION_DIRECT_REQ2_SEND U(1 << 10) /* * Reserve a special value for traffic targeted to the Hypervisor or SPM. diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h index e093a82b2..6fd0f2bbe 100644 --- a/services/std_svc/spm/el3_spmc/spmc.h +++ b/services/std_svc/spm/el3_spmc/spmc.h @@ -134,6 +134,9 @@ struct sp_exec_ctx { /* Track the source partition ID to validate a direct response. */ uint16_t dir_req_origin_id; + + /* Track direct message function id to validate a direct response. */ + uint16_t dir_req_funcid; }; /* diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c index f434acd05..9004ef276 100644 --- a/services/std_svc/spm/el3_spmc/spmc_main.c +++ b/services/std_svc/spm/el3_spmc/spmc_main.c @@ -304,6 +304,7 @@ static bool direct_msg_validate_lp_resp(uint16_t origin_id, uint16_t lp_id, void *handle) { /* Retrieve populated Direct Response Arguments. */ + uint64_t smc_fid = SMC_GET_GP(handle, CTX_GPREG_X0); uint64_t x1 = SMC_GET_GP(handle, CTX_GPREG_X1); uint64_t x2 = SMC_GET_GP(handle, CTX_GPREG_X2); uint16_t src_id = ffa_endpoint_source(x1); @@ -323,13 +324,29 @@ static bool direct_msg_validate_lp_resp(uint16_t origin_id, uint16_t lp_id, return false; } - if (!direct_msg_validate_arg2(x2)) { + if ((smc_fid != FFA_MSG_SEND_DIRECT_RESP2_SMC64) && + !direct_msg_validate_arg2(x2)) { ERROR("Invalid EL3 LP message encoding.\n"); return false; } return true; } +/******************************************************************************* + * Helper function to check that partition can receive direct msg or not. + ******************************************************************************/ +static bool direct_msg_receivable(uint32_t properties, uint16_t dir_req_fnum) +{ + if ((dir_req_fnum == FFA_FNUM_MSG_SEND_DIRECT_REQ && + ((properties & FFA_PARTITION_DIRECT_REQ_RECV) == 0U)) || + (dir_req_fnum == FFA_FNUM_MSG_SEND_DIRECT_REQ2 && + ((properties & FFA_PARTITION_DIRECT_REQ2_RECV) == 0U))) { + return false; + } + + return true; +} + /******************************************************************************* * Handle direct request messages and route to the appropriate destination. ******************************************************************************/ @@ -345,14 +362,21 @@ static uint64_t direct_req_smc_handler(uint32_t smc_fid, { uint16_t src_id = ffa_endpoint_source(x1); uint16_t dst_id = ffa_endpoint_destination(x1); + uint16_t dir_req_funcid; struct el3_lp_desc *el3_lp_descs; struct secure_partition_desc *sp; unsigned int idx; - /* Check if arg2 has been populated correctly based on message type. */ - if (!direct_msg_validate_arg2(x2)) { - return spmc_ffa_error_return(handle, - FFA_ERROR_INVALID_PARAMETER); + dir_req_funcid = (smc_fid != FFA_MSG_SEND_DIRECT_REQ2_SMC64) ? + FFA_FNUM_MSG_SEND_DIRECT_REQ : FFA_FNUM_MSG_SEND_DIRECT_REQ2; + + /* + * Sanity check for DIRECT_REQ: + * Check if arg2 has been populated correctly based on message type + */ + if ((dir_req_funcid == FFA_FNUM_MSG_SEND_DIRECT_REQ) && + !direct_msg_validate_arg2(x2)) { + return spmc_ffa_error_return(handle, FFA_ERROR_INVALID_PARAMETER); } /* Validate Sender is either the current SP or from the normal world. */ @@ -368,6 +392,10 @@ static uint64_t direct_req_smc_handler(uint32_t smc_fid, /* Check if the request is destined for a Logical Partition. */ for (unsigned int i = 0U; i < MAX_EL3_LP_DESCS_COUNT; i++) { if (el3_lp_descs[i].sp_id == dst_id) { + if (!direct_msg_receivable(el3_lp_descs[i].properties, dir_req_funcid)) { + return spmc_ffa_error_return(handle, FFA_ERROR_DENIED); + } + uint64_t ret = el3_lp_descs[i].direct_req( smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); @@ -402,6 +430,10 @@ static uint64_t direct_req_smc_handler(uint32_t smc_fid, FFA_ERROR_INVALID_PARAMETER); } + if (!direct_msg_receivable(sp->properties, dir_req_funcid)) { + return spmc_ffa_error_return(handle, FFA_ERROR_DENIED); + } + /* Protect the runtime state of a UP S-EL0 SP with a lock. */ if (sp->runtime_el == S_EL0) { spin_lock(&sp->rt_state_lock); @@ -430,6 +462,7 @@ static uint64_t direct_req_smc_handler(uint32_t smc_fid, sp->ec[idx].rt_state = RT_STATE_RUNNING; sp->ec[idx].rt_model = RT_MODEL_DIR_REQ; sp->ec[idx].dir_req_origin_id = src_id; + sp->ec[idx].dir_req_funcid = dir_req_funcid; if (sp->runtime_el == S_EL0) { spin_unlock(&sp->rt_state_lock); @@ -453,9 +486,13 @@ static uint64_t direct_resp_smc_handler(uint32_t smc_fid, uint64_t flags) { uint16_t dst_id = ffa_endpoint_destination(x1); + uint16_t dir_req_funcid; struct secure_partition_desc *sp; unsigned int idx; + dir_req_funcid = (smc_fid != FFA_MSG_SEND_DIRECT_RESP2_SMC64) ? + FFA_FNUM_MSG_SEND_DIRECT_REQ : FFA_FNUM_MSG_SEND_DIRECT_REQ2; + /* Check if arg2 has been populated correctly based on message type. */ if (!direct_msg_validate_arg2(x2)) { return spmc_ffa_error_return(handle, @@ -507,6 +544,15 @@ static uint64_t direct_resp_smc_handler(uint32_t smc_fid, return spmc_ffa_error_return(handle, FFA_ERROR_DENIED); } + if (dir_req_funcid != sp->ec[idx].dir_req_funcid) { + WARN("Unmatched direct req/resp func id. req:%x, resp:%x on core%u.\n", + sp->ec[idx].dir_req_funcid, (smc_fid & FUNCID_NUM_MASK), idx); + if (sp->runtime_el == S_EL0) { + spin_unlock(&sp->rt_state_lock); + } + return spmc_ffa_error_return(handle, FFA_ERROR_DENIED); + } + if (sp->ec[idx].dir_req_origin_id != dst_id) { WARN("Invalid direct resp partition ID 0x%x != 0x%x on core%u.\n", dst_id, sp->ec[idx].dir_req_origin_id, idx); @@ -522,6 +568,9 @@ static uint64_t direct_resp_smc_handler(uint32_t smc_fid, /* Clear the ongoing direct request ID. */ sp->ec[idx].dir_req_origin_id = INV_SP_ID; + /* Clear the ongoing direct request message version. */ + sp->ec[idx].dir_req_funcid = 0U; + if (sp->runtime_el == S_EL0) { spin_unlock(&sp->rt_state_lock); } @@ -1267,6 +1316,7 @@ static uint64_t ffa_features_handler(uint32_t smc_fid, case FFA_RX_RELEASE: case FFA_MSG_SEND_DIRECT_REQ_SMC32: case FFA_MSG_SEND_DIRECT_REQ_SMC64: + case FFA_MSG_SEND_DIRECT_REQ2_SMC64: case FFA_PARTITION_INFO_GET: case FFA_RXTX_MAP_SMC32: case FFA_RXTX_MAP_SMC64: @@ -1289,6 +1339,7 @@ static uint64_t ffa_features_handler(uint32_t smc_fid, case FFA_SECONDARY_EP_REGISTER_SMC64: case FFA_MSG_SEND_DIRECT_RESP_SMC32: case FFA_MSG_SEND_DIRECT_RESP_SMC64: + case FFA_MSG_SEND_DIRECT_RESP2_SMC64: case FFA_MEM_RELINQUISH: case FFA_MSG_WAIT: case FFA_CONSOLE_LOG_SMC32: @@ -1909,7 +1960,9 @@ static int sp_manifest_parse(void *sp_manifest, int offset, /* Validate this entry, we currently only support direct messaging. */ if ((config_32 & ~(FFA_PARTITION_DIRECT_REQ_RECV | - FFA_PARTITION_DIRECT_REQ_SEND)) != 0U) { + FFA_PARTITION_DIRECT_REQ_SEND | + FFA_PARTITION_DIRECT_REQ2_RECV | + FFA_PARTITION_DIRECT_REQ2_SEND)) != 0U) { WARN("Invalid Secure Partition messaging method (0x%x)\n", config_32); return -EINVAL; @@ -2351,11 +2404,13 @@ uint64_t spmc_smc_handler(uint32_t smc_fid, case FFA_MSG_SEND_DIRECT_REQ_SMC32: case FFA_MSG_SEND_DIRECT_REQ_SMC64: + case FFA_MSG_SEND_DIRECT_REQ2_SMC64: return direct_req_smc_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); case FFA_MSG_SEND_DIRECT_RESP_SMC32: case FFA_MSG_SEND_DIRECT_RESP_SMC64: + case FFA_MSG_SEND_DIRECT_RESP2_SMC64: return direct_resp_smc_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); diff --git a/services/std_svc/spm/el3_spmc/spmc_pm.c b/services/std_svc/spm/el3_spmc/spmc_pm.c index 517d6d5ee..0a6215c2f 100644 --- a/services/std_svc/spm/el3_spmc/spmc_pm.c +++ b/services/std_svc/spm/el3_spmc/spmc_pm.c @@ -147,6 +147,8 @@ static int32_t spmc_send_pm_msg(uint8_t pm_msg_type, ec->rt_model = RT_MODEL_DIR_REQ; ec->rt_state = RT_STATE_RUNNING; ec->dir_req_origin_id = FFA_SPMC_ID; + /* Expect a direct message response from the SP. */ + ec->dir_req_funcid = FFA_FNUM_MSG_SEND_DIRECT_REQ; rc = spmc_sp_synchronous_entry(ec); if (rc != 0ULL) { From e1168bc37563d1f18d6d2a6dc4ed468eadf673f2 Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Wed, 13 Nov 2024 08:35:47 +0000 Subject: [PATCH 8/8] feat(el3_spmc): ffa error handling in direct msg When an FFA_ERROR happens while handling a direct message from normal world, return to normal world with FFA_ERROR. Otherwise, the system would re-enter the secure partition with FFA_ERROR. Change-Id: I3d9a68a41b4815c1a8e10354cfcf68fec9f4b800 Signed-off-by: Levi Yun --- services/std_svc/spm/el3_spmc/spmc_main.c | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c index 9004ef276..b0d6ba66d 100644 --- a/services/std_svc/spm/el3_spmc/spmc_main.c +++ b/services/std_svc/spm/el3_spmc/spmc_main.c @@ -696,6 +696,8 @@ static uint64_t ffa_error_handler(uint32_t smc_fid, { struct secure_partition_desc *sp; unsigned int idx; + uint16_t dst_id = ffa_endpoint_destination(x1); + bool cancel_dir_req = false; /* Check that the response did not originate from the Normal world. */ if (!secure_origin) { @@ -723,6 +725,32 @@ static uint64_t ffa_error_handler(uint32_t smc_fid, panic(); } + if (sp->runtime_el == S_EL0) { + spin_lock(&sp->rt_state_lock); + } + + if (sp->ec[idx].rt_state == RT_STATE_RUNNING && + sp->ec[idx].rt_model == RT_MODEL_DIR_REQ) { + sp->ec[idx].rt_state = RT_STATE_WAITING; + sp->ec[idx].dir_req_origin_id = INV_SP_ID; + sp->ec[idx].dir_req_funcid = 0x00; + cancel_dir_req = true; + } + + if (sp->runtime_el == S_EL0) { + spin_unlock(&sp->rt_state_lock); + } + + if (cancel_dir_req) { + if (dst_id == FFA_SPMC_ID) { + spmc_sp_synchronous_exit(&sp->ec[idx], x4); + /* Should not get here. */ + panic(); + } else + return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4, + handle, cookie, flags, dst_id); + } + return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED); }