blob: 2731dd3e6dc25086b95e07a5d0eaa811bc1f21b9 [file] [log] [blame]
Ken Liu5d73c872021-08-19 19:23:17 +08001/*
2 * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include <stdint.h>
9#include "thread.h"
10#include "tfm_arch.h"
11#include "utilities.h"
12
13/* Force ZERO in case ZI(bss) clear is missing. */
14static struct thread_t *p_thrd_head = NULL; /* Point to the first thread. */
15static struct thread_t *p_rnbl_head = NULL; /* Point to the first runnable. */
16
17/* Define Macro to fetch global to support future expansion (PERCPU e.g.) */
18#define LIST_HEAD p_thrd_head
19#define RNBL_HEAD p_rnbl_head
20
21struct thread_t *thrd_next(void)
22{
23 struct thread_t *p_thrd = RNBL_HEAD;
24 /*
25 * First runnable thread has highest priority since threads are
26 * sorted by priority.
27 */
28 while (p_thrd && p_thrd->state != THRD_STATE_RUNNABLE) {
29 p_thrd = p_thrd->next;
30 }
31
32 return p_thrd;
33}
34
35static void insert_by_prior(struct thread_t **head, struct thread_t *node)
36{
37 if (*head == NULL || (node->priority <= (*head)->priority)) {
38 node->next = *head;
39 *head = node;
40 } else {
41 struct thread_t *iter = *head;
42
43 while (iter->next && (node->priority > iter->next->priority)) {
44 iter = iter->next;
45 }
46
47 node->next = iter->next;
48 iter->next = node;
49 }
50}
51
52void thrd_start(struct thread_t *p_thrd,
53 thrd_fn_t fn, void *param,
54 uintptr_t sp_limit, uintptr_t sp)
55{
56 TFM_CORE_ASSERT(p_thrd != NULL);
57
58 /* Insert a new thread with priority */
59 insert_by_prior(&LIST_HEAD, p_thrd);
60
61 /* Mark it as RUNNABLE after insertion */
62 thrd_set_state(p_thrd, THRD_STATE_RUNNABLE);
63
64 tfm_arch_init_context(p_thrd->p_context_ctrl, (uintptr_t)fn, param,
65 (uintptr_t)fn&~1UL, sp_limit, sp);
66}
67
68void thrd_set_state(struct thread_t *p_thrd, uint32_t new_state)
69{
70 TFM_CORE_ASSERT(p_thrd != NULL);
71
72 p_thrd->state = new_state;
73
74 /*
75 * Set first runnable thread as head to reduce enumerate
76 * depth while searching for a first runnable thread.
77 */
78 if ((p_thrd->state == THRD_STATE_RUNNABLE) &&
79 ((RNBL_HEAD == NULL) || (p_thrd->priority < RNBL_HEAD->priority))) {
80 RNBL_HEAD = p_thrd;
81 } else {
82 RNBL_HEAD = LIST_HEAD;
83 }
84}
85
86uint32_t thrd_start_scheduler(struct thread_t **ppth)
87{
88 struct thread_t *pth = thrd_next();
89
90 tfm_arch_trigger_pendsv();
91
92 if (ppth) {
93 *ppth = pth;
94 }
95
96 return tfm_arch_refresh_hardware_context(pth->p_context_ctrl);
97}
98
99void thrd_wait_on(struct sync_obj_t *p_sync_obj, struct thread_t *pth)
100{
101 TFM_CORE_ASSERT(p_sync_obj && p_sync_obj->magic == THRD_SYNC_MAGIC);
102
103 p_sync_obj->owner = pth;
104 thrd_set_state(pth, THRD_STATE_BLOCK);
105 tfm_arch_trigger_pendsv();
106}
107
108void thrd_wake_up(struct sync_obj_t *p_sync_obj, uint32_t ret_val)
109{
110 TFM_CORE_ASSERT(p_sync_obj && p_sync_obj->magic == THRD_SYNC_MAGIC);
111
112 if (p_sync_obj->owner && p_sync_obj->owner->state == THRD_STATE_BLOCK) {
113 thrd_set_state(p_sync_obj->owner, THRD_STATE_RUNNABLE);
114 tfm_arch_set_context_ret_code(p_sync_obj->owner->p_context_ctrl,
115 ret_val);
116 p_sync_obj->owner = NULL;
117 tfm_arch_trigger_pendsv();
118 }
119}