SPM: Prevent simultaneous blocking calls
authorAntonio Nino Diaz <antonio.ninodiaz@arm.com>
Tue, 3 Jul 2018 18:54:59 +0000 (19:54 +0100)
committerAntonio Nino Diaz <antonio.ninodiaz@arm.com>
Tue, 11 Dec 2018 15:04:24 +0000 (15:04 +0000)
Blocking calls can only succeed if the target Secure Partition is idle.

Change-Id: Iabeaa0b8d3e653fd8581fa086758936abfc1c772
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
services/std_svc/spm/spci.c
services/std_svc/spm/spm_main.c
services/std_svc/spm/spm_private.h

index cbb0f3cc379dc12f52340c950f82f8081fc98469..1544ae16240435592427cd9212daa2e49997e48d 100644 (file)
@@ -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);
index b1d5dd86d7acb94cd7f62cf2a69a06ece858c2d6..050c66cc1bd2326bedace54ff54413c1e3e877b6 100644 (file)
@@ -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
index a8234c36f08ee6b7a84e34d417f2c12de4bd3ff2..a7bd760bd725463abae5d890209788df4a471252 100644 (file)
@@ -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);