Skip to content

Commit 2f23bf0

Browse files
authored
Merge pull request #356 from Patater/stack-fault-recovery
Stack fault recovery
2 parents b5ec8ba + 5d0f159 commit 2f23bf0

File tree

9 files changed

+283
-203
lines changed

9 files changed

+283
-203
lines changed

api/inc/unvic_exports.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
/* this value refers to the minimum allowable priority in the physical NVIC
2323
* module, but not in the virtualised one (vIRQ) */
24-
#define __UVISOR_NVIC_MIN_PRIORITY ((uint32_t) 1)
24+
#define __UVISOR_NVIC_MIN_PRIORITY ((uint32_t) 2)
2525

2626
/* this is the maximum priority allowed for the vIRQ module */
2727
/* users of uVisor APIs can use this to determine the maximum level of

core/debug/inc/debug.h

+7
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ uint32_t debug_get_version(void);
4242
void debug_halt_error(THaltError reason);
4343
void debug_reboot(TResetReason reason);
4444

45+
/* Enter the debug box from a privileged mode exception handler. This function
46+
* requires the caller to have already switched the PSP to the debug box stack.
47+
* We currently only call this on MPU faults and Hard Faults in
48+
* vmpu_sys_mux_handler. If called from outside a privileged mode exception
49+
* handler, this function does nothing. */
50+
uint32_t debug_box_enter_from_priv(uint32_t lr);
51+
4552
#ifdef NDEBUG
4653

4754
#define DEBUG_INIT(...) {}

core/debug/src/debug_box.c

+30-2
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@ static void debug_deprivilege_and_return(void * debug_handler, void * return_han
4747
{
4848
/* Source box: Get the current stack pointer. */
4949
/* Note: The source stack pointer is only used to assess the stack
50-
* alignment. */
50+
* alignment and to read the xpsr. */
5151
uint32_t src_sp = context_validate_exc_sf(__get_PSP());
5252

5353
/* Destination box: The debug box. */
5454
uint8_t dst_id = g_debug_box.box_id;
5555

5656
/* Copy the xPSR from the source exception stack frame. */
57-
uint32_t xpsr = ((uint32_t *) src_sp)[7];
57+
uint32_t xpsr = vmpu_unpriv_uint32_read((uint32_t) &((uint32_t *) src_sp)[7]);
5858

5959
/* Destination box: Forge the destination stack frame. */
6060
/* Note: We manually have to set the 4 parameters on the destination stack,
@@ -142,3 +142,31 @@ void debug_register_driver(const TUvisorDebugDriver * const driver)
142142
g_debug_box.box_id = g_active_box;
143143
g_debug_box.initialized = 1;
144144
}
145+
146+
/* FIXME This is a bit platform specific. Consider moving to a platform
147+
* specific location. */
148+
uint32_t debug_box_enter_from_priv(uint32_t lr) {
149+
uint32_t shcsr;
150+
uint32_t from_priv = !(lr & 0x4);
151+
152+
/* If we are not handling an exception caused from privileged mode, return
153+
* the original lr. */
154+
if (!from_priv) {
155+
return lr;
156+
}
157+
158+
shcsr = SCB->SHCSR;
159+
160+
/* Make sure SVC is active. */
161+
assert(shcsr & SCB_SHCSR_SVCALLACT_Msk);
162+
163+
/* We had a fault (from SVC), so clear the SVC fault before returning. SVC
164+
* and all other exceptions must be no longer active after the EXC RETURN,
165+
* or else we cause usage faults when doing SVCs later (for example, to
166+
* reboot via the debug_reboot SVC). */
167+
SCB->SHCSR = shcsr & ~SCB_SHCSR_SVCALLACT_Msk;
168+
169+
/* Return to Thread mode and use the Process Stack for return. The PSP will
170+
* have been changed already. */
171+
return 0xFFFFFFFD;
172+
}

core/system/src/system.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,8 @@ void UVISOR_NAKED UVISOR_NORETURN isr_default_sys_handler(void)
9191
asm volatile(
9292
"mov r0, lr\n"
9393
"mrs r1, MSP\n"
94-
"push {lr}\n"
95-
"blx vmpu_sys_mux_handler\n"
96-
"pop {pc}\n"
94+
"bl vmpu_sys_mux_handler\n"
95+
"bx r0\n"
9796
);
9897
}
9998

core/system/src/unvic.c

+20-6
Original file line numberDiff line numberDiff line change
@@ -579,15 +579,29 @@ void unvic_init(void)
579579
/* Verify that the priority bits read at runtime are realistic. */
580580
assert(g_nvic_prio_bits > 0 && g_nvic_prio_bits <= 8);
581581

582-
/* check that minimum priority is still in the range of possible priority
583-
* levels */
582+
/* Check that minimum priority is still in the range of possible priority
583+
* levels. */
584584
assert(__UVISOR_NVIC_MIN_PRIORITY < UVISOR_VIRQ_MAX_PRIORITY);
585585

586-
/* by setting the priority group to 0 we make sure that all priority levels
586+
/* Set the priority of each exception. SVC is lower priority than
587+
* MemManage, BusFault, and UsageFault, so that we can recover from
588+
* stacking MemManage faults more simply. */
589+
static const uint32_t priority_0 = __UVISOR_NVIC_MIN_PRIORITY - 2;
590+
static const uint32_t priority_1 = __UVISOR_NVIC_MIN_PRIORITY - 1;
591+
assert(priority_0 < __UVISOR_NVIC_MIN_PRIORITY);
592+
assert(priority_1 < __UVISOR_NVIC_MIN_PRIORITY);
593+
NVIC_SetPriority(MemoryManagement_IRQn, priority_0);
594+
NVIC_SetPriority(BusFault_IRQn, priority_0);
595+
NVIC_SetPriority(UsageFault_IRQn, priority_0);
596+
NVIC_SetPriority(SVCall_IRQn, priority_1);
597+
NVIC_SetPriority(DebugMonitor_IRQn, __UVISOR_NVIC_MIN_PRIORITY);
598+
NVIC_SetPriority(PendSV_IRQn, UVISOR_VIRQ_MAX_PRIORITY);
599+
NVIC_SetPriority(SysTick_IRQn, UVISOR_VIRQ_MAX_PRIORITY);
600+
601+
/* By setting the priority group to 0 we make sure that all priority levels
587602
* are available for pre-emption and that interrupts with the same priority
588603
* level occurring at the same time are served in the default way, that is,
589-
* by IRQ number
590-
* for example, IRQ 0 has precedence over IRQ 1 if both have the same
591-
* priority level */
604+
* by IRQ number. For example, IRQ 0 has precedence over IRQ 1 if both have
605+
* the same priority level. */
592606
NVIC_SetPriorityGrouping(0);
593607
}

core/vmpu/inc/vmpu.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,9 @@ extern void vmpu_arch_init_hw(void);
155155
extern int vmpu_init_pre(void);
156156
extern void vmpu_init_post(void);
157157

158-
extern void vmpu_sys_mux_handler(uint32_t lr, uint32_t msp);
158+
/* Handle system exceptions and interrupts. Return the EXC_RETURN desired for
159+
* returning from exception mode. */
160+
extern uint32_t vmpu_sys_mux_handler(uint32_t lr, uint32_t msp);
159161

160162
/* contains the total number of boxes
161163
* boxes are enumerated from 0 to (g_vmpu_box_count - 1) and the following

0 commit comments

Comments
 (0)