blob: c9cdc3b132e652969bb971ca07326d353afa39c1 [file] [log] [blame]
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +01001/*
2 * Copyright (c) 2021, Nordic Semiconductor ASA. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <string.h>
8#include "tfm_arch.h"
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +01009#include "tfm_spm_log.h"
Dávid Házibe7f0de2023-07-19 11:25:38 +020010/* "exception_info.h" must be the last include because of the IAR pragma */
11#include "exception_info.h"
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +010012
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +010013static struct exception_info_t exception_info;
14
15/**
16 * \brief Check whether the exception was triggered in thread or handler mode.
17 *
18 * \param[in] lr LR register containing the EXC_RETURN value.
19 *
20 * \retval true The exception will return to thread mode.
21 */
22__STATIC_INLINE bool is_return_thread_mode(uint32_t lr)
23{
24#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
25 return !((lr == EXC_RETURN_HANDLER) || (lr == EXC_RETURN_HANDLER_FPU));
26#elif defined(__ARM_ARCH_8M_BASE__) || defined(__ARM_ARCH_8M_MAIN__) \
27 || defined(__ARM_ARCH_8_1M_MAIN__)
28 return (lr & EXC_RETURN_MODE);
29#else
30 return !(lr == EXC_RETURN_HANDLER);
31#endif
32}
33
34/**
35 * \brief Check whether the PSP or MSP is used to restore stack frame on
36 * exception return.
37 *
38 * \param[in] lr LR register containing the EXC_RETURN value.
39 *
40 * \retval true The exception frame is on the PSP
41 */
42__STATIC_INLINE bool is_return_psp(uint32_t lr)
43{
44#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
45 return ((lr == EXC_RETURN_THREAD_PSP) || (lr == EXC_RETURN_THREAD_PSP_FPU));
46#elif defined(__ARM_ARCH_8M_BASE__) || defined(__ARM_ARCH_8M_MAIN__) \
47 || defined(__ARM_ARCH_8_1M_MAIN__)
48 /* PSP is used only if SPSEL is set, and we came from thread mode. */
49 return ((lr & EXC_RETURN_SPSEL) && is_return_thread_mode(lr));
50#else
51 return (lr == EXC_RETURN_THREAD_PSP);
52#endif
53}
54
55/**
56 * \brief Get a pointer to the current exception frame
57 *
58 * \param[in] lr LR register containing the EXC_RETURN value.
59 * \param[in] msp The MSP at the start of the exception handler.
60 * \param[in] psp The PSP at the start of the exception handler.
61 *
62 * \return A pointer to the current exception frame.
63 */
64__STATIC_INLINE
65uint32_t *get_exception_frame(uint32_t lr, uint32_t msp, uint32_t psp)
66{
67#if defined(__ARM_ARCH_8M_BASE__) || defined(__ARM_ARCH_8M_MAIN__) \
68 || defined(__ARM_ARCH_8_1M_MAIN__)
69 bool is_psp = is_return_psp(lr);
70
71 return (uint32_t *)(is_return_secure_stack(lr)
72 ? (is_psp ? psp : msp)
73 : (is_psp ? __TZ_get_PSP_NS() : __TZ_get_MSP_NS()));
74#else
75 return (uint32_t *)(is_return_psp(lr) ? psp : msp);
76#endif
77}
78
Joakim Anderssona4066d82022-04-06 16:32:09 +020079static void dump_exception_info(bool stack_error,
Joakim Andersson90e0c062023-11-13 13:48:08 +010080 const struct exception_info_t *ctx)
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +010081{
Joakim Andersson53831432021-11-03 15:44:28 +010082 SPMLOG_DBGMSG("Here is some context for the exception:\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +010083 SPMLOG_DBGMSGVAL(" EXC_RETURN (LR): ", ctx->EXC_RETURN);
84 SPMLOG_DBGMSG(" Exception came from");
85#ifdef TRUSTZONE_PRESENT
86 if (is_return_secure_stack(ctx->EXC_RETURN)) {
87 SPMLOG_DBGMSG(" secure FW in");
88 } else {
89 SPMLOG_DBGMSG(" non-secure FW in");
90 }
91#endif
92
93 if (is_return_thread_mode(ctx->EXC_RETURN)) {
Joakim Andersson53831432021-11-03 15:44:28 +010094 SPMLOG_DBGMSG(" thread mode.\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +010095 } else {
Joakim Andersson53831432021-11-03 15:44:28 +010096 SPMLOG_DBGMSG(" handler mode.\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +010097 }
98 SPMLOG_DBGMSGVAL(" xPSR: ", ctx->xPSR);
99 SPMLOG_DBGMSGVAL(" MSP: ", ctx->MSP);
100 SPMLOG_DBGMSGVAL(" PSP: ", ctx->PSP);
101#ifdef TRUSTZONE_PRESENT
102 SPMLOG_DBGMSGVAL(" MSP_NS: ", __TZ_get_MSP_NS());
103 SPMLOG_DBGMSGVAL(" PSP_NS: ", __TZ_get_PSP_NS());
104#endif
105
106 SPMLOG_DBGMSGVAL(" Exception frame at: ", (uint32_t)ctx->EXC_FRAME);
107 if (stack_error) {
108 SPMLOG_DBGMSG(
Joakim Andersson53831432021-11-03 15:44:28 +0100109 " (Note that the exception frame may be corrupted for this type of error.)\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100110 }
111 SPMLOG_DBGMSGVAL(" R0: ", ctx->EXC_FRAME_COPY[0]);
112 SPMLOG_DBGMSGVAL(" R1: ", ctx->EXC_FRAME_COPY[1]);
113 SPMLOG_DBGMSGVAL(" R2: ", ctx->EXC_FRAME_COPY[2]);
114 SPMLOG_DBGMSGVAL(" R3: ", ctx->EXC_FRAME_COPY[3]);
115 SPMLOG_DBGMSGVAL(" R12: ", ctx->EXC_FRAME_COPY[4]);
116 SPMLOG_DBGMSGVAL(" LR: ", ctx->EXC_FRAME_COPY[5]);
117 SPMLOG_DBGMSGVAL(" PC: ", ctx->EXC_FRAME_COPY[6]);
118 SPMLOG_DBGMSGVAL(" xPSR: ", ctx->EXC_FRAME_COPY[7]);
119
Joakim Anderssondbdcfa02023-11-14 14:49:26 +0100120 SPMLOG_DBGMSG(" Callee saved register state:");
121 SPMLOG_DBGMSGVAL(" R4: ", ctx->CALLEE_SAVED_COPY[0]);
122 SPMLOG_DBGMSGVAL(" R5: ", ctx->CALLEE_SAVED_COPY[1]);
123 SPMLOG_DBGMSGVAL(" R6: ", ctx->CALLEE_SAVED_COPY[2]);
124 SPMLOG_DBGMSGVAL(" R7: ", ctx->CALLEE_SAVED_COPY[3]);
125 SPMLOG_DBGMSGVAL(" R8: ", ctx->CALLEE_SAVED_COPY[4]);
126 SPMLOG_DBGMSGVAL(" R9: ", ctx->CALLEE_SAVED_COPY[5]);
127 SPMLOG_DBGMSGVAL(" R10: ", ctx->CALLEE_SAVED_COPY[6]);
128 SPMLOG_DBGMSGVAL(" R11: ", ctx->CALLEE_SAVED_COPY[7]);
129
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100130#ifdef FAULT_STATUS_PRESENT
131 SPMLOG_DBGMSGVAL(" CFSR: ", ctx->CFSR);
132 SPMLOG_DBGMSGVAL(" BFSR: ",
133 (ctx->CFSR & SCB_CFSR_BUSFAULTSR_Msk) >> SCB_CFSR_BUSFAULTSR_Pos);
134 if (ctx->BFARVALID) {
135 SPMLOG_DBGMSGVAL(" BFAR: ", ctx->BFAR);
136 } else {
Joakim Andersson53831432021-11-03 15:44:28 +0100137 SPMLOG_DBGMSG(" BFAR: Not Valid\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100138 }
139 SPMLOG_DBGMSGVAL(" MMFSR: ",
140 (ctx->CFSR & SCB_CFSR_MEMFAULTSR_Msk) >> SCB_CFSR_MEMFAULTSR_Pos);
141 if (ctx->MMARVALID) {
142 SPMLOG_DBGMSGVAL(" MMFAR: ", ctx->MMFAR);
143 } else {
Joakim Andersson53831432021-11-03 15:44:28 +0100144 SPMLOG_DBGMSG(" MMFAR: Not Valid\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100145 }
146 SPMLOG_DBGMSGVAL(" UFSR: ",
147 (ctx->CFSR & SCB_CFSR_USGFAULTSR_Msk) >> SCB_CFSR_USGFAULTSR_Pos);
148 SPMLOG_DBGMSGVAL(" HFSR: ", ctx->HFSR);
149#ifdef TRUSTZONE_PRESENT
150 SPMLOG_DBGMSGVAL(" SFSR: ", ctx->SFSR);
151 if (ctx->SFARVALID) {
152 SPMLOG_DBGMSGVAL(" SFAR: ", ctx->SFAR);
153 } else {
Joakim Andersson53831432021-11-03 15:44:28 +0100154 SPMLOG_DBGMSG(" SFAR: Not Valid\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100155 }
156#endif
157
158#endif
159}
160
Joakim Andersson90e0c062023-11-13 13:48:08 +0100161static void dump_error(const struct exception_info_t *ctx)
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100162{
163 bool stack_error = false;
164
Joakim Andersson3d3c4452021-11-11 14:29:25 +0100165 SPMLOG_ERRMSG("FATAL ERROR: ");
Joakim Andersson90e0c062023-11-13 13:48:08 +0100166 switch (ctx->VECTACTIVE) {
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100167 case EXCEPTION_TYPE_HARDFAULT:
Joakim Andersson3d3c4452021-11-11 14:29:25 +0100168 SPMLOG_ERRMSG("HardFault\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100169 break;
Joakim Andersson90e0c062023-11-13 13:48:08 +0100170#ifdef FAULT_STATUS_PRESENT
171 case EXCEPTION_TYPE_MEMMANAGEFAULT:
Joakim Andersson3d3c4452021-11-11 14:29:25 +0100172 SPMLOG_ERRMSG("MemManage fault\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100173 stack_error = true;
174 break;
175 case EXCEPTION_TYPE_BUSFAULT:
Joakim Andersson3d3c4452021-11-11 14:29:25 +0100176 SPMLOG_ERRMSG("BusFault\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100177 stack_error = true;
178 break;
179 case EXCEPTION_TYPE_USAGEFAULT:
Joakim Andersson3d3c4452021-11-11 14:29:25 +0100180 SPMLOG_ERRMSG("UsageFault\r\n");
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100181 stack_error = true;
182 break;
Joakim Andersson90e0c062023-11-13 13:48:08 +0100183#ifdef TRUSTZONE_PRESENT
184 case EXCEPTION_TYPE_SECUREFAULT:
185 SPMLOG_ERRMSG("SecureFault\r\n");
186 break;
187#endif
188#endif
189 /* Platform specific external interrupt secure handler. */
190 default:
191 if (ctx->VECTACTIVE < 16) {
192 SPMLOG_ERRMSGVAL("Reserved Exception ", ctx->VECTACTIVE);
193 } else {
194 SPMLOG_ERRMSGVAL("Platform external interrupt (IRQn): ", ctx->VECTACTIVE - 16);
195 }
Joakim Anderssona4066d82022-04-06 16:32:09 +0200196 /* Depends on the platform, assume it may cause stack error */
197 stack_error = true;
198 break;
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100199 }
Joakim Anderssona4066d82022-04-06 16:32:09 +0200200
Joakim Andersson90e0c062023-11-13 13:48:08 +0100201 dump_exception_info(stack_error, ctx);
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100202}
203
Chris Coleman9dd58c92023-10-08 13:49:23 -0400204void tfm_exception_info_get_context(struct exception_info_t *ctx)
205{
206 memcpy(ctx, &exception_info, sizeof(exception_info));
207}
208
Joakim Anderssondbdcfa02023-11-14 14:49:26 +0100209void store_and_dump_context(uint32_t MSP_in, uint32_t PSP_in, uint32_t LR_in,
210 uint32_t *callee_saved)
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100211{
212 struct exception_info_t *ctx = &exception_info;
213
Joakim Andersson90e0c062023-11-13 13:48:08 +0100214 ctx->VECTACTIVE = SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk;
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100215 ctx->xPSR = __get_xPSR();
216 ctx->EXC_RETURN = LR_in;
217 ctx->MSP = MSP_in;
218 ctx->PSP = PSP_in;
219 ctx->EXC_FRAME = get_exception_frame(ctx->EXC_RETURN, ctx->MSP, ctx->PSP);
Ken Liub671d682022-05-12 20:39:29 +0800220 memcpy(ctx->EXC_FRAME_COPY, ctx->EXC_FRAME, sizeof(ctx->EXC_FRAME_COPY));
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100221
Joakim Anderssondbdcfa02023-11-14 14:49:26 +0100222 if (callee_saved) {
223 memcpy(ctx->CALLEE_SAVED_COPY, callee_saved, sizeof(ctx->CALLEE_SAVED_COPY));
224 }
225
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100226#ifdef FAULT_STATUS_PRESENT
227 ctx->CFSR = SCB->CFSR;
228 ctx->HFSR = SCB->HFSR;
229 ctx->BFAR = SCB->BFAR;
230 ctx->BFARVALID = ctx->CFSR & SCB_CFSR_BFARVALID_Msk;
231 ctx->MMFAR = SCB->MMFAR;
232 ctx->MMARVALID = ctx->CFSR & SCB_CFSR_MMARVALID_Msk;
233 SCB->CFSR = ctx->CFSR; /* Clear bits. CFSR is write-one-to-clear. */
234 SCB->HFSR = ctx->HFSR; /* Clear bits. HFSR is write-one-to-clear. */
235#ifdef TRUSTZONE_PRESENT
236 ctx->SFSR = SAU->SFSR;
237 ctx->SFAR = SAU->SFAR;
238 ctx->SFARVALID = ctx->SFSR & SAU_SFSR_SFARVALID_Msk;
239 SAU->SFSR = ctx->SFSR; /* Clear bits. SFSR is write-one-to-clear. */
240#endif
241#endif
242
Joakim Andersson90e0c062023-11-13 13:48:08 +0100243 dump_error(ctx);
Øyvind Rønningstadf2c8dad2021-01-15 15:33:33 +0100244}