diff --git a/include/lib/sprt/sprt_common.h b/include/lib/sprt/sprt_common.h new file mode 100644 index 0000000..27d5027 --- /dev/null +++ b/include/lib/sprt/sprt_common.h @@ -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 index 0000000..f888141 --- /dev/null +++ b/include/lib/sprt/sprt_host.h @@ -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 + +#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 index 0000000..c4d436e --- /dev/null +++ b/lib/sprt/sprt_host.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#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 index 0000000..abcfe5e --- /dev/null +++ b/lib/sprt/sprt_host.mk @@ -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 index 0000000..2bd4139 --- /dev/null +++ b/lib/sprt/sprt_queue.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +#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 index 0000000..4ea1bc2 --- /dev/null +++ b/lib/sprt/sprt_queue.h @@ -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 + +/* 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 */ diff --git a/services/std_svc/spm/spm.mk b/services/std_svc/spm/spm.mk index 889c77d..a191f6f 100644 --- a/services/std_svc/spm/spm.mk +++ b/services/std_svc/spm/spm.mk @@ -11,6 +11,8 @@ $(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 @@ 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