TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tfm_spe_mailbox.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "cmsis_compiler.h"
9 
10 #include "psa/error.h"
11 #include "tfm_core_utils.h"
12 #include "utilities.h"
13 #include "tfm_spe_mailbox.h"
14 #include "tfm_rpc.h"
15 
16 #define NS_CALLER_FLAG (true)
17 
18 static struct secure_mailbox_queue_t spe_mailbox_queue;
19 
20 static int32_t tfm_mailbox_dispatch(uint32_t call_type,
21  const struct psa_client_params_t *params,
22  int32_t client_id,
23  psa_status_t *psa_ret)
24 {
25  struct client_call_params_t spm_params = {0};
26 
27  TFM_CORE_ASSERT(params != NULL);
28  TFM_CORE_ASSERT(psa_ret != NULL);
29 
30  (void)client_id;
31 
32  switch (call_type) {
34  *psa_ret = tfm_rpc_psa_framework_version();
35  return MAILBOX_SUCCESS;
37  spm_params.sid = params->psa_version_params.sid;
38  *psa_ret = tfm_rpc_psa_version(&spm_params, NS_CALLER_FLAG);
39  return MAILBOX_SUCCESS;
41  spm_params.sid = params->psa_connect_params.sid;
42  spm_params.version = params->psa_connect_params.version;
43  *psa_ret = tfm_rpc_psa_connect(&spm_params, NS_CALLER_FLAG);
44  return MAILBOX_SUCCESS;
45  case MAILBOX_PSA_CALL:
46  spm_params.handle = params->psa_call_params.handle;
47  spm_params.type = params->psa_call_params.type;
48  spm_params.in_vec = params->psa_call_params.in_vec;
49  spm_params.in_len = params->psa_call_params.in_len;
50  spm_params.out_vec = params->psa_call_params.out_vec;
51  spm_params.out_len = params->psa_call_params.out_len;
52  *psa_ret = tfm_rpc_psa_call(&spm_params, NS_CALLER_FLAG);
53  return MAILBOX_SUCCESS;
54  case MAILBOX_PSA_CLOSE:
55  spm_params.handle = params->psa_close_params.handle;
56  tfm_rpc_psa_close(&spm_params, NS_CALLER_FLAG);
57  return MAILBOX_SUCCESS;
58  default:
59  return MAILBOX_INVAL_PARAMS;
60  }
61 }
62 
63 __STATIC_INLINE void set_spe_queue_empty_status(uint8_t idx)
64 {
65  if (idx < NUM_MAILBOX_QUEUE_SLOT) {
66  spe_mailbox_queue.empty_slots |= (1 << idx);
67  }
68 }
69 
70 __STATIC_INLINE void clear_spe_queue_empty_status(uint8_t idx)
71 {
72  if (idx < NUM_MAILBOX_QUEUE_SLOT) {
73  spe_mailbox_queue.empty_slots &= ~(1 << idx);
74  }
75 }
76 
77 __STATIC_INLINE bool get_spe_queue_empty_status(uint8_t idx)
78 {
79  if ((idx < NUM_MAILBOX_QUEUE_SLOT) &&
80  (spe_mailbox_queue.empty_slots & (1 << idx))) {
81  return true;
82  }
83 
84  return false;
85 }
86 
88  const struct ns_mailbox_queue_t *ns_queue)
89 {
90  return ns_queue->pend_slots;
91 }
92 
93 __STATIC_INLINE void set_nspe_queue_replied_status(
94  struct ns_mailbox_queue_t *ns_queue,
96 {
97  ns_queue->replied_slots |= mask;
98 }
99 
100 __STATIC_INLINE void clear_nspe_queue_pend_status(
101  struct ns_mailbox_queue_t *ns_queue,
103 {
104  ns_queue->pend_slots &= ~mask;
105 }
106 
107 __STATIC_INLINE int32_t get_spe_mailbox_msg_handle(uint8_t idx,
108  mailbox_msg_handle_t *handle)
109 {
110  if ((idx >= NUM_MAILBOX_QUEUE_SLOT) || !handle) {
111  return MAILBOX_INVAL_PARAMS;
112  }
113 
114  *handle = (mailbox_msg_handle_t)(idx + 1);
115 
116  return MAILBOX_SUCCESS;
117 }
118 
119 __STATIC_INLINE int32_t get_spe_mailbox_msg_idx(mailbox_msg_handle_t handle,
120  uint8_t *idx)
121 {
122  if ((handle == MAILBOX_MSG_NULL_HANDLE) || !idx) {
123  return MAILBOX_INVAL_PARAMS;
124  }
125 
126  *idx = (uint8_t)(handle - 1);
127 
128  return MAILBOX_SUCCESS;
129 }
130 
131 static void mailbox_clean_queue_slot(uint8_t idx)
132 {
133  if (idx >= NUM_MAILBOX_QUEUE_SLOT) {
134  return;
135  }
136 
137  spm_memset(&spe_mailbox_queue.queue[idx], 0,
138  sizeof(spe_mailbox_queue.queue[idx]));
140 }
141 
142 __STATIC_INLINE struct mailbox_reply_t *get_nspe_reply_addr(uint8_t idx)
143 {
144  uint8_t ns_slot_idx;
145 
146  if (idx >= NUM_MAILBOX_QUEUE_SLOT) {
147  return NULL;
148  }
149 
150  ns_slot_idx = spe_mailbox_queue.queue[idx].ns_slot_idx;
151 
152  return &spe_mailbox_queue.ns_queue->queue[ns_slot_idx].reply;
153 }
154 
155 static void mailbox_direct_reply(uint8_t idx, uint32_t result)
156 {
157  struct mailbox_reply_t *reply_ptr;
158  uint32_t ret_result = result;
159 
160  /* Get reply address */
161  reply_ptr = get_nspe_reply_addr(idx);
162  spm_memcpy(&reply_ptr->return_val, &ret_result,
163  sizeof(reply_ptr->return_val));
164 
165  mailbox_clean_queue_slot(idx);
166 
167  /*
168  * Skip NSPE queue status update after single reply.
169  * Update NSPE queue status after all the mailbox messages are completed
170  */
171 }
172 
173 __STATIC_INLINE int32_t check_mailbox_msg(const struct mailbox_msg_t *msg)
174 {
175  /*
176  * TODO
177  * Comprehensive check of mailbox msessage content can be implemented here.
178  */
179  (void)msg;
180  return MAILBOX_SUCCESS;
181 }
182 
184 {
185  uint8_t idx;
186  int32_t result;
188  mailbox_queue_status_t mask_bits, pend_slots, reply_slots = 0;
189  struct ns_mailbox_queue_t *ns_queue = spe_mailbox_queue.ns_queue;
190  struct mailbox_msg_t *msg_ptr;
191 
192  TFM_CORE_ASSERT(ns_queue != NULL);
193 
195 
196  /* Check if NSPE mailbox did assert a PSA client call request */
197  if (!ns_queue->pend_slots) {
199  return MAILBOX_NO_PEND_EVENT;
200  }
201 
202  pend_slots = get_nspe_queue_pend_status(ns_queue);
203 
205 
206  for (idx = 0; idx < NUM_MAILBOX_QUEUE_SLOT; idx++) {
207  mask_bits = (1 << idx);
208  /* Check if current NSPE mailbox queue slot is pending for handling */
209  if (!(pend_slots & mask_bits)) {
210  continue;
211  }
212 
213  /*
214  * TODO
215  * The operations are simplified here. Use the SPE mailbox queue
216  * slot with the same idx as that of the NSPE mailbox queue slot.
217  * A more general implementation should dynamically search and
218  * select an empty SPE mailbox queue slot.
219  */
221  spe_mailbox_queue.queue[idx].ns_slot_idx = idx;
222 
223  msg_ptr = &spe_mailbox_queue.queue[idx].msg;
224  spm_memcpy(msg_ptr, &ns_queue->queue[idx].msg, sizeof(*msg_ptr));
225 
226  if (check_mailbox_msg(msg_ptr) != MAILBOX_SUCCESS) {
227  mailbox_clean_queue_slot(idx);
228  continue;
229  }
230 
232  &spe_mailbox_queue.queue[idx].msg_handle);
233 
234  /*
235  * Set the current slot index under processing.
236  * The value is used in mailbox_get_caller_data() to identify the
237  * mailbox queue slot.
238  */
239  spe_mailbox_queue.cur_proc_slot_idx = idx;
240 
241  result = tfm_mailbox_dispatch(msg_ptr->call_type, &msg_ptr->params,
242  msg_ptr->client_id, &psa_ret);
243  if (result != MAILBOX_SUCCESS) {
244  mailbox_clean_queue_slot(idx);
245  continue;
246  }
247 
248  /* Clean up the current slot index under processing */
249  spe_mailbox_queue.cur_proc_slot_idx = NUM_MAILBOX_QUEUE_SLOT;
250 
251  if ((msg_ptr->call_type == MAILBOX_PSA_FRAMEWORK_VERSION) ||
252  (msg_ptr->call_type == MAILBOX_PSA_VERSION)) {
253  /*
254  * Directly write the result to NSPE for psa_framework_version() and
255  * psa_version().
256  */
257  reply_slots |= (1 << idx);
258 
259  mailbox_direct_reply(idx, (uint32_t)psa_ret);
260  } else if ((msg_ptr->call_type == MAILBOX_PSA_CONNECT) ||
261  (msg_ptr->call_type == MAILBOX_PSA_CALL)) {
262  /*
263  * If it failed to deliver psa_connect() or psa_call() request to
264  * TF-M IPC SPM, the failure result should be returned immediately.
265  */
266  if (psa_ret != PSA_SUCCESS) {
267  reply_slots |= (1 << idx);
268  mailbox_direct_reply(idx, (uint32_t)psa_ret);
269  }
270  }
271  /*
272  * Skip checking psa_call() since it neither returns immediately nor
273  * has return value.
274  */
275  }
276 
278 
279  /* Clean the NSPE mailbox pending status. */
280  clear_nspe_queue_pend_status(ns_queue, pend_slots);
281 
282  /* Set the NSPE mailbox replied status */
283  set_nspe_queue_replied_status(ns_queue, reply_slots);
284 
286 
287  if (reply_slots) {
289  }
290 
291  return MAILBOX_SUCCESS;
292 }
293 
294 int32_t tfm_mailbox_reply_msg(mailbox_msg_handle_t handle, int32_t reply)
295 {
296  uint8_t idx;
297  int32_t ret;
298  struct ns_mailbox_queue_t *ns_queue = spe_mailbox_queue.ns_queue;
299 
300  TFM_CORE_ASSERT(ns_queue != NULL);
301 
302  /*
303  * If handle == MAILBOX_MSG_NULL_HANDLE, reply to the mailbox message
304  * in the first slot.
305  * When multiple ongoing PSA client calls from NSPE are supported,
306  * additional check might be necessary to avoid spoofing the first slot.
307  */
308  if (handle == MAILBOX_MSG_NULL_HANDLE) {
309  idx = 0;
310  } else {
311  ret = get_spe_mailbox_msg_idx(handle, &idx);
312  if (ret != MAILBOX_SUCCESS) {
313  return ret;
314  }
315  }
316 
317  if (get_spe_queue_empty_status(idx)) {
318  return MAILBOX_NO_PEND_EVENT;
319  }
320 
321  mailbox_direct_reply(idx, (uint32_t)reply);
322 
324 
325  /* Set the NSPE mailbox replied status */
326  set_nspe_queue_replied_status(ns_queue, (1 << idx));
327 
329 
331 
332  return MAILBOX_SUCCESS;
333 }
334 
335 /* RPC handle_req() callback */
336 static void mailbox_handle_req(void)
337 {
338  (void)tfm_mailbox_handle_msg();
339 }
340 
341 /* RPC reply() callback */
342 static void mailbox_reply(const void *owner, int32_t ret)
343 {
345 
346  /* If the owner is specified */
347  if (owner) {
348  handle = *((mailbox_msg_handle_t *)owner);
349  }
350 
351  (void)tfm_mailbox_reply_msg(handle, ret);
352 }
353 
354 /* RPC get_caller_data() callback */
355 static const void *mailbox_get_caller_data(int32_t client_id)
356 {
357  uint8_t idx;
358 
359  (void)client_id;
360 
361  idx = spe_mailbox_queue.cur_proc_slot_idx;
362  if (idx < NUM_MAILBOX_QUEUE_SLOT) {
363  return (const void *)&spe_mailbox_queue.queue[idx].msg_handle;
364  }
365 
366  return NULL;
367 }
368 
369 /* Mailbox specific operations callback for TF-M RPC */
370 static const struct tfm_rpc_ops_t mailbox_rpc_ops = {
371  .handle_req = mailbox_handle_req,
372  .reply = mailbox_reply,
373  .get_caller_data = mailbox_get_caller_data,
374 };
375 
376 int32_t tfm_mailbox_init(void)
377 {
378  int32_t ret;
379 
380  spm_memset(&spe_mailbox_queue, 0, sizeof(spe_mailbox_queue));
381 
382  spe_mailbox_queue.empty_slots =
383  (mailbox_queue_status_t)((1UL << (NUM_MAILBOX_QUEUE_SLOT - 1)) - 1);
384  spe_mailbox_queue.empty_slots +=
386 
387  /* Register RPC callbacks */
388  ret = tfm_rpc_register_ops(&mailbox_rpc_ops);
389  if (ret != TFM_RPC_SUCCESS) {
391  }
392 
393  /*
394  * Platform specific initialization.
395  * Initialize Inter-Processor Communication and achieve the base address of
396  * NSPE mailbox queue
397  */
398  ret = tfm_mailbox_hal_init(&spe_mailbox_queue);
399  if (ret != MAILBOX_SUCCESS) {
401 
402  return ret;
403  }
404 
405  return MAILBOX_SUCCESS;
406 }
__STATIC_INLINE struct mailbox_reply_t * get_nspe_reply_addr(uint8_t idx)
psa_status_t tfm_rpc_psa_connect(const struct client_call_params_t *params, bool ns_caller)
Definition: tfm_rpc.c:49
psa_status_t tfm_rpc_psa_call(const struct client_call_params_t *params, bool ns_caller)
Definition: tfm_rpc.c:57
struct ns_mailbox_queue_t * ns_queue
struct mailbox_reply_t reply
Definition: tfm_mailbox.h:137
__STATIC_INLINE void clear_spe_queue_empty_status(uint8_t idx)
struct psa_client_params_t::@2::@7 psa_close_params
mailbox_queue_status_t replied_slots
Definition: tfm_mailbox.h:155
void tfm_rpc_psa_close(const struct client_call_params_t *params, bool ns_caller)
Definition: tfm_rpc.c:68
#define PSA_SUCCESS
Definition: crypto_values.h:35
struct psa_client_params_t::@2::@6 psa_call_params
#define MAILBOX_PSA_CALL
Definition: tfm_mailbox.h:64
#define MAILBOX_INVAL_PARAMS
Definition: tfm_mailbox.h:70
int32_t tfm_mailbox_hal_init(struct secure_mailbox_queue_t *s_queue)
Platform specific initialization of SPE mailbox.
struct psa_client_params_t params
Definition: tfm_mailbox.h:109
__STATIC_INLINE void clear_nspe_queue_pend_status(struct ns_mailbox_queue_t *ns_queue, mailbox_queue_status_t mask)
mailbox_queue_status_t empty_slots
mailbox_msg_handle_t msg_handle
#define MAILBOX_SUCCESS
Definition: tfm_mailbox.h:68
uint32_t call_type
Definition: tfm_mailbox.h:108
__STATIC_INLINE bool get_spe_queue_empty_status(uint8_t idx)
mailbox_queue_status_t pend_slots
Definition: tfm_mailbox.h:152
#define MAILBOX_PSA_CLOSE
Definition: tfm_mailbox.h:65
int32_t client_id
Definition: tfm_mailbox.h:113
Standard error codes for the SPM and RoT Services.
struct ns_mailbox_slot_t queue[(1)]
Definition: tfm_mailbox.h:160
int32_t tfm_mailbox_init(void)
SPE mailbox initialization.
int32_t tfm_mailbox_hal_notify_peer(void)
Notify NSPE that a PSA client call return result is replied. Implemented by platform specific inter-p...
#define MAILBOX_PSA_CONNECT
Definition: tfm_mailbox.h:63
uint32_t tfm_rpc_psa_framework_version(void)
Definition: tfm_rpc.c:36
#define PSA_ERROR_GENERIC_ERROR
Definition: crypto_values.h:43
__STATIC_INLINE int32_t get_spe_mailbox_msg_idx(mailbox_msg_handle_t handle, uint8_t *idx)
#define NUM_MAILBOX_QUEUE_SLOT
Definition: tfm_mailbox.h:57
__STATIC_INLINE void set_spe_queue_empty_status(uint8_t idx)
#define MAILBOX_NO_PEND_EVENT
Definition: tfm_mailbox.h:72
uint32_t mailbox_queue_status_t
Definition: tfm_mailbox.h:147
__STATIC_INLINE mailbox_queue_status_t get_nspe_queue_pend_status(const struct ns_mailbox_queue_t *ns_queue)
int32_t mailbox_msg_handle_t
Definition: tfm_mailbox.h:122
#define MAILBOX_CALLBACK_REG_ERROR
Definition: tfm_mailbox.h:74
void * spm_memcpy(void *dest, const void *src, size_t n)
Memory copy function for TF-M core.
void * spm_memset(void *s, int c, size_t n)
Memory set function for TF-M core.
int32_t tfm_mailbox_reply_msg(mailbox_msg_handle_t handle, int32_t reply)
Return PSA client call return result to NSPE.
void tfm_mailbox_hal_enter_critical(void)
Enter critical section of NSPE mailbox.
__STATIC_INLINE int32_t check_mailbox_msg(const struct mailbox_msg_t *msg)
#define TFM_CORE_ASSERT(cond)
Definition: utilities.h:21
void tfm_rpc_unregister_ops(void)
Definition: tfm_rpc.c:100
__STATIC_INLINE int32_t get_spe_mailbox_msg_handle(uint8_t idx, mailbox_msg_handle_t *handle)
int32_t return_val
Definition: tfm_mailbox.h:131
struct mailbox_msg_t msg
int32_t tfm_rpc_register_ops(const struct tfm_rpc_ops_t *ops_ptr)
Definition: tfm_rpc.c:76
__STATIC_INLINE void set_nspe_queue_replied_status(struct ns_mailbox_queue_t *ns_queue, mailbox_queue_status_t mask)
struct mailbox_msg_t msg
Definition: tfm_mailbox.h:136
void tfm_mailbox_hal_exit_critical(void)
Exit critical section of NSPE mailbox.
struct psa_client_params_t::@2::@5 psa_connect_params
#define MAILBOX_PSA_FRAMEWORK_VERSION
Definition: tfm_mailbox.h:61
uint32_t tfm_rpc_psa_version(const struct client_call_params_t *params, bool ns_caller)
Definition: tfm_rpc.c:41
#define MAILBOX_MSG_NULL_HANDLE
Definition: tfm_mailbox.h:124
struct secure_mailbox_slot_t queue[NUM_MAILBOX_QUEUE_SLOT]
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
int32_t tfm_mailbox_handle_msg(void)
Handle mailbox message(s) from NSPE.
#define NS_CALLER_FLAG
#define MAILBOX_PSA_VERSION
Definition: tfm_mailbox.h:62
struct psa_client_params_t::@2::@4 psa_version_params