Skip to content

Commit 7eaafd8

Browse files
adamgreenfacchinm
authored andcommitted
Refactor fault handling code
The code now records the original addresses of the fault handlers before switching them to the debug stubs to reduce code duplication by having a unique stub for each of HardFault, MemManagement, BusFault, and UsageFault that just loads the original address into R3 and then transfers control to the common mriFaultHandlerStub().
1 parent 6d5ec5a commit 7eaafd8

File tree

2 files changed

+90
-15
lines changed

2 files changed

+90
-15
lines changed

libraries/ThreadMRI/src/ThreadMRI.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ volatile osThreadId_t mriThreadSingleStepThreadId;
100100
volatile uint32_t mriThreadOrigSVCall;
101101
volatile uint32_t mriThreadOrigSysTick;
102102
volatile uint32_t mriThreadOrigPendSV;
103+
// Addresses of the original fault handlers before being replaced with debugger specific ones.
104+
volatile uint32_t mriThreadOrigHardFault;
105+
volatile uint32_t mriThreadOrigMemManagement;
106+
volatile uint32_t mriThreadOrigBusFault;
107+
volatile uint32_t mriThreadOrigUsageFault;
103108

104109
// UNDONE: For debugging. If different than g_haltedThreadId then the mriMain() thread was signalled when the previous
105110
// instance was still running.
@@ -108,9 +113,12 @@ static volatile osThreadId_t g_debugThreadId;
108113

109114

110115

111-
// Assembly Language fault handling stubs. They do some preprocessing and then call the C handlers below if appropriate.
116+
// Assembly Language fault handling stubs. They do some preprocessing and then call the C handlers if appropriate.
112117
extern "C" void mriDebugMonitorHandlerStub(void);
113-
extern "C" void mriFaultHandlerStub(void);
118+
extern "C" void mriHardFaultHandlerStub(void);
119+
extern "C" void mriMemManagementHandlerStub(void);
120+
extern "C" void mriBusFaultHandlerStub(void);
121+
extern "C" void mriUsageFaultHandlerStub(void);
114122
// Assembly Language stubs for RTX context switching routines. They check to see if DebugMon should be pended before
115123
// calling the actual RTX handlers.
116124
extern "C" void mriSVCHandlerStub(void);
@@ -128,7 +136,7 @@ static bool hasEncounteredDebugEvent();
128136
static void recordAndClearFaultStatusBits();
129137
static void wakeMriMainToDebugCurrentThread();
130138
static void stopSingleStepping();
131-
static void switchFaultHandlersToDebugger();
139+
static void recordAndSwitchFaultHandlersToDebugger();
132140

133141

134142

@@ -306,15 +314,20 @@ void Platform_Init(Token* pParameterTokens)
306314

307315
g_enableDWTandFPB = 0;
308316
mriThreadSingleStepThreadId = NULL;
309-
switchFaultHandlersToDebugger();
317+
recordAndSwitchFaultHandlersToDebugger();
310318
}
311319

312-
static void switchFaultHandlersToDebugger(void)
320+
static void recordAndSwitchFaultHandlersToDebugger()
313321
{
314-
NVIC_SetVector(HardFault_IRQn, (uint32_t)mriFaultHandlerStub);
315-
NVIC_SetVector(MemoryManagement_IRQn, (uint32_t)mriFaultHandlerStub);
316-
NVIC_SetVector(BusFault_IRQn, (uint32_t)mriFaultHandlerStub);
317-
NVIC_SetVector(UsageFault_IRQn, (uint32_t)mriFaultHandlerStub);
322+
mriThreadOrigHardFault = NVIC_GetVector(HardFault_IRQn);
323+
mriThreadOrigMemManagement = NVIC_GetVector(MemoryManagement_IRQn);
324+
mriThreadOrigBusFault = NVIC_GetVector(BusFault_IRQn);
325+
mriThreadOrigUsageFault = NVIC_GetVector(UsageFault_IRQn);
326+
327+
NVIC_SetVector(HardFault_IRQn, (uint32_t)mriHardFaultHandlerStub);
328+
NVIC_SetVector(MemoryManagement_IRQn, (uint32_t)mriMemManagementHandlerStub);
329+
NVIC_SetVector(BusFault_IRQn, (uint32_t)mriBusFaultHandlerStub);
330+
NVIC_SetVector(UsageFault_IRQn, (uint32_t)mriUsageFaultHandlerStub);
318331
NVIC_SetVector(DebugMonitor_IRQn, (uint32_t)mriDebugMonitorHandlerStub);
319332
}
320333

libraries/ThreadMRI/src/ThreadMRI_asm.S

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ mriDebugMonitorHandlerStub:
4848
.size mriDebugMonitorHandlerStub, .-mriDebugMonitorHandlerStub
4949

5050

51-
// UNDONE: Have a separate stub for each fault handler (hard, memmanage, bus, usage)
5251
.global mriFaultHandlerStub
5352
.type mriFaultHandlerStub, function
5453
.thumb_func
5554
/* extern "C" void mriFaultHandlerStub(void);
56-
This stub is called whenever a fault fires. It checks the EXC_RETURN value to determine if thread or handler
57-
mode caused fault:
55+
This stub is called whenever a fault fires w/ R3 set to the original handler for the particular fault. This
56+
allows the original handler to be called if a crash occurs in handler mode which can't be debugged by ThreadMRI.
57+
It checks the EXC_RETURN value to determine if thread or handler mode caused fault:
5858
Thread: Pass control to mriFaultHandler() so that it can be debugged.
5959
Handler: If caused by debug event, pass control to mriFaultHandler() so that break/watchpoints can be disabled.
6060
Otherwise pass control to the standard mbed-os HardFault_Handler so that crash can be dumped.
@@ -72,14 +72,76 @@ mriFaultHandlerStub:
7272
ldr r1, =HFSR
7373
ldr r1, [r1]
7474
tst r1, #HFSR_DEBUG_EVENT_BIT
75-
/* If not a debug event then fall through to default hard fault handler as something bad has happened. */
76-
beq.w HardFault_Handler
7775
/* If forced into hard fault due to debug event then breakpoint/watchpoint occurred and needs to be ignored. */
78-
b.w mriFaultHandler
76+
bne.w mriFaultHandler
77+
/* If not a debug event then fall through to default hard fault handler as something bad has happened. */
78+
mov pc, r3
7979
.pool
8080
.size mriFaultHandlerStub, .-mriFaultHandlerStub
8181

8282

83+
.global mriHardFaultHandlerStub
84+
.type mriHardFaultHandlerStub, function
85+
.thumb_func
86+
/* extern "C" void mriHardFaultHandlerStub(void);
87+
This stub is called whenever a Hard Fault fires.
88+
*/
89+
mriHardFaultHandlerStub:
90+
/* Load address of real fault handler into r3 & call generic fault stub. */
91+
ldr r3, =mriThreadOrigHardFault
92+
ldr r3, [r3]
93+
b mriFaultHandlerStub
94+
.pool
95+
.size mriHardFaultHandlerStub, .-mriHardFaultHandlerStub
96+
97+
98+
.global mriMemManagementHandlerStub
99+
.type mriMemManagementHandlerStub, function
100+
.thumb_func
101+
/* extern "C" void mriMemManagementHandlerStub(void);
102+
This stub is called whenever a MemManagement fault fires.
103+
*/
104+
mriMemManagementHandlerStub:
105+
/* Load address of real fault handler into r3 & call generic fault stub. */
106+
ldr r3, =mriThreadOrigMemManagement
107+
ldr r3, [r3]
108+
b mriFaultHandlerStub
109+
.pool
110+
.size mriMemManagementHandlerStub, .-mriMemManagementHandlerStub
111+
112+
113+
.global mriBusFaultHandlerStub
114+
.type mriBusFaultHandlerStub, function
115+
.thumb_func
116+
/* extern "C" void mriBusFaultHandlerStub(void);
117+
This stub is called whenever a Bus Fault fires.
118+
*/
119+
mriBusFaultHandlerStub:
120+
/* Load address of real fault handler into r3 & call generic fault stub. */
121+
ldr r3, =mriThreadOrigBusFault
122+
ldr r3, [r3]
123+
b mriFaultHandlerStub
124+
.pool
125+
.size mriBusFaultHandlerStub, .-mriBusFaultHandlerStub
126+
127+
128+
.global mriUsageFaultHandlerStub
129+
.type mriUsageFaultHandlerStub, function
130+
.thumb_func
131+
/* extern "C" void mriUsageFaultHandlerStub(void);
132+
This stub is called whenever a Usage Fault fires.
133+
*/
134+
mriUsageFaultHandlerStub:
135+
/* Load address of real fault handler into r3 & call generic fault stub. */
136+
ldr r3, =mriThreadOrigUsageFault
137+
ldr r3, [r3]
138+
b mriFaultHandlerStub
139+
.pool
140+
.size mriUsageFaultHandlerStub, .-mriUsageFaultHandlerStub
141+
142+
143+
144+
83145
.global mriRTXHandlerStub
84146
.type mriRTXHandlerStub, function
85147
.thumb_func

0 commit comments

Comments
 (0)