mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Committer:
kenjiArai
Date:
Tue Dec 17 23:23:45 2019 +0000
Revision:
0:5b88d5760320
mbed-os5 only for TYBLE16

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:5b88d5760320 1 /*
kenjiArai 0:5b88d5760320 2 * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
kenjiArai 0:5b88d5760320 3 *
kenjiArai 0:5b88d5760320 4 * SPDX-License-Identifier: BSD-3-Clause
kenjiArai 0:5b88d5760320 5 *
kenjiArai 0:5b88d5760320 6 */
kenjiArai 0:5b88d5760320 7 #include <inttypes.h>
kenjiArai 0:5b88d5760320 8 #include <stdio.h>
kenjiArai 0:5b88d5760320 9 #include "tfm_arch_v8m.h"
kenjiArai 0:5b88d5760320 10 #include "tfm_thread.h"
kenjiArai 0:5b88d5760320 11 #include "tfm_utils.h"
kenjiArai 0:5b88d5760320 12 #include "tfm_memory_utils.h"
kenjiArai 0:5b88d5760320 13 #include "tfm_svc.h"
kenjiArai 0:5b88d5760320 14 #include "spm_api.h"
kenjiArai 0:5b88d5760320 15
kenjiArai 0:5b88d5760320 16 /* Force ZERO in case ZI(bss) clear is missing */
kenjiArai 0:5b88d5760320 17 static struct tfm_thrd_ctx *p_thrd_head = NULL;
kenjiArai 0:5b88d5760320 18 static struct tfm_thrd_ctx *p_runn_head = NULL;
kenjiArai 0:5b88d5760320 19 static struct tfm_thrd_ctx *p_curr_thrd = NULL;
kenjiArai 0:5b88d5760320 20
kenjiArai 0:5b88d5760320 21 /* Define Macro to fetch global to support future expansion (PERCPU e.g.) */
kenjiArai 0:5b88d5760320 22 #define LIST_HEAD p_thrd_head
kenjiArai 0:5b88d5760320 23 #define RUNN_HEAD p_runn_head
kenjiArai 0:5b88d5760320 24 #define CURR_THRD p_curr_thrd
kenjiArai 0:5b88d5760320 25
kenjiArai 0:5b88d5760320 26 static struct tfm_thrd_ctx *find_next_running_thread(struct tfm_thrd_ctx *pth)
kenjiArai 0:5b88d5760320 27 {
kenjiArai 0:5b88d5760320 28 while (pth && pth->status != THRD_STAT_RUNNING) {
kenjiArai 0:5b88d5760320 29 pth = pth->next;
kenjiArai 0:5b88d5760320 30 }
kenjiArai 0:5b88d5760320 31
kenjiArai 0:5b88d5760320 32 return pth;
kenjiArai 0:5b88d5760320 33 }
kenjiArai 0:5b88d5760320 34
kenjiArai 0:5b88d5760320 35 /* To get next running thread for scheduler */
kenjiArai 0:5b88d5760320 36 struct tfm_thrd_ctx *tfm_thrd_next_thread(void)
kenjiArai 0:5b88d5760320 37 {
kenjiArai 0:5b88d5760320 38 /*
kenjiArai 0:5b88d5760320 39 * First RUNNING thread has highest priority since threads are sorted with
kenjiArai 0:5b88d5760320 40 * priority.
kenjiArai 0:5b88d5760320 41 */
kenjiArai 0:5b88d5760320 42 return find_next_running_thread(RUNN_HEAD);
kenjiArai 0:5b88d5760320 43 }
kenjiArai 0:5b88d5760320 44
kenjiArai 0:5b88d5760320 45 /* To get current thread for caller */
kenjiArai 0:5b88d5760320 46 struct tfm_thrd_ctx *tfm_thrd_curr_thread()
kenjiArai 0:5b88d5760320 47 {
kenjiArai 0:5b88d5760320 48 return CURR_THRD;
kenjiArai 0:5b88d5760320 49 }
kenjiArai 0:5b88d5760320 50
kenjiArai 0:5b88d5760320 51 /* Insert a new thread into list by descending priority (Highest at head) */
kenjiArai 0:5b88d5760320 52 static void insert_by_prior(struct tfm_thrd_ctx **head,
kenjiArai 0:5b88d5760320 53 struct tfm_thrd_ctx *node)
kenjiArai 0:5b88d5760320 54 {
kenjiArai 0:5b88d5760320 55 if (*head == NULL || (node->prior <= (*head)->prior)) {
kenjiArai 0:5b88d5760320 56 node->next = *head;
kenjiArai 0:5b88d5760320 57 *head = node;
kenjiArai 0:5b88d5760320 58 } else {
kenjiArai 0:5b88d5760320 59 struct tfm_thrd_ctx *iter = *head;
kenjiArai 0:5b88d5760320 60
kenjiArai 0:5b88d5760320 61 while (iter->next && (node->prior > iter->next->prior)) {
kenjiArai 0:5b88d5760320 62 iter = iter->next;
kenjiArai 0:5b88d5760320 63 }
kenjiArai 0:5b88d5760320 64 node->next = iter->next;
kenjiArai 0:5b88d5760320 65 iter->next = node;
kenjiArai 0:5b88d5760320 66 }
kenjiArai 0:5b88d5760320 67 }
kenjiArai 0:5b88d5760320 68
kenjiArai 0:5b88d5760320 69 /*
kenjiArai 0:5b88d5760320 70 * Set first running thread as head to reduce enumerate
kenjiArai 0:5b88d5760320 71 * depth while searching for a first running thread.
kenjiArai 0:5b88d5760320 72 */
kenjiArai 0:5b88d5760320 73 static void update_running_head(struct tfm_thrd_ctx **runn,
kenjiArai 0:5b88d5760320 74 struct tfm_thrd_ctx *node)
kenjiArai 0:5b88d5760320 75 {
kenjiArai 0:5b88d5760320 76 if ((node->status == THRD_STAT_RUNNING) &&
kenjiArai 0:5b88d5760320 77 (*runn == NULL || (node->prior < (*runn)->prior))) {
kenjiArai 0:5b88d5760320 78 *runn = node;
kenjiArai 0:5b88d5760320 79 } else {
kenjiArai 0:5b88d5760320 80 *runn = find_next_running_thread(LIST_HEAD);
kenjiArai 0:5b88d5760320 81 }
kenjiArai 0:5b88d5760320 82 }
kenjiArai 0:5b88d5760320 83
kenjiArai 0:5b88d5760320 84 /* Set context members only. No validation here */
kenjiArai 0:5b88d5760320 85 void tfm_thrd_init(struct tfm_thrd_ctx *pth,
kenjiArai 0:5b88d5760320 86 tfm_thrd_func_t pfn, void *param,
kenjiArai 0:5b88d5760320 87 uint8_t *sp_base, uint8_t *sp_top)
kenjiArai 0:5b88d5760320 88 {
kenjiArai 0:5b88d5760320 89 pth->prior = THRD_PRIOR_MEDIUM;
kenjiArai 0:5b88d5760320 90 pth->status = THRD_STAT_CREATING;
kenjiArai 0:5b88d5760320 91 pth->pfn = pfn;
kenjiArai 0:5b88d5760320 92 pth->param = param;
kenjiArai 0:5b88d5760320 93 pth->sp_base = sp_base;
kenjiArai 0:5b88d5760320 94 pth->sp_top = sp_top;
kenjiArai 0:5b88d5760320 95 }
kenjiArai 0:5b88d5760320 96
kenjiArai 0:5b88d5760320 97 uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth)
kenjiArai 0:5b88d5760320 98 {
kenjiArai 0:5b88d5760320 99 /* Validate parameters before really start */
kenjiArai 0:5b88d5760320 100 if ((pth->status != THRD_STAT_CREATING) ||
kenjiArai 0:5b88d5760320 101 (pth->pfn == NULL) ||
kenjiArai 0:5b88d5760320 102 (pth->sp_base == NULL) ||
kenjiArai 0:5b88d5760320 103 (pth->sp_top == NULL)) {
kenjiArai 0:5b88d5760320 104 return THRD_ERR_INVALID_PARAM;
kenjiArai 0:5b88d5760320 105 }
kenjiArai 0:5b88d5760320 106
kenjiArai 0:5b88d5760320 107 /* Thread management runs in handler mode; set context for thread mode. */
kenjiArai 0:5b88d5760320 108 tfm_initialize_context(&pth->state_ctx,
kenjiArai 0:5b88d5760320 109 (uint32_t)pth->param, (uint32_t)pth->pfn,
kenjiArai 0:5b88d5760320 110 (uint32_t)pth->sp_base, (uint32_t)pth->sp_top);
kenjiArai 0:5b88d5760320 111
kenjiArai 0:5b88d5760320 112 /* Insert a new thread with priority */
kenjiArai 0:5b88d5760320 113 insert_by_prior(&LIST_HEAD, pth);
kenjiArai 0:5b88d5760320 114
kenjiArai 0:5b88d5760320 115 /* Mark it as RUNNING after insertion */
kenjiArai 0:5b88d5760320 116 tfm_thrd_set_status(pth, THRD_STAT_RUNNING);
kenjiArai 0:5b88d5760320 117
kenjiArai 0:5b88d5760320 118 return THRD_SUCCESS;
kenjiArai 0:5b88d5760320 119 }
kenjiArai 0:5b88d5760320 120
kenjiArai 0:5b88d5760320 121 void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status)
kenjiArai 0:5b88d5760320 122 {
kenjiArai 0:5b88d5760320 123 TFM_ASSERT(pth != NULL && new_status < THRD_STAT_INVALID);
kenjiArai 0:5b88d5760320 124
kenjiArai 0:5b88d5760320 125 pth->status = new_status;
kenjiArai 0:5b88d5760320 126 update_running_head(&RUNN_HEAD, pth);
kenjiArai 0:5b88d5760320 127 }
kenjiArai 0:5b88d5760320 128
kenjiArai 0:5b88d5760320 129 /* Scheduling won't happen immediately but after the exception returns */
kenjiArai 0:5b88d5760320 130 void tfm_thrd_activate_schedule(void)
kenjiArai 0:5b88d5760320 131 {
kenjiArai 0:5b88d5760320 132 tfm_trigger_pendsv();
kenjiArai 0:5b88d5760320 133 }
kenjiArai 0:5b88d5760320 134
kenjiArai 0:5b88d5760320 135 void tfm_thrd_start_scheduler(struct tfm_thrd_ctx *pth)
kenjiArai 0:5b88d5760320 136 {
kenjiArai 0:5b88d5760320 137 /*
kenjiArai 0:5b88d5760320 138 * There is no selected thread before scheduler start, assign
kenjiArai 0:5b88d5760320 139 * a caller provided thread as current thread. This function
kenjiArai 0:5b88d5760320 140 * should get called only ONCE; further calling triggers assert.
kenjiArai 0:5b88d5760320 141 */
kenjiArai 0:5b88d5760320 142 TFM_ASSERT(CURR_THRD == NULL);
kenjiArai 0:5b88d5760320 143 TFM_ASSERT(pth != NULL);
kenjiArai 0:5b88d5760320 144
kenjiArai 0:5b88d5760320 145 CURR_THRD = pth;
kenjiArai 0:5b88d5760320 146 tfm_thrd_activate_schedule();
kenjiArai 0:5b88d5760320 147 }
kenjiArai 0:5b88d5760320 148
kenjiArai 0:5b88d5760320 149 /* Remove current thread out of the schedulable list */
kenjiArai 0:5b88d5760320 150 void tfm_svcall_thrd_exit(void)
kenjiArai 0:5b88d5760320 151 {
kenjiArai 0:5b88d5760320 152 CURR_THRD->status = THRD_STAT_DETACH;
kenjiArai 0:5b88d5760320 153 tfm_trigger_pendsv();
kenjiArai 0:5b88d5760320 154 }
kenjiArai 0:5b88d5760320 155
kenjiArai 0:5b88d5760320 156 __attribute__((section("SFN")))
kenjiArai 0:5b88d5760320 157 void tfm_thrd_exit(void)
kenjiArai 0:5b88d5760320 158 {
kenjiArai 0:5b88d5760320 159 SVC(TFM_SVC_EXIT_THRD);
kenjiArai 0:5b88d5760320 160 while (1) {
kenjiArai 0:5b88d5760320 161 ;
kenjiArai 0:5b88d5760320 162 }
kenjiArai 0:5b88d5760320 163 }
kenjiArai 0:5b88d5760320 164
kenjiArai 0:5b88d5760320 165 void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
kenjiArai 0:5b88d5760320 166 struct tfm_thrd_ctx *prev,
kenjiArai 0:5b88d5760320 167 struct tfm_thrd_ctx *next)
kenjiArai 0:5b88d5760320 168 {
kenjiArai 0:5b88d5760320 169 TFM_ASSERT(prev != NULL);
kenjiArai 0:5b88d5760320 170 TFM_ASSERT(next != NULL);
kenjiArai 0:5b88d5760320 171
kenjiArai 0:5b88d5760320 172 /*
kenjiArai 0:5b88d5760320 173 * First, update latest context into the current thread context.
kenjiArai 0:5b88d5760320 174 * Then, update background context with next thread's context.
kenjiArai 0:5b88d5760320 175 */
kenjiArai 0:5b88d5760320 176 tfm_memcpy(&prev->state_ctx.ctxb, ctxb, sizeof(*ctxb));
kenjiArai 0:5b88d5760320 177 tfm_memcpy(ctxb, &next->state_ctx.ctxb, sizeof(next->state_ctx.ctxb));
kenjiArai 0:5b88d5760320 178
kenjiArai 0:5b88d5760320 179 /* Update current thread indicator */
kenjiArai 0:5b88d5760320 180 CURR_THRD = next;
kenjiArai 0:5b88d5760320 181 }