feat(spmc/lsp): add logical partition framework

Introduce a framework to support running logical
partitions alongside the SPMC in EL3  as per the
v1.1 FF-A spec.

The DECLARE_LOGICAL_PARTITION macro has been added to
simplify the process to define a Logical Partition.
The partitions themselves are statically allocated
with the descriptors placed in RO memory.

It is assumed that the MAX_EL3_LP_DESCS_COUNT will
be defined by the platform.

Change-Id: I1c2523e0ad2d9c5d36aeeef6b8bcb1e80db7c443
Signed-off-by: Marc Bonnici <marc.bonnici@arm.com>
This commit is contained in:
Marc Bonnici 2022-02-14 17:06:09 +00:00
parent 6dc0f1f329
commit 7affa25cad
8 changed files with 276 additions and 8 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

@ -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

@ -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"
/*
@ -184,4 +185,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,8 @@ endif
SPMC_SOURCES := $(addprefix services/std_svc/spm/el3_spmc/, \
spmc_main.c \
spmc_setup.c)
spmc_setup.c \
logical_sp.c)
# 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");
@ -621,6 +655,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;
@ -725,6 +790,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) */