GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <asm_macros.S>
|
||||
#include "spm_common.h"
|
||||
|
||||
.global spm_secure_partition_enter
|
||||
.global spm_secure_partition_exit
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* This function is called with SP_EL0 as stack. Here we stash our EL3
|
||||
* callee-saved registers on to the stack as a part of saving the C
|
||||
* runtime and enter the secure payload.
|
||||
* 'x0' contains a pointer to the memory where the address of the C
|
||||
* runtime context is to be saved.
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
func spm_secure_partition_enter
|
||||
/* Make space for the registers that we're going to save */
|
||||
mov x3, sp
|
||||
str x3, [x0, #0]
|
||||
sub sp, sp, #SP_C_RT_CTX_SIZE
|
||||
|
||||
/* Save callee-saved registers on to the stack */
|
||||
stp x19, x20, [sp, #SP_C_RT_CTX_X19]
|
||||
stp x21, x22, [sp, #SP_C_RT_CTX_X21]
|
||||
stp x23, x24, [sp, #SP_C_RT_CTX_X23]
|
||||
stp x25, x26, [sp, #SP_C_RT_CTX_X25]
|
||||
stp x27, x28, [sp, #SP_C_RT_CTX_X27]
|
||||
stp x29, x30, [sp, #SP_C_RT_CTX_X29]
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Everything is setup now. el3_exit() will use the secure context to
|
||||
* restore to the general purpose and EL3 system registers to ERET
|
||||
* into the secure payload.
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
b el3_exit
|
||||
endfunc spm_secure_partition_enter
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* This function is called with 'x0' pointing to a C runtime context
|
||||
* saved in spm_secure_partition_enter().
|
||||
* It restores the saved registers and jumps to that runtime with 'x0'
|
||||
* as the new SP register. This destroys the C runtime context that had
|
||||
* been built on the stack below the saved context by the caller. Later
|
||||
* the second parameter 'x1' is passed as a return value to the caller.
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
func spm_secure_partition_exit
|
||||
/* Restore the previous stack */
|
||||
mov sp, x0
|
||||
|
||||
/* Restore callee-saved registers on to the stack */
|
||||
ldp x19, x20, [x0, #(SP_C_RT_CTX_X19 - SP_C_RT_CTX_SIZE)]
|
||||
ldp x21, x22, [x0, #(SP_C_RT_CTX_X21 - SP_C_RT_CTX_SIZE)]
|
||||
ldp x23, x24, [x0, #(SP_C_RT_CTX_X23 - SP_C_RT_CTX_SIZE)]
|
||||
ldp x25, x26, [x0, #(SP_C_RT_CTX_X25 - SP_C_RT_CTX_SIZE)]
|
||||
ldp x27, x28, [x0, #(SP_C_RT_CTX_X27 - SP_C_RT_CTX_SIZE)]
|
||||
ldp x29, x30, [x0, #(SP_C_RT_CTX_X29 - SP_C_RT_CTX_SIZE)]
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* This should take us back to the instruction after the call to the
|
||||
* last spm_secure_partition_enter().* Place the second parameter to x0
|
||||
* so that the caller will see it as a return value from the original
|
||||
* entry call.
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
mov x0, x1
|
||||
ret
|
||||
endfunc spm_secure_partition_exit
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SPM_COMMON_H
|
||||
#define SPM_COMMON_H
|
||||
|
||||
#include <context.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* Constants that allow assembler code to preserve callee-saved registers of the
|
||||
* C runtime context while performing a security state switch.
|
||||
******************************************************************************/
|
||||
#define SP_C_RT_CTX_X19 0x0
|
||||
#define SP_C_RT_CTX_X20 0x8
|
||||
#define SP_C_RT_CTX_X21 0x10
|
||||
#define SP_C_RT_CTX_X22 0x18
|
||||
#define SP_C_RT_CTX_X23 0x20
|
||||
#define SP_C_RT_CTX_X24 0x28
|
||||
#define SP_C_RT_CTX_X25 0x30
|
||||
#define SP_C_RT_CTX_X26 0x38
|
||||
#define SP_C_RT_CTX_X27 0x40
|
||||
#define SP_C_RT_CTX_X28 0x48
|
||||
#define SP_C_RT_CTX_X29 0x50
|
||||
#define SP_C_RT_CTX_X30 0x58
|
||||
|
||||
#define SP_C_RT_CTX_SIZE 0x60
|
||||
#define SP_C_RT_CTX_ENTRIES (SP_C_RT_CTX_SIZE >> DWORD_SHIFT)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Assembly helpers */
|
||||
uint64_t spm_secure_partition_enter(uint64_t *c_rt_ctx);
|
||||
void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret);
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* SPM_COMMON_H */
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
ifneq (${ARCH},aarch64)
|
||||
$(error "Error: SPM is only supported on aarch64.")
|
||||
endif
|
||||
|
||||
INCLUDES += -Iservices/std_svc/spm/common/include
|
||||
|
||||
SPM_SOURCES := $(addprefix services/std_svc/spm/common/,\
|
||||
${ARCH}/spm_helpers.S)
|
||||
|
||||
# Let the top-level Makefile know that we intend to include a BL32 image
|
||||
NEED_BL32 := yes
|
||||
+107
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SPMC_H
|
||||
#define SPMC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <common/bl_common.h>
|
||||
#include <lib/psci/psci.h>
|
||||
#include <lib/spinlock.h>
|
||||
#include <services/el3_spmc_logical_sp.h>
|
||||
#include "spm_common.h"
|
||||
|
||||
/*
|
||||
* Ranges of FF-A IDs for Normal world and Secure world components. The
|
||||
* convention matches that used by other SPMCs i.e. Hafnium and OP-TEE.
|
||||
*/
|
||||
#define FFA_NWD_ID_BASE 0x0
|
||||
#define FFA_NWD_ID_LIMIT 0x7FFF
|
||||
#define FFA_SWD_ID_BASE 0x8000
|
||||
#define FFA_SWD_ID_LIMIT SPMD_DIRECT_MSG_ENDPOINT_ID - 1
|
||||
#define FFA_SWD_ID_MASK 0x8000
|
||||
|
||||
/* ID 0 is reserved for the normal world entity, (Hypervisor or OS Kernel). */
|
||||
#define FFA_NWD_ID U(0)
|
||||
/* First ID is reserved for the SPMC */
|
||||
#define FFA_SPMC_ID U(FFA_SWD_ID_BASE)
|
||||
/* SP IDs are allocated after the SPMC ID */
|
||||
#define FFA_SP_ID_BASE (FFA_SPMC_ID + 1)
|
||||
/* Align with Hafnium implementation */
|
||||
#define INV_SP_ID 0x7FFF
|
||||
|
||||
/* FF-A Related helper macros. */
|
||||
#define FFA_ID_MASK U(0xFFFF)
|
||||
#define FFA_PARTITION_ID_SHIFT U(16)
|
||||
#define FFA_FEATURES_BIT31_MASK U(0x1u << 31)
|
||||
#define FFA_FEATURES_RET_REQ_NS_BIT U(0x1 << 1)
|
||||
|
||||
#define FFA_RUN_EP_ID(ep_vcpu_ids) \
|
||||
((ep_vcpu_ids >> FFA_PARTITION_ID_SHIFT) & FFA_ID_MASK)
|
||||
#define FFA_RUN_VCPU_ID(ep_vcpu_ids) \
|
||||
(ep_vcpu_ids & FFA_ID_MASK)
|
||||
|
||||
#define FFA_PAGE_SIZE (4096)
|
||||
#define FFA_RXTX_PAGE_COUNT_MASK 0x1F
|
||||
|
||||
/* Ensure that the page size used by TF-A is 4k aligned. */
|
||||
CASSERT((PAGE_SIZE % FFA_PAGE_SIZE) == 0, assert_aligned_page_size);
|
||||
|
||||
/*
|
||||
* Defines to allow an SP to subscribe for power management messages
|
||||
*/
|
||||
#define FFA_PM_MSG_SUB_CPU_OFF U(1 << 0)
|
||||
#define FFA_PM_MSG_SUB_CPU_SUSPEND U(1 << 1)
|
||||
#define FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME U(1 << 2)
|
||||
|
||||
/*
|
||||
* Runtime states of an execution context as per the FF-A v1.1 specification.
|
||||
*/
|
||||
enum sp_runtime_states {
|
||||
RT_STATE_WAITING,
|
||||
RT_STATE_RUNNING,
|
||||
RT_STATE_PREEMPTED,
|
||||
RT_STATE_BLOCKED
|
||||
};
|
||||
|
||||
/*
|
||||
* Runtime model of an execution context as per the FF-A v1.1 specification. Its
|
||||
* value is valid only if the execution context is not in the waiting state.
|
||||
*/
|
||||
enum sp_runtime_model {
|
||||
RT_MODEL_DIR_REQ,
|
||||
RT_MODEL_RUN,
|
||||
RT_MODEL_INIT,
|
||||
RT_MODEL_INTR
|
||||
};
|
||||
|
||||
enum sp_runtime_el {
|
||||
EL1 = 0,
|
||||
S_EL0,
|
||||
S_EL1
|
||||
};
|
||||
|
||||
enum sp_execution_state {
|
||||
SP_STATE_AARCH64 = 0,
|
||||
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.
|
||||
*/
|
||||
struct sp_exec_ctx {
|
||||
/*
|
||||
* Store the stack address to restore C runtime context from after
|
||||
* returning from a synchronous entry into the SP.
|
||||
*/
|
||||
uint64_t c_rt_ctx;
|
||||
|
||||
/* Space to maintain the architectural state of an SP. */
|
||||
cpu_context_t cpu_ctx;
|
||||
|
||||
/* Track the current runtime state of the SP. */
|
||||
enum sp_runtime_states rt_state;
|
||||
|
||||
/* Track the current runtime model of the SP. */
|
||||
enum sp_runtime_model rt_model;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure to describe the cumulative properties of an SP.
|
||||
*/
|
||||
struct secure_partition_desc {
|
||||
/*
|
||||
* Execution contexts allocated to this endpoint. Ideally,
|
||||
* we need as many contexts as there are physical cpus only
|
||||
* for a S-EL1 SP which is MP-pinned.
|
||||
*/
|
||||
struct sp_exec_ctx ec[PLATFORM_CORE_COUNT];
|
||||
|
||||
/* ID of the Secure Partition. */
|
||||
uint16_t sp_id;
|
||||
|
||||
/* Runtime EL. */
|
||||
enum sp_runtime_el runtime_el;
|
||||
|
||||
/* Partition UUID. */
|
||||
uint32_t uuid[4];
|
||||
|
||||
/* Partition Properties. */
|
||||
uint32_t properties;
|
||||
|
||||
/* Supported FF-A Version. */
|
||||
uint32_t ffa_version;
|
||||
|
||||
/* 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;
|
||||
|
||||
/*
|
||||
* Store whether the SP has subscribed to any power management messages.
|
||||
*/
|
||||
uint16_t pwr_mgmt_msgs;
|
||||
|
||||
/*
|
||||
* Store whether the SP has requested the use of the NS bit for memory
|
||||
* management transactions if it is using FF-A v1.0.
|
||||
*/
|
||||
bool ns_bit_requested;
|
||||
};
|
||||
|
||||
/*
|
||||
* This define identifies the only SP that will be initialised and participate
|
||||
* in FF-A communication. The implementation leaves the door open for more SPs
|
||||
* to be managed in future but for now it is reasonable to assume that either a
|
||||
* single S-EL0 or a single S-EL1 SP will be supported. This define will be used
|
||||
* to identify which SP descriptor to initialise and manage during SP runtime.
|
||||
*/
|
||||
#define ACTIVE_SP_DESC_INDEX 0
|
||||
|
||||
/*
|
||||
* Structure to describe the cumulative properties of the Hypervisor and
|
||||
* NS-Endpoints.
|
||||
*/
|
||||
struct ns_endpoint_desc {
|
||||
/*
|
||||
* ID of the NS-Endpoint or Hypervisor.
|
||||
*/
|
||||
uint16_t ns_ep_id;
|
||||
|
||||
/*
|
||||
* Mailbox tracking.
|
||||
*/
|
||||
struct mailbox mailbox;
|
||||
|
||||
/*
|
||||
* Supported FF-A Version
|
||||
*/
|
||||
uint32_t ffa_version;
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds information returned for each partition by the FFA_PARTITION_INFO_GET
|
||||
* interface.
|
||||
*/
|
||||
struct ffa_partition_info_v1_0 {
|
||||
uint16_t ep_id;
|
||||
uint16_t execution_ctx_count;
|
||||
uint32_t properties;
|
||||
};
|
||||
|
||||
/* Extended structure for v1.1. */
|
||||
struct ffa_partition_info_v1_1 {
|
||||
uint16_t ep_id;
|
||||
uint16_t execution_ctx_count;
|
||||
uint32_t properties;
|
||||
uint32_t uuid[4];
|
||||
};
|
||||
|
||||
/* Reference to power management hooks */
|
||||
extern const spd_pm_ops_t spmc_pm;
|
||||
|
||||
/* Setup Function for different SP types. */
|
||||
void spmc_sp_common_setup(struct secure_partition_desc *sp,
|
||||
entry_point_info_t *ep_info,
|
||||
int32_t boot_info_reg);
|
||||
void spmc_el1_sp_setup(struct secure_partition_desc *sp,
|
||||
entry_point_info_t *ep_info);
|
||||
void spmc_sp_common_ep_commit(struct secure_partition_desc *sp,
|
||||
entry_point_info_t *ep_info);
|
||||
|
||||
/*
|
||||
* Helper function to perform a synchronous entry into a SP.
|
||||
*/
|
||||
uint64_t spmc_sp_synchronous_entry(struct sp_exec_ctx *ec);
|
||||
|
||||
/*
|
||||
* Helper function to obtain the descriptor of the current SP on a physical cpu.
|
||||
*/
|
||||
struct secure_partition_desc *spmc_get_current_sp_ctx(void);
|
||||
|
||||
/*
|
||||
* Helper function to obtain the execution context of an SP on a
|
||||
* physical cpu.
|
||||
*/
|
||||
struct sp_exec_ctx *spmc_get_sp_ec(struct secure_partition_desc *sp);
|
||||
|
||||
/*
|
||||
* Helper function to obtain the index of the execution context of an SP on a
|
||||
* physical cpu.
|
||||
*/
|
||||
unsigned int get_ec_index(struct secure_partition_desc *sp);
|
||||
|
||||
uint64_t spmc_ffa_error_return(void *handle, int error_code);
|
||||
|
||||
/*
|
||||
* Ensure a partition ID does not clash and follows the secure world convention.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Helper function to obtain the RX/TX buffer pair descriptor of the Hypervisor
|
||||
* or OS kernel in the normal world or the last SP that was run.
|
||||
*/
|
||||
struct mailbox *spmc_get_mbox_desc(bool secure_origin);
|
||||
|
||||
/*
|
||||
* Helper function to obtain the context of an SP with a given partition ID.
|
||||
*/
|
||||
struct secure_partition_desc *spmc_get_sp_ctx(uint16_t id);
|
||||
|
||||
/*
|
||||
* Add helper function to obtain the FF-A version of the calling
|
||||
* partition.
|
||||
*/
|
||||
uint32_t get_partition_ffa_version(bool secure_origin);
|
||||
|
||||
|
||||
#endif /* SPMC_H */
|
||||
@@ -0,0 +1,44 @@
|
||||
#
|
||||
# Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
ifneq (${ARCH},aarch64)
|
||||
$(error "Error: SPMC is only supported on aarch64.")
|
||||
endif
|
||||
|
||||
SPMC_SOURCES := $(addprefix services/std_svc/spm/el3_spmc/, \
|
||||
spmc_main.c \
|
||||
spmc_setup.c \
|
||||
logical_sp.c \
|
||||
spmc_pm.c \
|
||||
spmc_shared_mem.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
|
||||
|
||||
ifndef BL32
|
||||
# The SPMC is paired with a Test Secure Payload source and we intend to
|
||||
# build the Test Secure Payload if no other image has been provided
|
||||
# for BL32.
|
||||
#
|
||||
# In cases where an associated Secure Payload lies outside this build
|
||||
# system/source tree, the dispatcher Makefile can either invoke an external
|
||||
# build command or assume it is pre-built.
|
||||
|
||||
BL32_ROOT := bl32/tsp
|
||||
|
||||
# Conditionally include SP's Makefile. The assumption is that the TSP's build
|
||||
# system is compatible with that of Trusted Firmware, and it'll add and populate
|
||||
# necessary build targets and variables.
|
||||
|
||||
include ${BL32_ROOT}/tsp.mk
|
||||
endif
|
||||
+1995
File diff suppressed because it is too large
Load Diff
+283
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <lib/el3_runtime/context_mgmt.h>
|
||||
#include <lib/spinlock.h>
|
||||
#include <plat/common/common_def.h>
|
||||
#include <plat/common/platform.h>
|
||||
#include <services/ffa_svc.h>
|
||||
#include "spmc.h"
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* spmc_build_pm_message
|
||||
*
|
||||
* Builds an SPMC to SP direct message request.
|
||||
******************************************************************************/
|
||||
static void spmc_build_pm_message(gp_regs_t *gpregs,
|
||||
unsigned long long message,
|
||||
uint8_t pm_msg_type,
|
||||
uint16_t sp_id)
|
||||
{
|
||||
write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32);
|
||||
write_ctx_reg(gpregs, CTX_GPREG_X1,
|
||||
(FFA_SPMC_ID << FFA_DIRECT_MSG_SOURCE_SHIFT) |
|
||||
sp_id);
|
||||
write_ctx_reg(gpregs, CTX_GPREG_X2, FFA_FWK_MSG_BIT |
|
||||
(pm_msg_type & FFA_FWK_MSG_MASK));
|
||||
write_ctx_reg(gpregs, CTX_GPREG_X3, message);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This CPU has been turned on. Enter the SP to initialise S-EL1.
|
||||
******************************************************************************/
|
||||
static void spmc_cpu_on_finish_handler(u_register_t unused)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
struct sp_exec_ctx *ec;
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
entry_point_info_t sec_ec_ep_info = {0};
|
||||
uint64_t rc;
|
||||
|
||||
/* Sanity check for a NULL pointer dereference. */
|
||||
assert(sp != NULL);
|
||||
|
||||
/* Initialize entry point information for the SP. */
|
||||
SET_PARAM_HEAD(&sec_ec_ep_info, PARAM_EP, VERSION_1,
|
||||
SECURE | EP_ST_ENABLE);
|
||||
|
||||
/*
|
||||
* Check if the primary execution context registered an entry point else
|
||||
* bail out early.
|
||||
* TODO: Add support for boot reason in manifest to allow jumping to
|
||||
* entrypoint into the primary execution context.
|
||||
*/
|
||||
if (sp->secondary_ep == 0) {
|
||||
WARN("%s: No secondary ep on core%u\n", __func__, linear_id);
|
||||
return;
|
||||
}
|
||||
|
||||
sec_ec_ep_info.pc = sp->secondary_ep;
|
||||
|
||||
/*
|
||||
* Setup and initialise the SP execution context on this physical cpu.
|
||||
*/
|
||||
spmc_el1_sp_setup(sp, &sec_ec_ep_info);
|
||||
spmc_sp_common_ep_commit(sp, &sec_ec_ep_info);
|
||||
|
||||
/* Obtain a reference to the SP execution context. */
|
||||
ec = spmc_get_sp_ec(sp);
|
||||
|
||||
/*
|
||||
* TODO: Should we do some PM related state tracking of the SP execution
|
||||
* context here?
|
||||
*/
|
||||
|
||||
/* Update the runtime model and state of the partition. */
|
||||
ec->rt_model = RT_MODEL_INIT;
|
||||
ec->rt_state = RT_STATE_RUNNING;
|
||||
|
||||
INFO("SP (0x%x) init start on core%u.\n", sp->sp_id, linear_id);
|
||||
|
||||
rc = spmc_sp_synchronous_entry(ec);
|
||||
if (rc != 0ULL) {
|
||||
ERROR("%s failed (%lu) on CPU%u\n", __func__, rc, linear_id);
|
||||
}
|
||||
|
||||
/* Update the runtime state of the partition. */
|
||||
ec->rt_state = RT_STATE_WAITING;
|
||||
|
||||
VERBOSE("CPU %u on!\n", linear_id);
|
||||
}
|
||||
/*******************************************************************************
|
||||
* Helper function to send a FF-A power management message to an SP.
|
||||
******************************************************************************/
|
||||
static int32_t spmc_send_pm_msg(uint8_t pm_msg_type,
|
||||
unsigned long long psci_event)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
struct sp_exec_ctx *ec;
|
||||
gp_regs_t *gpregs_ctx;
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
u_register_t resp;
|
||||
uint64_t rc;
|
||||
|
||||
/* Obtain a reference to the SP execution context. */
|
||||
ec = spmc_get_sp_ec(sp);
|
||||
|
||||
/*
|
||||
* TODO: Should we do some PM related state tracking of the SP execution
|
||||
* context here?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Build an SPMC to SP direct message request.
|
||||
* Note that x4-x6 should be populated with the original PSCI arguments.
|
||||
*/
|
||||
spmc_build_pm_message(get_gpregs_ctx(&ec->cpu_ctx),
|
||||
psci_event,
|
||||
pm_msg_type,
|
||||
sp->sp_id);
|
||||
|
||||
/* Sanity check partition state. */
|
||||
assert(ec->rt_state == RT_STATE_WAITING);
|
||||
|
||||
/* Update the runtime model and state of the partition. */
|
||||
ec->rt_model = RT_MODEL_DIR_REQ;
|
||||
ec->rt_state = RT_STATE_RUNNING;
|
||||
|
||||
rc = spmc_sp_synchronous_entry(ec);
|
||||
if (rc != 0ULL) {
|
||||
ERROR("%s failed (%lu) on CPU%u.\n", __func__, rc, linear_id);
|
||||
assert(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate we receive an expected response from the SP.
|
||||
* TODO: We don't currently support aborting an SP in the scenario
|
||||
* where it is misbehaving so assert these conditions are not
|
||||
* met for now.
|
||||
*/
|
||||
gpregs_ctx = get_gpregs_ctx(&ec->cpu_ctx);
|
||||
|
||||
/* Expect a direct message response from the SP. */
|
||||
resp = read_ctx_reg(gpregs_ctx, CTX_GPREG_X0);
|
||||
if (resp != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
|
||||
ERROR("%s invalid SP response (%lx).\n", __func__, resp);
|
||||
assert(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Ensure the sender and receiver are populated correctly. */
|
||||
resp = read_ctx_reg(gpregs_ctx, CTX_GPREG_X1);
|
||||
if (!(ffa_endpoint_source(resp) == sp->sp_id &&
|
||||
ffa_endpoint_destination(resp) == FFA_SPMC_ID)) {
|
||||
ERROR("%s invalid src/dst response (%lx).\n", __func__, resp);
|
||||
assert(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Expect a PM message response from the SP. */
|
||||
resp = read_ctx_reg(gpregs_ctx, CTX_GPREG_X2);
|
||||
if ((resp & FFA_FWK_MSG_BIT) == 0U ||
|
||||
((resp & FFA_FWK_MSG_MASK) != FFA_PM_MSG_PM_RESP)) {
|
||||
ERROR("%s invalid PM response (%lx).\n", __func__, resp);
|
||||
assert(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Update the runtime state of the partition. */
|
||||
ec->rt_state = RT_STATE_WAITING;
|
||||
|
||||
/* Return the status code returned by the SP */
|
||||
return read_ctx_reg(gpregs_ctx, CTX_GPREG_X3);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* spmc_cpu_suspend_finish_handler
|
||||
******************************************************************************/
|
||||
static void spmc_cpu_suspend_finish_handler(u_register_t unused)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
int32_t rc;
|
||||
|
||||
/* Sanity check for a NULL pointer dereference. */
|
||||
assert(sp != NULL);
|
||||
|
||||
/*
|
||||
* Check if the SP has subscribed for this power management message.
|
||||
* If not then we don't have anything else to do here.
|
||||
*/
|
||||
if ((sp->pwr_mgmt_msgs & FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME) == 0U) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = spmc_send_pm_msg(FFA_PM_MSG_WB_REQ, FFA_WB_TYPE_NOTS2RAM);
|
||||
if (rc < 0) {
|
||||
ERROR("%s failed (%d) on CPU%u\n", __func__, rc, linear_id);
|
||||
return;
|
||||
}
|
||||
|
||||
exit:
|
||||
VERBOSE("CPU %u resumed!\n", linear_id);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* spmc_cpu_suspend_handler
|
||||
******************************************************************************/
|
||||
static void spmc_cpu_suspend_handler(u_register_t unused)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
int32_t rc;
|
||||
|
||||
/* Sanity check for a NULL pointer dereference. */
|
||||
assert(sp != NULL);
|
||||
|
||||
/*
|
||||
* Check if the SP has subscribed for this power management message.
|
||||
* If not then we don't have anything else to do here.
|
||||
*/
|
||||
if ((sp->pwr_mgmt_msgs & FFA_PM_MSG_SUB_CPU_SUSPEND) == 0U) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = spmc_send_pm_msg(FFA_FWK_MSG_PSCI, PSCI_CPU_SUSPEND_AARCH64);
|
||||
if (rc < 0) {
|
||||
ERROR("%s failed (%d) on CPU%u\n", __func__, rc, linear_id);
|
||||
return;
|
||||
}
|
||||
exit:
|
||||
VERBOSE("CPU %u suspend!\n", linear_id);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* spmc_cpu_off_handler
|
||||
******************************************************************************/
|
||||
static int32_t spmc_cpu_off_handler(u_register_t unused)
|
||||
{
|
||||
struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
|
||||
unsigned int linear_id = plat_my_core_pos();
|
||||
int32_t ret = 0;
|
||||
|
||||
/* Sanity check for a NULL pointer dereference. */
|
||||
assert(sp != NULL);
|
||||
|
||||
/*
|
||||
* Check if the SP has subscribed for this power management message.
|
||||
* If not then we don't have anything else to do here.
|
||||
*/
|
||||
if ((sp->pwr_mgmt_msgs & FFA_PM_MSG_SUB_CPU_OFF) == 0U) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = spmc_send_pm_msg(FFA_FWK_MSG_PSCI, PSCI_CPU_OFF);
|
||||
if (ret < 0) {
|
||||
ERROR("%s failed (%d) on CPU%u\n", __func__, ret, linear_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
exit:
|
||||
VERBOSE("CPU %u off!\n", linear_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Structure populated by the SPM Core to perform any bookkeeping before
|
||||
* PSCI executes a power mgmt. operation.
|
||||
******************************************************************************/
|
||||
const spd_pm_ops_t spmc_pm = {
|
||||
.svc_on_finish = spmc_cpu_on_finish_handler,
|
||||
.svc_off = spmc_cpu_off_handler,
|
||||
.svc_suspend = spmc_cpu_suspend_handler,
|
||||
.svc_suspend_finish = spmc_cpu_suspend_finish_handler
|
||||
};
|
||||
+278
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <common/fdt_wrappers.h>
|
||||
#include <context.h>
|
||||
#include <lib/el3_runtime/context_mgmt.h>
|
||||
#include <lib/utils.h>
|
||||
#include <lib/xlat_tables/xlat_tables_v2.h>
|
||||
#include <libfdt.h>
|
||||
#include <plat/common/common_def.h>
|
||||
#include <plat/common/platform.h>
|
||||
#include <services/ffa_svc.h>
|
||||
#include "spm_common.h"
|
||||
#include "spmc.h"
|
||||
#include <tools_share/firmware_image_package.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
/*
|
||||
* Statically allocate a page of memory for passing boot information to an SP.
|
||||
*/
|
||||
static uint8_t ffa_boot_info_mem[PAGE_SIZE] __aligned(PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* This function creates a initialization descriptor in the memory reserved
|
||||
* for passing boot information to an SP. It then copies the partition manifest
|
||||
* into this region and ensures that its reference in the initialization
|
||||
* descriptor is updated.
|
||||
*/
|
||||
static void spmc_create_boot_info(entry_point_info_t *ep_info,
|
||||
struct secure_partition_desc *sp)
|
||||
{
|
||||
struct ffa_boot_info_header *boot_header;
|
||||
struct ffa_boot_info_desc *boot_descriptor;
|
||||
uintptr_t manifest_addr;
|
||||
|
||||
/*
|
||||
* Calculate the maximum size of the manifest that can be accommodated
|
||||
* in the boot information memory region.
|
||||
*/
|
||||
const unsigned int
|
||||
max_manifest_sz = sizeof(ffa_boot_info_mem) -
|
||||
(sizeof(struct ffa_boot_info_header) +
|
||||
sizeof(struct ffa_boot_info_desc));
|
||||
|
||||
/*
|
||||
* The current implementation only supports the FF-A v1.1
|
||||
* implementation of the boot protocol, therefore check
|
||||
* that a v1.0 SP has not requested use of the protocol.
|
||||
*/
|
||||
if (sp->ffa_version == MAKE_FFA_VERSION(1, 0)) {
|
||||
ERROR("FF-A boot protocol not supported for v1.0 clients\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the manifest will fit into the boot info memory region else
|
||||
* bail.
|
||||
*/
|
||||
if (ep_info->args.arg1 > max_manifest_sz) {
|
||||
WARN("Unable to copy manifest into boot information. ");
|
||||
WARN("Max sz = %u bytes. Manifest sz = %lu bytes\n",
|
||||
max_manifest_sz, ep_info->args.arg1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Zero the memory region before populating. */
|
||||
memset(ffa_boot_info_mem, 0, PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Populate the ffa_boot_info_header at the start of the boot info
|
||||
* region.
|
||||
*/
|
||||
boot_header = (struct ffa_boot_info_header *) ffa_boot_info_mem;
|
||||
|
||||
/* Position the ffa_boot_info_desc after the ffa_boot_info_header. */
|
||||
boot_header->offset_boot_info_desc =
|
||||
sizeof(struct ffa_boot_info_header);
|
||||
boot_descriptor = (struct ffa_boot_info_desc *)
|
||||
(ffa_boot_info_mem +
|
||||
boot_header->offset_boot_info_desc);
|
||||
|
||||
/*
|
||||
* We must use the FF-A version coresponding to the version implemented
|
||||
* by the SP. Currently this can only be v1.1.
|
||||
*/
|
||||
boot_header->version = sp->ffa_version;
|
||||
|
||||
/* Populate the boot information header. */
|
||||
boot_header->size_boot_info_desc = sizeof(struct ffa_boot_info_desc);
|
||||
|
||||
/* Set the signature "0xFFA". */
|
||||
boot_header->signature = FFA_INIT_DESC_SIGNATURE;
|
||||
|
||||
/* Set the count. Currently 1 since only the manifest is specified. */
|
||||
boot_header->count_boot_info_desc = 1;
|
||||
|
||||
/* Populate the boot information descriptor for the manifest. */
|
||||
boot_descriptor->type =
|
||||
FFA_BOOT_INFO_TYPE(FFA_BOOT_INFO_TYPE_STD) |
|
||||
FFA_BOOT_INFO_TYPE_ID(FFA_BOOT_INFO_TYPE_ID_FDT);
|
||||
|
||||
boot_descriptor->flags =
|
||||
FFA_BOOT_INFO_FLAG_NAME(FFA_BOOT_INFO_FLAG_NAME_UUID) |
|
||||
FFA_BOOT_INFO_FLAG_CONTENT(FFA_BOOT_INFO_FLAG_CONTENT_ADR);
|
||||
|
||||
/*
|
||||
* Copy the manifest into boot info region after the boot information
|
||||
* descriptor.
|
||||
*/
|
||||
boot_descriptor->size_boot_info = (uint32_t) ep_info->args.arg1;
|
||||
|
||||
manifest_addr = (uintptr_t) (ffa_boot_info_mem +
|
||||
boot_header->offset_boot_info_desc +
|
||||
boot_header->size_boot_info_desc);
|
||||
|
||||
memcpy((void *) manifest_addr, (void *) ep_info->args.arg0,
|
||||
boot_descriptor->size_boot_info);
|
||||
|
||||
boot_descriptor->content = manifest_addr;
|
||||
|
||||
/* Calculate the size of the total boot info blob. */
|
||||
boot_header->size_boot_info_blob = boot_header->offset_boot_info_desc +
|
||||
boot_descriptor->size_boot_info +
|
||||
(boot_header->count_boot_info_desc *
|
||||
boot_header->size_boot_info_desc);
|
||||
|
||||
INFO("SP boot info @ 0x%lx, size: %u bytes.\n",
|
||||
(uintptr_t) ffa_boot_info_mem,
|
||||
boot_header->size_boot_info_blob);
|
||||
INFO("SP manifest @ 0x%lx, size: %u bytes.\n",
|
||||
boot_descriptor->content,
|
||||
boot_descriptor->size_boot_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* We are assuming that the index of the execution
|
||||
* context used is the linear index of the current physical cpu.
|
||||
*/
|
||||
unsigned int get_ec_index(struct secure_partition_desc *sp)
|
||||
{
|
||||
return plat_my_core_pos();
|
||||
}
|
||||
|
||||
/* S-EL1 partition specific initialisation. */
|
||||
void spmc_el1_sp_setup(struct secure_partition_desc *sp,
|
||||
entry_point_info_t *ep_info)
|
||||
{
|
||||
/* Sanity check input arguments. */
|
||||
assert(sp != NULL);
|
||||
assert(ep_info != NULL);
|
||||
|
||||
/* Initialise the SPSR for S-EL1 SPs. */
|
||||
ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
|
||||
DISABLE_ALL_EXCEPTIONS);
|
||||
|
||||
/*
|
||||
* TF-A Implementation defined behaviour to provide the linear
|
||||
* core ID in the x4 register.
|
||||
*/
|
||||
ep_info->args.arg4 = (uintptr_t) plat_my_core_pos();
|
||||
|
||||
/*
|
||||
* Check whether setup is being performed for the primary or a secondary
|
||||
* execution context. In the latter case, indicate to the SP that this
|
||||
* is a warm boot.
|
||||
* TODO: This check would need to be reworked if the same entry point is
|
||||
* used for both primary and secondary initialisation.
|
||||
*/
|
||||
if (sp->secondary_ep != 0U) {
|
||||
/*
|
||||
* Sanity check that the secondary entry point is still what was
|
||||
* originally set.
|
||||
*/
|
||||
assert(sp->secondary_ep == ep_info->pc);
|
||||
ep_info->args.arg0 = FFA_WB_TYPE_S2RAM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Common initialisation for all SPs. */
|
||||
void spmc_sp_common_setup(struct secure_partition_desc *sp,
|
||||
entry_point_info_t *ep_info,
|
||||
int32_t boot_info_reg)
|
||||
{
|
||||
uint16_t sp_id;
|
||||
|
||||
/* Assign FF-A Partition ID if not already assigned. */
|
||||
if (sp->sp_id == INV_SP_ID) {
|
||||
sp_id = FFA_SP_ID_BASE + ACTIVE_SP_DESC_INDEX;
|
||||
/*
|
||||
* Ensure we don't clash with previously assigned partition
|
||||
* IDs.
|
||||
*/
|
||||
while (!is_ffa_secure_id_valid(sp_id)) {
|
||||
sp_id++;
|
||||
|
||||
if (sp_id == FFA_SWD_ID_LIMIT) {
|
||||
ERROR("Unable to determine valid SP ID.\n");
|
||||
panic();
|
||||
}
|
||||
}
|
||||
sp->sp_id = sp_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* We currently only support S-EL1 partitions so ensure this is the
|
||||
* case.
|
||||
*/
|
||||
assert(sp->runtime_el == S_EL1);
|
||||
|
||||
/* Check if the SP wants to use the FF-A boot protocol. */
|
||||
if (boot_info_reg >= 0) {
|
||||
/*
|
||||
* Create a boot information descriptor and copy the partition
|
||||
* manifest into the reserved memory region for consumption by
|
||||
* the SP.
|
||||
*/
|
||||
spmc_create_boot_info(ep_info, sp);
|
||||
|
||||
/*
|
||||
* We have consumed what we need from ep args so we can now
|
||||
* zero them before we start populating with new information
|
||||
* specifically for the SP.
|
||||
*/
|
||||
zeromem(&ep_info->args, sizeof(ep_info->args));
|
||||
|
||||
/*
|
||||
* Pass the address of the boot information in the
|
||||
* boot_info_reg.
|
||||
*/
|
||||
switch (boot_info_reg) {
|
||||
case 0:
|
||||
ep_info->args.arg0 = (uintptr_t) ffa_boot_info_mem;
|
||||
break;
|
||||
case 1:
|
||||
ep_info->args.arg1 = (uintptr_t) ffa_boot_info_mem;
|
||||
break;
|
||||
case 2:
|
||||
ep_info->args.arg2 = (uintptr_t) ffa_boot_info_mem;
|
||||
break;
|
||||
case 3:
|
||||
ep_info->args.arg3 = (uintptr_t) ffa_boot_info_mem;
|
||||
break;
|
||||
default:
|
||||
ERROR("Invalid value for \"gp-register-num\" %d.\n",
|
||||
boot_info_reg);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We don't need any of the information that was populated
|
||||
* in ep_args so we can clear them.
|
||||
*/
|
||||
zeromem(&ep_info->args, sizeof(ep_info->args));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the SP context now we have populated the common and EL specific
|
||||
* entrypoint information.
|
||||
*/
|
||||
void spmc_sp_common_ep_commit(struct secure_partition_desc *sp,
|
||||
entry_point_info_t *ep_info)
|
||||
{
|
||||
cpu_context_t *cpu_ctx;
|
||||
|
||||
cpu_ctx = &(spmc_get_sp_ec(sp)->cpu_ctx);
|
||||
print_entry_point_info(ep_info);
|
||||
cm_setup_context(cpu_ctx, ep_info);
|
||||
}
|
||||
+1861
File diff suppressed because it is too large
Load Diff
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SPMC_SHARED_MEM_H
|
||||
#define SPMC_SHARED_MEM_H
|
||||
|
||||
#include <services/el3_spmc_ffa_memory.h>
|
||||
|
||||
/**
|
||||
* struct ffa_mem_relinquish_descriptor - Relinquish request descriptor.
|
||||
* @handle:
|
||||
* Id of shared memory object to relinquish.
|
||||
* @flags:
|
||||
* If bit 0 is set clear memory after unmapping from borrower. Must be 0
|
||||
* for share. Bit[1]: Time slicing. Not supported, must be 0. All other
|
||||
* bits are reserved 0.
|
||||
* @endpoint_count:
|
||||
* Number of entries in @endpoint_array.
|
||||
* @endpoint_array:
|
||||
* Array of endpoint ids.
|
||||
*/
|
||||
struct ffa_mem_relinquish_descriptor {
|
||||
uint64_t handle;
|
||||
uint32_t flags;
|
||||
uint32_t endpoint_count;
|
||||
ffa_endpoint_id16_t endpoint_array[];
|
||||
};
|
||||
CASSERT(sizeof(struct ffa_mem_relinquish_descriptor) == 16,
|
||||
assert_ffa_mem_relinquish_descriptor_size_mismatch);
|
||||
|
||||
/**
|
||||
* struct spmc_shmem_obj_state - Global state.
|
||||
* @data: Backing store for spmc_shmem_obj objects.
|
||||
* @data_size: The size allocated for the backing store.
|
||||
* @allocated: Number of bytes allocated in @data.
|
||||
* @next_handle: Handle used for next allocated object.
|
||||
* @lock: Lock protecting all state in this file.
|
||||
*/
|
||||
struct spmc_shmem_obj_state {
|
||||
uint8_t *data;
|
||||
size_t data_size;
|
||||
size_t allocated;
|
||||
uint64_t next_handle;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
extern struct spmc_shmem_obj_state spmc_shmem_obj_state;
|
||||
extern int plat_spmc_shmem_begin(struct ffa_mtd *desc);
|
||||
extern int plat_spmc_shmem_reclaim(struct ffa_mtd *desc);
|
||||
|
||||
long spmc_ffa_mem_send(uint32_t smc_fid,
|
||||
bool secure_origin,
|
||||
uint64_t total_length,
|
||||
uint32_t fragment_length,
|
||||
uint64_t address,
|
||||
uint32_t page_count,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
uint64_t flags);
|
||||
|
||||
long spmc_ffa_mem_frag_tx(uint32_t smc_fid,
|
||||
bool secure_origin,
|
||||
uint64_t handle_low,
|
||||
uint64_t handle_high,
|
||||
uint32_t fragment_length,
|
||||
uint32_t sender_id,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
uint64_t flags);
|
||||
|
||||
long spmc_ffa_mem_retrieve_req(uint32_t smc_fid,
|
||||
bool secure_origin,
|
||||
uint32_t total_length,
|
||||
uint32_t fragment_length,
|
||||
uint64_t address,
|
||||
uint32_t page_count,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
uint64_t flags);
|
||||
|
||||
long spmc_ffa_mem_frag_rx(uint32_t smc_fid,
|
||||
bool secure_origin,
|
||||
uint32_t handle_low,
|
||||
uint32_t handle_high,
|
||||
uint32_t fragment_offset,
|
||||
uint32_t sender_id,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
uint64_t flags);
|
||||
|
||||
|
||||
int spmc_ffa_mem_relinquish(uint32_t smc_fid,
|
||||
bool secure_origin,
|
||||
uint32_t handle_low,
|
||||
uint32_t handle_high,
|
||||
uint32_t fragment_offset,
|
||||
uint32_t sender_id,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
uint64_t flags);
|
||||
|
||||
int spmc_ffa_mem_reclaim(uint32_t smc_fid,
|
||||
bool secure_origin,
|
||||
uint32_t handle_low,
|
||||
uint32_t handle_high,
|
||||
uint32_t mem_flags,
|
||||
uint64_t x4,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
uint64_t flags);
|
||||
|
||||
#endif /* SPMC_SHARED_MEM_H */
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch.h>
|
||||
#include <asm_macros.S>
|
||||
#include <common/bl_common.h>
|
||||
#include <context.h>
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Very simple stackless exception handlers used by the spm shim layer.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
.globl spm_shim_exceptions_ptr
|
||||
|
||||
vector_base spm_shim_exceptions_ptr, .spm_shim_exceptions
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* Current EL with SP0 : 0x0 - 0x200
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
vector_entry SynchronousExceptionSP0, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry SynchronousExceptionSP0
|
||||
|
||||
vector_entry IrqSP0, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry IrqSP0
|
||||
|
||||
vector_entry FiqSP0, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry FiqSP0
|
||||
|
||||
vector_entry SErrorSP0, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry SErrorSP0
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* Current EL with SPx: 0x200 - 0x400
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
vector_entry SynchronousExceptionSPx, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry SynchronousExceptionSPx
|
||||
|
||||
vector_entry IrqSPx, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry IrqSPx
|
||||
|
||||
vector_entry FiqSPx, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry FiqSPx
|
||||
|
||||
vector_entry SErrorSPx, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry SErrorSPx
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* Lower EL using AArch64 : 0x400 - 0x600. No exceptions
|
||||
* are handled since secure_partition does not implement
|
||||
* a lower EL
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
vector_entry SynchronousExceptionA64, .spm_shim_exceptions
|
||||
msr tpidr_el1, x30
|
||||
mrs x30, esr_el1
|
||||
ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
|
||||
|
||||
cmp x30, #EC_AARCH64_SVC
|
||||
b.eq do_smc
|
||||
|
||||
cmp x30, #EC_AARCH32_SVC
|
||||
b.eq do_smc
|
||||
|
||||
cmp x30, #EC_AARCH64_SYS
|
||||
b.eq handle_sys_trap
|
||||
|
||||
/* Fail in all the other cases */
|
||||
b panic
|
||||
|
||||
/* ---------------------------------------------
|
||||
* Tell SPM that we are done initialising
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
do_smc:
|
||||
mrs x30, tpidr_el1
|
||||
smc #0
|
||||
exception_return
|
||||
|
||||
/* AArch64 system instructions trap are handled as a panic for now */
|
||||
handle_sys_trap:
|
||||
panic:
|
||||
b panic
|
||||
end_vector_entry SynchronousExceptionA64
|
||||
|
||||
vector_entry IrqA64, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry IrqA64
|
||||
|
||||
vector_entry FiqA64, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry FiqA64
|
||||
|
||||
vector_entry SErrorA64, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry SErrorA64
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* Lower EL using AArch32 : 0x600 - 0x800
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
vector_entry SynchronousExceptionA32, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry SynchronousExceptionA32
|
||||
|
||||
vector_entry IrqA32, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry IrqA32
|
||||
|
||||
vector_entry FiqA32, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry FiqA32
|
||||
|
||||
vector_entry SErrorA32, .spm_shim_exceptions
|
||||
b .
|
||||
end_vector_entry SErrorA32
|
||||
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
ifneq (${SPD},none)
|
||||
$(error "Error: SPD and SPM_MM are incompatible build options.")
|
||||
endif
|
||||
ifneq (${ARCH},aarch64)
|
||||
$(error "Error: SPM_MM is only supported on aarch64.")
|
||||
endif
|
||||
ifeq (${ENABLE_SVE_FOR_NS},1)
|
||||
$(error "Error: SPM_MM is not compatible with ENABLE_SVE_FOR_NS")
|
||||
endif
|
||||
ifeq (${ENABLE_SME_FOR_NS},1)
|
||||
$(error "Error: SPM_MM is not compatible with ENABLE_SME_FOR_NS")
|
||||
endif
|
||||
ifeq (${CTX_INCLUDE_FPREGS},0)
|
||||
$(warning "Warning: SPM_MM: CTX_INCLUDE_FPREGS is set to 0")
|
||||
endif
|
||||
|
||||
SPM_MM_SOURCES := $(addprefix services/std_svc/spm/spm_mm/, \
|
||||
${ARCH}/spm_mm_shim_exceptions.S \
|
||||
spm_mm_main.c \
|
||||
spm_mm_setup.c \
|
||||
spm_mm_xlat.c)
|
||||
|
||||
|
||||
# Let the top-level Makefile know that we intend to include a BL32 image
|
||||
NEED_BL32 := yes
|
||||
|
||||
# required so that SPM code executing at S-EL0 can access the timer registers
|
||||
NS_TIMER_SWITCH := 1
|
||||
+370
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <bl31/bl31.h>
|
||||
#include <bl31/ehf.h>
|
||||
#include <common/debug.h>
|
||||
#include <common/runtime_svc.h>
|
||||
#include <lib/el3_runtime/context_mgmt.h>
|
||||
#include <lib/smccc.h>
|
||||
#include <lib/spinlock.h>
|
||||
#include <lib/utils.h>
|
||||
#include <lib/xlat_tables/xlat_tables_v2.h>
|
||||
#include <plat/common/platform.h>
|
||||
#include <services/spm_mm_partition.h>
|
||||
#include <services/spm_mm_svc.h>
|
||||
#include <smccc_helpers.h>
|
||||
|
||||
#include "spm_common.h"
|
||||
#include "spm_mm_private.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Secure Partition context information.
|
||||
******************************************************************************/
|
||||
static sp_context_t sp_ctx;
|
||||
|
||||
/*******************************************************************************
|
||||
* Set state of a Secure Partition context.
|
||||
******************************************************************************/
|
||||
void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
|
||||
{
|
||||
spin_lock(&(sp_ptr->state_lock));
|
||||
sp_ptr->state = state;
|
||||
spin_unlock(&(sp_ptr->state_lock));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Wait until the state of a Secure Partition is the specified one and change it
|
||||
* to the desired state.
|
||||
******************************************************************************/
|
||||
void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
|
||||
{
|
||||
int success = 0;
|
||||
|
||||
while (success == 0) {
|
||||
spin_lock(&(sp_ptr->state_lock));
|
||||
|
||||
if (sp_ptr->state == from) {
|
||||
sp_ptr->state = to;
|
||||
|
||||
success = 1;
|
||||
}
|
||||
|
||||
spin_unlock(&(sp_ptr->state_lock));
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Check if the state of a Secure Partition is the specified one and, if so,
|
||||
* change it to the desired state. Returns 0 on success, -1 on error.
|
||||
******************************************************************************/
|
||||
int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
spin_lock(&(sp_ptr->state_lock));
|
||||
|
||||
if (sp_ptr->state == from) {
|
||||
sp_ptr->state = to;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
spin_unlock(&(sp_ptr->state_lock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function takes an SP context pointer and performs a synchronous entry
|
||||
* into it.
|
||||
******************************************************************************/
|
||||
static uint64_t spm_sp_synchronous_entry(sp_context_t *ctx)
|
||||
{
|
||||
uint64_t rc;
|
||||
|
||||
assert(ctx != NULL);
|
||||
|
||||
/* Assign the context of the SP to this CPU */
|
||||
cm_set_context(&(ctx->cpu_ctx), SECURE);
|
||||
|
||||
/* Restore the context assigned above */
|
||||
cm_el1_sysregs_context_restore(SECURE);
|
||||
cm_set_next_eret_context(SECURE);
|
||||
|
||||
/* Invalidate TLBs at EL1. */
|
||||
tlbivmalle1();
|
||||
dsbish();
|
||||
|
||||
/* Enter Secure Partition */
|
||||
rc = spm_secure_partition_enter(&ctx->c_rt_ctx);
|
||||
|
||||
/* Save secure state */
|
||||
cm_el1_sysregs_context_save(SECURE);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function returns to the place where spm_sp_synchronous_entry() was
|
||||
* called originally.
|
||||
******************************************************************************/
|
||||
__dead2 static void spm_sp_synchronous_exit(uint64_t rc)
|
||||
{
|
||||
sp_context_t *ctx = &sp_ctx;
|
||||
|
||||
/*
|
||||
* The SPM must have initiated the original request through a
|
||||
* synchronous entry into the secure partition. Jump back to the
|
||||
* original C runtime context with the value of rc in x0;
|
||||
*/
|
||||
spm_secure_partition_exit(ctx->c_rt_ctx, rc);
|
||||
|
||||
panic();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Jump to each Secure Partition for the first time.
|
||||
******************************************************************************/
|
||||
static int32_t spm_init(void)
|
||||
{
|
||||
uint64_t rc;
|
||||
sp_context_t *ctx;
|
||||
|
||||
INFO("Secure Partition init...\n");
|
||||
|
||||
ctx = &sp_ctx;
|
||||
|
||||
ctx->state = SP_STATE_RESET;
|
||||
|
||||
rc = spm_sp_synchronous_entry(ctx);
|
||||
assert(rc == 0);
|
||||
|
||||
ctx->state = SP_STATE_IDLE;
|
||||
|
||||
INFO("Secure Partition initialized.\n");
|
||||
|
||||
return !rc;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Initialize contexts of all Secure Partitions.
|
||||
******************************************************************************/
|
||||
int32_t spm_mm_setup(void)
|
||||
{
|
||||
sp_context_t *ctx;
|
||||
|
||||
/* Disable MMU at EL1 (initialized by BL2) */
|
||||
disable_mmu_icache_el1();
|
||||
|
||||
/* Initialize context of the SP */
|
||||
INFO("Secure Partition context setup start...\n");
|
||||
|
||||
ctx = &sp_ctx;
|
||||
|
||||
/* Assign translation tables context. */
|
||||
ctx->xlat_ctx_handle = spm_get_sp_xlat_context();
|
||||
|
||||
spm_sp_setup(ctx);
|
||||
|
||||
/* Register init function for deferred init. */
|
||||
bl31_register_bl32_init(&spm_init);
|
||||
|
||||
INFO("Secure Partition setup done.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Function to perform a call to a Secure Partition.
|
||||
******************************************************************************/
|
||||
uint64_t spm_mm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3)
|
||||
{
|
||||
uint64_t rc;
|
||||
sp_context_t *sp_ptr = &sp_ctx;
|
||||
|
||||
#if CTX_INCLUDE_FPREGS
|
||||
/*
|
||||
* SP runs to completion, no need to restore FP registers of secure context.
|
||||
* Save FP registers only for non secure context.
|
||||
*/
|
||||
fpregs_context_save(get_fpregs_ctx(cm_get_context(NON_SECURE)));
|
||||
#endif
|
||||
|
||||
/* Wait until the Secure Partition is idle and set it to busy. */
|
||||
sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY);
|
||||
|
||||
/* Set values for registers on SP entry */
|
||||
cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx);
|
||||
|
||||
write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid);
|
||||
write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1);
|
||||
write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2);
|
||||
write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3);
|
||||
|
||||
/* Jump to the Secure Partition. */
|
||||
rc = spm_sp_synchronous_entry(sp_ptr);
|
||||
|
||||
/* Flag Secure Partition as idle. */
|
||||
assert(sp_ptr->state == SP_STATE_BUSY);
|
||||
sp_state_set(sp_ptr, SP_STATE_IDLE);
|
||||
|
||||
#if CTX_INCLUDE_FPREGS
|
||||
/*
|
||||
* SP runs to completion, no need to save FP registers of secure context.
|
||||
* Restore only non secure world FP registers.
|
||||
*/
|
||||
fpregs_context_restore(get_fpregs_ctx(cm_get_context(NON_SECURE)));
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* MM_COMMUNICATE handler
|
||||
******************************************************************************/
|
||||
static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie,
|
||||
uint64_t comm_buffer_address,
|
||||
uint64_t comm_size_address, void *handle)
|
||||
{
|
||||
uint64_t rc;
|
||||
|
||||
/* Cookie. Reserved for future use. It must be zero. */
|
||||
if (mm_cookie != 0U) {
|
||||
ERROR("MM_COMMUNICATE: cookie is not zero\n");
|
||||
SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
if (comm_buffer_address == 0U) {
|
||||
ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
|
||||
SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
if (comm_size_address != 0U) {
|
||||
VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* The current secure partition design mandates
|
||||
* - at any point, only a single core can be
|
||||
* executing in the secure partiton.
|
||||
* - a core cannot be preempted by an interrupt
|
||||
* while executing in secure partition.
|
||||
* Raise the running priority of the core to the
|
||||
* interrupt level configured for secure partition
|
||||
* so as to block any interrupt from preempting this
|
||||
* core.
|
||||
*/
|
||||
ehf_activate_priority(PLAT_SP_PRI);
|
||||
|
||||
/* Save the Normal world context */
|
||||
cm_el1_sysregs_context_save(NON_SECURE);
|
||||
|
||||
rc = spm_mm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
|
||||
plat_my_core_pos());
|
||||
|
||||
/* Restore non-secure state */
|
||||
cm_el1_sysregs_context_restore(NON_SECURE);
|
||||
cm_set_next_eret_context(NON_SECURE);
|
||||
|
||||
/*
|
||||
* Exited from secure partition. This core can take
|
||||
* interrupts now.
|
||||
*/
|
||||
ehf_deactivate_priority(PLAT_SP_PRI);
|
||||
|
||||
SMC_RET1(handle, rc);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Secure Partition Manager SMC handler.
|
||||
******************************************************************************/
|
||||
uint64_t spm_mm_smc_handler(uint32_t smc_fid,
|
||||
uint64_t x1,
|
||||
uint64_t x2,
|
||||
uint64_t x3,
|
||||
uint64_t x4,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
uint64_t flags)
|
||||
{
|
||||
unsigned int ns;
|
||||
|
||||
/* Determine which security state this SMC originated from */
|
||||
ns = is_caller_non_secure(flags);
|
||||
|
||||
if (ns == SMC_FROM_SECURE) {
|
||||
|
||||
/* Handle SMCs from Secure world. */
|
||||
|
||||
assert(handle == cm_get_context(SECURE));
|
||||
|
||||
/* Make next ERET jump to S-EL0 instead of S-EL1. */
|
||||
cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
|
||||
|
||||
switch (smc_fid) {
|
||||
|
||||
case SPM_MM_VERSION_AARCH32:
|
||||
SMC_RET1(handle, SPM_MM_VERSION_COMPILED);
|
||||
|
||||
case MM_SP_EVENT_COMPLETE_AARCH64:
|
||||
spm_sp_synchronous_exit(x1);
|
||||
|
||||
case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
|
||||
INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
|
||||
|
||||
if (sp_ctx.state != SP_STATE_RESET) {
|
||||
WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
|
||||
SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
|
||||
}
|
||||
SMC_RET1(handle,
|
||||
spm_memory_attributes_get_smc_handler(
|
||||
&sp_ctx, x1));
|
||||
|
||||
case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
|
||||
INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
|
||||
|
||||
if (sp_ctx.state != SP_STATE_RESET) {
|
||||
WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
|
||||
SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
|
||||
}
|
||||
SMC_RET1(handle,
|
||||
spm_memory_attributes_set_smc_handler(
|
||||
&sp_ctx, x1, x2, x3));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Handle SMCs from Non-secure world. */
|
||||
|
||||
assert(handle == cm_get_context(NON_SECURE));
|
||||
|
||||
switch (smc_fid) {
|
||||
|
||||
case MM_VERSION_AARCH32:
|
||||
SMC_RET1(handle, MM_VERSION_COMPILED);
|
||||
|
||||
case MM_COMMUNICATE_AARCH32:
|
||||
case MM_COMMUNICATE_AARCH64:
|
||||
return mm_communicate(smc_fid, x1, x2, x3, handle);
|
||||
|
||||
case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
|
||||
case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
|
||||
/* SMC interfaces reserved for secure callers. */
|
||||
SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SMC_RET1(handle, SMC_UNK);
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SPM_MM_PRIVATE_H
|
||||
#define SPM_MM_PRIVATE_H
|
||||
|
||||
#include <context.h>
|
||||
#include "spm_common.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Constants that allow assembler code to preserve callee-saved registers of the
|
||||
* C runtime context while performing a security state switch.
|
||||
******************************************************************************/
|
||||
#define SP_C_RT_CTX_X19 0x0
|
||||
#define SP_C_RT_CTX_X20 0x8
|
||||
#define SP_C_RT_CTX_X21 0x10
|
||||
#define SP_C_RT_CTX_X22 0x18
|
||||
#define SP_C_RT_CTX_X23 0x20
|
||||
#define SP_C_RT_CTX_X24 0x28
|
||||
#define SP_C_RT_CTX_X25 0x30
|
||||
#define SP_C_RT_CTX_X26 0x38
|
||||
#define SP_C_RT_CTX_X27 0x40
|
||||
#define SP_C_RT_CTX_X28 0x48
|
||||
#define SP_C_RT_CTX_X29 0x50
|
||||
#define SP_C_RT_CTX_X30 0x58
|
||||
|
||||
#define SP_C_RT_CTX_SIZE 0x60
|
||||
#define SP_C_RT_CTX_ENTRIES (SP_C_RT_CTX_SIZE >> DWORD_SHIFT)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <lib/spinlock.h>
|
||||
#include <lib/xlat_tables/xlat_tables_v2.h>
|
||||
|
||||
typedef enum sp_state {
|
||||
SP_STATE_RESET = 0,
|
||||
SP_STATE_IDLE,
|
||||
SP_STATE_BUSY
|
||||
} sp_state_t;
|
||||
|
||||
typedef struct sp_context {
|
||||
uint64_t c_rt_ctx;
|
||||
cpu_context_t cpu_ctx;
|
||||
xlat_ctx_t *xlat_ctx_handle;
|
||||
|
||||
sp_state_t state;
|
||||
spinlock_t state_lock;
|
||||
} sp_context_t;
|
||||
|
||||
|
||||
void spm_sp_setup(sp_context_t *sp_ctx);
|
||||
|
||||
xlat_ctx_t *spm_get_sp_xlat_context(void);
|
||||
|
||||
int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx,
|
||||
uintptr_t base_va);
|
||||
int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx,
|
||||
u_register_t page_address,
|
||||
u_register_t pages_count,
|
||||
u_register_t smc_attributes);
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* SPM_MM_PRIVATE_H */
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <context.h>
|
||||
#include <common/debug.h>
|
||||
#include <lib/el3_runtime/context_mgmt.h>
|
||||
#include <lib/xlat_tables/xlat_tables_v2.h>
|
||||
#include <platform_def.h>
|
||||
#include <plat/common/common_def.h>
|
||||
#include <plat/common/platform.h>
|
||||
#include <services/spm_mm_partition.h>
|
||||
|
||||
#include "spm_common.h"
|
||||
#include "spm_mm_private.h"
|
||||
#include "spm_mm_shim_private.h"
|
||||
|
||||
/* Setup context of the Secure Partition */
|
||||
void spm_sp_setup(sp_context_t *sp_ctx)
|
||||
{
|
||||
cpu_context_t *ctx = &(sp_ctx->cpu_ctx);
|
||||
|
||||
/* Pointer to the MP information from the platform port. */
|
||||
const spm_mm_boot_info_t *sp_boot_info =
|
||||
plat_get_secure_partition_boot_info(NULL);
|
||||
|
||||
/*
|
||||
* Initialize CPU context
|
||||
* ----------------------
|
||||
*/
|
||||
|
||||
entry_point_info_t ep_info = {0};
|
||||
|
||||
SET_PARAM_HEAD(&ep_info, PARAM_EP, VERSION_1, SECURE | EP_ST_ENABLE);
|
||||
|
||||
/* Setup entrypoint and SPSR */
|
||||
ep_info.pc = sp_boot_info->sp_image_base;
|
||||
ep_info.spsr = SPSR_64(MODE_EL0, MODE_SP_EL0, DISABLE_ALL_EXCEPTIONS);
|
||||
|
||||
/*
|
||||
* X0: Virtual address of a buffer shared between EL3 and Secure EL0.
|
||||
* The buffer will be mapped in the Secure EL1 translation regime
|
||||
* with Normal IS WBWA attributes and RO data and Execute Never
|
||||
* instruction access permissions.
|
||||
*
|
||||
* X1: Size of the buffer in bytes
|
||||
*
|
||||
* X2: cookie value (Implementation Defined)
|
||||
*
|
||||
* X3: cookie value (Implementation Defined)
|
||||
*
|
||||
* X4 to X7 = 0
|
||||
*/
|
||||
ep_info.args.arg0 = sp_boot_info->sp_shared_buf_base;
|
||||
ep_info.args.arg1 = sp_boot_info->sp_shared_buf_size;
|
||||
ep_info.args.arg2 = PLAT_SPM_COOKIE_0;
|
||||
ep_info.args.arg3 = PLAT_SPM_COOKIE_1;
|
||||
|
||||
cm_setup_context(ctx, &ep_info);
|
||||
|
||||
/*
|
||||
* SP_EL0: A non-zero value will indicate to the SP that the SPM has
|
||||
* initialized the stack pointer for the current CPU through
|
||||
* implementation defined means. The value will be 0 otherwise.
|
||||
*/
|
||||
write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_SP_EL0,
|
||||
sp_boot_info->sp_stack_base + sp_boot_info->sp_pcpu_stack_size);
|
||||
|
||||
/*
|
||||
* Setup translation tables
|
||||
* ------------------------
|
||||
*/
|
||||
|
||||
#if ENABLE_ASSERTIONS
|
||||
|
||||
/* Get max granularity supported by the platform. */
|
||||
unsigned int max_granule = xlat_arch_get_max_supported_granule_size();
|
||||
|
||||
VERBOSE("Max translation granule size supported: %u KiB\n",
|
||||
max_granule / 1024U);
|
||||
|
||||
unsigned int max_granule_mask = max_granule - 1U;
|
||||
|
||||
/* Base must be aligned to the max granularity */
|
||||
assert((sp_boot_info->sp_ns_comm_buf_base & max_granule_mask) == 0);
|
||||
|
||||
/* Size must be a multiple of the max granularity */
|
||||
assert((sp_boot_info->sp_ns_comm_buf_size & max_granule_mask) == 0);
|
||||
|
||||
#endif /* ENABLE_ASSERTIONS */
|
||||
|
||||
/* This region contains the exception vectors used at S-EL1. */
|
||||
const mmap_region_t sel1_exception_vectors =
|
||||
MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START,
|
||||
SPM_SHIM_EXCEPTIONS_SIZE,
|
||||
MT_CODE | MT_SECURE | MT_PRIVILEGED);
|
||||
mmap_add_region_ctx(sp_ctx->xlat_ctx_handle,
|
||||
&sel1_exception_vectors);
|
||||
|
||||
mmap_add_ctx(sp_ctx->xlat_ctx_handle,
|
||||
plat_get_secure_partition_mmap(NULL));
|
||||
|
||||
init_xlat_tables_ctx(sp_ctx->xlat_ctx_handle);
|
||||
|
||||
/*
|
||||
* MMU-related registers
|
||||
* ---------------------
|
||||
*/
|
||||
xlat_ctx_t *xlat_ctx = sp_ctx->xlat_ctx_handle;
|
||||
|
||||
uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
|
||||
|
||||
setup_mmu_cfg((uint64_t *)&mmu_cfg_params, 0, xlat_ctx->base_table,
|
||||
xlat_ctx->pa_max_address, xlat_ctx->va_max_address,
|
||||
EL1_EL0_REGIME);
|
||||
|
||||
write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_MAIR_EL1,
|
||||
mmu_cfg_params[MMU_CFG_MAIR]);
|
||||
|
||||
write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TCR_EL1,
|
||||
mmu_cfg_params[MMU_CFG_TCR]);
|
||||
|
||||
write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TTBR0_EL1,
|
||||
mmu_cfg_params[MMU_CFG_TTBR0]);
|
||||
|
||||
/* Setup SCTLR_EL1 */
|
||||
u_register_t sctlr_el1 = read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1);
|
||||
|
||||
sctlr_el1 |=
|
||||
/*SCTLR_EL1_RES1 |*/
|
||||
/* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */
|
||||
SCTLR_UCI_BIT |
|
||||
/* RW regions at xlat regime EL1&0 are forced to be XN. */
|
||||
SCTLR_WXN_BIT |
|
||||
/* Don't trap to EL1 execution of WFI or WFE at EL0. */
|
||||
SCTLR_NTWI_BIT | SCTLR_NTWE_BIT |
|
||||
/* Don't trap to EL1 accesses to CTR_EL0 from EL0. */
|
||||
SCTLR_UCT_BIT |
|
||||
/* Don't trap to EL1 execution of DZ ZVA at EL0. */
|
||||
SCTLR_DZE_BIT |
|
||||
/* Enable SP Alignment check for EL0 */
|
||||
SCTLR_SA0_BIT |
|
||||
/* Don't change PSTATE.PAN on taking an exception to EL1 */
|
||||
SCTLR_SPAN_BIT |
|
||||
/* Allow cacheable data and instr. accesses to normal memory. */
|
||||
SCTLR_C_BIT | SCTLR_I_BIT |
|
||||
/* Enable MMU. */
|
||||
SCTLR_M_BIT
|
||||
;
|
||||
|
||||
sctlr_el1 &= ~(
|
||||
/* Explicit data accesses at EL0 are little-endian. */
|
||||
SCTLR_E0E_BIT |
|
||||
/*
|
||||
* Alignment fault checking disabled when at EL1 and EL0 as
|
||||
* the UEFI spec permits unaligned accesses.
|
||||
*/
|
||||
SCTLR_A_BIT |
|
||||
/* Accesses to DAIF from EL0 are trapped to EL1. */
|
||||
SCTLR_UMA_BIT
|
||||
);
|
||||
|
||||
write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
|
||||
|
||||
/*
|
||||
* Setup other system registers
|
||||
* ----------------------------
|
||||
*/
|
||||
|
||||
/* Shim Exception Vector Base Address */
|
||||
write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_VBAR_EL1,
|
||||
SPM_SHIM_EXCEPTIONS_PTR);
|
||||
|
||||
write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CNTKCTL_EL1,
|
||||
EL0PTEN_BIT | EL0VTEN_BIT | EL0PCTEN_BIT | EL0VCTEN_BIT);
|
||||
|
||||
/*
|
||||
* FPEN: Allow the Secure Partition to access FP/SIMD registers.
|
||||
* Note that SPM will not do any saving/restoring of these registers on
|
||||
* behalf of the SP. This falls under the SP's responsibility.
|
||||
* TTA: Enable access to trace registers.
|
||||
* ZEN (v8.2): Trap SVE instructions and access to SVE registers.
|
||||
*/
|
||||
write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CPACR_EL1,
|
||||
CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
|
||||
|
||||
/*
|
||||
* Prepare information in buffer shared between EL3 and S-EL0
|
||||
* ----------------------------------------------------------
|
||||
*/
|
||||
|
||||
void *shared_buf_ptr = (void *) sp_boot_info->sp_shared_buf_base;
|
||||
|
||||
/* Copy the boot information into the shared buffer with the SP. */
|
||||
assert((uintptr_t)shared_buf_ptr + sizeof(spm_mm_boot_info_t)
|
||||
<= (sp_boot_info->sp_shared_buf_base + sp_boot_info->sp_shared_buf_size));
|
||||
|
||||
assert(sp_boot_info->sp_shared_buf_base <=
|
||||
(UINTPTR_MAX - sp_boot_info->sp_shared_buf_size + 1));
|
||||
|
||||
assert(sp_boot_info != NULL);
|
||||
|
||||
memcpy((void *) shared_buf_ptr, (const void *) sp_boot_info,
|
||||
sizeof(spm_mm_boot_info_t));
|
||||
|
||||
/* Pointer to the MP information from the platform port. */
|
||||
spm_mm_mp_info_t *sp_mp_info =
|
||||
((spm_mm_boot_info_t *) shared_buf_ptr)->mp_info;
|
||||
|
||||
assert(sp_mp_info != NULL);
|
||||
|
||||
/*
|
||||
* Point the shared buffer MP information pointer to where the info will
|
||||
* be populated, just after the boot info.
|
||||
*/
|
||||
((spm_mm_boot_info_t *) shared_buf_ptr)->mp_info =
|
||||
(spm_mm_mp_info_t *) ((uintptr_t)shared_buf_ptr
|
||||
+ sizeof(spm_mm_boot_info_t));
|
||||
|
||||
/*
|
||||
* Update the shared buffer pointer to where the MP information for the
|
||||
* payload will be populated
|
||||
*/
|
||||
shared_buf_ptr = ((spm_mm_boot_info_t *) shared_buf_ptr)->mp_info;
|
||||
|
||||
/*
|
||||
* Copy the cpu information into the shared buffer area after the boot
|
||||
* information.
|
||||
*/
|
||||
assert(sp_boot_info->num_cpus <= PLATFORM_CORE_COUNT);
|
||||
|
||||
assert((uintptr_t)shared_buf_ptr
|
||||
<= (sp_boot_info->sp_shared_buf_base + sp_boot_info->sp_shared_buf_size -
|
||||
(sp_boot_info->num_cpus * sizeof(*sp_mp_info))));
|
||||
|
||||
memcpy(shared_buf_ptr, (const void *) sp_mp_info,
|
||||
sp_boot_info->num_cpus * sizeof(*sp_mp_info));
|
||||
|
||||
/*
|
||||
* Calculate the linear indices of cores in boot information for the
|
||||
* secure partition and flag the primary CPU
|
||||
*/
|
||||
sp_mp_info = (spm_mm_mp_info_t *) shared_buf_ptr;
|
||||
|
||||
for (unsigned int index = 0; index < sp_boot_info->num_cpus; index++) {
|
||||
u_register_t mpidr = sp_mp_info[index].mpidr;
|
||||
|
||||
sp_mp_info[index].linear_id = plat_core_pos_by_mpidr(mpidr);
|
||||
if (plat_my_core_pos() == sp_mp_info[index].linear_id)
|
||||
sp_mp_info[index].flags |= MP_INFO_FLAG_PRIMARY_CPU;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SPM_MM_SHIM_PRIVATE_H
|
||||
#define SPM_MM_SHIM_PRIVATE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <lib/utils_def.h>
|
||||
|
||||
/* Assembly source */
|
||||
IMPORT_SYM(uintptr_t, spm_shim_exceptions_ptr, SPM_SHIM_EXCEPTIONS_PTR);
|
||||
|
||||
/* Linker symbols */
|
||||
IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_START__, SPM_SHIM_EXCEPTIONS_START);
|
||||
IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_END__, SPM_SHIM_EXCEPTIONS_END);
|
||||
|
||||
/* Definitions */
|
||||
|
||||
#define SPM_SHIM_EXCEPTIONS_SIZE \
|
||||
(SPM_SHIM_EXCEPTIONS_END - SPM_SHIM_EXCEPTIONS_START)
|
||||
|
||||
#endif /* SPM_MM_SHIM_PRIVATE_H */
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <lib/xlat_tables/xlat_tables_v2.h>
|
||||
#include <platform_def.h>
|
||||
#include <plat/common/platform.h>
|
||||
#include <services/spm_mm_partition.h>
|
||||
#include <services/spm_mm_svc.h>
|
||||
|
||||
#include "spm_mm_private.h"
|
||||
#include "spm_mm_shim_private.h"
|
||||
|
||||
/* Place translation tables by default along with the ones used by BL31. */
|
||||
#ifndef PLAT_SP_IMAGE_XLAT_SECTION_NAME
|
||||
#define PLAT_SP_IMAGE_XLAT_SECTION_NAME "xlat_table"
|
||||
#endif
|
||||
#ifndef PLAT_SP_IMAGE_BASE_XLAT_SECTION_NAME
|
||||
#define PLAT_SP_IMAGE_BASE_XLAT_SECTION_NAME ".bss"
|
||||
#endif
|
||||
|
||||
/* Allocate and initialise the translation context for the secure partitions. */
|
||||
REGISTER_XLAT_CONTEXT2(sp,
|
||||
PLAT_SP_IMAGE_MMAP_REGIONS,
|
||||
PLAT_SP_IMAGE_MAX_XLAT_TABLES,
|
||||
PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE,
|
||||
EL1_EL0_REGIME, PLAT_SP_IMAGE_XLAT_SECTION_NAME,
|
||||
PLAT_SP_IMAGE_BASE_XLAT_SECTION_NAME);
|
||||
|
||||
/* Lock used for SP_MEMORY_ATTRIBUTES_GET and SP_MEMORY_ATTRIBUTES_SET */
|
||||
static spinlock_t mem_attr_smc_lock;
|
||||
|
||||
/* Get handle of Secure Partition translation context */
|
||||
xlat_ctx_t *spm_get_sp_xlat_context(void)
|
||||
{
|
||||
return &sp_xlat_ctx;
|
||||
};
|
||||
|
||||
/*
|
||||
* Attributes are encoded using a different format in the SMC interface than in
|
||||
* the Trusted Firmware, where the mmap_attr_t enum type is used. This function
|
||||
* converts an attributes value from the SMC format to the mmap_attr_t format by
|
||||
* setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
|
||||
* The other fields are left as 0 because they are ignored by the function
|
||||
* xlat_change_mem_attributes_ctx().
|
||||
*/
|
||||
static unsigned int smc_attr_to_mmap_attr(unsigned int attributes)
|
||||
{
|
||||
unsigned int tf_attr = 0U;
|
||||
|
||||
unsigned int access = (attributes & MM_SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
|
||||
>> MM_SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
|
||||
|
||||
if (access == MM_SP_MEMORY_ATTRIBUTES_ACCESS_RW) {
|
||||
tf_attr |= MT_RW | MT_USER;
|
||||
} else if (access == MM_SP_MEMORY_ATTRIBUTES_ACCESS_RO) {
|
||||
tf_attr |= MT_RO | MT_USER;
|
||||
} else {
|
||||
/* Other values are reserved. */
|
||||
assert(access == MM_SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS);
|
||||
/* The only requirement is that there's no access from EL0 */
|
||||
tf_attr |= MT_RO | MT_PRIVILEGED;
|
||||
}
|
||||
|
||||
if ((attributes & MM_SP_MEMORY_ATTRIBUTES_NON_EXEC) == 0) {
|
||||
tf_attr |= MT_EXECUTE;
|
||||
} else {
|
||||
tf_attr |= MT_EXECUTE_NEVER;
|
||||
}
|
||||
|
||||
return tf_attr;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function converts attributes from the Trusted Firmware format into the
|
||||
* SMC interface format.
|
||||
*/
|
||||
static unsigned int smc_mmap_to_smc_attr(unsigned int attr)
|
||||
{
|
||||
unsigned int smc_attr = 0U;
|
||||
|
||||
unsigned int data_access;
|
||||
|
||||
if ((attr & MT_USER) == 0) {
|
||||
/* No access from EL0. */
|
||||
data_access = MM_SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS;
|
||||
} else {
|
||||
if ((attr & MT_RW) != 0) {
|
||||
assert(MT_TYPE(attr) != MT_DEVICE);
|
||||
data_access = MM_SP_MEMORY_ATTRIBUTES_ACCESS_RW;
|
||||
} else {
|
||||
data_access = MM_SP_MEMORY_ATTRIBUTES_ACCESS_RO;
|
||||
}
|
||||
}
|
||||
|
||||
smc_attr |= (data_access & MM_SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
|
||||
<< MM_SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
|
||||
|
||||
if ((attr & MT_EXECUTE_NEVER) != 0U) {
|
||||
smc_attr |= MM_SP_MEMORY_ATTRIBUTES_NON_EXEC;
|
||||
}
|
||||
|
||||
return smc_attr;
|
||||
}
|
||||
|
||||
int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx,
|
||||
uintptr_t base_va)
|
||||
{
|
||||
uint32_t attributes;
|
||||
|
||||
spin_lock(&mem_attr_smc_lock);
|
||||
|
||||
int rc = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
|
||||
base_va, &attributes);
|
||||
|
||||
spin_unlock(&mem_attr_smc_lock);
|
||||
|
||||
/* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */
|
||||
assert((rc == 0) || (rc == -EINVAL));
|
||||
|
||||
if (rc == 0) {
|
||||
return (int32_t) smc_mmap_to_smc_attr(attributes);
|
||||
} else {
|
||||
return SPM_MM_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx,
|
||||
u_register_t page_address,
|
||||
u_register_t pages_count,
|
||||
u_register_t smc_attributes)
|
||||
{
|
||||
uintptr_t base_va = (uintptr_t) page_address;
|
||||
size_t size = (size_t) (pages_count * PAGE_SIZE);
|
||||
uint32_t attributes = (uint32_t) smc_attributes;
|
||||
|
||||
INFO(" Start address : 0x%lx\n", base_va);
|
||||
INFO(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
|
||||
INFO(" Attributes : 0x%x\n", attributes);
|
||||
|
||||
spin_lock(&mem_attr_smc_lock);
|
||||
|
||||
int ret = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
|
||||
base_va, size,
|
||||
smc_attr_to_mmap_attr(attributes));
|
||||
|
||||
spin_unlock(&mem_attr_smc_lock);
|
||||
|
||||
/* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */
|
||||
assert((ret == 0) || (ret == -EINVAL));
|
||||
|
||||
return (ret == 0) ? SPM_MM_SUCCESS : SPM_MM_INVALID_PARAMETER;
|
||||
}
|
||||
Reference in New Issue
Block a user