Merge changes from topic "ffa_el3_spmc" into integration

* changes:
  feat(spmc): enable checking of execution ctx count
  feat(spmc): enable parsing of UUID from SP Manifest
  feat(spmc): add partition mailbox structs
  feat(plat/arm): allow BL32 specific defines to be used by SPMC_AT_EL3
  feat(plat/fvp): add EL3 SPMC #defines
  test(plat/fvp/lsp): add example logical partition
  feat(spmc/lsp): add logical partition framework
This commit is contained in:
Olivier Deprez 2022-05-06 15:58:03 +02:00 committed by TrustedFirmware Code Review
commit 44b9d577c0
12 changed files with 452 additions and 16 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -81,6 +81,10 @@
#define __RODATA_END__ Load$$__RODATA_EPILOGUE__$$Base
#define __RT_SVC_DESCS_START__ Load$$__RT_SVC_DESCS__$$Base
#define __RT_SVC_DESCS_END__ Load$$__RT_SVC_DESCS__$$Limit
#if SPMC_AT_EL3
#define __EL3_LP_DESCS_START__ Load$$__EL3_LP_DESCS__$$Base
#define __EL3_LP_DESCS_END__ Load$$__EL3_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

View file

@ -39,6 +39,16 @@
KEEP(*(rt_svc_descs)) \
__RT_SVC_DESCS_END__ = .;
#if SPMC_AT_EL3
#define EL3_LP_DESCS \
. = ALIGN(STRUCT_ALIGN); \
__EL3_LP_DESCS_START__ = .; \
KEEP(*(el3_lp_descs)) \
__EL3_LP_DESCS_END__ = .;
#else
#define EL3_LP_DESCS
#endif
#define PMF_SVC_DESCS \
. = ALIGN(STRUCT_ALIGN); \
__PMF_SVC_DESCS_START__ = .; \
@ -89,7 +99,8 @@
PARSER_LIB_DESCS \
CPU_OPS \
GOT \
BASE_XLAT_TABLE_RO
BASE_XLAT_TABLE_RO \
EL3_LP_DESCS
/*
* .data must be placed at a lower address than the stacks if the stack

View file

@ -618,7 +618,7 @@
* Trusted DRAM (if available) or the DRAM region secured by the TrustZone
* controller.
*/
# if SPM_MM
# if SPM_MM || SPMC_AT_EL3
# define TSP_SEC_MEM_BASE (ARM_AP_TZC_DRAM1_BASE + ULL(0x200000))
# define TSP_SEC_MEM_SIZE (ARM_AP_TZC_DRAM1_SIZE - ULL(0x200000))
# define BL32_BASE (ARM_AP_TZC_DRAM1_BASE + ULL(0x200000))
@ -664,12 +664,13 @@
/*
* BL32 is mandatory in AArch32. In AArch64, undefine BL32_BASE if there is no
* SPD and no SPM-MM, as they are the only ones that can be used as BL32.
* SPD and no SPM-MM and no SPMC-AT-EL3, as they are the only ones that can be
* used as BL32.
*/
#if defined(__aarch64__) && !JUNO_AARCH32_EL3_RUNTIME
# if defined(SPD_none) && !SPM_MM
# if defined(SPD_none) && !SPM_MM && !SPMC_AT_EL3
# undef BL32_BASE
# endif /* defined(SPD_none) && !SPM_MM */
# endif /* defined(SPD_none) && !SPM_MM || !SPMC_AT_EL3 */
#endif /* defined(__aarch64__) && !JUNO_AARCH32_EL3_RUNTIME */
/*******************************************************************************

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef EL3_SP_H
#define EL3_SP_H
#include <common/bl_common.h>
#include <lib/cassert.h>
/*******************************************************************************
* Structure definition, typedefs & constants for the Logical SPs.
******************************************************************************/
typedef uint64_t (*direct_msg_handler)(uint32_t smc_fid, bool secure_origin,
uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, void *cookie, void *handle,
uint64_t flags);
/* Prototype for logical partition initializing function. */
typedef int32_t (*ffa_partition_init_t)(void);
/* Logical Partition Descriptor. */
struct el3_lp_desc {
ffa_partition_init_t init;
uint16_t sp_id;
uint32_t properties;
uint32_t uuid[4]; /* Little Endian. */
direct_msg_handler direct_req;
const char *debug_name;
};
/* Convenience macro to declare a logical partition descriptor. */
#define DECLARE_LOGICAL_PARTITION(_name, _init, _sp_id, _uuid, _properties, \
_direct_req) \
static const struct el3_lp_desc __partition_desc_ ## _name \
__section("el3_lp_descs") __used = { \
.debug_name = #_name, \
.init = (_init), \
.sp_id = (_sp_id), \
.uuid = _uuid, \
.properties = (_properties), \
.direct_req = (_direct_req), \
}
/*******************************************************************************
* Function & variable prototypes.
******************************************************************************/
int el3_sp_desc_validate(void);
uintptr_t handle_el3_sp(uint32_t smc_fid, void *cookie, void *handle,
unsigned int flags);
IMPORT_SYM(uintptr_t, __EL3_LP_DESCS_START__, EL3_LP_DESCS_START);
IMPORT_SYM(uintptr_t, __EL3_LP_DESCS_END__, EL3_LP_DESCS_END);
#define EL3_LP_DESCS_COUNT ((EL3_LP_DESCS_END - EL3_LP_DESCS_START) \
/ sizeof(struct el3_lp_desc))
#endif /* EL3_SP_H */

View file

@ -163,6 +163,13 @@
#define FFA_NOTIFICATION_INFO_GET_SMC64 \
FFA_FID(SMC_64, FFA_FNUM_NOTIFICATION_INFO_GET)
/*
* FF-A partition properties values.
*/
#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)
/*
* Reserve a special value for traffic targeted to the Hypervisor or SPM.
*/

View file

@ -127,7 +127,7 @@ const mmap_region_t plat_arm_mmap[] = {
*/
ARM_MAP_BL1_RW,
#endif /* CRYPTO_SUPPORT && !BL2_AT_EL3 */
#if SPM_MM
#if SPM_MM || SPMC_AT_EL3
ARM_SP_IMAGE_MMAP,
#endif
#if ARM_BL31_IN_DRAM

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <services/el3_spmc_logical_sp.h>
#include <services/ffa_svc.h>
#include <smccc_helpers.h>
#define LP_PARTITION_ID 0xC001
#define LP_UUID {0x47a3bf57, 0xe98e43ad, 0xb7db524f, 0x1588f4e3}
/* Our Logical SP currently only supports receipt of direct messaging. */
#define PARTITION_PROPERTIES FFA_PARTITION_DIRECT_REQ_RECV
static int32_t sp_init(void)
{
INFO("LSP: Init function called.\n");
return 0;
}
static uint64_t handle_ffa_direct_request(uint32_t smc_fid, bool secure_origin,
uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, void *cookie,
void *handle, uint64_t flags)
{
uint64_t ret;
/* Determine if we have a 64 or 32 direct request. */
if (smc_fid == FFA_MSG_SEND_DIRECT_REQ_SMC32) {
ret = FFA_MSG_SEND_DIRECT_RESP_SMC32;
} else if (smc_fid == FFA_MSG_SEND_DIRECT_REQ_SMC64) {
ret = FFA_MSG_SEND_DIRECT_RESP_SMC64;
} else {
panic(); /* Unknown SMC. */
}
/*
* Handle the incoming request. For testing purposes we echo the
* incoming message.
*/
INFO("Logical Partition: Received Direct Request from %s world!\n",
secure_origin ? "Secure" : "Normal");
/*
* Logical SP's must always send a direct response so we can populate
* our response directly.
*/
SMC_RET8(handle, ret, 0, 0, x4, 0, 0, 0, 0);
}
/* Register logical partition */
DECLARE_LOGICAL_PARTITION(
my_logical_partition,
sp_init, /* Init Function */
LP_PARTITION_ID, /* FF-A Partition ID */
LP_UUID, /* UUID */
PARTITION_PROPERTIES, /* Partition Properties. */
handle_ffa_direct_request /* Callback for direct requests. */
);

View file

@ -86,6 +86,35 @@
#define FVP_DTB_DRAM_MAP_START ULL(0x82000000)
#define FVP_DTB_DRAM_MAP_SIZE ULL(0x02000000) /* 32 MB */
#define ARM_DTB_DRAM_NS MAP_REGION_FLAT( \
FVP_DTB_DRAM_MAP_START, \
FVP_DTB_DRAM_MAP_SIZE, \
MT_MEMORY | MT_RO | MT_NS)
#if SPMC_AT_EL3
/*
* Number of Secure Partitions supported.
* SPMC at EL3, uses this count to configure the maximum number of supported
* secure partitions.
*/
#define SECURE_PARTITION_COUNT 1
/*
* Number of Normal World Partitions supported.
* SPMC at EL3, uses this count to configure the maximum number of supported
* NWd partitions.
*/
#define NS_PARTITION_COUNT 1
/*
* Number of Logical Partitions supported.
* SPMC at EL3, uses this count to configure the maximum number of supported
* logical partitions.
*/
#define MAX_EL3_LP_DESCS_COUNT 1
#endif /* SPMC_AT_EL3 */
/*
* Load address of BL33 for this platform port
*/
@ -102,9 +131,12 @@
# define MAX_XLAT_TABLES 11
# else
# define MAX_XLAT_TABLES 9
# endif
# endif
# define PLAT_SP_IMAGE_MMAP_REGIONS 30
# define PLAT_SP_IMAGE_MAX_XLAT_TABLES 10
# elif SPMC_AT_EL3
# define PLAT_ARM_MMAP_ENTRIES 13
# define MAX_XLAT_TABLES 11
# else
# define PLAT_ARM_MMAP_ENTRIES 9
# if USE_DEBUGFS
@ -122,8 +154,13 @@
# endif
# endif
#elif defined(IMAGE_BL32)
# define PLAT_ARM_MMAP_ENTRIES 9
# define MAX_XLAT_TABLES 6
# if SPMC_AT_EL3
# define PLAT_ARM_MMAP_ENTRIES 270
# define MAX_XLAT_TABLES 10
# else
# define PLAT_ARM_MMAP_ENTRIES 9
# define MAX_XLAT_TABLES 6
# endif
#elif !USE_ROMLIB
# define PLAT_ARM_MMAP_ENTRIES 11
# define MAX_XLAT_TABLES 5

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <common/debug.h>
#include <services/el3_spmc_logical_sp.h>
#include <services/ffa_svc.h>
#include "spmc.h"
/*******************************************************************************
* Validate any logical partition descriptors before we initialise.
* Initialization of said partitions will be taken care of during SPMC boot.
******************************************************************************/
int el3_sp_desc_validate(void)
{
struct el3_lp_desc *lp_array;
/*
* Assert the number of descriptors is less than maximum allowed.
* This constant should be define on a per platform basis.
*/
assert(EL3_LP_DESCS_COUNT <= MAX_EL3_LP_DESCS_COUNT);
/* Check the array bounds are valid. */
assert(EL3_LP_DESCS_END >= EL3_LP_DESCS_START);
/* If no logical partitions are implemented then simply bail out. */
if (EL3_LP_DESCS_COUNT == 0U) {
return 0;
}
lp_array = get_el3_lp_array();
for (unsigned int index = 0; index < EL3_LP_DESCS_COUNT; index++) {
struct el3_lp_desc *lp_desc = &lp_array[index];
/* Validate our logical partition descriptors. */
if (lp_desc == NULL) {
ERROR("Invalid Logical SP Descriptor\n");
return -EINVAL;
}
/*
* Ensure the ID follows the convention to indidate it resides
* in the secure world.
*/
if (!ffa_is_secure_world_id(lp_desc->sp_id)) {
ERROR("Invalid Logical SP ID (0x%x)\n",
lp_desc->sp_id);
return -EINVAL;
}
/* Ensure we don't conflict with the SPMC partition ID. */
if (lp_desc->sp_id == FFA_SPMC_ID) {
ERROR("Logical SP ID clashes with SPMC 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 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 LP only supports receiving direct requests. */
if (lp_desc->properties &
~(FFA_PARTITION_DIRECT_REQ_RECV)) {
ERROR("Invalid partition properties (0x%x)\n",
lp_desc->properties);
return -EINVAL;
}
/* Ensure direct request function callback is registered. */
if (lp_desc->direct_req == NULL) {
ERROR("No Direct Req handler for Logical SP (0x%x)\n",
lp_desc->sp_id);
return -EINVAL;
}
/* Ensure that all partition IDs are unique. */
for (unsigned int inner_idx = index + 1;
inner_idx < EL3_LP_DESCS_COUNT; inner_idx++) {
if (lp_desc->sp_id == lp_array[inner_idx].sp_id) {
ERROR("Duplicate SP ID Detected (0x%x)\n",
lp_desc->sp_id);
return -EINVAL;
}
}
}
return 0;
}

View file

@ -11,6 +11,7 @@
#include <lib/psci/psci.h>
#include <lib/spinlock.h>
#include <services/el3_spmc_logical_sp.h>
#include "spm_common.h"
/*
@ -68,6 +69,28 @@ enum sp_execution_state {
SP_STATE_AARCH32
};
enum mailbox_state {
/* There is no message in the mailbox. */
MAILBOX_STATE_EMPTY,
/* There is a message that has been populated in the mailbox. */
MAILBOX_STATE_FULL,
};
struct mailbox {
enum mailbox_state state;
/* RX/TX Buffers. */
void *rx_buffer;
const void *tx_buffer;
/* Size of RX/TX Buffer. */
uint32_t rxtx_page_count;
/* Lock access to mailbox. */
spinlock_t lock;
};
/*
* Execution context members for an SP. This is a bit like struct
* vcpu in a hypervisor.
@ -118,6 +141,9 @@ struct secure_partition_desc {
/* Execution State. */
enum sp_execution_state execution_state;
/* Mailbox tracking. */
struct mailbox mailbox;
/* Secondary entrypoint. Only valid for a S-EL1 SP. */
uintptr_t secondary_ep;
};
@ -142,7 +168,12 @@ struct ns_endpoint_desc {
uint16_t ns_ep_id;
/*
* Supported FF-A Version.
* Mailbox tracking.
*/
struct mailbox mailbox;
/*
* Supported FF-A Version
*/
uint32_t ffa_version;
};
@ -184,4 +215,10 @@ uint64_t spmc_ffa_error_return(void *handle, int error_code);
*/
bool is_ffa_secure_id_valid(uint16_t partition_id);
/*
* Helper function to obtain the array storing the EL3
* Logical Partition descriptors.
*/
struct el3_lp_desc *get_el3_lp_array(void);
#endif /* SPMC_H */

View file

@ -10,8 +10,15 @@ endif
SPMC_SOURCES := $(addprefix services/std_svc/spm/el3_spmc/, \
spmc_main.c \
spmc_setup.c)
spmc_setup.c \
logical_sp.c)
# Specify platform specific logical partition implementation.
SPMC_LP_SOURCES := $(addprefix ${PLAT_DIR}/, \
${PLAT}_el3_spmc_logical_sp.c)
SPMC_SOURCES += $(SPMC_LP_SOURCES)
# Let the top-level Makefile know that we intend to include a BL32 image
NEED_BL32 := yes

View file

@ -19,6 +19,7 @@
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <libfdt.h>
#include <plat/common/platform.h>
#include <services/el3_spmc_logical_sp.h>
#include <services/ffa_svc.h>
#include <services/spmc_svc.h>
#include <services/spmd_svc.h>
@ -40,6 +41,15 @@ static struct secure_partition_desc sp_desc[SECURE_PARTITION_COUNT];
*/
static struct ns_endpoint_desc ns_ep_desc[NS_PARTITION_COUNT];
/*
* Helper function to obtain the array storing the EL3
* Logical Partition descriptors.
*/
struct el3_lp_desc *get_el3_lp_array(void)
{
return (struct el3_lp_desc *) EL3_LP_DESCS_START;
}
/*
* Helper function to obtain the descriptor of the last SP to whom control was
* handed to on this physical cpu. Currently, we assume there is only one SP.
@ -105,6 +115,8 @@ uint64_t spmc_ffa_error_return(void *handle, int error_code)
******************************************************************************/
bool is_ffa_secure_id_valid(uint16_t partition_id)
{
struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
/* Ensure the ID is not the invalid partition ID. */
if (partition_id == INV_SP_ID) {
return false;
@ -133,12 +145,22 @@ bool is_ffa_secure_id_valid(uint16_t partition_id)
return false;
}
/* Ensure we don't clash with any Logical SP's. */
for (unsigned int i = 0U; i < EL3_LP_DESCS_COUNT; i++) {
if (el3_lp_descs[i].sp_id == partition_id) {
return false;
}
}
return true;
}
/*******************************************************************************
* This function either forwards the request to the other world or returns
* with an ERET depending on the source of the call.
* We can assume that the destination is for an entity at a lower exception
* level as any messages destined for a logical SP resident in EL3 will have
* already been taken care of by the SPMC before entering this function.
******************************************************************************/
static uint64_t spmc_smc_return(uint32_t smc_fid,
bool secure_origin,
@ -210,6 +232,7 @@ static uint64_t direct_req_smc_handler(uint32_t smc_fid,
uint64_t flags)
{
uint16_t dst_id = ffa_endpoint_destination(x1);
struct el3_lp_desc *el3_lp_descs;
struct secure_partition_desc *sp;
unsigned int idx;
@ -219,11 +242,22 @@ static uint64_t direct_req_smc_handler(uint32_t smc_fid,
FFA_ERROR_INVALID_PARAMETER);
}
el3_lp_descs = get_el3_lp_array();
/* 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) {
return el3_lp_descs[i].direct_req(
smc_fid, secure_origin, x1, x2, x3, x4,
cookie, handle, flags);
}
}
/*
* If called by the secure world it is an invalid call since a
* SP cannot call into the Normal world and there is no other SP to call
* into. If there are other SPs in future then the partition runtime
* model would need to be validated as well.
* If the request was not targeted to a LSP and from the secure world
* then it is invalid since a SP cannot call into the Normal world and
* there is no other SP to call into. If there are other SPs in future
* then the partition runtime model would need to be validated as well.
*/
if (secure_origin) {
VERBOSE("Direct request not supported to the Normal World.\n");
@ -479,6 +513,13 @@ static int sp_manifest_parse(void *sp_manifest, int offset,
return node;
}
ret = fdt_read_uint32_array(sp_manifest, node, "uuid",
ARRAY_SIZE(sp->uuid), sp->uuid);
if (ret != 0) {
ERROR("Missing Secure Partition UUID.\n");
return ret;
}
ret = fdt_read_uint32(sp_manifest, node, "exception-level", &config_32);
if (ret != 0) {
ERROR("Missing SP Exception Level information.\n");
@ -503,6 +544,25 @@ static int sp_manifest_parse(void *sp_manifest, int offset,
sp->execution_state = config_32;
ret = fdt_read_uint32(sp_manifest, node,
"execution-ctx-count", &config_32);
if (ret != 0) {
ERROR("Missing SP Execution Context Count.\n");
return ret;
}
/*
* Ensure this field is set correctly in the manifest however
* since this is currently a hardcoded value for S-EL1 partitions
* we don't need to save it here, just validate.
*/
if (config_32 != PLATFORM_CORE_COUNT) {
ERROR("SP Execution Context Count (%u) must be %u.\n",
config_32, PLATFORM_CORE_COUNT);
return -EINVAL;
}
/*
* Look for the optional fields that are expected to be present in
* an SP manifest.
@ -621,6 +681,37 @@ static int find_and_prepare_sp_context(void)
* This function takes an SP context pointer and performs a synchronous entry
* into it.
******************************************************************************/
static int32_t logical_sp_init(void)
{
int32_t rc = 0;
struct el3_lp_desc *el3_lp_descs;
/* Perform initial validation of the Logical Partitions. */
rc = el3_sp_desc_validate();
if (rc != 0) {
ERROR("Logical Partition validation failed!\n");
return rc;
}
el3_lp_descs = get_el3_lp_array();
INFO("Logical Secure Partition init start.\n");
for (unsigned int i = 0U; i < EL3_LP_DESCS_COUNT; i++) {
rc = el3_lp_descs[i].init();
if (rc != 0) {
ERROR("Logical SP (0x%x) Failed to Initialize\n",
el3_lp_descs[i].sp_id);
return rc;
}
VERBOSE("Logical SP (0x%x) Initialized\n",
el3_lp_descs[i].sp_id);
}
INFO("Logical Secure Partition init completed.\n");
return rc;
}
uint64_t spmc_sp_synchronous_entry(struct sp_exec_ctx *ec)
{
uint64_t rc;
@ -684,6 +775,9 @@ static void initalize_sp_descs(void)
for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) {
sp = &sp_desc[i];
sp->sp_id = INV_SP_ID;
sp->mailbox.rx_buffer = NULL;
sp->mailbox.tx_buffer = NULL;
sp->mailbox.state = MAILBOX_STATE_EMPTY;
sp->secondary_ep = 0;
}
}
@ -700,6 +794,9 @@ static void initalize_ns_ep_descs(void)
*/
ns_ep->ns_ep_id = 0;
ns_ep->ffa_version = 0;
ns_ep->mailbox.rx_buffer = NULL;
ns_ep->mailbox.tx_buffer = NULL;
ns_ep->mailbox.state = MAILBOX_STATE_EMPTY;
}
}
@ -725,6 +822,13 @@ int32_t spmc_setup(void)
initalize_sp_descs();
initalize_ns_ep_descs();
/* Setup logical SPs. */
ret = logical_sp_init();
if (ret != 0) {
ERROR("Failed to initialize Logical Partitions.\n");
return ret;
}
/* Perform physical SP setup. */
/* Disable MMU at EL1 (initialized by BL2) */