Commit d54f0cab authored by Antonio Nino Diaz's avatar Antonio Nino Diaz
Browse files

SPM: Support blocking calls



Note that the arguments passed during the SMC call don't comply with the
SPCI specifications. This will be fixed in following patches, but it is
needed to implement a few more SPCI SMCs to be able to do it. The
current code allows us to start testing it.

Change-Id: Ief0e75d072b311737fcdb0c6a60ba5b7406a9ee5
Signed-off-by: default avatarAntonio Nino Diaz <antonio.ninodiaz@arm.com>
parent 07c13a30
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <platform_def.h> #include <platform_def.h>
#include <platform.h> #include <platform.h>
#include <sp_res_desc.h> #include <sp_res_desc.h>
#include <sprt_host.h>
#include <string.h> #include <string.h>
#include <xlat_tables_v2.h> #include <xlat_tables_v2.h>
...@@ -132,4 +133,13 @@ void spm_sp_setup(sp_context_t *sp_ctx) ...@@ -132,4 +133,13 @@ void spm_sp_setup(sp_context_t *sp_ctx)
*/ */
write_ctx_reg(get_sysregs_ctx(ctx), CTX_CPACR_EL1, write_ctx_reg(get_sysregs_ctx(ctx), CTX_CPACR_EL1,
CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE)); CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
/*
* Prepare shared buffers
* ----------------------
*/
/* Initialize SPRT queues */
sprt_initialize_queues((void *)sp_ctx->spm_sp_buffer_base,
sp_ctx->spm_sp_buffer_size);
} }
...@@ -5,11 +5,15 @@ ...@@ -5,11 +5,15 @@
*/ */
#include <assert.h> #include <assert.h>
#include <context_mgmt.h>
#include <debug.h> #include <debug.h>
#include <errno.h>
#include <smccc.h> #include <smccc.h>
#include <smccc_helpers.h> #include <smccc_helpers.h>
#include <spci_svc.h> #include <spci_svc.h>
#include <spinlock.h> #include <spinlock.h>
#include <sprt_host.h>
#include <sprt_svc.h>
#include <string.h> #include <string.h>
#include <utils.h> #include <utils.h>
...@@ -242,6 +246,116 @@ static uint64_t spci_service_handle_close(void *handle, u_register_t x1) ...@@ -242,6 +246,116 @@ static uint64_t spci_service_handle_close(void *handle, u_register_t x1)
SMC_RET1(handle, SPCI_SUCCESS); SMC_RET1(handle, SPCI_SUCCESS);
} }
/*******************************************************************************
* This function requests a Secure Service from a given handle and client ID.
******************************************************************************/
static uint64_t spci_service_request_blocking(void *handle,
uint32_t smc_fid, u_register_t x1, u_register_t x2,
u_register_t x3, u_register_t x4, u_register_t x5,
u_register_t x6, u_register_t x7)
{
spci_handle_t *handle_info;
sp_context_t *sp_ctx;
cpu_context_t *cpu_ctx;
uint32_t rx0;
u_register_t rx1, rx2, rx3;
uint16_t request_handle, client_id;
/* Get handle array lock */
spin_lock(&spci_handles_lock);
/* Get pointer to struct of this open handle and client ID. */
request_handle = (x7 >> 16U) & 0x0000FFFFU;
client_id = x7 & 0x0000FFFFU;
handle_info = spci_handle_info_get(request_handle, client_id);
if (handle_info == NULL) {
spin_unlock(&spci_handles_lock);
WARN("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Not found.\n");
WARN(" Handle 0x%04x. Client ID 0x%04x\n", request_handle,
client_id);
SMC_RET1(handle, SPCI_BUSY);
}
/* Get pointer to the Secure Partition that handles the service */
sp_ctx = handle_info->sp_ctx;
assert(sp_ctx != NULL);
cpu_ctx = &(sp_ctx->cpu_ctx);
/* Blocking requests are only allowed if the queue is empty */
if (handle_info->num_active_requests > 0) {
spin_unlock(&spci_handles_lock);
SMC_RET1(handle, SPCI_BUSY);
}
/* Prevent this handle from being closed */
handle_info->num_active_requests += 1;
/* Release handle lock */
spin_unlock(&spci_handles_lock);
/* Save the Normal world context */
cm_el1_sysregs_context_save(NON_SECURE);
/* Wait until the Secure Partition is idle and set it to busy. */
sp_state_wait_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY);
/* Pass arguments to the Secure Partition */
struct sprt_queue_entry_message message = {
.type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST,
.client_id = client_id,
.service_handle = request_handle,
.session_id = x6,
.token = 0, /* No token needed for blocking requests */
.args = {smc_fid, x1, x2, x3, x4, x5}
};
spin_lock(&(sp_ctx->spm_sp_buffer_lock));
int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message,
SPRT_QUEUE_NUM_BLOCKING);
spin_unlock(&(sp_ctx->spm_sp_buffer_lock));
if (rc != 0) {
/*
* This shouldn't happen, blocking requests can only be made if
* the request queue is empty.
*/
assert(rc == -ENOMEM);
ERROR("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Queue is full.\n");
panic();
}
/* Jump to the Secure Partition. */
rx0 = spm_sp_synchronous_entry(sp_ctx);
/* Verify returned value */
if (rx0 != SPRT_PUT_RESPONSE_AARCH64) {
ERROR("SPM: %s: Unexpected x0 value 0x%x\n", __func__, rx0);
panic();
}
rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
/* Flag Secure Partition as idle. */
assert(sp_ctx->state == SP_STATE_BUSY);
sp_state_set(sp_ctx, SP_STATE_IDLE);
/* Decrease count of requests. */
spin_lock(&spci_handles_lock);
handle_info->num_active_requests -= 1;
spin_unlock(&spci_handles_lock);
/* Restore non-secure state */
cm_el1_sysregs_context_restore(NON_SECURE);
cm_set_next_eret_context(NON_SECURE);
SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
}
/******************************************************************************* /*******************************************************************************
* This function handles all SMCs in the range reserved for SPCI. * This function handles all SMCs in the range reserved for SPCI.
******************************************************************************/ ******************************************************************************/
...@@ -285,6 +399,16 @@ uint64_t spci_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, ...@@ -285,6 +399,16 @@ uint64_t spci_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
case SPCI_FID_SERVICE_HANDLE_CLOSE: case SPCI_FID_SERVICE_HANDLE_CLOSE:
return spci_service_handle_close(handle, x1); return spci_service_handle_close(handle, x1);
case SPCI_FID_SERVICE_REQUEST_BLOCKING:
{
uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
return spci_service_request_blocking(handle,
smc_fid, x1, x2, x3, x4, x5, x6, x7);
}
default: default:
break; break;
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <spinlock.h> #include <spinlock.h>
#include <string.h> #include <string.h>
#include <spm_svc.h> #include <spm_svc.h>
#include <sprt_svc.h>
#include <utils.h> #include <utils.h>
#include <xlat_tables_v2.h> #include <xlat_tables_v2.h>
...@@ -133,7 +134,7 @@ int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to) ...@@ -133,7 +134,7 @@ int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
* This function takes an SP context pointer and performs a synchronous entry * This function takes an SP context pointer and performs a synchronous entry
* into it. * into it.
******************************************************************************/ ******************************************************************************/
static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx) uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
{ {
uint64_t rc; uint64_t rc;
unsigned int linear_id = plat_my_core_pos(); unsigned int linear_id = plat_my_core_pos();
...@@ -165,7 +166,7 @@ static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx) ...@@ -165,7 +166,7 @@ static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
* This function returns to the place where spm_sp_synchronous_entry() was * This function returns to the place where spm_sp_synchronous_entry() was
* called originally. * called originally.
******************************************************************************/ ******************************************************************************/
__dead2 static void spm_sp_synchronous_exit(uint64_t rc) __dead2 void spm_sp_synchronous_exit(uint64_t rc)
{ {
/* Get context of the SP in use by this CPU. */ /* Get context of the SP in use by this CPU. */
unsigned int linear_id = plat_my_core_pos(); unsigned int linear_id = plat_my_core_pos();
...@@ -202,7 +203,10 @@ static int32_t spm_init(void) ...@@ -202,7 +203,10 @@ static int32_t spm_init(void)
ctx->state = SP_STATE_RESET; ctx->state = SP_STATE_RESET;
rc = spm_sp_synchronous_entry(ctx); rc = spm_sp_synchronous_entry(ctx);
assert(rc == 0); if (rc != SPRT_YIELD_AARCH64) {
ERROR("Unexpected return value 0x%llx\n", rc);
panic();
}
ctx->state = SP_STATE_IDLE; ctx->state = SP_STATE_IDLE;
......
...@@ -61,8 +61,13 @@ typedef struct sp_context { ...@@ -61,8 +61,13 @@ typedef struct sp_context {
/* Base and size of the shared SPM<->SP buffer */ /* Base and size of the shared SPM<->SP buffer */
uintptr_t spm_sp_buffer_base; uintptr_t spm_sp_buffer_base;
size_t spm_sp_buffer_size; size_t spm_sp_buffer_size;
spinlock_t spm_sp_buffer_lock;
} sp_context_t; } sp_context_t;
/* Functions used to enter/exit a Secure Partition synchronously */
uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx);
__dead2 void spm_sp_synchronous_exit(uint64_t rc);
/* Assembly helpers */ /* Assembly helpers */
uint64_t spm_secure_partition_enter(uint64_t *c_rt_ctx); 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); void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret);
...@@ -70,6 +75,11 @@ void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret); ...@@ -70,6 +75,11 @@ void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret);
/* Secure Partition setup */ /* Secure Partition setup */
void spm_sp_setup(sp_context_t *sp_ctx); void spm_sp_setup(sp_context_t *sp_ctx);
/* Secure Partition state management helpers */
void sp_state_set(sp_context_t *sp_ptr, sp_state_t state);
void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to);
int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to);
/* Functions related to the translation tables management */ /* Functions related to the translation tables management */
xlat_ctx_t *spm_sp_xlat_context_alloc(void); xlat_ctx_t *spm_sp_xlat_context_alloc(void);
void sp_map_memory_regions(sp_context_t *sp_ctx); void sp_map_memory_regions(sp_context_t *sp_ctx);
......
...@@ -39,6 +39,20 @@ uint64_t sprt_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, ...@@ -39,6 +39,20 @@ uint64_t sprt_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
case SPRT_VERSION: case SPRT_VERSION:
SMC_RET1(handle, SPRT_VERSION_COMPILED); SMC_RET1(handle, SPRT_VERSION_COMPILED);
case SPRT_PUT_RESPONSE_AARCH64:
/*
* Registers x1-x3 aren't saved by default to the context,
* but they are needed after spm_sp_synchronous_exit() because
* they hold return values.
*/
SMC_SET_GP(handle, CTX_GPREG_X1, x1);
SMC_SET_GP(handle, CTX_GPREG_X2, x2);
SMC_SET_GP(handle, CTX_GPREG_X3, x3);
spm_sp_synchronous_exit(SPRT_PUT_RESPONSE_AARCH64);
case SPRT_YIELD_AARCH64:
spm_sp_synchronous_exit(SPRT_YIELD_AARCH64);
default: default:
break; break;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment