feat(rme): add context management changes for FEAT_RME

This patch adds a new context for realm world and realm world
awareness in context management.

Signed-off-by: Zelalem Aweke <zelalem.aweke@arm.com>
Signed-off-by: Subhasish Ghosh <subhasish.ghosh@arm.com>
Change-Id: Ic17469393603e789d7adc025880346bc3d6233d7
This commit is contained in:
Zelalem Aweke 2021-07-09 17:54:30 -05:00
parent 50a3056a3c
commit c5ea4f8a66
4 changed files with 116 additions and 39 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -19,9 +19,9 @@
******************************************************************************/
void *cm_get_context(uint32_t security_state)
{
assert(security_state <= NON_SECURE);
assert(sec_state_is_valid(security_state));
return get_cpu_data(cpu_context[security_state]);
return get_cpu_data(cpu_context[get_cpu_context_index(security_state)]);
}
/*******************************************************************************
@ -30,9 +30,10 @@ void *cm_get_context(uint32_t security_state)
******************************************************************************/
void cm_set_context(void *context, uint32_t security_state)
{
assert(security_state <= NON_SECURE);
assert(sec_state_is_valid(security_state));
set_cpu_data(cpu_context[security_state], context);
set_cpu_data(cpu_context[get_cpu_context_index(security_state)],
context);
}
/*******************************************************************************
@ -46,7 +47,8 @@ void *cm_get_context_by_index(unsigned int cpu_idx,
{
assert(sec_state_is_valid(security_state));
return get_cpu_data_by_index(cpu_idx, cpu_context[security_state]);
return get_cpu_data_by_index(cpu_idx,
cpu_context[get_cpu_context_index(security_state)]);
}
/*******************************************************************************
@ -58,5 +60,7 @@ void cm_set_context_by_index(unsigned int cpu_idx, void *context,
{
assert(sec_state_is_valid(security_state));
set_cpu_data_by_index(cpu_idx, cpu_context[security_state], context);
set_cpu_data_by_index(cpu_idx,
cpu_context[get_cpu_context_index(security_state)],
context);
}

View File

@ -405,13 +405,12 @@ DEFINE_REG_STRUCT(pauth, CTX_PAUTH_REGS_ALL);
= (uint64_t) (val))
/*
* Top-level context structure which is used by EL3 firmware to
* preserve the state of a core at EL1 in one of the two security
* states and save enough EL3 meta data to be able to return to that
* EL and security state. The context management library will be used
* to ensure that SP_EL3 always points to an instance of this
* structure at exception entry and exit. Each instance will
* correspond to either the secure or the non-secure state.
* Top-level context structure which is used by EL3 firmware to preserve
* the state of a core at the next lower EL in a given security state and
* save enough EL3 meta data to be able to return to that EL and security
* state. The context management library will be used to ensure that
* SP_EL3 always points to an instance of this structure at exception
* entry and exit.
*/
typedef struct cpu_context {
gp_regs_t gpregs_ctx;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -19,16 +19,25 @@
/* 8-bytes aligned size of psci_cpu_data structure */
#define PSCI_CPU_DATA_SIZE_ALIGNED ((PSCI_CPU_DATA_SIZE + 7) & ~7)
#if ENABLE_RME
/* Size of cpu_context array */
#define CPU_DATA_CONTEXT_NUM 3
/* Offset of cpu_ops_ptr, size 8 bytes */
#define CPU_DATA_CPU_OPS_PTR 0x18
#else /* ENABLE_RME */
#define CPU_DATA_CONTEXT_NUM 2
#define CPU_DATA_CPU_OPS_PTR 0x10
#endif /* ENABLE_RME */
#if ENABLE_PAUTH
/* 8-bytes aligned offset of apiakey[2], size 16 bytes */
#define CPU_DATA_APIAKEY_OFFSET (0x18 + PSCI_CPU_DATA_SIZE_ALIGNED)
#define CPU_DATA_CRASH_BUF_OFFSET (CPU_DATA_APIAKEY_OFFSET + 0x10)
#else
#define CPU_DATA_CRASH_BUF_OFFSET (0x18 + PSCI_CPU_DATA_SIZE_ALIGNED)
#endif /* ENABLE_PAUTH */
#define CPU_DATA_APIAKEY_OFFSET (0x8 + PSCI_CPU_DATA_SIZE_ALIGNED \
+ CPU_DATA_CPU_OPS_PTR)
#define CPU_DATA_CRASH_BUF_OFFSET (0x10 + CPU_DATA_APIAKEY_OFFSET)
#else /* ENABLE_PAUTH */
#define CPU_DATA_CRASH_BUF_OFFSET (0x8 + PSCI_CPU_DATA_SIZE_ALIGNED \
+ CPU_DATA_CPU_OPS_PTR)
#endif /* ENABLE_PAUTH */
/* need enough space in crash buffer to save 8 registers */
#define CPU_DATA_CRASH_BUF_SIZE 64
@ -65,11 +74,14 @@
#ifndef __ASSEMBLER__
#include <assert.h>
#include <stdint.h>
#include <arch_helpers.h>
#include <lib/cassert.h>
#include <lib/psci/psci.h>
#include <platform_def.h>
#include <stdint.h>
/* Offsets for the cpu_data structure */
#define CPU_DATA_PSCI_LOCK_OFFSET __builtin_offsetof\
@ -80,27 +92,34 @@
(cpu_data_t, platform_cpu_data)
#endif
typedef enum context_pas {
CPU_CONTEXT_SECURE = 0,
CPU_CONTEXT_NS,
#if ENABLE_RME
CPU_CONTEXT_REALM,
#endif
CPU_CONTEXT_NUM
} context_pas_t;
/*******************************************************************************
* Function & variable prototypes
******************************************************************************/
/*******************************************************************************
* Cache of frequently used per-cpu data:
* Pointers to non-secure and secure security state contexts
* Pointers to non-secure, realm, and secure security state contexts
* Address of the crash stack
* It is aligned to the cache line boundary to allow efficient concurrent
* manipulation of these pointers on different cpus
*
* TODO: Add other commonly used variables to this (tf_issues#90)
*
* The data structure and the _cpu_data accessors should not be used directly
* by components that have per-cpu members. The member access macros should be
* used for this.
******************************************************************************/
typedef struct cpu_data {
#ifdef __aarch64__
void *cpu_context[2];
#endif
void *cpu_context[CPU_DATA_CONTEXT_NUM];
#endif /* __aarch64__ */
uintptr_t cpu_ops_ptr;
struct psci_cpu_data psci_svc_cpu_data;
#if ENABLE_PAUTH
@ -122,6 +141,11 @@ typedef struct cpu_data {
extern cpu_data_t percpu_data[PLATFORM_CORE_COUNT];
#ifdef __aarch64__
CASSERT(CPU_DATA_CONTEXT_NUM == CPU_CONTEXT_NUM,
assert_cpu_data_context_num_mismatch);
#endif
#if ENABLE_PAUTH
CASSERT(CPU_DATA_APIAKEY_OFFSET == __builtin_offsetof
(cpu_data_t, apiakey),
@ -160,6 +184,31 @@ static inline struct cpu_data *_cpu_data(void)
struct cpu_data *_cpu_data(void);
#endif
/*
* Returns the index of the cpu_context array for the given security state.
* All accesses to cpu_context should be through this helper to make sure
* an access is not out-of-bounds. The function assumes security_state is
* valid.
*/
static inline context_pas_t get_cpu_context_index(uint32_t security_state)
{
if (security_state == SECURE) {
return CPU_CONTEXT_SECURE;
} else {
#if ENABLE_RME
if (security_state == NON_SECURE) {
return CPU_CONTEXT_NS;
} else {
assert(security_state == REALM);
return CPU_CONTEXT_REALM;
}
#else
assert(security_state == NON_SECURE);
return CPU_CONTEXT_NS;
#endif
}
}
/**************************************************************************
* APIs for initialising and accessing per-cpu data
*************************************************************************/

View File

@ -93,24 +93,41 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
scr_el3 = read_scr();
scr_el3 &= ~(SCR_NS_BIT | SCR_RW_BIT | SCR_FIQ_BIT | SCR_IRQ_BIT |
SCR_ST_BIT | SCR_HCE_BIT);
#if ENABLE_RME
/* When RME support is enabled, clear the NSE bit as well. */
scr_el3 &= ~SCR_NSE_BIT;
#endif /* ENABLE_RME */
/*
* SCR_NS: Set the security state of the next EL.
*/
if (security_state != SECURE)
if (security_state == NON_SECURE) {
scr_el3 |= SCR_NS_BIT;
}
#if ENABLE_RME
/* Check for realm state if RME support enabled. */
if (security_state == REALM) {
scr_el3 |= SCR_NS_BIT | SCR_NSE_BIT | SCR_EnSCXT_BIT;
}
#endif /* ENABLE_RME */
/*
* SCR_EL3.RW: Set the execution state, AArch32 or AArch64, for next
* Exception level as specified by SPSR.
*/
if (GET_RW(ep->spsr) == MODE_RW_64)
if (GET_RW(ep->spsr) == MODE_RW_64) {
scr_el3 |= SCR_RW_BIT;
}
/*
* SCR_EL3.ST: Traps Secure EL1 accesses to the Counter-timer Physical
* Secure timer registers to EL3, from AArch64 state only, if specified
* by the entrypoint attributes.
*/
if (EP_GET_ST(ep->h.attr) != 0U)
if (EP_GET_ST(ep->h.attr) != 0U) {
scr_el3 |= SCR_ST_BIT;
}
/*
* If FEAT_HCX is enabled, enable access to HCRX_EL2 by setting
@ -152,8 +169,9 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
* If the Secure world wants to use pointer authentication,
* CTX_INCLUDE_PAUTH_REGS must be set to 1.
*/
if (security_state == NON_SECURE)
if (security_state == NON_SECURE) {
scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
}
#endif /* !CTX_INCLUDE_PAUTH_REGS */
#if !CTX_INCLUDE_MTE_REGS || ENABLE_ASSERTIONS
@ -188,8 +206,14 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
/*
* SCR_EL3.IRQ, SCR_EL3.FIQ: Enable the physical FIQ and IRQ routing as
* indicated by the interrupt routing model for BL31.
*
* TODO: The interrupt routing model code is not updated for REALM
* state. Use the default values of IRQ = FIQ = 0 for REALM security
* state for now.
*/
scr_el3 |= get_scr_el3_from_routing_model(security_state);
if (security_state != REALM) {
scr_el3 |= get_scr_el3_from_routing_model(security_state);
}
#endif
/* Save the initialized value of CPTR_EL3 register */
@ -256,9 +280,9 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
* required by PSCI specification)
*/
sctlr_elx = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0U;
if (GET_RW(ep->spsr) == MODE_RW_64)
if (GET_RW(ep->spsr) == MODE_RW_64) {
sctlr_elx |= SCTLR_EL1_RES1;
else {
} else {
/*
* If the target execution state is AArch32 then the following
* fields need to be set.
@ -413,7 +437,8 @@ void cm_init_my_context(const entry_point_info_t *ep)
}
/*******************************************************************************
* Prepare the CPU system registers for first entry into secure or normal world
* Prepare the CPU system registers for first entry into realm, secure, or
* normal world.
*
* If execution is requested to EL2 or hyp mode, SCTLR_EL2 is initialized
* If execution is requested to non-secure EL1 or svc mode, and the CPU supports
@ -497,7 +522,7 @@ void cm_prepare_el3_exit(uint32_t security_state)
* architecturally UNKNOWN on reset and are set to zero
* except for field(s) listed below.
*
* CNTHCTL_EL2.EL1PCEN: Set to one to disable traps to
* CNTHCTL_EL2.EL1PTEN: Set to one to disable traps to
* Hyp mode of Non-secure EL0 and EL1 accesses to the
* physical timer registers.
*
@ -645,10 +670,10 @@ void cm_el2_sysregs_context_save(uint32_t security_state)
u_register_t scr_el3 = read_scr();
/*
* Always save the non-secure EL2 context, only save the
* Always save the non-secure and realm EL2 context, only save the
* S-EL2 context if S-EL2 is enabled.
*/
if ((security_state == NON_SECURE) ||
if ((security_state != SECURE) ||
((security_state == SECURE) && ((scr_el3 & SCR_EEL2_BIT) != 0U))) {
cpu_context_t *ctx;
@ -667,10 +692,10 @@ void cm_el2_sysregs_context_restore(uint32_t security_state)
u_register_t scr_el3 = read_scr();
/*
* Always restore the non-secure EL2 context, only restore the
* Always restore the non-secure and realm EL2 context, only restore the
* S-EL2 context if S-EL2 is enabled.
*/
if ((security_state == NON_SECURE) ||
if ((security_state != SECURE) ||
((security_state == SECURE) && ((scr_el3 & SCR_EEL2_BIT) != 0U))) {
cpu_context_t *ctx;