SPM: Introduce SPRT C host library
authorAntonio Nino Diaz <antonio.ninodiaz@arm.com>
Thu, 8 Nov 2018 09:21:48 +0000 (09:21 +0000)
committerAntonio Nino Diaz <antonio.ninodiaz@arm.com>
Tue, 11 Dec 2018 15:04:24 +0000 (15:04 +0000)
Change-Id: If57ec9cc0791f49d9ade83dff9d24ef9047963a8
Co-authored-by: Jean-Paul Etienne <jean-paul.etienne@arm.com>
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
include/lib/sprt/sprt_common.h [new file with mode: 0644]
include/lib/sprt/sprt_host.h [new file with mode: 0644]
lib/sprt/sprt_host.c [new file with mode: 0644]
lib/sprt/sprt_host.mk [new file with mode: 0644]
lib/sprt/sprt_queue.c [new file with mode: 0644]
lib/sprt/sprt_queue.h [new file with mode: 0644]
services/std_svc/spm/spm.mk

diff --git a/include/lib/sprt/sprt_common.h b/include/lib/sprt/sprt_common.h
new file mode 100644 (file)
index 0000000..27d5027
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPRT_COMMON_H
+#define SPRT_COMMON_H
+
+#define SPRT_MAX_MSG_ARGS      6
+
+/*
+ * Message types supported.
+ */
+#define SPRT_MSG_TYPE_SERVICE_HANDLE_OPEN              1
+#define SPRT_MSG_TYPE_SERVICE_HANDLE_CLOSE             2
+/* TODO: Add other types of SPRT messages. */
+#define SPRT_MSG_TYPE_SERVICE_TUN_REQUEST              10
+
+/*
+ * Struct that defines the layout of the fields corresponding to a request in
+ * shared memory.
+ */
+struct __attribute__((__packed__)) sprt_queue_entry_message {
+       uint32_t type;          /* Type of message (result of an SPCI call). */
+       uint16_t client_id;     /* SPCI client ID */
+       uint16_t service_handle;/* SPCI service handle */
+       uint32_t session_id;    /* Optional SPCI session ID */
+       uint32_t token;         /* SPCI request token */
+       uint64_t args[SPRT_MAX_MSG_ARGS];
+};
+
+#define SPRT_QUEUE_ENTRY_MSG_SIZE      (sizeof(struct sprt_queue_entry_message))
+
+#define SPRT_QUEUE_NUM_BLOCKING                0
+#define SPRT_QUEUE_NUM_NON_BLOCKING    1
+
+#endif /* SPRT_COMMON_H */
diff --git a/include/lib/sprt/sprt_host.h b/include/lib/sprt/sprt_host.h
new file mode 100644 (file)
index 0000000..f888141
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SPRT_HOST_H
+#define SPRT_HOST_H
+
+#include <stddef.h>
+
+#include "sprt_common.h"
+
+/*
+ * Initialize the specified buffer to be used by SPM.
+ */
+void sprt_initialize_queues(void *buffer_base, size_t buffer_size);
+
+/*
+ * Push a message to the queue number `queue_num` in a buffer that has been
+ * initialized by `sprt_initialize_queues`.
+ */
+int sprt_push_message(void *buffer_base,
+                     const struct sprt_queue_entry_message *message,
+                     int queue_num);
+
+#endif /* SPRT_HOST_H */
diff --git a/lib/sprt/sprt_host.c b/lib/sprt/sprt_host.c
new file mode 100644 (file)
index 0000000..c4d436e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sprt_common.h"
+#include "sprt_queue.h"
+
+void sprt_initialize_queues(void *buffer_base, size_t buffer_size)
+{
+       /* Initialize queue for blocking messages */
+
+       void *blocking_base = buffer_base;
+       uint32_t blocking_num = 4U;
+       size_t blocking_size = SPRT_QUEUE_HEADER_SIZE +
+                              SPRT_QUEUE_ENTRY_MSG_SIZE * blocking_num;
+
+       sprt_queue_init(blocking_base, blocking_num, SPRT_QUEUE_ENTRY_MSG_SIZE);
+
+       /* Initialize queue for non-blocking messages */
+
+       void *non_blocking_base = (void *)((uintptr_t)blocking_base + blocking_size);
+       size_t non_blocking_size = buffer_size - blocking_size;
+       uint32_t non_blocking_num = (non_blocking_size - SPRT_QUEUE_HEADER_SIZE) /
+               SPRT_QUEUE_ENTRY_MSG_SIZE;
+
+       sprt_queue_init(non_blocking_base, non_blocking_num, SPRT_QUEUE_ENTRY_MSG_SIZE);
+}
+
+int sprt_push_message(void *buffer_base,
+                     const struct sprt_queue_entry_message *message,
+                     int queue_num)
+{
+       struct sprt_queue *q = buffer_base;
+
+       while (queue_num-- > 0) {
+               uintptr_t next_addr = (uintptr_t)q + sizeof(struct sprt_queue) +
+                                     q->entry_num * q->entry_size;
+               q = (struct sprt_queue *) next_addr;
+       }
+
+       return sprt_queue_push(q, message);
+}
diff --git a/lib/sprt/sprt_host.mk b/lib/sprt/sprt_host.mk
new file mode 100644 (file)
index 0000000..abcfe5e
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+SPRT_LIB_SOURCES       :=      $(addprefix lib/sprt/,                  \
+                                       sprt_host.c                     \
+                                       sprt_queue.c)
+
+SPRT_LIB_INCLUDES      :=      -Iinclude/lib/sprt/
diff --git a/lib/sprt/sprt_queue.c b/lib/sprt/sprt_queue.c
new file mode 100644 (file)
index 0000000..2bd4139
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "sprt_queue.h"
+
+void sprt_queue_init(void *queue_base, uint32_t entry_num, uint32_t entry_size)
+{
+       assert(queue_base != NULL);
+       assert(entry_size > 0U);
+       assert(entry_num > 0U);
+
+       struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+       queue->entry_num = entry_num;
+       queue->entry_size = entry_size;
+       queue->idx_write = 0U;
+       queue->idx_read = 0U;
+
+       memset(queue->data, 0, entry_num * entry_size);
+}
+
+int sprt_queue_is_empty(void *queue_base)
+{
+       assert(queue_base != NULL);
+
+       struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+       return (queue->idx_write == queue->idx_read);
+}
+
+int sprt_queue_is_full(void *queue_base)
+{
+       assert(queue_base != NULL);
+
+       struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+       uint32_t idx_next_write = (queue->idx_write + 1) % queue->entry_num;
+
+       return (idx_next_write == queue->idx_read);
+}
+
+int sprt_queue_push(void *queue_base, const void *entry)
+{
+       assert(entry != NULL);
+       assert(queue_base != NULL);
+
+       if (sprt_queue_is_full(queue_base) != 0) {
+               return -ENOMEM;
+       }
+
+       struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+       uint8_t *dst_entry = &queue->data[queue->entry_size * queue->idx_write];
+
+       memcpy(dst_entry, entry, queue->entry_size);
+
+       /*
+        * Make sure that the message data is visible before increasing the
+        * counter of available messages.
+        */
+       __asm__ volatile("dmb st" ::: "memory");
+
+       queue->idx_write = (queue->idx_write + 1) % queue->entry_num;
+
+       __asm__ volatile("dmb st" ::: "memory");
+
+       return 0;
+}
+
+int sprt_queue_pop(void *queue_base, void *entry)
+{
+       assert(entry != NULL);
+       assert(queue_base != NULL);
+
+       if (sprt_queue_is_empty(queue_base) != 0) {
+               return -ENOENT;
+       }
+
+       struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+       uint8_t *src_entry = &queue->data[queue->entry_size * queue->idx_read];
+
+       memcpy(entry, src_entry, queue->entry_size);
+
+       /*
+        * Make sure that the message data is visible before increasing the
+        * counter of read messages.
+        */
+       __asm__ volatile("dmb st" ::: "memory");
+
+       queue->idx_read = (queue->idx_read + 1) % queue->entry_num;
+
+       __asm__ volatile("dmb st" ::: "memory");
+
+       return 0;
+}
diff --git a/lib/sprt/sprt_queue.h b/lib/sprt/sprt_queue.h
new file mode 100644 (file)
index 0000000..4ea1bc2
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPRT_QUEUE_H
+#define SPRT_QUEUE_H
+
+#include <stdint.h>
+
+/* Struct that defines a queue. Not to be used directly. */
+struct __attribute__((__packed__)) sprt_queue {
+       uint32_t entry_num;     /* Number of entries */
+       uint32_t entry_size;    /* Size of an entry */
+       uint32_t idx_write;     /* Index of first empty entry */
+       uint32_t idx_read;      /* Index of first entry to read */
+       uint8_t  data[0];       /* Start of data */
+};
+
+#define SPRT_QUEUE_HEADER_SIZE (sizeof(struct sprt_queue))
+
+/*
+ * Initializes a memory region to be used as a queue of the given number of
+ * entries with the specified size.
+ */
+void sprt_queue_init(void *queue_base, uint32_t entry_num, uint32_t entry_size);
+
+/* Returns 1 if the queue is empty, 0 otherwise */
+int sprt_queue_is_empty(void *queue_base);
+
+/* Returns 1 if the queue is full, 0 otherwise */
+int sprt_queue_is_full(void *queue_base);
+
+/*
+ * Pushes a new entry intro the queue. Returns 0 on success, -ENOMEM if the
+ * queue is full.
+ */
+int sprt_queue_push(void *queue_base, const void *entry);
+
+/*
+ * Pops an entry from the queue. Returns 0 on success, -ENOENT if the queue is
+ * empty.
+ */
+int sprt_queue_pop(void *queue_base, void *entry);
+
+#endif /* SPRT_QUEUE_H */
index 889c77d25b1ba8e02f263078ba9c12717ff3a379..a191f6ff11c70801ff7083a40cecddbd770c6787 100644 (file)
@@ -11,6 +11,8 @@ ifneq (${ARCH},aarch64)
         $(error "Error: SPM is only supported on aarch64.")
 endif
 
+include lib/sprt/sprt_host.mk
+
 SPM_SOURCES    :=      $(addprefix services/std_svc/spm/,      \
                        ${ARCH}/spm_helpers.S                   \
                        ${ARCH}/spm_shim_exceptions.S           \
@@ -18,8 +20,10 @@ SPM_SOURCES  :=      $(addprefix services/std_svc/spm/,      \
                        sp_xlat.c                               \
                        spci.c                                  \
                        spm_main.c                              \
-                       sprt.c)
+                       sprt.c)                                 \
+                       ${SPRT_LIB_SOURCES}
 
+INCLUDES       +=      ${SPRT_LIB_INCLUDES}
 
 # Force SMC Calling Convention 2 when using SPM
 SMCCC_MAJOR_VERSION    :=      2