diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h index 01dbea979..f5a9a2dc0 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. @@ -208,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/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/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, 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) 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 \ 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 c6ec30c3d..b0d6ba66d 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); } @@ -647,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) { @@ -674,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); } @@ -1267,6 +1344,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 +1367,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 +1988,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; @@ -2077,39 +2158,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; } @@ -2356,11 +2432,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); @@ -2426,11 +2504,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); 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) { 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 */ 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 }