blob: 8a54e0f87236a087e6c92ea8c3414564de86d75f [file] [log] [blame]
Kevin Peng3f67b2e2021-10-18 17:47:27 +08001/*
2 * Copyright (c) 2021, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include "interrupt.h"
9
10#include "bitops.h"
11#include "spm_ipc.h"
12#include "tfm_arch.h"
13#include "tfm_hal_interrupt.h"
14#include "tfm_hal_isolation.h"
15#include "thread.h"
16#include "utilities.h"
17
18#include "load/spm_load_api.h"
19
20__attribute__((naked))
21static psa_flih_result_t tfm_flih_deprivileged_handling(void *p_pt,
22 uintptr_t fn_flih,
23 void *p_context_ctrl)
24{
25 __ASM volatile("SVC %0 \n"
26 "BX LR \n"
27 : : "I" (TFM_SVC_PREPARE_DEPRIV_FLIH));
28}
29
30struct irq_load_info_t *get_irq_info_for_signal(
31 const struct partition_load_info_t *p_ldinf,
32 psa_signal_t signal)
33{
34 size_t i;
35 struct irq_load_info_t *irq_info;
36
37 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
38 return NULL;
39 }
40
41 irq_info = (struct irq_load_info_t *)LOAD_INFO_IRQ(p_ldinf);
42 for (i = 0; i < p_ldinf->nirqs; i++) {
43 if (irq_info[i].signal == signal) {
44 return &irq_info[i];
45 }
46 }
47
48 return NULL;
49}
50
51extern void tfm_flih_func_return(psa_flih_result_t result);
52
53uint32_t tfm_flih_prepare_depriv_flih(uint32_t *svc_args)
54{
55 struct partition_t *p_curr_sp;
56 struct partition_t *p_owner_sp = (struct partition_t *)svc_args[0];
57 uintptr_t sp_limit, stack;
58 struct context_ctrl_t flih_ctx_ctrl;
59
60 /* Come too early before runtime setup, should not happen. */
61 if (!CURRENT_THREAD) {
62 tfm_core_panic();
63 }
64
65 p_curr_sp = GET_CTX_OWNER(CURRENT_THREAD->p_context_ctrl);
66 sp_limit =
67 ((struct context_ctrl_t *)p_owner_sp->thrd.p_context_ctrl)->sp_limit;
68
69 if (p_owner_sp == p_curr_sp) {
70 stack = (uintptr_t)__get_PSP();
71 } else {
72 stack = ((struct context_ctrl_t *)p_owner_sp->thrd.p_context_ctrl)->sp;
73
74 if (p_owner_sp->p_boundaries != p_curr_sp->p_boundaries) {
75 tfm_hal_update_boundaries(p_owner_sp->p_ldinf,
76 p_owner_sp->p_boundaries);
77 }
78
79 /*
80 * CURRENT_THREAD->p_context_ctrl is the svc_args[2] on MSP, safe to
81 * update it. It is only used to track the owner of the thread data,
82 * i.e. the partition that has been interrupted.
83 */
84 THRD_UPDATE_CUR_CTXCTRL(&(p_owner_sp->ctx_ctrl));
85 }
86
87 tfm_arch_init_context(&flih_ctx_ctrl,
88 (uintptr_t)svc_args[1], NULL,
89 (uintptr_t)tfm_flih_func_return,
90 sp_limit, stack);
91
92 (void)tfm_arch_refresh_hardware_context(&flih_ctx_ctrl);
93
94 return flih_ctx_ctrl.exc_ret;
95}
96
97/* Go back to ISR from FLIH functions */
98uint32_t tfm_flih_return_to_isr(psa_flih_result_t result, uint32_t *msp)
99{
100 struct partition_t *p_prev_sp, *p_owner_sp;
101 struct context_flih_ret_t *p_ctx_flih_ret =
102 (struct context_flih_ret_t *)msp;
103
104 p_prev_sp = GET_CTX_OWNER(p_ctx_flih_ret->state_ctx.r2);
105 p_owner_sp = GET_CTX_OWNER(CURRENT_THREAD->p_context_ctrl);
106
107 if (p_owner_sp->p_boundaries != p_prev_sp->p_boundaries) {
108 tfm_hal_update_boundaries(p_prev_sp->p_ldinf,
109 p_prev_sp->p_boundaries);
110 }
111
112 /* Restore context pointer */
113 THRD_UPDATE_CUR_CTXCTRL(p_ctx_flih_ret->state_ctx.r2);
114
115 tfm_arch_set_psplim(
116 ((struct context_ctrl_t *)CURRENT_THREAD->p_context_ctrl)->sp_limit);
117 __set_PSP(p_ctx_flih_ret->psp);
118
119 /* Set FLIH result to the ISR */
120 p_ctx_flih_ret->state_ctx.r0 = (uint32_t)result;
121
122 return p_ctx_flih_ret->exc_ret;
123}
124
125void spm_handle_interrupt(void *p_pt, struct irq_load_info_t *p_ildi)
126{
127 psa_flih_result_t flih_result;
128 struct partition_t *p_part;
129
130 if (!p_pt || !p_ildi) {
131 tfm_core_panic();
132 }
133
134 p_part = (struct partition_t *)p_pt;
135
136 if (p_ildi->pid != p_part->p_ldinf->pid) {
137 tfm_core_panic();
138 }
139
140 if (p_ildi->flih_func == NULL) {
141 /* SLIH Model Handling */
142 tfm_hal_irq_disable(p_ildi->source);
143 flih_result = PSA_FLIH_SIGNAL;
144 } else {
145 /* FLIH Model Handling */
146 if (tfm_spm_partition_get_privileged_mode(p_part->p_ldinf->flags) ==
147 TFM_PARTITION_PRIVILEGED_MODE) {
148 flih_result = p_ildi->flih_func();
149 } else {
150 flih_result = tfm_flih_deprivileged_handling(
151 p_part,
152 (uintptr_t)p_ildi->flih_func,
153 CURRENT_THREAD->p_context_ctrl);
154 }
155 }
156
157 if (flih_result == PSA_FLIH_SIGNAL) {
158 spm_assert_signal(p_pt, p_ildi->signal);
Kevin Peng8a579692021-12-15 13:44:42 +0800159
160 if (THRD_EXPECTING_SCHEDULE()) {
161 tfm_arch_trigger_pendsv();
162 }
Kevin Peng3f67b2e2021-10-18 17:47:27 +0800163 }
164}