From 2f48ddae740aa89dde84945bbebed26c17098af2 Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Tue, 3 Jul 2018 19:54:59 +0100 Subject: SPM: Prevent simultaneous blocking calls Blocking calls can only succeed if the target Secure Partition is idle. Change-Id: Iabeaa0b8d3e653fd8581fa086758936abfc1c772 Signed-off-by: Antonio Nino Diaz --- services/std_svc/spm/spci.c | 7 +++++++ services/std_svc/spm/spm_main.c | 33 +++++++++++++++++++++++++++++++++ services/std_svc/spm/spm_private.h | 8 ++++++++ 3 files changed, 48 insertions(+) (limited to 'services') diff --git a/services/std_svc/spm/spci.c b/services/std_svc/spm/spci.c index cbb0f3cc..1544ae16 100644 --- a/services/std_svc/spm/spci.c +++ b/services/std_svc/spm/spci.c @@ -291,6 +291,12 @@ static uint64_t spci_service_request_blocking(void *handle, SMC_RET1(handle, SPCI_BUSY); } + if (spm_sp_request_increase_if_zero(sp_ctx) == -1) { + spin_unlock(&spci_handles_lock); + + SMC_RET1(handle, SPCI_BUSY); + } + /* Prevent this handle from being closed */ handle_info->num_active_requests += 1; @@ -348,6 +354,7 @@ static uint64_t spci_service_request_blocking(void *handle, spin_lock(&spci_handles_lock); handle_info->num_active_requests -= 1; spin_unlock(&spci_handles_lock); + spm_sp_request_decrease(sp_ctx); /* Restore non-secure state */ cm_el1_sysregs_context_restore(NON_SECURE); diff --git a/services/std_svc/spm/spm_main.c b/services/std_svc/spm/spm_main.c index b1d5dd86..050c66cc 100644 --- a/services/std_svc/spm/spm_main.c +++ b/services/std_svc/spm/spm_main.c @@ -46,6 +46,39 @@ sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id) return cpu_sp_ctx[linear_id]; } +/******************************************************************************* + * Functions to keep track of how many requests a Secure Partition has received + * and hasn't finished. + ******************************************************************************/ +void spm_sp_request_increase(sp_context_t *sp_ctx) +{ + spin_lock(&(sp_ctx->request_count_lock)); + sp_ctx->request_count++; + spin_unlock(&(sp_ctx->request_count_lock)); +} + +void spm_sp_request_decrease(sp_context_t *sp_ctx) +{ + spin_lock(&(sp_ctx->request_count_lock)); + sp_ctx->request_count--; + spin_unlock(&(sp_ctx->request_count_lock)); +} + +/* Returns 0 if it was originally 0, -1 otherwise. */ +int spm_sp_request_increase_if_zero(sp_context_t *sp_ctx) +{ + int ret = -1; + + spin_lock(&(sp_ctx->request_count_lock)); + if (sp_ctx->request_count == 0U) { + sp_ctx->request_count++; + ret = 0U; + } + spin_unlock(&(sp_ctx->request_count_lock)); + + return ret; +} + /******************************************************************************* * This function returns a pointer to the context of the Secure Partition that * handles the service specified by an UUID. It returns NULL if the UUID wasn't diff --git a/services/std_svc/spm/spm_private.h b/services/std_svc/spm/spm_private.h index a8234c36..a7bd760b 100644 --- a/services/std_svc/spm/spm_private.h +++ b/services/std_svc/spm/spm_private.h @@ -58,6 +58,9 @@ typedef struct sp_context { sp_state_t state; spinlock_t state_lock; + unsigned int request_count; + spinlock_t request_count_lock; + /* Base and size of the shared SPM<->SP buffer */ uintptr_t spm_sp_buffer_base; size_t spm_sp_buffer_size; @@ -80,6 +83,11 @@ 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 to keep track of the number of active requests per SP */ +void spm_sp_request_increase(sp_context_t *sp_ctx); +void spm_sp_request_decrease(sp_context_t *sp_ctx); +int spm_sp_request_increase_if_zero(sp_context_t *sp_ctx); + /* Functions related to the translation tables management */ xlat_ctx_t *spm_sp_xlat_context_alloc(void); void sp_map_memory_regions(sp_context_t *sp_ctx); -- cgit v1.2.3