diff options
author | Antonio Nino Diaz <antonio.ninodiaz@arm.com> | 2018-11-08 10:58:26 +0000 |
---|---|---|
committer | Antonio Nino Diaz <antonio.ninodiaz@arm.com> | 2018-12-11 15:04:14 +0000 |
commit | e46924ea53f8c2c300b1ab1cf9e0c5676511ae67 (patch) | |
tree | 5ee86e7eeedf7c5e8d95695a9e21dbb826a52e51 /lib | |
parent | fdd08233fb104176d3480cdcb23aacb2ec6e2b83 (diff) |
SPM: Introduce SPRT C client library
Change-Id: I2f110b4d06d2821d8bdf818ab7523a5c0a6b9ab9
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/sprt/aarch64/sprt_client_helpers.S | 41 | ||||
-rw-r--r-- | lib/sprt/sprt_client.c | 80 | ||||
-rw-r--r-- | lib/sprt/sprt_client.mk | 12 | ||||
-rw-r--r-- | lib/sprt/sprt_client_private.h | 35 | ||||
-rw-r--r-- | lib/sprt/sprt_queue.c | 104 | ||||
-rw-r--r-- | lib/sprt/sprt_queue.h | 47 |
6 files changed, 319 insertions, 0 deletions
diff --git a/lib/sprt/aarch64/sprt_client_helpers.S b/lib/sprt/aarch64/sprt_client_helpers.S new file mode 100644 index 0000000..4606854 --- /dev/null +++ b/lib/sprt/aarch64/sprt_client_helpers.S @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm_macros.S> + + .globl sprt_client_svc + +func sprt_client_svc + /* + * Save the address of the svc_args structure on the stack. + * + * Although x0 contains an 8-byte value, we are allocating 16 bytes + * on the stack to respect the 16-byte stack-alignment. + */ + str x0, [sp, #-16]! + + /* Load the SVC arguments values into the appropriate registers. */ + ldp x6, x7, [x0, #48] + ldp x4, x5, [x0, #32] + ldp x2, x3, [x0, #16] + ldp x0, x1, [x0, #0] + + svc #0 + + /* + * Pop the svc_args structure address from the stack into a caller-saved + * register. + */ + ldr x9, [sp], #16 + + /* + * The return values are stored in x0-x3, put them in the svc_args + * return structure. + */ + stp x0, x1, [x9, #0] + stp x2, x3, [x9, #16] + ret +endfunc sprt_client_svc diff --git a/lib/sprt/sprt_client.c b/lib/sprt/sprt_client.c new file mode 100644 index 0000000..41f5307 --- /dev/null +++ b/lib/sprt/sprt_client.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <sprt_svc.h> +#include <stddef.h> + +#include "sprt_client.h" +#include "sprt_client_private.h" +#include "sprt_common.h" +#include "sprt_queue.h" + +uint32_t sprt_version(void) +{ + struct svc_args args; + + args.arg0 = SPRT_VERSION; + + return sprt_client_svc(&args); +} + +void sprt_wait_for_messages(void) +{ + struct svc_args args; + + args.arg0 = SPRT_YIELD_AARCH64; + + sprt_client_svc(&args); +} + +/* + * Variable that points to the memory buffer that contains the queues used by + * this Secure Partition. + */ +static void *queue_messages; + +void sprt_initialize_queues(void *buffer_base) +{ + queue_messages = buffer_base; +} + +int sprt_get_next_message(struct sprt_queue_entry_message *message, + int queue_num) +{ + struct sprt_queue *q = queue_messages; + + 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_pop(q, message); +} + +void sprt_message_end(struct sprt_queue_entry_message *message, + u_register_t arg0, u_register_t arg1, u_register_t arg2, + u_register_t arg3) +{ + struct svc_args args; + + if (message->type == SPRT_MSG_TYPE_SERVICE_REQUEST) { + args.arg0 = SPRT_PUT_RESPONSE_AARCH64; + args.arg1 = message->token; + } + + args.arg2 = arg0; + args.arg3 = arg1; + args.arg4 = arg2; + args.arg5 = arg3; + args.arg6 = ((uint32_t)message->service_handle << 16U) + | message->client_id; + args.arg7 = message->session_id; + + sprt_client_svc(&args); +} diff --git a/lib/sprt/sprt_client.mk b/lib/sprt/sprt_client.mk new file mode 100644 index 0000000..8d22430 --- /dev/null +++ b/lib/sprt/sprt_client.mk @@ -0,0 +1,12 @@ +# +# Copyright (c) 2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +SPRT_LIB_SOURCES := $(addprefix lib/sprt/, \ + ${ARCH}/sprt_client_helpers.S \ + sprt_client.c \ + sprt_queue.c) + +SPRT_LIB_INCLUDES := -Iinclude/lib/sprt/ diff --git a/lib/sprt/sprt_client_private.h b/lib/sprt/sprt_client_private.h new file mode 100644 index 0000000..57d8dc5 --- /dev/null +++ b/lib/sprt/sprt_client_private.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SPRT_CLIENT_PRIVATE_H +#define SPRT_CLIENT_PRIVATE_H + +#include <stdint.h> + +struct svc_args { + u_register_t arg0; + u_register_t arg1; + u_register_t arg2; + u_register_t arg3; + u_register_t arg4; + u_register_t arg5; + u_register_t arg6; + u_register_t arg7; +}; + +/* + * Invoke an SVC call. + * + * The arguments to pass through the SVC call must be stored in the svc_args + * structure. The return values of the SVC call will be stored in the same + * structure (overriding the input arguments). + * + * Returns the first return value. It is equivalent to args.arg0 but is also + * provided as the return value for convenience. + */ +u_register_t sprt_client_svc(struct svc_args *args); + +#endif /* SPRT_CLIENT_PRIVATE_H */ 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 <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 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 <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 */ |