mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-23 21:44:15 +00:00
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:
parent
6dc0f1f329
commit
7affa25cad
8 changed files with 276 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
60
include/services/el3_spmc_logical_sp.h
Normal file
60
include/services/el3_spmc_logical_sp.h
Normal 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 */
|
|
@ -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.
|
||||
*/
|
||||
|
|
107
services/std_svc/spm/el3_spmc/logical_sp.c
Normal file
107
services/std_svc/spm/el3_spmc/logical_sp.c
Normal 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;
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) */
|
||||
|
|
Loading…
Add table
Reference in a new issue