Skip to content

Commit aea9e2c

Browse files
authored
Merge pull request #470 from romkuz01/romkuz01_dev
Provide a structure with the debug information to debug_halt() handler
2 parents 391d080 + 5f876d5 commit aea9e2c

File tree

12 files changed

+158
-52
lines changed

12 files changed

+158
-52
lines changed

api/inc/debug_exports.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@
1717
#ifndef __UVISOR_API_DEBUG_EXPORTS_H__
1818
#define __UVISOR_API_DEBUG_EXPORTS_H__
1919

20+
#include "api/inc/halt_exports.h"
2021
#include <stdint.h>
2122

2223
/* Debug box driver -- Version 0
2324
* A constant instance of this struct must be instantiated by the unprivileged
2425
* code to setup a debug box.*/
2526
typedef struct TUvisorDebugDriver {
2627
uint32_t (*get_version)(void);
27-
void (*halt_error)(int);
28+
void (*halt_error)(THaltError, const THaltInfo *);
2829
} TUvisorDebugDriver;
2930

3031
/* Number of handlers in the debug box driver */

api/inc/halt_exports.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,33 @@ typedef struct {
7272
uint32_t retpsr;
7373
} UVISOR_PACKED exception_frame_t;
7474

75+
/* A pointer to this structure will be given to halt_error() handler
76+
* of the debug box driver. */
77+
typedef struct {
78+
/* A basic exception stack frame that is always present with a valid stack. */
79+
exception_frame_t stack_frame;
80+
81+
/* A few registers that may be useful for debug. */
82+
uint32_t lr;
83+
uint32_t control;
84+
uint32_t ipsr;
85+
86+
/* Fault status registers. */
87+
uint32_t mmfar;
88+
uint32_t bfar;
89+
uint32_t cfsr;
90+
uint32_t hfsr;
91+
uint32_t dfsr;
92+
uint32_t afsr;
93+
94+
/* Bitmask telling which of the above regions are valid. */
95+
uint32_t valid_data;
96+
} UVISOR_PACKED THaltInfo;
97+
98+
/* Bitmask to specify which HaltInfo regions are valid. */
99+
typedef enum {
100+
HALT_INFO_STACK_FRAME = 0x1,
101+
HALT_INFO_REGISTERS = 0x2
102+
} THaltInfoValidMask;
103+
75104
#endif /* __UVISOR_API_HALT_EXPORTS_H__ */

core/debug/inc/debug.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void debug_fault(THaltError reason, uint32_t lr, uint32_t sp);
4141
/* Debug box */
4242
void debug_register_driver(const TUvisorDebugDriver * const driver);
4343
uint32_t debug_get_version(void);
44-
void debug_halt_error(THaltError reason);
44+
void debug_halt_error(THaltError reason, const THaltInfo *halt_info);
4545
void debug_reboot(TResetReason reason);
4646

4747
/* Enter the debug box from a privileged mode exception handler. This function
@@ -54,6 +54,7 @@ uint32_t debug_box_enter_from_priv(uint32_t lr);
5454
void debug_die(void);
5555
void debug_deprivilege_and_return(void * debug_handler, void * return_handler,
5656
uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3);
57+
bool debug_collect_halt_info(uint32_t lr, uint32_t sp, THaltInfo *halt_info);
5758

5859
#ifdef NDEBUG
5960

core/debug/src/debug.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,3 +432,48 @@ void debug_fault(THaltError reason, uint32_t lr, uint32_t sp)
432432
#endif /* defined(ARCH_MPU_ARMv8M) */
433433
DEBUG_PRINT_END();
434434
}
435+
436+
bool debug_collect_halt_info(uint32_t lr, uint32_t sp, THaltInfo *halt_info)
437+
{
438+
/* For security reasons we don't want to print uVisor faults, since it
439+
* could expose secrets. To debug uVisor faults users will have to use
440+
* a uVisor debug build with semihosting. */
441+
#if defined(ARCH_MPU_ARMv8M)
442+
bool no_halt_info = EXC_FROM_S(lr);
443+
#else
444+
bool no_halt_info = !EXC_FROM_PSP(lr);
445+
#endif /* defined(ARCH_MPU_ARMv8M) */
446+
447+
halt_info->valid_data = 0;
448+
if (no_halt_info) {
449+
return false;
450+
}
451+
452+
/* CPU registers useful for debug. */
453+
halt_info->lr = lr;
454+
halt_info->ipsr = __get_IPSR();
455+
halt_info->control = __get_CONTROL();
456+
457+
/* Save the status registers in the halt info. */
458+
halt_info->mmfar = SCB->MMFAR;
459+
halt_info->bfar = SCB->BFAR;
460+
halt_info->cfsr = SCB->CFSR;
461+
halt_info->hfsr = SCB->HFSR;
462+
halt_info->dfsr = SCB->DFSR;
463+
halt_info->afsr = SCB->AFSR;
464+
halt_info->valid_data |= HALT_INFO_REGISTERS;
465+
466+
/* Copy the exception stack frame into the halt info.
467+
* Make sure that we're not dealing with stacking error in which case we
468+
* don't have a valid exception stack frame.
469+
* Stacking error may happen in case of Bus Fault, MemManage Fault or
470+
* their escalation to Hard Fault. */
471+
static const uint32_t stack_error_msk = SCB_CFSR_MSTKERR_Msk | SCB_CFSR_STKERR_Msk;
472+
if (!(halt_info->cfsr & stack_error_msk)) {
473+
memcpy((void *)&halt_info->stack_frame, (void *)sp,
474+
CONTEXT_SWITCH_EXC_SF_BYTES);
475+
halt_info->valid_data |= HALT_INFO_STACK_FRAME;
476+
}
477+
478+
return true;
479+
}

core/debug/src/debug_box.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ TDebugBox g_debug_box;
2727
void debug_reboot(TResetReason reason)
2828
{
2929
if (!g_debug_box.initialized || g_active_box != g_debug_box.box_id || reason >= __TRESETREASON_MAX) {
30-
halt(NOT_ALLOWED);
30+
halt(NOT_ALLOWED, NULL);
3131
}
3232

3333
/* Note: Currently we do not act differently based on the reset reason. */
@@ -45,9 +45,12 @@ uint32_t debug_get_version(void)
4545
return 0;
4646
}
4747

48-
void debug_halt_error(THaltError reason)
48+
uint32_t g_debug_interrupt_sp[UVISOR_MAX_BOXES];
49+
50+
void debug_halt_error(THaltError reason, const THaltInfo *halt_info)
4951
{
5052
static int debugged_once_before = 0;
53+
void *info = NULL;
5154

5255
/* If the debug box does not exist (or it has not been initialized yet), or
5356
* the debug box was already called once, just loop forever. */
@@ -56,16 +59,22 @@ void debug_halt_error(THaltError reason)
5659
} else {
5760
/* Remember that debug_deprivilege_and_return() has been called once. */
5861
debugged_once_before = 1;
62+
63+
/* Place the halt info on the interrupt stack. */
64+
if (halt_info) {
65+
g_debug_interrupt_sp[g_debug_box.box_id] -= sizeof(THaltInfo);
66+
info = (void *)g_debug_interrupt_sp[g_debug_box.box_id];
67+
memcpy(info, halt_info, sizeof(THaltInfo));
68+
}
5969

6070
/* The following arguments are passed to the destination function:
6171
* 1. reason
72+
* 2. halt info
6273
* Upon return from the debug handler, the system will die. */
63-
debug_deprivilege_and_return(g_debug_box.driver->halt_error, debug_die, reason, 0, 0, 0);
74+
debug_deprivilege_and_return(g_debug_box.driver->halt_error, debug_die, reason, (uint32_t)info, 0, 0);
6475
}
6576
}
6677

67-
uint32_t g_debug_interrupt_sp[UVISOR_MAX_BOXES];
68-
6978
void debug_register_driver(const TUvisorDebugDriver * const driver)
7079
{
7180
int i;

core/system/inc/halt.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,19 @@
2020
#include "api/inc/halt_exports.h"
2121

2222
#ifdef NDEBUG
23-
#define HALT_ERROR(reason, ...) halt(reason)
23+
#define HALT_ERROR(reason, ...) halt(reason, NULL)
24+
#define HALT_ERROR_EXTENDED(reason, halt_info, ...) halt(reason, halt_info)
2425
#else /*NDEBUG*/
2526
#define HALT_ERROR(reason, ...) \
26-
halt_line(__FILE__, __LINE__, reason, ##__VA_ARGS__)
27+
halt_line(__FILE__, __LINE__, reason, NULL, ##__VA_ARGS__)
28+
#define HALT_ERROR_EXTENDED(reason, halt_info, ...) \
29+
halt_line(__FILE__, __LINE__, reason, halt_info, ##__VA_ARGS__)
2730
#endif/*NDEBUG*/
2831

2932
extern void halt_user_error(THaltUserError reason);
30-
extern void halt(THaltError reason);
31-
extern void halt_error(THaltError reason, const char *fmt, ...);
33+
extern void halt(THaltError reason, const THaltInfo *halt_info);
34+
extern void halt_error(THaltError reason, const THaltInfo *halt_info, const char *fmt, ...);
3235
extern void halt_line(const char *file, uint32_t line, THaltError reason,
33-
const char *fmt, ...);
36+
const THaltInfo *halt_info, const char *fmt, ...);
3437

3538
#endif/*__HALT_H__*/

core/system/src/halt.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ static void halt_printf(const char *fmt, ...)
3333
va_end(va);
3434
}
3535

36-
void halt(THaltError reason)
36+
void halt(THaltError reason, const THaltInfo *halt_info)
3737
{
3838
/* Die. */
39-
debug_halt_error(reason);
39+
debug_halt_error(reason, halt_info);
4040
}
4141

42-
void halt_error(THaltError reason, const char *fmt, ...)
42+
void halt_error(THaltError reason, const THaltInfo *halt_info, const char *fmt, ...)
4343
{
4444
halt_printf("HALT_ERROR: ");
4545

@@ -53,11 +53,11 @@ void halt_error(THaltError reason, const char *fmt, ...)
5353
default_putc('\n');
5454

5555
/* Die. */
56-
halt(reason);
56+
halt(reason, halt_info);
5757
}
5858

5959
void halt_line(const char *file, uint32_t line, THaltError reason,
60-
const char *fmt, ...)
60+
const THaltInfo *halt_info, const char *fmt, ...)
6161
{
6262
halt_printf("HALT_ERROR(%s#%i): ", file, line);
6363

@@ -71,7 +71,7 @@ void halt_line(const char *file, uint32_t line, THaltError reason,
7171
default_putc('\n');
7272

7373
/* Die. */
74-
halt(reason);
74+
halt(reason, halt_info);
7575
}
7676

7777
void halt_user_error(THaltUserError reason)

core/uvisor-config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#define UVISOR_FLASH_LENGTH_MAX 0x4000
3333
#else
3434
/* Debug builds can be up to this big. */
35-
#define UVISOR_FLASH_LENGTH_MAX 0xC000
35+
#define UVISOR_FLASH_LENGTH_MAX 0xC0A0
3636
#endif
3737

3838
/** Size of the SRAM space protected by uVisor for its own SRAM sections

core/vmpu/src/mpu_armv7m/vmpu_armv7m.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,21 @@ uint32_t vmpu_sys_mux_handler(uint32_t lr, uint32_t msp)
130130
/* Determine the origin of the exception. */
131131
bool from_psp = EXC_FROM_PSP(lr);
132132
uint32_t sp = from_psp ? __get_PSP() : msp;
133+
134+
/* Collect fault information that will be given to the halt handler in case of halt. */
135+
THaltInfo info, *halt_info = NULL;
136+
if (debug_collect_halt_info(lr, sp, &info)) {
137+
halt_info = &info;
138+
}
133139

134140
switch (ipsr) {
135141
case NonMaskableInt_IRQn:
136-
HALT_ERROR(NOT_IMPLEMENTED, "No NonMaskableInt IRQ handler registered.");
142+
HALT_ERROR_EXTENDED(NOT_IMPLEMENTED, halt_info, "No NonMaskableInt IRQ handler registered.");
137143
break;
138144

139145
case HardFault_IRQn:
140146
DEBUG_FAULT(FAULT_HARD, lr, sp);
141-
HALT_ERROR(FAULT_HARD, "Cannot recover from a hard fault.");
147+
HALT_ERROR_EXTENDED(FAULT_HARD, halt_info, "Cannot recover from a hard fault.");
142148
lr = debug_box_enter_from_priv(lr);
143149
break;
144150

@@ -180,7 +186,7 @@ uint32_t vmpu_sys_mux_handler(uint32_t lr, uint32_t msp)
180186
/* If recovery was not successful, throw an error and halt. */
181187
DEBUG_FAULT(FAULT_MEMMANAGE, lr, sp);
182188
VMPU_SCB_MMFSR = fault_status;
183-
HALT_ERROR(PERMISSION_DENIED, "Access to restricted resource denied.");
189+
HALT_ERROR_EXTENDED(PERMISSION_DENIED, halt_info, "Access to restricted resource denied.");
184190
lr = debug_box_enter_from_priv(lr);
185191
break;
186192

@@ -211,33 +217,33 @@ uint32_t vmpu_sys_mux_handler(uint32_t lr, uint32_t msp)
211217

212218
/* If recovery was not successful, throw an error and halt. */
213219
DEBUG_FAULT(FAULT_BUS, lr, sp);
214-
HALT_ERROR(PERMISSION_DENIED, "Access to restricted resource denied.");
220+
HALT_ERROR_EXTENDED(PERMISSION_DENIED, halt_info, "Access to restricted resource denied.");
215221
break;
216222

217223
case UsageFault_IRQn:
218224
DEBUG_FAULT(FAULT_USAGE, lr, sp);
219-
HALT_ERROR(FAULT_USAGE, "Cannot recover from a usage fault.");
225+
HALT_ERROR_EXTENDED(FAULT_USAGE, halt_info, "Cannot recover from a usage fault.");
220226
break;
221227

222228
case SVCall_IRQn:
223-
HALT_ERROR(NOT_IMPLEMENTED, "No SVCall IRQ handler registered.");
229+
HALT_ERROR_EXTENDED(NOT_IMPLEMENTED, halt_info, "No SVCall IRQ handler registered.");
224230
break;
225231

226232
case DebugMonitor_IRQn:
227233
DEBUG_FAULT(FAULT_DEBUG, lr, sp);
228-
HALT_ERROR(FAULT_DEBUG, "Cannot recover from a DebugMonitor fault.");
234+
HALT_ERROR_EXTENDED(FAULT_DEBUG, halt_info, "Cannot recover from a DebugMonitor fault.");
229235
break;
230236

231237
case PendSV_IRQn:
232-
HALT_ERROR(NOT_IMPLEMENTED, "No PendSV IRQ handler registered.");
238+
HALT_ERROR_EXTENDED(NOT_IMPLEMENTED, halt_info, "No PendSV IRQ handler registered.");
233239
break;
234240

235241
case SysTick_IRQn:
236-
HALT_ERROR(NOT_IMPLEMENTED, "No SysTick IRQ handler registered.");
242+
HALT_ERROR_EXTENDED(NOT_IMPLEMENTED, halt_info, "No SysTick IRQ handler registered.");
237243
break;
238244

239245
default:
240-
HALT_ERROR(NOT_ALLOWED, "Active IRQn (%i) is not a system interrupt.", ipsr);
246+
HALT_ERROR_EXTENDED(NOT_ALLOWED, halt_info, "Active IRQn (%i) is not a system interrupt.", ipsr);
241247
break;
242248
}
243249

core/vmpu/src/mpu_armv8m/vmpu_armv8m.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -119,30 +119,36 @@ uint32_t vmpu_sys_mux_handler(uint32_t lr, uint32_t msp_s)
119119
bool from_psp = EXC_FROM_PSP(lr);
120120
uint32_t sp = from_s ? (from_np ? (from_psp ? __get_PSP() : msp_s) : msp_s) :
121121
(from_np ? (from_psp ? __TZ_get_PSP_NS() : __TZ_get_MSP_NS()) : __TZ_get_MSP_NS());
122+
123+
/* Collect fault information that will be given to the halt handler in case of halt. */
124+
THaltInfo info, *halt_info = NULL;
125+
if (debug_collect_halt_info(lr, sp, &info)) {
126+
halt_info = &info;
127+
}
122128

123129
switch(ipsr) {
124130
case NonMaskableInt_IRQn:
125-
HALT_ERROR(NOT_IMPLEMENTED, "No NonMaskableInt IRQ handler registered.");
131+
HALT_ERROR_EXTENDED(NOT_IMPLEMENTED, halt_info, "No NonMaskableInt IRQ handler registered.");
126132
break;
127133

128134
case HardFault_IRQn:
129135
DEBUG_FAULT(FAULT_HARD, lr, sp);
130-
HALT_ERROR(FAULT_HARD, "Cannot recover from a hard fault.");
136+
HALT_ERROR_EXTENDED(FAULT_HARD, halt_info, "Cannot recover from a hard fault.");
131137
break;
132138

133139
case MemoryManagement_IRQn:
134140
DEBUG_FAULT(FAULT_MEMMANAGE, lr, sp);
135-
HALT_ERROR(FAULT_MEMMANAGE, "Cannot recover from a memory management fault.");
141+
HALT_ERROR_EXTENDED(FAULT_MEMMANAGE, halt_info, "Cannot recover from a memory management fault.");
136142
break;
137143

138144
case BusFault_IRQn:
139145
DEBUG_FAULT(FAULT_BUS, lr, sp);
140-
HALT_ERROR(FAULT_BUS, "Cannot recover from a bus fault.");
146+
HALT_ERROR_EXTENDED(FAULT_BUS, halt_info, "Cannot recover from a bus fault.");
141147
break;
142148

143149
case UsageFault_IRQn:
144150
DEBUG_FAULT(FAULT_USAGE, lr, sp);
145-
HALT_ERROR(FAULT_USAGE, "Cannot recover from a usage fault.");
151+
HALT_ERROR_EXTENDED(FAULT_USAGE, halt_info, "Cannot recover from a usage fault.");
146152
break;
147153

148154
case SecureFault_IRQn:
@@ -158,28 +164,28 @@ uint32_t vmpu_sys_mux_handler(uint32_t lr, uint32_t msp_s)
158164
}
159165
}
160166
DEBUG_FAULT(FAULT_SECURE, lr, sp);
161-
HALT_ERROR(PERMISSION_DENIED, "Cannot recover from a secure fault.");
167+
HALT_ERROR_EXTENDED(PERMISSION_DENIED, halt_info, "Cannot recover from a secure fault.");
162168
break;
163169

164170
case SVCall_IRQn:
165-
HALT_ERROR(NOT_IMPLEMENTED, "No SVCall IRQ handler registered.");
171+
HALT_ERROR_EXTENDED(NOT_IMPLEMENTED, halt_info, "No SVCall IRQ handler registered.");
166172
break;
167173

168174
case DebugMonitor_IRQn:
169175
DEBUG_FAULT(FAULT_DEBUG, lr, sp);
170-
HALT_ERROR(FAULT_DEBUG, "Cannot recover from a DebugMonitor fault.");
176+
HALT_ERROR_EXTENDED(FAULT_DEBUG, halt_info, "Cannot recover from a DebugMonitor fault.");
171177
break;
172178

173179
case PendSV_IRQn:
174-
HALT_ERROR(NOT_IMPLEMENTED, "No PendSV IRQ handler registered.");
180+
HALT_ERROR_EXTENDED(NOT_IMPLEMENTED, halt_info, "No PendSV IRQ handler registered.");
175181
break;
176182

177183
case SysTick_IRQn:
178-
HALT_ERROR(NOT_IMPLEMENTED, "No SysTick IRQ handler registered.");
184+
HALT_ERROR_EXTENDED(NOT_IMPLEMENTED, halt_info, "No SysTick IRQ handler registered.");
179185
break;
180186

181187
default:
182-
HALT_ERROR(NOT_ALLOWED, "Active IRQn (%i) is not a system interrupt.", ipsr);
188+
HALT_ERROR_EXTENDED(NOT_ALLOWED, halt_info, "Active IRQn (%i) is not a system interrupt.", ipsr);
183189
break;
184190
}
185191

0 commit comments

Comments
 (0)