TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tfm_thread.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 #include <inttypes.h>
8 #include "tfm_arch.h"
9 #include "tfm_thread.h"
10 #include "utilities.h"
11 #include "tfm_memory_utils.h"
12 #include "tfm/tfm_core_svc.h"
13 #include "tfm_core_utils.h"
14 
15 /* Force ZERO in case ZI(bss) clear is missing */
16 static struct tfm_core_thread_t *p_thrd_head = NULL;
17 static struct tfm_core_thread_t *p_runn_head = NULL;
18 static struct tfm_core_thread_t *p_curr_thrd = NULL;
19 
20 /* Define Macro to fetch global to support future expansion (PERCPU e.g.) */
21 #define LIST_HEAD p_thrd_head
22 #define RUNN_HEAD p_runn_head
23 #define CURR_THRD p_curr_thrd
24 
25 static struct tfm_core_thread_t *find_next_running_thread(
26  struct tfm_core_thread_t *pth)
27 {
28  while (pth && pth->state != THRD_STATE_RUNNING) {
29  pth = pth->next;
30  }
31 
32  return pth;
33 }
34 
35 /* To get next running thread for scheduler */
37 {
38  /*
39  * First RUNNING thread has highest priority since threads are sorted with
40  * priority.
41  */
42  return find_next_running_thread(RUNN_HEAD);
43 }
44 
45 /* To get current thread for caller */
47 {
48  return CURR_THRD;
49 }
50 
51 /* Insert a new thread into list by descending priority (Highest at head) */
52 static void insert_by_prior(struct tfm_core_thread_t **head,
53  struct tfm_core_thread_t *node)
54 {
55  if (*head == NULL || (node->prior <= (*head)->prior)) {
56  node->next = *head;
57  *head = node;
58  } else {
59  struct tfm_core_thread_t *iter = *head;
60 
61  while (iter->next && (node->prior > iter->next->prior)) {
62  iter = iter->next;
63  }
64  node->next = iter->next;
65  iter->next = node;
66  }
67 }
68 
69 /*
70  * Set first running thread as head to reduce enumerate
71  * depth while searching for a first running thread.
72  */
73 static void update_running_head(struct tfm_core_thread_t **runn,
74  struct tfm_core_thread_t *node)
75 {
76  if ((node->state == THRD_STATE_RUNNING) &&
77  (*runn == NULL || (node->prior < (*runn)->prior))) {
78  *runn = node;
79  } else {
80  *runn = LIST_HEAD;
81  }
82 }
83 
84 /* Set context members only. No validation here */
87  uintptr_t stk_top, uintptr_t stk_btm)
88 {
89  pth->prior = THRD_PRIOR_MEDIUM;
91  pth->pfn = pfn;
92  pth->param = param;
93  pth->stk_btm = stk_btm;
94  pth->stk_top = stk_top;
95 }
96 
98 {
99  /* Validate parameters before really start */
100  if ((pth->state != THRD_STATE_CREATING) ||
101  (pth->pfn == NULL) ||
102  (pth->stk_btm == 0) ||
103  (pth->stk_top == 0)) {
104  return THRD_ERR_INVALID_PARAM;
105  }
106 
107  /* Thread management runs in handler mode; set context for thread mode. */
108  tfm_arch_init_context(&pth->arch_ctx, pth->param, (uintptr_t)pth->pfn,
109  pth->stk_btm, pth->stk_top);
110 
111  /* Insert a new thread with priority */
112  insert_by_prior(&LIST_HEAD, pth);
113 
114  /* Mark it as RUNNING after insertion */
116 
117  return THRD_SUCCESS;
118 }
119 
120 void tfm_core_thrd_set_state(struct tfm_core_thread_t *pth, uint32_t new_state)
121 {
122  TFM_CORE_ASSERT(pth != NULL && new_state < THRD_STATE_INVALID);
123 
124  pth->state = new_state;
125  update_running_head(&RUNN_HEAD, pth);
126 }
127 
128 /* Scheduling won't happen immediately but after the exception returns */
130 {
132 }
133 
135 {
136  /*
137  * There is no selected thread before scheduler start, assign the caller
138  * provided thread as the current thread. Update the hardware PSP/PSPLIM
139  * with the value in thread context to ensure they are identical.
140  * This function can be called only ONCE; further calling triggers assert.
141  */
142  TFM_CORE_ASSERT(CURR_THRD == NULL);
143  TFM_CORE_ASSERT(pth != NULL);
144  TFM_CORE_ASSERT(pth->arch_ctx.sp != 0);
145 
147 
148  CURR_THRD = pth;
149 
151 }
152 
154  struct tfm_core_thread_t *prev,
155  struct tfm_core_thread_t *next)
156 {
157  TFM_CORE_ASSERT(prev != NULL);
158  TFM_CORE_ASSERT(next != NULL);
159 
160  /*
161  * First, update latest context into the current thread context.
162  * Then, update background context with next thread's context.
163  */
164  spm_memcpy(&prev->arch_ctx, p_actx, sizeof(*p_actx));
165  spm_memcpy(p_actx, &next->arch_ctx, sizeof(next->arch_ctx));
166 
167  /* Update current thread indicator */
168  CURR_THRD = next;
169 }
void tfm_arch_init_context(struct tfm_arch_ctx_t *p_actx, void *param, uintptr_t pfn, uintptr_t stk_btm, uintptr_t stk_top)
Definition: tfm_arch.c:57
#define CURR_THRD
Definition: tfm_thread.c:23
#define LIST_HEAD
Definition: tfm_thread.c:21
#define THRD_STATE_CREATING
Definition: tfm_thread.h:16
tfm_core_thrd_entry_t pfn
Definition: tfm_thread.h:42
void *(* tfm_core_thrd_entry_t)(void *)
Definition: tfm_thread.h:38
#define THRD_PRIOR_MEDIUM
Definition: tfm_thread.h:30
#define THRD_ERR_INVALID_PARAM
Definition: tfm_thread.h:35
uint32_t tfm_core_thrd_start(struct tfm_core_thread_t *pth)
Definition: tfm_thread.c:97
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
__STATIC_INLINE void tfm_arch_update_ctx(struct tfm_arch_ctx_t *p_actx)
Update architecture context value into hardware.
void * spm_memcpy(void *dest, const void *src, size_t n)
Memory copy function for TF-M core.
#define THRD_SUCCESS
Definition: tfm_thread.h:34
struct tfm_core_thread_t * tfm_core_thrd_get_curr_thread(void)
Definition: tfm_thread.c:46
#define TFM_CORE_ASSERT(cond)
Definition: utilities.h:21
#define THRD_STATE_INVALID
Definition: tfm_thread.h:20
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
void tfm_core_thrd_set_state(struct tfm_core_thread_t *pth, uint32_t new_state)
Definition: tfm_thread.c:120
uint32_t prior
Definition: tfm_thread.h:46
void tfm_core_thrd_activate_schedule(void)
Definition: tfm_thread.c:129
struct tfm_core_thread_t * next
Definition: tfm_thread.h:50
__STATIC_INLINE void tfm_arch_trigger_pendsv(void)
Definition: tfm_arch.h:44
#define RUNN_HEAD
Definition: tfm_thread.c:22
uintptr_t stk_top
Definition: tfm_thread.h:45
#define THRD_STATE_RUNNING
Definition: tfm_thread.h:17
uintptr_t stk_btm
Definition: tfm_thread.h:44
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
uint32_t state
Definition: tfm_thread.h:47