TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
spm_ipc.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <inttypes.h>
9 #include <stdbool.h>
10 #include "psa/client.h"
11 #include "psa/service.h"
12 #include "tfm_thread.h"
13 #include "tfm_wait.h"
14 #include "tfm_internal_defines.h"
15 #include "tfm_spm_hal.h"
16 #include "tfm_irq_list.h"
17 #include "tfm_api.h"
18 #include "tfm_secure_api.h"
19 #include "tfm_memory_utils.h"
20 #include "tfm_hal_defs.h"
21 #include "tfm_hal_isolation.h"
22 #include "spm_ipc.h"
23 #include "tfm_peripherals_def.h"
24 #include "tfm_core_utils.h"
25 #include "tfm_rpc.h"
26 #include "tfm_core_trustzone.h"
27 #include "tfm_list.h"
28 #include "tfm_hal_isolation.h"
29 #include "tfm_pools.h"
30 #include "region.h"
31 #include "region_defs.h"
32 #include "spm_partition_defs.h"
33 #include "psa_manifest/pid.h"
34 #include "tfm/tfm_spm_services.h"
35 
37 #include "tfm_spm_db_ipc.inc"
38 
39 /* Extern service variable */
40 extern struct tfm_spm_service_t service[];
41 extern const struct tfm_spm_service_db_t service_db[];
42 
43 /* Pools */
44 TFM_POOL_DECLARE(conn_handle_pool, sizeof(struct tfm_conn_handle_t),
46 
48  IRQn_Type irq_line);
49 
51 
52 /*********************** Connection handle conversion APIs *******************/
53 
54 /* Set a minimal value here for feature expansion. */
55 #define CLIENT_HANDLE_VALUE_MIN 32
56 
57 #define CONVERSION_FACTOR_BITOFFSET 3
58 #define CONVERSION_FACTOR_VALUE (1 << CONVERSION_FACTOR_BITOFFSET)
59 /* Set 32 as the maximum */
60 #define CONVERSION_FACTOR_VALUE_MAX 0x20
61 
62 #if CONVERSION_FACTOR_VALUE > CONVERSION_FACTOR_VALUE_MAX
63 #error "CONVERSION FACTOR OUT OF RANGE"
64 #endif
65 
66 static uint32_t loop_index;
67 
68 /*
69  * A handle instance psa_handle_t allocated inside SPM is actually a memory
70  * address among the handle pool. Return this handle to the client directly
71  * exposes information of secure memory address. In this case, converting the
72  * handle into another value does not represent the memory address to avoid
73  * exposing secure memory directly to clients.
74  *
75  * This function converts the handle instance into another value by scaling the
76  * handle in pool offset, the converted value is named as a user handle.
77  *
78  * The formula:
79  * user_handle = (handle_instance - POOL_START) * CONVERSION_FACTOR_VALUE +
80  * CLIENT_HANDLE_VALUE_MIN + loop_index
81  * where:
82  * CONVERSION_FACTOR_VALUE = 1 << CONVERSION_FACTOR_BITOFFSET, and should not
83  * exceed CONVERSION_FACTOR_VALUE_MAX.
84  *
85  * handle_instance in RANGE[POOL_START, POOL_END]
86  * user_handle in RANGE[CLIENT_HANDLE_VALUE_MIN, 0x3FFFFFFF]
87  * loop_index in RANGE[0, CONVERSION_FACTOR_VALUE - 1]
88  *
89  * note:
90  * loop_index is used to promise same handle instance is converted into
91  * different user handles in short time.
92  */
94 {
95  psa_handle_t user_handle;
96 
97  loop_index = (loop_index + 1) % CONVERSION_FACTOR_VALUE;
98  user_handle = (psa_handle_t)((((uintptr_t)handle_instance -
99  (uintptr_t)conn_handle_pool) << CONVERSION_FACTOR_BITOFFSET) +
100  CLIENT_HANDLE_VALUE_MIN + loop_index);
101 
102  return user_handle;
103 }
104 
105 /*
106  * This function converts a user handle into a corresponded handle instance.
107  * The converted value is validated before returning, an invalid handle instance
108  * is returned as NULL.
109  *
110  * The formula:
111  * handle_instance = ((user_handle - CLIENT_HANDLE_VALUE_MIN) /
112  * CONVERSION_FACTOR_VALUE) + POOL_START
113  * where:
114  * CONVERSION_FACTOR_VALUE = 1 << CONVERSION_FACTOR_BITOFFSET, and should not
115  * exceed CONVERSION_FACTOR_VALUE_MAX.
116  *
117  * handle_instance in RANGE[POOL_START, POOL_END]
118  * user_handle in RANGE[CLIENT_HANDLE_VALUE_MIN, 0x3FFFFFFF]
119  * loop_index in RANGE[0, CONVERSION_FACTOR_VALUE - 1]
120  */
122 {
123  struct tfm_conn_handle_t *handle_instance;
124 
125  if (user_handle == PSA_NULL_HANDLE) {
126  return NULL;
127  }
128 
129  handle_instance = (struct tfm_conn_handle_t *)((((uintptr_t)user_handle -
131  (uintptr_t)conn_handle_pool);
132 
133  return handle_instance;
134 }
135 
136 /* Service handle management functions */
138  struct tfm_spm_service_t *service,
139  int32_t client_id)
140 {
141  struct tfm_conn_handle_t *p_handle;
142 
143  TFM_CORE_ASSERT(service);
144 
145  /* Get buffer for handle list structure from handle pool */
146  p_handle = (struct tfm_conn_handle_t *)tfm_pool_alloc(conn_handle_pool);
147  if (!p_handle) {
148  return NULL;
149  }
150 
151  p_handle->service = service;
152  p_handle->status = TFM_HANDLE_STATUS_IDLE;
153  p_handle->client_id = client_id;
154 
155  /* Add handle node to list for next psa functions */
156  tfm_list_add_tail(&service->handle_list, &p_handle->list);
157 
158  return p_handle;
159 }
160 
162  const struct tfm_conn_handle_t *conn_handle,
163  int32_t client_id)
164 {
165  /* Check the handle address is validated */
166  if (is_valid_chunk_data_in_pool(conn_handle_pool,
167  (uint8_t *)conn_handle) != true) {
168  return IPC_ERROR_GENERIC;
169  }
170 
171  /* Check the handle caller is correct */
172  if (conn_handle->client_id != client_id) {
173  return IPC_ERROR_GENERIC;
174  }
175 
176  return IPC_SUCCESS;
177 }
178 
180  struct tfm_conn_handle_t *conn_handle)
181 {
182  TFM_CORE_ASSERT(service);
183  TFM_CORE_ASSERT(conn_handle != NULL);
184 
185  /* Clear magic as the handler is not used anymore */
186  conn_handle->internal_msg.magic = 0;
187 
188  /* Remove node from handle list */
189  tfm_list_del_node(&conn_handle->list);
190 
191  /* Back handle buffer to pool */
192  tfm_pool_free(conn_handle);
193  return IPC_SUCCESS;
194 }
195 
197  struct tfm_conn_handle_t *conn_handle,
198  void *rhandle)
199 {
200  TFM_CORE_ASSERT(service);
201  /* Set reverse handle value only be allowed for a connected handle */
202  TFM_CORE_ASSERT(conn_handle != NULL);
203 
204  conn_handle->rhandle = rhandle;
205  return IPC_SUCCESS;
206 }
207 
221 static void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
222  struct tfm_conn_handle_t *conn_handle)
223 {
224  TFM_CORE_ASSERT(service);
225  /* Get reverse handle value only be allowed for a connected handle */
226  TFM_CORE_ASSERT(conn_handle != NULL);
227 
228  return conn_handle->rhandle;
229 }
230 
231 /* Partition management functions */
232 
234  psa_signal_t signal)
235 {
236  struct tfm_list_node_t *node, *head;
237  struct tfm_msg_body_t *tmp_msg, *msg = NULL;
238 
239  TFM_CORE_ASSERT(partition);
240 
241  head = &partition->msg_list;
242 
243  if (tfm_list_is_empty(head)) {
244  return NULL;
245  }
246 
247  /*
248  * There may be multiple messages for this RoT Service signal, do not clear
249  * partition mask until no remaining message. Search may be optimized.
250  */
251  TFM_LIST_FOR_EACH(node, head) {
252  tmp_msg = TFM_GET_CONTAINER_PTR(node, struct tfm_msg_body_t, msg_node);
253  if (tmp_msg->service->service_db->signal == signal && msg) {
254  return msg;
255  } else if (tmp_msg->service->service_db->signal == signal) {
256  msg = tmp_msg;
257  tfm_list_del_node(node);
258  }
259  }
260 
261  partition->signals_asserted &= ~signal;
262 
263  return msg;
264 }
265 
274 static uint32_t get_partition_idx(uint32_t partition_id)
275 {
276  uint32_t i;
277 
278  if (partition_id == INVALID_PARTITION_ID) {
280  }
281 
282  for (i = 0; i < g_spm_partition_db.partition_count; ++i) {
284  partition_id) {
285  return i;
286  }
287  }
289 }
290 
300 static uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx)
301 {
302  return g_spm_partition_db.partitions[partition_idx].static_data->
303  partition_flags;
304 }
305 
306 #if TFM_LVL != 1
307 
318 static void tfm_spm_partition_change_privilege(uint32_t privileged)
319 {
320  CONTROL_Type ctrl;
321 
322  ctrl.w = __get_CONTROL();
323 
324  if (privileged == TFM_PARTITION_PRIVILEGED_MODE) {
325  ctrl.b.nPRIV = 0;
326  } else {
327  ctrl.b.nPRIV = 1;
328  }
329 
330  __set_CONTROL(ctrl.w);
331 }
332 #endif /* if(TFM_LVL != 1) */
333 
334 uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_flags)
335 {
336  if (partition_flags & SPM_PART_FLAG_PSA_ROT) {
338  } else {
340  }
341 }
342 
343 bool tfm_is_partition_privileged(uint32_t partition_idx)
344 {
345  uint32_t flags = tfm_spm_partition_get_flags(partition_idx);
346 
349 }
350 
352 {
353  uint32_t i, num;
354 
355  num = sizeof(service) / sizeof(struct tfm_spm_service_t);
356  for (i = 0; i < num; i++) {
357  if (service[i].service_db->sid == sid) {
358  return &service[i];
359  }
360  }
361 
362  return NULL;
363 }
364 
374 static struct partition_t *tfm_spm_get_partition_by_id(int32_t partition_id)
375 {
376  uint32_t idx = get_partition_idx(partition_id);
377 
378  if (idx != SPM_INVALID_PARTITION_IDX) {
379  return &(g_spm_partition_db.partitions[idx]);
380  }
381  return NULL;
382 }
383 
385 {
387  struct partition_t *partition;
388 
389  partition = TFM_GET_CONTAINER_PTR(pth, struct partition_t, sp_thread);
390 
391  return partition;
392 }
393 
395  uint32_t version)
396 {
397  TFM_CORE_ASSERT(service);
398 
399  switch (service->service_db->version_policy) {
401  if (version > service->service_db->version) {
402  return IPC_ERROR_VERSION;
403  }
404  break;
406  if (version != service->service_db->version) {
407  return IPC_ERROR_VERSION;
408  }
409  break;
410  default:
411  return IPC_ERROR_VERSION;
412  }
413  return IPC_SUCCESS;
414 }
415 
416 int32_t tfm_spm_check_authorization(uint32_t sid,
417  struct tfm_spm_service_t *service,
418  bool ns_caller)
419 {
420  struct partition_t *partition = NULL;
421  int32_t i;
422 
423  TFM_CORE_ASSERT(service);
424 
425  if (ns_caller) {
426  if (!service->service_db->non_secure_client) {
427  return IPC_ERROR_GENERIC;
428  }
429  } else {
430  partition = tfm_spm_get_running_partition();
431  if (!partition) {
432  tfm_core_panic();
433  }
434 
435  for (i = 0; i < partition->static_data->dependencies_num; i++) {
436  if (partition->static_data->p_dependencies[i] == sid) {
437  break;
438  }
439  }
440 
441  if (i == partition->static_data->dependencies_num) {
442  return IPC_ERROR_GENERIC;
443  }
444  }
445  return IPC_SUCCESS;
446 }
447 
448 /* Message functions */
449 
451 {
452  /*
453  * The message handler passed by the caller is considered invalid in the
454  * following cases:
455  * 1. Not a valid message handle. (The address of a message is not the
456  * address of a possible handle from the pool
457  * 2. Handle not belongs to the caller partition (The handle is either
458  * unused, or owned by anither partition)
459  * Check the conditions above
460  */
461  struct tfm_msg_body_t *p_msg;
462  uint32_t partition_id;
463  struct tfm_conn_handle_t *p_conn_handle =
464  tfm_spm_to_handle_instance(msg_handle);
465 
467  conn_handle_pool, (uint8_t *)p_conn_handle) != 1) {
468  return NULL;
469  }
470 
471  p_msg = &p_conn_handle->internal_msg;
472 
473  /*
474  * Check that the magic number is correct. This proves that the message
475  * structure contains an active message.
476  */
477  if (p_msg->magic != TFM_MSG_MAGIC) {
478  return NULL;
479  }
480 
481  /* Check that the running partition owns the message */
483  if (partition_id != p_msg->service->partition->static_data->partition_id) {
484  return NULL;
485  }
486 
487  return p_msg;
488 }
489 
490 struct tfm_msg_body_t *
492 {
493  TFM_CORE_ASSERT(conn_handle != NULL);
494 
495  return &(conn_handle->internal_msg);
496 }
497 
499  struct tfm_spm_service_t *service,
500  psa_handle_t handle,
501  int32_t type, int32_t client_id,
502  psa_invec *invec, size_t in_len,
503  psa_outvec *outvec, size_t out_len,
505 {
506  uint32_t i;
507  struct tfm_conn_handle_t *conn_handle;
508 
509  TFM_CORE_ASSERT(msg);
510  TFM_CORE_ASSERT(service);
511  TFM_CORE_ASSERT(!(invec == NULL && in_len != 0));
512  TFM_CORE_ASSERT(!(outvec == NULL && out_len != 0));
513  TFM_CORE_ASSERT(in_len <= PSA_MAX_IOVEC);
514  TFM_CORE_ASSERT(out_len <= PSA_MAX_IOVEC);
515  TFM_CORE_ASSERT(in_len + out_len <= PSA_MAX_IOVEC);
516 
517  /* Clear message buffer before using it */
518  spm_memset(msg, 0, sizeof(struct tfm_msg_body_t));
519 
520  tfm_event_init(&msg->ack_evnt);
521  msg->magic = TFM_MSG_MAGIC;
522  msg->service = service;
523  msg->caller_outvec = caller_outvec;
524  msg->msg.client_id = client_id;
525 
526  /* Copy contents */
527  msg->msg.type = type;
528 
529  for (i = 0; i < in_len; i++) {
530  msg->msg.in_size[i] = invec[i].len;
531  msg->invec[i].base = invec[i].base;
532  }
533 
534  for (i = 0; i < out_len; i++) {
535  msg->msg.out_size[i] = outvec[i].len;
536  msg->outvec[i].base = outvec[i].base;
537  /* Out len is used to record the writed number, set 0 here again */
538  msg->outvec[i].len = 0;
539  }
540 
541  /* Use the user connect handle as the message handle */
542  msg->msg.handle = handle;
543 
544  conn_handle = tfm_spm_to_handle_instance(handle);
545  /* For connected handle, set rhandle to every message */
546  if (conn_handle) {
547  msg->msg.rhandle = tfm_spm_get_rhandle(service, conn_handle);
548  }
549 
550  /* Set the private data of NSPE client caller in multi-core topology */
551  if (TFM_CLIENT_ID_IS_NS(client_id)) {
552  tfm_rpc_set_caller_data(msg, client_id);
553  }
554 }
555 
557  struct tfm_msg_body_t *msg)
558 {
559  struct partition_t *partition = service->partition;
560 
561  TFM_CORE_ASSERT(service);
562  TFM_CORE_ASSERT(msg);
563 
564  /* Add message to partition message list tail */
565  tfm_list_add_tail(&partition->msg_list, &msg->msg_node);
566 
567  /* Messages put. Update signals */
568  partition->signals_asserted |= service->service_db->signal;
569 
570  tfm_event_wake(&partition->event,
571  (partition->signals_asserted & partition->signals_waiting));
572 
573  /*
574  * If it is a NS request via RPC, it is unnecessary to block current
575  * thread.
576  */
577  if (!is_tfm_rpc_msg(msg)) {
578  tfm_event_wait(&msg->ack_evnt);
579  }
580 
581  return IPC_SUCCESS;
582 }
583 
585 {
586  struct partition_t *partition;
587 
588  partition = tfm_spm_get_running_partition();
589  if (partition && partition->static_data) {
590  return partition->static_data->partition_id;
591  } else {
592  return INVALID_PARTITION_ID;
593  }
594 }
595 
596 int32_t tfm_memory_check(const void *buffer, size_t len, bool ns_caller,
597  enum tfm_memory_access_e access,
598  uint32_t privileged)
599 {
600  enum tfm_hal_status_t err;
601  uint32_t attr = 0;
602 
603  /* If len is zero, this indicates an empty buffer and base is ignored */
604  if (len == 0) {
605  return IPC_SUCCESS;
606  }
607 
608  if (!buffer) {
610  }
611 
612  if ((uintptr_t)buffer > (UINTPTR_MAX - len)) {
613  return IPC_ERROR_MEMORY_CHECK;
614  }
615 
616  if (access == TFM_MEMORY_ACCESS_RW) {
617  attr |= (TFM_HAL_ACCESS_READABLE | TFM_HAL_ACCESS_WRITABLE);
618  } else {
619  attr |= TFM_HAL_ACCESS_READABLE;
620  }
621 
622  if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
623  attr |= TFM_HAL_ACCESS_UNPRIVILEGED;
624  } else {
625  attr &= ~TFM_HAL_ACCESS_UNPRIVILEGED;
626  }
627 
628  if (ns_caller) {
629  attr |= TFM_HAL_ACCESS_NS;
630  }
631 
632  err = tfm_hal_memory_has_access((uintptr_t)buffer, len, attr);
633 
634  if (err == TFM_HAL_SUCCESS) {
635  return IPC_SUCCESS;
636  }
637 
638  return IPC_ERROR_MEMORY_CHECK;
639 }
640 
641 uint32_t tfm_spm_init(void)
642 {
643  uint32_t i, j, num;
644  struct partition_t *partition;
645  struct tfm_core_thread_t *pth, *p_ns_entry_thread = NULL;
646  const struct tfm_spm_partition_platform_data_t **platform_data_p;
647 
648  tfm_pool_init(conn_handle_pool,
649  POOL_BUFFER_SIZE(conn_handle_pool),
650  sizeof(struct tfm_conn_handle_t),
652 
653  /* Init partition first for it will be used when init service */
654  for (i = 0; i < g_spm_partition_db.partition_count; i++) {
655  partition = &g_spm_partition_db.partitions[i];
656 
657  if (!partition || !partition->memory_data || !partition->static_data) {
658  tfm_core_panic();
659  }
660 
661  if (!(partition->static_data->partition_flags & SPM_PART_FLAG_IPC)) {
662  tfm_core_panic();
663  }
664 
665  /* Check if the PSA framework version matches. */
666  if (partition->static_data->psa_framework_version !=
668  ERROR_MSG("Warning: PSA Framework Verison does not match!");
669  continue;
670  }
671 
672  platform_data_p = partition->platform_data_list;
673  if (platform_data_p != NULL) {
674  while ((*platform_data_p) != NULL) {
675  if (tfm_spm_hal_configure_default_isolation(i,
676  *platform_data_p) != TFM_PLAT_ERR_SUCCESS) {
677  tfm_core_panic();
678  }
679  ++platform_data_p;
680  }
681  }
682 
683  /* Add PSA_DOORBELL signal to assigned_signals */
684  partition->signals_allowed |= PSA_DOORBELL;
685 
686  /* TODO: This can be optimized by generating the assigned signal
687  * in code generation time.
688  */
689  for (j = 0; j < tfm_core_irq_signals_count; ++j) {
690  if (tfm_core_irq_signals[j].partition_id ==
691  partition->static_data->partition_id) {
692  partition->signals_allowed |=
694  }
695  }
696 
697  tfm_event_init(&partition->event);
698  tfm_list_init(&partition->msg_list);
699 
700  pth = &partition->sp_thread;
701  if (!pth) {
702  tfm_core_panic();
703  }
704 
705  tfm_core_thrd_init(pth,
707  partition->static_data->partition_init,
708  NULL,
709  (uintptr_t)partition->memory_data->stack_top,
710  (uintptr_t)partition->memory_data->stack_bottom);
711 
712  pth->prior = partition->static_data->partition_priority;
713 
714  if (partition->static_data->partition_id == TFM_SP_NON_SECURE_ID) {
715  p_ns_entry_thread = pth;
716  pth->param = (void *)tfm_spm_hal_get_ns_entry_point();
717  }
718 
719  /* Kick off */
720  if (tfm_core_thrd_start(pth) != THRD_SUCCESS) {
721  tfm_core_panic();
722  }
723  }
724 
725  /* Init Service */
726  num = sizeof(service) / sizeof(struct tfm_spm_service_t);
727  for (i = 0; i < num; i++) {
728  service[i].service_db = &service_db[i];
729  partition =
730  tfm_spm_get_partition_by_id(service[i].service_db->partition_id);
731  if (!partition) {
732  tfm_core_panic();
733  }
734  service[i].partition = partition;
735  partition->signals_allowed |= service[i].service_db->signal;
736 
737  tfm_list_init(&service[i].handle_list);
738  }
739 
740  /*
741  * All threads initialized, start the scheduler.
742  *
743  * NOTE:
744  * It is worthy to give the thread object to scheduler if the background
745  * context belongs to one of the threads. Here the background thread is the
746  * initialization thread who calls SPM SVC, which re-uses the non-secure
747  * entry thread's stack. After SPM initialization is done, this stack is
748  * cleaned up and the background context is never going to return. Tell
749  * the scheduler that the current thread is non-secure entry thread.
750  */
751  tfm_core_thrd_start_scheduler(p_ns_entry_thread);
752 
753  return p_ns_entry_thread->arch_ctx.lr;
754 }
755 
757 {
758 #if TFM_LVL != 1
759  struct partition_t *p_next_partition;
760  uint32_t is_privileged;
761 #endif
764 
765  if (pth_next != NULL && pth_curr != pth_next) {
766 #if TFM_LVL != 1
767  p_next_partition = TFM_GET_CONTAINER_PTR(pth_next,
768  struct partition_t,
769  sp_thread);
770 
771  if (p_next_partition->static_data->partition_flags &
773  is_privileged = TFM_PARTITION_PRIVILEGED_MODE;
774  } else {
775  is_privileged = TFM_PARTITION_UNPRIVILEGED_MODE;
776  }
777 
778  tfm_spm_partition_change_privilege(is_privileged);
779 #if TFM_LVL == 3
780  /*
781  * FIXME: To implement isolations among partitions in isolation level 3,
782  * each partition needs to run in unprivileged mode. Currently some
783  * PRoTs cannot work in unprivileged mode, make them privileged now.
784  */
785  if (is_privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
786  /* FIXME: only MPU-based implementations are supported currently */
787  if (tfm_hal_mpu_update_partition_boundary(
788  p_next_partition->memory_data->data_start,
789  p_next_partition->memory_data->data_limit)
790  != TFM_HAL_SUCCESS) {
791  tfm_core_panic();
792  }
793  }
794 #endif /* TFM_LVL == 3 */
795 #endif /* TFM_LVL != 1 */
796 
797  tfm_core_thrd_switch_context(p_actx, pth_curr, pth_next);
798  }
799 
800  /*
801  * Handle pending mailbox message from NS in multi-core topology.
802  * Empty operation on single Armv8-M platform.
803  */
805 }
806 
808 {
809  uint32_t i;
810 
811  /*
812  * FixeMe: abstract these part into dedicated functions to avoid
813  * accessing thread context in psa layer
814  */
815  /* If it is a NS request via RPC, the owner of this message is not set */
816  if (!is_tfm_rpc_msg(msg)) {
818  }
819 
820  for (i = 0; i < PSA_MAX_IOVEC; i++) {
821  if (msg->msg.out_size[i] == 0) {
822  continue;
823  }
824 
825  TFM_CORE_ASSERT(msg->caller_outvec[i].base == msg->outvec[i].base);
826 
827  msg->caller_outvec[i].len = msg->outvec[i].len;
828  }
829 }
830 
831 void notify_with_signal(int32_t partition_id, psa_signal_t signal)
832 {
833  struct partition_t *partition = NULL;
834 
835  /*
836  * The value of partition_id must be greater than zero as the target of
837  * notification must be a Secure Partition, providing a Non-secure
838  * Partition ID is a fatal error.
839  */
840  if (!TFM_CLIENT_ID_IS_S(partition_id)) {
841  tfm_core_panic();
842  }
843 
844  /*
845  * It is a fatal error if partition_id does not correspond to a Secure
846  * Partition.
847  */
848  partition = tfm_spm_get_partition_by_id(partition_id);
849  if (!partition) {
850  tfm_core_panic();
851  }
852 
853  partition->signals_asserted |= signal;
854 
855  /*
856  * The target partition may be blocked with waiting for signals after
857  * called psa_wait(). Set the return value with the available signals
858  * before wake it up with tfm_event_signal().
859  */
860  tfm_event_wake(&partition->event,
861  partition->signals_asserted & partition->signals_waiting);
862 }
863 
874 void tfm_irq_handler(uint32_t partition_id, psa_signal_t signal,
875  IRQn_Type irq_line)
876 {
877  tfm_spm_hal_disable_irq(irq_line);
878  notify_with_signal(partition_id, signal);
879 }
880 
881 int32_t get_irq_line_for_signal(int32_t partition_id,
882  psa_signal_t signal,
883  IRQn_Type *irq_line)
884 {
885  size_t i;
886 
887  for (i = 0; i < tfm_core_irq_signals_count; ++i) {
888  if (tfm_core_irq_signals[i].partition_id == partition_id &&
889  tfm_core_irq_signals[i].signal_value == signal) {
890  *irq_line = tfm_core_irq_signals[i].irq_line;
891  return IPC_SUCCESS;
892  }
893  }
894  return IPC_ERROR_GENERIC;
895 }
896 
897 void tfm_spm_enable_irq(uint32_t *args)
898 {
899  struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)args;
900  psa_signal_t irq_signal = svc_ctx->r0;
901  IRQn_Type irq_line = (IRQn_Type) 0;
902  int32_t ret;
903  struct partition_t *partition = NULL;
904 
905  /* It is a fatal error if passed signal indicates more than one signals. */
906  if (!tfm_is_one_bit_set(irq_signal)) {
907  tfm_core_panic();
908  }
909 
910  partition = tfm_spm_get_running_partition();
911  if (!partition) {
912  tfm_core_panic();
913  }
914 
916  irq_signal, &irq_line);
917  /* It is a fatal error if passed signal is not an interrupt signal. */
918  if (ret != IPC_SUCCESS) {
919  tfm_core_panic();
920  }
921 
922  tfm_spm_hal_enable_irq(irq_line);
923 }
924 
925 void tfm_spm_disable_irq(uint32_t *args)
926 {
927  struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)args;
928  psa_signal_t irq_signal = svc_ctx->r0;
929  IRQn_Type irq_line = (IRQn_Type) 0;
930  int32_t ret;
931  struct partition_t *partition = NULL;
932 
933  /* It is a fatal error if passed signal indicates more than one signals. */
934  if (!tfm_is_one_bit_set(irq_signal)) {
935  tfm_core_panic();
936  }
937 
938  partition = tfm_spm_get_running_partition();
939  if (!partition) {
940  tfm_core_panic();
941  }
942 
944  irq_signal, &irq_line);
945  /* It is a fatal error if passed signal is not an interrupt signal. */
946  if (ret != IPC_SUCCESS) {
947  tfm_core_panic();
948  }
949 
950  tfm_spm_hal_disable_irq(irq_line);
951 }
952 
953 void tfm_spm_validate_caller(struct partition_t *p_cur_sp, uint32_t *p_ctx,
954  uint32_t exc_return, bool ns_caller)
955 {
956  uintptr_t stacked_ctx_pos;
957 
958  if (ns_caller) {
959  /*
960  * The background IRQ can't be supported, since if SP is executing,
961  * the preempted context of SP can be different with the one who
962  * preempts veneer.
963  */
964  if (p_cur_sp->static_data->partition_id != TFM_SP_NON_SECURE_ID) {
965  tfm_core_panic();
966  }
967 
968  /*
969  * It is non-secure caller, check if veneer stack contains
970  * multiple contexts.
971  */
972  stacked_ctx_pos = (uintptr_t)p_ctx +
973  sizeof(struct tfm_state_context_t) +
975 
976  if (is_stack_alloc_fp_space(exc_return)) {
977 #if defined (__FPU_USED) && (__FPU_USED == 1U)
978  if (FPU->FPCCR & FPU_FPCCR_TS_Msk) {
979  stacked_ctx_pos += TFM_ADDTIONAL_FP_CONTEXT_WORDS *
980  sizeof(uint32_t);
981  }
982 #endif
983  stacked_ctx_pos += TFM_BASIC_FP_CONTEXT_WORDS * sizeof(uint32_t);
984  }
985 
986  if (stacked_ctx_pos != p_cur_sp->sp_thread.stk_top) {
987  tfm_core_panic();
988  }
989  } else if (p_cur_sp->static_data->partition_id <= 0) {
990  tfm_core_panic();
991  }
992 }
993 
994 void tfm_spm_request_handler(const struct tfm_state_context_t *svc_ctx)
995 {
996  uint32_t *res_ptr = (uint32_t *)&svc_ctx->r0;
997  uint32_t running_partition_flags = 0;
998  const struct partition_t *partition = NULL;
999 
1000  /* Check permissions on request type basis */
1001 
1002  switch (svc_ctx->r0) {
1004  partition = tfm_spm_get_running_partition();
1005  if (!partition) {
1006  tfm_core_panic();
1007  }
1008  running_partition_flags = partition->static_data->partition_flags;
1009 
1010  /* Currently only PSA Root of Trust services are allowed to make Reset
1011  * vote request
1012  */
1013  if ((running_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
1014  *res_ptr = (uint32_t)TFM_ERROR_GENERIC;
1015  }
1016 
1017  /* FixMe: this is a placeholder for checks to be performed before
1018  * allowing execution of reset
1019  */
1020  *res_ptr = (uint32_t)TFM_SUCCESS;
1021 
1022  break;
1023  default:
1024  *res_ptr = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
1025  }
1026 }
1027 
1029 {
1030  uint32_t i;
1031 
1032  /* This function initialises partition db */
1033 
1034  for (i = 0; i < g_spm_partition_db.partition_count; i++) {
1038  g_spm_partition_db.partitions[i].memory_data = &memory_data_list[i];
1039  }
1041 
1042  return SPM_ERR_OK;
1043 }
struct tfm_list_node_t list
Definition: spm_ipc.h:165
void tfm_irq_handler(uint32_t partition_id, psa_signal_t signal, IRQn_Type irq_line)
assert signal for a given IRQ line.
Definition: spm_ipc.c:874
#define TFM_PARTITION_UNPRIVILEGED_MODE
Definition: spm_func.h:32
uint32_t psa_signal_t
Definition: service.h:50
#define PSA_FRAMEWORK_VERSION
Definition: client.h:26
void * base
Definition: client.h:75
bool tfm_is_partition_privileged(uint32_t partition_idx)
Return whether a secure partition is privileged.
Definition: spm_ipc.c:343
const struct tfm_core_irq_signal_data_t tfm_core_irq_signals[]
tfm_memory_access_e
Definition: spm_ipc.h:168
__STATIC_INLINE void tfm_list_del_node(struct tfm_list_node_t *node)
Delete one node from list.
Definition: tfm_list.h:88
const struct tfm_spm_partition_platform_data_t ** platform_data_list_list[]
int32_t type
Definition: service.h:56
void tfm_event_wake(struct tfm_event_t *pevnt, uint32_t retval)
Definition: tfm_wait.c:20
enum spm_err_t tfm_spm_db_init(void)
Initialize partition database.
Definition: spm_ipc.c:1028
#define PSA_DOORBELL
Definition: service.h:41
void tfm_pool_free(void *ptr)
Free the allocated memory.
Definition: tfm_pools.c:80
__STATIC_INLINE bool is_stack_alloc_fp_space(uint32_t lr)
Check whether the stack frame for this exception has space allocated for Floating Point(FP) state inf...
Definition: tfm_arch_v8m.h:97
size_t len
Definition: client.h:68
void *(* tfm_core_thrd_entry_t)(void *)
Definition: tfm_thread.h:38
const struct tfm_spm_partition_platform_data_t ** platform_data_list
Definition: spm_func.h:122
void * rhandle
Definition: spm_ipc.h:149
int32_t tfm_spm_check_authorization(uint32_t sid, struct tfm_spm_service_t *service, bool ns_caller)
Check the client access authorization.
Definition: spm_ipc.c:416
void tfm_spm_enable_irq(uint32_t *args)
SVC handler of enabling irq_line of the specified irq_signal.
Definition: spm_ipc.c:897
struct tfm_list_node_t msg_node
Definition: spm_ipc.h:77
void tfm_spm_validate_caller(struct partition_t *p_cur_sp, uint32_t *p_ctx, uint32_t exc_return, bool ns_caller)
Validate the whether NS caller re-enter.
Definition: spm_ipc.c:953
#define TFM_POOL_DECLARE(name, chunksz, num)
Definition: tfm_pools.h:54
struct tfm_list_node_t msg_list
Definition: spm_ipc.h:110
void tfm_spm_request_handler(const struct tfm_state_context_t *svc_ctx)
Handle an SPM request by a secure service.
Definition: spm_ipc.c:994
#define TFM_CLIENT_ID_IS_S(client_id)
Checks if the provided client ID is a secure client ID.
Definition: tfm_api.h:28
#define TFM_STACK_SEALED_SIZE
psa_outvec outvec[PSA_MAX_IOVEC]
Definition: spm_ipc.h:65
uint32_t tfm_spm_init(void)
SPM initialization implementation.
Definition: spm_ipc.c:641
struct tfm_list_node_t handle_list
Definition: spm_ipc.h:143
int32_t client_id
Definition: service.h:64
#define SPM_INVALID_PARTITION_IDX
Definition: spm_func.h:29
struct tfm_spm_service_t service[]
#define TFM_CONN_HANDLE_MAX_NUM
Definition: spm_ipc.h:30
const struct tfm_spm_service_db_t service_db[]
int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service, struct tfm_conn_handle_t *conn_handle, void *rhandle)
Set reverse handle value for connection.
Definition: spm_ipc.c:196
struct tfm_spm_service_t * service
Definition: spm_ipc.h:164
psa_outvec * caller_outvec
Definition: spm_ipc.h:66
uint32_t version_policy
Definition: spm_ipc.h:133
uint32_t tfm_core_thrd_start(struct tfm_core_thread_t *pth)
Definition: tfm_thread.c:97
#define TFM_LIST_FOR_EACH(node, head)
Definition: tfm_list.h:95
#define is_tfm_rpc_msg(x)
Definition: tfm_rpc.h:211
struct tfm_msg_body_t internal_msg
Definition: spm_ipc.h:163
#define CONVERSION_FACTOR_BITOFFSET
Definition: spm_ipc.c:57
#define TFM_VERSION_POLICY_STRICT
Definition: spm_ipc.h:21
psa_invec invec[PSA_MAX_IOVEC]
Definition: spm_ipc.h:64
const struct spm_partition_static_data_t static_data_list[]
uint32_t partition_flags
Definition: spm_ipc.h:88
int32_t tfm_spm_validate_conn_handle(const struct tfm_conn_handle_t *conn_handle, int32_t client_id)
Validate connection handle for client connect.
Definition: spm_ipc.c:161
struct tfm_conn_handle_t * tfm_spm_create_conn_handle(struct tfm_spm_service_t *service, int32_t client_id)
Create connection handle for client connect.
Definition: spm_ipc.c:137
void tfm_core_panic(void)
Definition: utilities.c:11
#define IPC_ERROR_VERSION
const struct spm_partition_static_data_t * static_data
Definition: spm_func.h:120
int32_t tfm_memory_check(const void *buffer, size_t len, bool ns_caller, enum tfm_memory_access_e access, uint32_t privileged)
Check the memory reference is valid.
Definition: spm_ipc.c:596
psa_handle_t handle
Definition: service.h:61
struct tfm_arch_ctx_t arch_ctx
Definition: tfm_thread.h:49
void tfm_core_thrd_start_scheduler(struct tfm_core_thread_t *pth)
Definition: tfm_thread.c:134
#define PSA_MAX_IOVEC
Definition: client.h:54
#define ERROR_MSG(msg)
Definition: utilities.h:36
void * tfm_pool_alloc(struct tfm_pool_instance_t *pool)
Allocate a memory from pool.
Definition: tfm_pools.c:58
#define CONVERSION_FACTOR_VALUE
Definition: spm_ipc.c:58
#define IPC_ERROR_BAD_PARAMETERS
struct partition_t * partition
Definition: spm_ipc.h:139
psa_handle_t tfm_spm_to_user_handle(struct tfm_conn_handle_t *handle_instance)
Converts a handle instance into a corresponded user handle.
Definition: spm_ipc.c:93
const struct tfm_spm_partition_platform_data_t ** platform_data_list
Definition: spm_ipc.h:115
uint32_t partition_count
Definition: spm_func.h:127
struct partition_t * tfm_spm_get_running_partition(void)
Get current running partition context.
Definition: spm_ipc.c:384
uint32_t signals_waiting
Definition: spm_ipc.h:112
#define IPC_ERROR_GENERIC
#define tfm_rpc_client_call_handler()
Definition: tfm_rpc.h:213
#define SPM_PART_FLAG_PSA_ROT
Definition: spm_func.h:36
struct tfm_event_t event
Definition: spm_ipc.h:109
void tfm_event_wait(struct tfm_event_t *pevnt)
Definition: tfm_wait.c:11
const size_t tfm_core_irq_signals_count
void tfm_pendsv_do_schedule(struct tfm_arch_ctx_t *p_actx)
Definition: spm_ipc.c:756
psa_msg_t msg
Definition: spm_ipc.h:63
struct tfm_msg_body_t * tfm_spm_get_msg_by_signal(struct partition_t *partition, psa_signal_t signal)
Get the msg context by signal.
Definition: spm_ipc.c:233
uint32_t partition_id
Definition: spm_ipc.h:87
const struct tfm_spm_partition_memory_data_t memory_data_list[]
void * spm_memset(void *s, int c, size_t n)
Memory set function for TF-M core.
#define CLIENT_HANDLE_VALUE_MIN
Definition: spm_ipc.c:55
struct spm_partition_db_t g_spm_partition_db
#define THRD_SUCCESS
Definition: tfm_thread.h:34
struct tfm_core_thread_t * owner
Definition: tfm_wait.h:19
sp_entry_point partition_init
Definition: spm_ipc.h:90
spm_err_t
Definition: spm_func.h:44
#define THRD_STATE_BLOCK
Definition: tfm_thread.h:18
struct tfm_core_thread_t * tfm_core_thrd_get_curr_thread(void)
Definition: tfm_thread.c:46
uint32_t * p_dependencies
Definition: spm_ipc.h:96
#define TFM_PARTITION_PRIVILEGED_MODE
Definition: spm_func.h:33
#define TFM_MSG_MAGIC
Definition: spm_ipc.h:47
uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_flags)
Get the current partition mode.
Definition: spm_ipc.c:334
size_t in_size[PSA_MAX_IOVEC]
Definition: service.h:70
struct tfm_spm_service_t * service
Definition: spm_ipc.h:61
int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz, size_t chunksz, size_t num)
Register a memory pool.
Definition: tfm_pools.c:22
#define TFM_CORE_ASSERT(cond)
Definition: utilities.h:21
uint32_t signals_allowed
Definition: spm_ipc.h:111
void tfm_core_thrd_switch_context(struct tfm_arch_ctx_t *p_actx, struct tfm_core_thread_t *prev, struct tfm_core_thread_t *next)
Definition: tfm_thread.c:153
#define PSA_NULL_HANDLE
Definition: client.h:38
uint32_t signals_asserted
Definition: spm_ipc.h:113
uint32_t prior
Definition: tfm_thread.h:46
uint32_t dependencies_num
Definition: spm_ipc.h:95
#define TFM_GET_CONTAINER_PTR(ptr, type, member)
Definition: utilities.h:33
uint32_t psa_framework_version
Definition: spm_ipc.h:86
size_t len
Definition: client.h:76
struct tfm_msg_body_t * tfm_spm_get_msg_buffer_from_conn_handle(struct tfm_conn_handle_t *conn_handle)
Get message context by connect handle.
Definition: spm_ipc.c:491
int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service, uint32_t version)
Check the client version according to version policy.
Definition: spm_ipc.c:394
#define POOL_BUFFER_SIZE(name)
Definition: tfm_pools.h:67
int32_t psa_handle_t
Definition: client.h:61
struct tfm_spm_service_t * tfm_spm_get_service_by_sid(uint32_t sid)
Get the service context by service ID.
Definition: spm_ipc.c:351
#define IPC_SUCCESS
void notify_with_signal(int32_t partition_id, psa_signal_t signal)
notify the partition with the signal.
Definition: spm_ipc.c:831
#define TFM_VERSION_POLICY_RELAXED
Definition: spm_ipc.h:20
psa_signal_t signal
Definition: spm_ipc.h:129
#define TFM_HANDLE_STATUS_IDLE
Definition: spm_ipc.h:23
uint32_t version
Definition: spm_ipc.h:132
#define tfm_rpc_set_caller_data(msg, client_id)
Definition: tfm_rpc.h:217
const struct partition_static_t * static_data
Definition: spm_ipc.h:104
#define TFM_CLIENT_ID_IS_NS(client_id)
Checks if the provided client ID is a non-secure client ID.
Definition: tfm_api.h:38
#define SPM_PART_FLAG_IPC
Definition: spm_func.h:37
#define TFM_SP_NON_SECURE_ID
__STATIC_INLINE void tfm_list_init(struct tfm_list_node_t *head)
Initialize list head.
Definition: tfm_list.h:21
uintptr_t stk_top
Definition: tfm_thread.h:45
void __STATIC_INLINE tfm_event_init(struct tfm_event_t *pevnt)
Definition: tfm_wait.h:28
#define TFM_BASIC_FP_CONTEXT_WORDS
size_t out_size[PSA_MAX_IOVEC]
Definition: service.h:73
#define INVALID_PARTITION_ID
int32_t client_id
Definition: spm_ipc.h:157
void tfm_spm_disable_irq(uint32_t *args)
SVC handler of disabling irq_line of the specified irq_signal.
Definition: spm_ipc.c:925
uint32_t is_init
Definition: spm_func.h:126
int32_t get_irq_line_for_signal(int32_t partition_id, psa_signal_t signal, IRQn_Type *irq_line)
Return the IRQ line number associated with a signal.
Definition: spm_ipc.c:881
struct tfm_event_t ack_evnt
Definition: spm_ipc.h:62
void update_caller_outvec_len(struct tfm_msg_body_t *msg)
Definition: spm_ipc.c:807
#define IPC_ERROR_MEMORY_CHECK
struct spm_partition_desc_t * partitions
Definition: spm_func.h:129
void * rhandle
Definition: service.h:65
uint32_t partition_id
Definition: spm_ipc.h:128
struct tfm_msg_body_t * tfm_spm_get_msg_from_handle(psa_handle_t msg_handle)
Get message context by message handle.
Definition: spm_ipc.c:450
const void * base
Definition: client.h:67
struct tfm_core_thread_t sp_thread
Definition: spm_ipc.h:108
int32_t tfm_spm_send_event(struct tfm_spm_service_t *service, struct tfm_msg_body_t *msg)
Send message and wake up the SP who is waiting on message queue, block the current thread and schedul...
Definition: spm_ipc.c:556
const struct tfm_spm_partition_memory_data_t * memory_data
Definition: spm_ipc.h:116
const struct tfm_spm_service_db_t * service_db
Definition: spm_ipc.h:138
int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service, struct tfm_conn_handle_t *conn_handle)
Free connection handle which not used anymore.
Definition: spm_ipc.c:179
struct tfm_conn_handle_t * tfm_spm_to_handle_instance(psa_handle_t user_handle)
Converts a user handle into a corresponded handle instance.
Definition: spm_ipc.c:121
uint32_t status
Definition: spm_ipc.h:150
__STATIC_INLINE int32_t tfm_list_is_empty(struct tfm_list_node_t *head)
Check if a list is empty.
Definition: tfm_list.h:49
__STATIC_INLINE void tfm_list_add_tail(struct tfm_list_node_t *head, struct tfm_list_node_t *node)
Add one node to list tail.
Definition: tfm_list.h:34
struct tfm_core_thread_t * tfm_core_thrd_get_next_thread(void)
Definition: tfm_thread.c:36
void tfm_core_thrd_init(struct tfm_core_thread_t *pth, tfm_core_thrd_entry_t pfn, void *param, uintptr_t stk_top, uintptr_t stk_btm)
Definition: tfm_thread.c:85
bool tfm_is_one_bit_set(uint32_t n)
Definition: utilities.c:24
bool is_valid_chunk_data_in_pool(struct tfm_pool_instance_t *pool, uint8_t *data)
Checks whether a pointer points to a chunk data in the pool.
Definition: tfm_pools.c:90
uint32_t state
Definition: tfm_thread.h:47
#define TFM_ADDTIONAL_FP_CONTEXT_WORDS
void tfm_spm_fill_msg(struct tfm_msg_body_t *msg, struct tfm_spm_service_t *service, psa_handle_t handle, int32_t type, int32_t client_id, psa_invec *invec, size_t in_len, psa_outvec *outvec, size_t out_len, psa_outvec *caller_outvec)
Fill the message for PSA client call.
Definition: spm_ipc.c:498
uint32_t partition_priority
Definition: spm_ipc.h:89
uint32_t tfm_spm_partition_get_running_partition_id(void)
Get the running partition ID.
Definition: spm_ipc.c:584
int32_t magic
Definition: spm_ipc.h:60