blob: 23e450eb0a2c27717e1fba82be693e88db018c99 [file] [log] [blame]
/*
* Copyright (c) 2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <string.h>
#include "tfm_ns_mailbox.h"
/* The pointer to NSPE mailbox queue */
static struct ns_mailbox_queue_t *mailbox_queue_ptr = NULL;
static inline void clear_queue_slot_empty(uint8_t idx)
{
if (idx < NUM_MAILBOX_QUEUE_SLOT) {
mailbox_queue_ptr->empty_slots &= ~(1 << idx);
}
}
static inline void set_queue_slot_empty(uint8_t idx)
{
if (idx < NUM_MAILBOX_QUEUE_SLOT) {
mailbox_queue_ptr->empty_slots |= (1 << idx);
}
}
static inline void set_queue_slot_pend(uint8_t idx)
{
if (idx < NUM_MAILBOX_QUEUE_SLOT) {
mailbox_queue_ptr->pend_slots |= (1 << idx);
}
}
static inline int32_t get_mailbox_msg_handle(uint8_t idx,
mailbox_msg_handle_t *handle)
{
if ((idx >= NUM_MAILBOX_QUEUE_SLOT) || !handle) {
return MAILBOX_INVAL_PARAMS;
}
*handle = (mailbox_msg_handle_t)(idx + 1);
return MAILBOX_SUCCESS;
}
static inline int32_t get_mailbox_msg_idx(mailbox_msg_handle_t handle,
uint8_t *idx)
{
if ((handle == MAILBOX_MSG_NULL_HANDLE) || !idx) {
return MAILBOX_INVAL_PARAMS;
}
*idx = (uint8_t)(handle - 1);
return MAILBOX_SUCCESS;
}
static inline void clear_queue_slot_replied(uint8_t idx)
{
if (idx < NUM_MAILBOX_QUEUE_SLOT) {
mailbox_queue_ptr->replied_slots &= ~(1 << idx);
}
}
static uint8_t acquire_empty_slot(const struct ns_mailbox_queue_t *queue)
{
uint8_t idx;
mailbox_queue_status_t status;
tfm_ns_mailbox_hal_enter_critical();
status = queue->empty_slots;
if (!status) {
/* No empty slot */
tfm_ns_mailbox_hal_exit_critical();
return NUM_MAILBOX_QUEUE_SLOT;
}
for (idx = 0; idx < NUM_MAILBOX_QUEUE_SLOT; idx++) {
if (status & (1 << idx)) {
break;
}
}
clear_queue_slot_empty(idx);
tfm_ns_mailbox_hal_exit_critical();
return idx;
}
mailbox_msg_handle_t tfm_ns_mailbox_tx_client_req(uint32_t call_type,
const struct psa_client_params_t *params,
int32_t client_id)
{
uint8_t idx;
struct mailbox_msg_t *msg_ptr;
mailbox_msg_handle_t handle;
if (!mailbox_queue_ptr) {
return MAILBOX_MSG_NULL_HANDLE;
}
if (!params) {
return MAILBOX_MSG_NULL_HANDLE;
}
idx = acquire_empty_slot(mailbox_queue_ptr);
if (idx >= NUM_MAILBOX_QUEUE_SLOT) {
return MAILBOX_QUEUE_FULL;
}
/* Fill the mailbox message */
msg_ptr = &mailbox_queue_ptr->queue[idx].msg;
msg_ptr->call_type = call_type;
memcpy(&msg_ptr->params, params, sizeof(msg_ptr->params));
msg_ptr->client_id = client_id;
get_mailbox_msg_handle(idx, &handle);
tfm_ns_mailbox_hal_enter_critical();
set_queue_slot_pend(idx);
tfm_ns_mailbox_hal_exit_critical();
tfm_ns_mailbox_hal_notify_peer();
return handle;
}
int32_t tfm_ns_mailbox_rx_client_reply(mailbox_msg_handle_t handle,
int32_t *reply)
{
uint8_t idx;
int32_t ret;
if (!mailbox_queue_ptr) {
return MAILBOX_INVAL_PARAMS;
}
if ((handle == MAILBOX_MSG_NULL_HANDLE) || (!reply)) {
return MAILBOX_INVAL_PARAMS;
}
ret = get_mailbox_msg_idx(handle, &idx);
if (ret != MAILBOX_SUCCESS) {
return ret;
}
*reply = mailbox_queue_ptr->queue[idx].reply.return_val;
tfm_ns_mailbox_hal_enter_critical();
set_queue_slot_empty(idx);
clear_queue_slot_replied(idx);
tfm_ns_mailbox_hal_exit_critical();
return MAILBOX_SUCCESS;
}
bool tfm_ns_mailbox_is_msg_replied(mailbox_msg_handle_t handle)
{
uint8_t idx;
int32_t ret;
mailbox_queue_status_t status;
if (!mailbox_queue_ptr) {
return false;
}
if (handle == MAILBOX_MSG_NULL_HANDLE) {
return false;
}
ret = get_mailbox_msg_idx(handle, &idx);
if (ret != MAILBOX_SUCCESS) {
return false;
}
tfm_ns_mailbox_hal_enter_critical();
status = mailbox_queue_ptr->replied_slots;
tfm_ns_mailbox_hal_exit_critical();
if (status & (1 << idx)) {
return true;
}
return false;
}
int32_t tfm_ns_mailbox_init(struct ns_mailbox_queue_t *queue)
{
int32_t ret;
if (!queue) {
return MAILBOX_INVAL_PARAMS;
}
/*
* Further verification of mailbox queue address may be required according
* to non-secure memory assignment.
*/
memset(queue, 0, sizeof(*queue));
/* Initialize empty bitmask */
queue->empty_slots = (mailbox_queue_status_t)((1 << NUM_MAILBOX_QUEUE_SLOT)
- 1);
mailbox_queue_ptr = queue;
/* Platform specific initialization. */
ret = tfm_ns_mailbox_hal_init(queue);
return ret;
}