Summer Qin | 90602de | 2020-08-04 10:23:39 +0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2018-2020, Arm Limited. All rights reserved. |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | * |
| 6 | */ |
| 7 | |
Summer Qin | 9c1fba1 | 2020-08-12 15:49:12 +0800 | [diff] [blame^] | 8 | #include "arch.h" |
Summer Qin | 90602de | 2020-08-04 10:23:39 +0800 | [diff] [blame] | 9 | #include "tfm_secure_api.h" |
Summer Qin | 90602de | 2020-08-04 10:23:39 +0800 | [diff] [blame] | 10 | #include "tfm/tfm_spm_services.h" |
| 11 | |
| 12 | nsfptr_t ns_entry; |
| 13 | |
| 14 | void jump_to_ns_code(void) |
| 15 | { |
| 16 | /* Calls the non-secure Reset_Handler to jump to the non-secure binary */ |
| 17 | ns_entry(); |
| 18 | } |
| 19 | |
| 20 | __attribute__((naked)) |
| 21 | int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id) |
| 22 | { |
| 23 | __ASM volatile( |
| 24 | "SVC %0\n" |
| 25 | "BX LR\n" |
| 26 | : : "I" (TFM_SVC_GET_CALLER_CLIENT_ID)); |
| 27 | } |
| 28 | |
| 29 | __attribute__((naked)) |
| 30 | int32_t tfm_spm_request(void) |
| 31 | { |
| 32 | __ASM volatile( |
| 33 | "SVC %0\n" |
| 34 | "BX lr\n" |
| 35 | : : "I" (TFM_SVC_SPM_REQUEST)); |
| 36 | } |
| 37 | |
| 38 | __attribute__((naked)) |
| 39 | int32_t tfm_spm_request_reset_vote(void) |
| 40 | { |
| 41 | __ASM volatile( |
| 42 | "MOVS R0, %0\n" |
| 43 | "B tfm_spm_request\n" |
| 44 | : : "I" (TFM_SPM_REQUEST_RESET_VOTE)); |
| 45 | } |
| 46 | |
| 47 | __attribute__((naked)) |
| 48 | void tfm_enable_irq(psa_signal_t irq_signal) |
| 49 | { |
| 50 | __ASM("SVC %0\n" |
| 51 | "BX LR\n" |
| 52 | : : "I" (TFM_SVC_ENABLE_IRQ)); |
| 53 | } |
| 54 | |
| 55 | __attribute__((naked)) |
| 56 | void tfm_disable_irq(psa_signal_t irq_signal) |
| 57 | { |
| 58 | __ASM("SVC %0\n" |
| 59 | "BX LR\n" |
| 60 | : : "I" (TFM_SVC_DISABLE_IRQ)); |
| 61 | } |
| 62 | |
| 63 | __attribute__((naked)) |
| 64 | static psa_signal_t psa_wait_internal(psa_signal_t signal_mask, |
| 65 | uint32_t timeout) |
| 66 | { |
| 67 | __ASM("SVC %0\n" |
| 68 | "BX LR\n" |
| 69 | : : "I" (TFM_SVC_PSA_WAIT)); |
| 70 | } |
| 71 | |
| 72 | psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout) |
| 73 | { |
| 74 | /* FIXME: By using the 'WFI' instruction this function blocks until an |
| 75 | * interrupt happens. It is necessary to do this here as tfm_core_psa_wait |
| 76 | * runs with the priority of the SVC, so it cannot be interrupted, so |
| 77 | * waiting in it for the required interrupt to happen is not an option. |
| 78 | */ |
| 79 | psa_signal_t actual_signal_mask; |
| 80 | |
| 81 | while (1) { |
| 82 | actual_signal_mask = psa_wait_internal(signal_mask, timeout); |
| 83 | if ((actual_signal_mask & signal_mask) != 0) { |
| 84 | return actual_signal_mask; |
| 85 | } |
| 86 | __WFI(); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | __attribute__((naked)) |
| 91 | void psa_eoi(psa_signal_t irq_signal) |
| 92 | { |
| 93 | __ASM("SVC %0\n" |
| 94 | "BX LR\n" |
| 95 | : : "I" (TFM_SVC_PSA_EOI)); |
| 96 | } |
| 97 | |
| 98 | #if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_ARCH_8M_MAIN__) |
| 99 | __attribute__((section("SFN"), naked)) |
| 100 | int32_t tfm_core_sfn_request(const struct tfm_sfn_req_s *desc_ptr) |
| 101 | { |
| 102 | __ASM volatile( |
| 103 | "PUSH {r4-r12, lr} \n" |
| 104 | "SVC %[SVC_REQ] \n" |
| 105 | "MOV r4, #0 \n" |
| 106 | "MOV r5, r4 \n" |
| 107 | "MOV r6, r4 \n" |
| 108 | "MOV r7, r4 \n" |
| 109 | "MOV r8, r4 \n" |
| 110 | "MOV r9, r4 \n" |
| 111 | "MOV r10, r4 \n" |
| 112 | "MOV r11, r4 \n" |
| 113 | "BLX lr \n" |
| 114 | "SVC %[SVC_RET] \n" |
| 115 | "POP {r4-r12, pc} \n" |
| 116 | : : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST), |
| 117 | [SVC_RET] "I" (TFM_SVC_SFN_RETURN) |
| 118 | ); |
| 119 | } |
| 120 | |
| 121 | __attribute__((section("SFN"), naked)) |
| 122 | void priv_irq_handler_main(uint32_t partition_id, uint32_t unpriv_handler, |
| 123 | uint32_t irq_signal, uint32_t irq_line) |
| 124 | { |
| 125 | __ASM( |
| 126 | /* Save the callee saved registers*/ |
| 127 | "PUSH {r4-r12, lr} \n" |
| 128 | /* Request SVC to configure environment for the unpriv IRQ handler */ |
| 129 | "SVC %[SVC_REQ] \n" |
| 130 | /* clear the callee saved registers to prevent information leak */ |
| 131 | "MOV r4, #0 \n" |
| 132 | "MOV r5, r4 \n" |
| 133 | "MOV r6, r4 \n" |
| 134 | "MOV r7, r4 \n" |
| 135 | "MOV r8, r4 \n" |
| 136 | "MOV r9, r4 \n" |
| 137 | "MOV r10, r4 \n" |
| 138 | "MOV r11, r4 \n" |
| 139 | /* Branch to the unprivileged handler */ |
| 140 | "BLX lr \n" |
| 141 | /* Request SVC to reconfigure the environment of the interrupted |
| 142 | * partition |
| 143 | */ |
| 144 | "SVC %[SVC_RET] \n" |
| 145 | /* restore callee saved registers and return */ |
| 146 | "POP {r4-r12, pc} \n" |
| 147 | : : [SVC_REQ] "I" (TFM_SVC_DEPRIV_REQ) |
| 148 | , [SVC_RET] "I" (TFM_SVC_DEPRIV_RET) |
| 149 | ); |
| 150 | } |
| 151 | #elif defined(__ARM_ARCH_8M_BASE__) |
| 152 | __attribute__((section("SFN"), naked)) |
| 153 | int32_t tfm_core_sfn_request(const struct tfm_sfn_req_s *desc_ptr) |
| 154 | { |
| 155 | __ASM volatile( |
| 156 | "PUSH {lr} \n" |
| 157 | "PUSH {r4-r7} \n" |
| 158 | "MOV r4, r8 \n" |
| 159 | "MOV r5, r9 \n" |
| 160 | "MOV r6, r10 \n" |
| 161 | "MOV r7, r11 \n" |
| 162 | "PUSH {r4-r7} \n" |
| 163 | "MOV r4, r12 \n" |
| 164 | "PUSH {r4} \n" |
| 165 | "SVC %[SVC_REQ] \n" |
| 166 | "MOVS r4, #0 \n" |
| 167 | "MOV r5, r4 \n" |
| 168 | "MOV r6, r4 \n" |
| 169 | "MOV r7, r4 \n" |
| 170 | "MOV r8, r4 \n" |
| 171 | "MOV r9, r4 \n" |
| 172 | "MOV r10, r4 \n" |
| 173 | "MOV r11, r4 \n" |
| 174 | "BLX lr \n" |
| 175 | "SVC %[SVC_RET] \n" |
| 176 | "POP {r4} \n" |
| 177 | "MOV r12, r4 \n" |
| 178 | "POP {r4-r7} \n" |
| 179 | "MOV r8, r4 \n" |
| 180 | "MOV r9, r5 \n" |
| 181 | "MOV r10, r6 \n" |
| 182 | "MOV r11, r7 \n" |
| 183 | "POP {r4-r7} \n" |
| 184 | "POP {pc} \n" |
| 185 | : : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST), |
| 186 | [SVC_RET] "I" (TFM_SVC_SFN_RETURN) |
| 187 | ); |
| 188 | } |
| 189 | |
| 190 | __attribute__((section("SFN"), naked)) |
| 191 | void priv_irq_handler_main(uint32_t partition_id, uint32_t unpriv_handler, |
| 192 | uint32_t irq_signal, uint32_t irq_line) |
| 193 | { |
| 194 | __ASM( |
| 195 | /* Save the callee saved registers*/ |
| 196 | "PUSH {r4-r7, lr} \n" |
| 197 | "MOV r4, r8 \n" |
| 198 | "MOV r5, r9 \n" |
| 199 | "MOV r6, r10 \n" |
| 200 | "MOV r7, r11 \n" |
| 201 | "PUSH {r4-r7} \n" |
| 202 | "MOV r4, r12 \n" |
| 203 | "PUSH {r4} \n" |
| 204 | /* Request SVC to configure environment for the unpriv IRQ handler */ |
| 205 | "SVC %[SVC_REQ] \n" |
| 206 | /* clear the callee saved registers to prevent information leak */ |
| 207 | "MOVS r4, #0 \n" |
| 208 | "MOV r5, r4 \n" |
| 209 | "MOV r6, r4 \n" |
| 210 | "MOV r7, r4 \n" |
| 211 | "MOV r8, r4 \n" |
| 212 | "MOV r9, r4 \n" |
| 213 | "MOV r10, r4 \n" |
| 214 | "MOV r11, r4 \n" |
| 215 | /* Branch to the unprivileged handler */ |
| 216 | "BLX lr \n" |
| 217 | /* Request SVC to reconfigure the environment of the interrupted |
| 218 | * partition |
| 219 | */ |
| 220 | "SVC %[SVC_RET] \n" |
| 221 | /* restore callee saved registers and return */ |
| 222 | "POP {r4} \n" |
| 223 | "MOV r12, r4 \n" |
| 224 | "POP {r4-r7} \n" |
| 225 | "MOV r8, r4 \n" |
| 226 | "MOV r9, r5 \n" |
| 227 | "MOV r10, r6 \n" |
| 228 | "MOV r11, r7 \n" |
| 229 | "POP {r4-r7, pc} \n" |
| 230 | : : [SVC_REQ] "I" (TFM_SVC_DEPRIV_REQ) |
| 231 | , [SVC_RET] "I" (TFM_SVC_DEPRIV_RET) |
| 232 | ); |
| 233 | } |
| 234 | #endif |
| 235 | |
| 236 | #if defined(__ARM_ARCH_8_1M_MAIN__) || \ |
| 237 | defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) |
| 238 | void tfm_arch_prioritize_secure_exception(void) |
| 239 | { |
| 240 | uint32_t VECTKEY; |
| 241 | SCB_Type *scb = SCB; |
| 242 | uint32_t AIRCR; |
| 243 | |
| 244 | /* Set PRIS flag in AIRCR */ |
| 245 | AIRCR = scb->AIRCR; |
| 246 | VECTKEY = (~AIRCR & SCB_AIRCR_VECTKEYSTAT_Msk); |
| 247 | scb->AIRCR = SCB_AIRCR_PRIS_Msk | |
| 248 | VECTKEY | |
| 249 | (AIRCR & ~SCB_AIRCR_VECTKEY_Msk); |
| 250 | } |
| 251 | #elif defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7M__) || \ |
| 252 | defined(__ARM_ARCH_7EM__) |
| 253 | void tfm_arch_prioritize_secure_exception(void) |
| 254 | { |
| 255 | } |
| 256 | #endif |
| 257 | |
| 258 | #if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_ARCH_8M_MAIN__) |
| 259 | __attribute__((naked)) void SVC_Handler(void) |
| 260 | { |
| 261 | __ASM volatile( |
| 262 | "MRS r2, MSP \n" |
| 263 | /* Check store SP in thread mode to r0 */ |
| 264 | "TST lr, #4 \n" |
| 265 | "ITE EQ \n" |
| 266 | "MOVEQ r0, r2 \n" |
| 267 | "MRSNE r0, PSP \n" |
| 268 | "MOV r1, lr \n" |
| 269 | "BL tfm_core_svc_handler \n" |
| 270 | "BX r0 \n" |
| 271 | ); |
| 272 | } |
| 273 | #elif defined(__ARM_ARCH_8M_BASE__) |
| 274 | __attribute__((naked)) void SVC_Handler(void) |
| 275 | { |
| 276 | __ASM volatile( |
| 277 | "MRS r2, MSP \n" |
| 278 | "MOVS r1, #4 \n" |
| 279 | "MOV r3, lr \n" |
| 280 | "MOV r0, r2 \n" |
| 281 | "TST r1, r3 \n" |
| 282 | "BEQ handler \n" |
| 283 | /* If SVC was made from thread mode, overwrite r0 with PSP */ |
| 284 | "MRS r0, PSP \n" |
| 285 | "handler: \n" |
| 286 | "MOV r1, lr \n" |
| 287 | "BL tfm_core_svc_handler \n" |
| 288 | "BX r0 \n" |
| 289 | ); |
| 290 | } |
| 291 | #elif defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7M__) || \ |
| 292 | defined(__ARM_ARCH_7EM__) |
| 293 | __attribute__((naked)) void SVC_Handler(void) |
| 294 | { |
| 295 | __ASM volatile( |
| 296 | "MOVS r0, #4 \n" /* Check store SP in thread mode to r0 */ |
| 297 | "MOV r1, lr \n" |
| 298 | "TST r0, r1 \n" |
| 299 | "BEQ handler \n" |
| 300 | "MRS r0, PSP \n" /* Coming from thread mode */ |
| 301 | "B sp_stored \n" |
| 302 | "handler: \n" |
| 303 | "BX lr \n" /* Coming from handler mode */ |
| 304 | "sp_stored: \n" |
| 305 | "MOV r1, lr \n" |
| 306 | "BL tfm_core_svc_handler \n" |
| 307 | "BX r0 \n" |
| 308 | ); |
| 309 | } |
| 310 | #endif |