diff --git a/Makefile b/Makefile index 4b96be16b..f3ab71aa2 100644 --- a/Makefile +++ b/Makefile @@ -623,6 +623,15 @@ ifneq (${SPD},none) # over the sources. endif #(SPD=none) +ifeq (${ENABLE_SPMD_LP}, 1) +ifneq (${SPD},spmd) + $(error Error: ENABLE_SPMD_LP requires SPD=spmd.) +endif +ifeq ($(SPMC_AT_EL3),1) + $(error SPMC at EL3 not supported when enabling SPMD Logical partitions.) +endif +endif + ifeq (${CTX_INCLUDE_EL2_REGS}, 1) ifeq (${SPD},none) ifeq (${ENABLE_RME},0) @@ -1181,6 +1190,7 @@ $(eval $(call assert_booleans,\ SPM_MM \ SPMC_AT_EL3 \ SPMD_SPM_AT_SEL2 \ + ENABLE_SPMD_LP \ TRUSTED_BOARD_BOOT \ USE_COHERENT_MEM \ USE_DEBUGFS \ @@ -1397,6 +1407,7 @@ $(eval $(call add_defines,\ CONDITIONAL_CMO \ IMPDEF_SYSREG_TRAP \ SVE_VECTOR_LEN \ + ENABLE_SPMD_LP \ ))) ifeq (${SANITIZE_UB},trap) diff --git a/include/common/bl_common.h b/include/common/bl_common.h index 539280e12..4c8a17c5b 100644 --- a/include/common/bl_common.h +++ b/include/common/bl_common.h @@ -85,6 +85,10 @@ #define __EL3_LP_DESCS_START__ Load$$__EL3_LP_DESCS__$$Base #define __EL3_LP_DESCS_END__ Load$$__EL3_LP_DESCS__$$Limit #endif +#if ENABLE_SPMD_LP +#define __SPMD_LP_DESCS_START__ Load$$__SPMD_LP_DESCS__$$Base +#define __SPMD_LP_DESCS_END__ Load$$__SPMD_LP_DESCS__$$Limit +#endif #define __RW_START__ Load$$LR$$LR_RW_DATA$$Base #define __RW_END__ Load$$LR$$LR_END$$Base #define __SPM_SHIM_EXCEPTIONS_START__ Load$$__SPM_SHIM_EXCEPTIONS__$$Base diff --git a/include/common/bl_common.ld.h b/include/common/bl_common.ld.h index c9bed1ad9..b6dd0f006 100644 --- a/include/common/bl_common.ld.h +++ b/include/common/bl_common.ld.h @@ -49,6 +49,15 @@ #define EL3_LP_DESCS #endif +#if ENABLE_SPMD_LP +#define SPMD_LP_DESCS \ + . = ALIGN(STRUCT_ALIGN); \ + __SPMD_LP_DESCS_START__ = .; \ + KEEP(*(.spmd_lp_descs)) \ + __SPMD_LP_DESCS_END__ = .; +#else +#define SPMD_LP_DESCS +#endif #define PMF_SVC_DESCS \ . = ALIGN(STRUCT_ALIGN); \ __PMF_SVC_DESCS_START__ = .; \ @@ -100,7 +109,8 @@ CPU_OPS \ GOT \ BASE_XLAT_TABLE_RO \ - EL3_LP_DESCS + EL3_LP_DESCS \ + SPMD_LP_DESCS /* * .data must be placed at a lower address than the stacks if the stack diff --git a/include/services/el3_spmd_logical_sp.h b/include/services/el3_spmd_logical_sp.h new file mode 100644 index 000000000..4725c159e --- /dev/null +++ b/include/services/el3_spmd_logical_sp.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef EL3_SPMD_LOGICAL_SP_H +#define EL3_SPMD_LOGICAL_SP_H + +#include +#include +#include + +/******************************************************************************* + * Structure definition, typedefs & constants for the SPMD Logical Partitions. + ******************************************************************************/ + +/* Prototype for SPMD logical partition initializing function. */ +typedef int32_t (*ffa_spmd_lp_init_t)(void); + +/* SPMD Logical Partition Descriptor. */ +struct spmd_lp_desc { + ffa_spmd_lp_init_t init; + uint16_t sp_id; + uint32_t properties; + uint32_t uuid[4]; /* Little Endian. */ + const char *debug_name; +}; + +/* Convenience macro to declare a SPMD logical partition descriptor. */ +#define DECLARE_SPMD_LOGICAL_PARTITION(_name, _init, _sp_id, _uuid, _properties) \ + static const struct spmd_lp_desc __partition_desc_ ## _name \ + __section(".spmd_lp_descs") __used = { \ + .debug_name = #_name, \ + .init = (_init), \ + .sp_id = (_sp_id), \ + .uuid = _uuid, \ + .properties = (_properties), \ + } + +IMPORT_SYM(uintptr_t, __SPMD_LP_DESCS_START__, SPMD_LP_DESCS_START); +IMPORT_SYM(uintptr_t, __SPMD_LP_DESCS_END__, SPMD_LP_DESCS_END); + +#define SPMD_LP_DESCS_COUNT ((SPMD_LP_DESCS_END - SPMD_LP_DESCS_START) \ + / sizeof(struct spmd_lp_desc)) +CASSERT(sizeof(struct spmd_lp_desc) == 40, assert_spmd_lp_desc_size_mismatch); + +/* + * Reserve 63 IDs for SPMD Logical Partitions. Currently, 0xFFC0 to 0xFFFE + * is reserved. + */ +#define SPMD_LP_ID_END (SPMD_DIRECT_MSG_ENDPOINT_ID - 1) +#define SPMD_LP_ID_START (SPMD_LP_ID_END - 62) + +static inline bool is_spmd_lp_id(unsigned int id) +{ + return (id >= SPMD_LP_ID_START && id <= SPMD_LP_ID_END); +} + +void spmd_logical_sp_set_spmc_initialized(void); +void spmc_logical_sp_set_spmc_failure(void); + +int32_t spmd_logical_sp_init(void); + +#endif /* EL3_SPMD_LOGICAL_SP_H */ diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index a06503913..964e0f925 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -508,3 +508,6 @@ DRTM_SUPPORT := 0 # Check platform if cache management operations should be performed. # Disabled by default. CONDITIONAL_CMO := 0 + +# By default, disable SPMD Logical partitions +ENABLE_SPMD_LP := 0 diff --git a/services/std_svc/spmd/spmd.mk b/services/std_svc/spmd/spmd.mk index 6f451c8db..cc0e3922f 100644 --- a/services/std_svc/spmd/spmd.mk +++ b/services/std_svc/spmd/spmd.mk @@ -15,7 +15,8 @@ endif SPMD_SOURCES += $(addprefix services/std_svc/spmd/, \ ${ARCH}/spmd_helpers.S \ spmd_pm.c \ - spmd_main.c) + spmd_main.c \ + spmd_logical_sp.c) # Let the top-level Makefile know that we intend to include a BL32 image NEED_BL32 := yes diff --git a/services/std_svc/spmd/spmd_logical_sp.c b/services/std_svc/spmd/spmd_logical_sp.c new file mode 100644 index 000000000..f3089c659 --- /dev/null +++ b/services/std_svc/spmd/spmd_logical_sp.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include +#include + +#if ENABLE_SPMD_LP +static bool is_spmd_lp_inited; +static bool is_spmc_inited; + +/* + * Helper function to obtain the array storing the EL3 + * SPMD Logical Partition descriptors. + */ +static struct spmd_lp_desc *get_spmd_el3_lp_array(void) +{ + return (struct spmd_lp_desc *) SPMD_LP_DESCS_START; +} + +/******************************************************************************* + * Validate any logical partition descriptors before we initialize. + * Initialization of said partitions will be taken care of during SPMD boot. + ******************************************************************************/ +static int el3_spmd_sp_desc_validate(struct spmd_lp_desc *lp_array) +{ + /* Check the array bounds are valid. */ + assert(SPMD_LP_DESCS_END > SPMD_LP_DESCS_START); + + /* If no SPMD logical partitions are implemented then simply bail out. */ + if (SPMD_LP_DESCS_COUNT == 0U) { + return -1; + } + + for (uint32_t index = 0U; index < SPMD_LP_DESCS_COUNT; index++) { + struct spmd_lp_desc *lp_desc = &lp_array[index]; + + /* Validate our logical partition descriptors. */ + if (lp_desc == NULL) { + ERROR("Invalid SPMD Logical SP Descriptor\n"); + return -EINVAL; + } + + /* + * Ensure the ID follows the convention to indicate it resides + * in the secure world. + */ + if (!ffa_is_secure_world_id(lp_desc->sp_id)) { + ERROR("Invalid SPMD Logical SP ID (0x%x)\n", + lp_desc->sp_id); + return -EINVAL; + } + + /* Ensure SPMD logical partition is in valid range. */ + if (!is_spmd_lp_id(lp_desc->sp_id)) { + ERROR("Invalid SPMD Logical Partition ID (0x%x)\n", + lp_desc->sp_id); + return -EINVAL; + } + + /* Ensure the UUID is not the NULL UUID. */ + if (lp_desc->uuid[0] == 0 && lp_desc->uuid[1] == 0 && + lp_desc->uuid[2] == 0 && lp_desc->uuid[3] == 0) { + ERROR("Invalid UUID for SPMD Logical SP (0x%x)\n", + lp_desc->sp_id); + return -EINVAL; + } + + /* Ensure init function callback is registered. */ + if (lp_desc->init == NULL) { + ERROR("Missing init function for Logical SP(0x%x)\n", + lp_desc->sp_id); + return -EINVAL; + } + + /* Ensure that SPMD LP only supports sending direct requests. */ + if (lp_desc->properties != FFA_PARTITION_DIRECT_REQ_SEND) { + ERROR("Invalid SPMD logical partition properties (0x%x)\n", + lp_desc->properties); + return -EINVAL; + } + + /* Ensure that all partition IDs are unique. */ + for (uint32_t inner_idx = index + 1; + inner_idx < SPMD_LP_DESCS_COUNT; inner_idx++) { + if (lp_desc->sp_id == lp_array[inner_idx].sp_id) { + ERROR("Duplicate SPMD logical SP ID Detected (0x%x)\n", + lp_desc->sp_id); + return -EINVAL; + } + } + } + return 0; +} +#endif + +/* + * Initialize SPMD logical partitions. This function assumes that it is called + * only after the SPMC has successfully initialized. + */ +int32_t spmd_logical_sp_init(void) +{ +#if ENABLE_SPMD_LP + int32_t rc = 0; + struct spmd_lp_desc *spmd_lp_descs; + + if (is_spmd_lp_inited == true) { + return 0; + } + + if (is_spmc_inited == false) { + return -1; + } + + spmd_lp_descs = get_spmd_el3_lp_array(); + + /* Perform initial validation of the SPMD Logical Partitions. */ + rc = el3_spmd_sp_desc_validate(spmd_lp_descs); + if (rc != 0) { + ERROR("Logical SPMD Partition validation failed!\n"); + return rc; + } + + VERBOSE("SPMD Logical Secure Partition init start.\n"); + for (unsigned int i = 0U; i < SPMD_LP_DESCS_COUNT; i++) { + rc = spmd_lp_descs[i].init(); + if (rc != 0) { + ERROR("SPMD Logical SP (0x%x) failed to initialize\n", + spmd_lp_descs[i].sp_id); + return rc; + } + VERBOSE("SPMD Logical SP (0x%x) Initialized\n", + spmd_lp_descs[i].sp_id); + } + + INFO("SPMD Logical Secure Partition init completed.\n"); + if (rc == 0) { + is_spmd_lp_inited = true; + } + return rc; +#else + return 0; +#endif +} + +void spmd_logical_sp_set_spmc_initialized(void) +{ +#if ENABLE_SPMD_LP + is_spmc_inited = true; +#endif +} + +void spmd_logical_sp_set_spmc_failure(void) +{ +#if ENABLE_SPMD_LP + is_spmc_inited = false; +#endif +} diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c index 587e60f4f..9b06b55c3 100644 --- a/services/std_svc/spmd/spmd_main.c +++ b/services/std_svc/spmd/spmd_main.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -190,6 +191,12 @@ static int32_t spmd_init(void) VERBOSE("SPM Core init end.\n"); + spmd_logical_sp_set_spmc_initialized(); + rc = spmd_logical_sp_init(); + if (rc != 0) { + WARN("SPMD Logical partitions failed init.\n"); + } + return 1; }