diff --git a/services/std_svc/spm/spci.c b/services/std_svc/spm/spci.c index cbb0f3c..1544ae1 100644 --- a/services/std_svc/spm/spci.c +++ b/services/std_svc/spm/spci.c @@ -291,6 +291,12 @@ 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 @@ 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 b1d5dd8..050c66c 100644 --- a/services/std_svc/spm/spm_main.c +++ b/services/std_svc/spm/spm_main.c @@ -47,6 +47,39 @@ } /******************************************************************************* + * 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 * found. diff --git a/services/std_svc/spm/spm_private.h b/services/std_svc/spm/spm_private.h index a8234c3..a7bd760 100644 --- a/services/std_svc/spm/spm_private.h +++ b/services/std_svc/spm/spm_private.h @@ -58,6 +58,9 @@ 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_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);