Skip to content

Commit

Permalink
Merge pull request #356 from Patater/stack-fault-recovery
Browse files Browse the repository at this point in the history
Stack fault recovery
  • Loading branch information
AlessandroA authored Nov 14, 2016
2 parents b5ec8ba + 5d0f159 commit 2f23bf0
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 203 deletions.
2 changes: 1 addition & 1 deletion api/inc/unvic_exports.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

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

/* this is the maximum priority allowed for the vIRQ module */
/* users of uVisor APIs can use this to determine the maximum level of
Expand Down
7 changes: 7 additions & 0 deletions core/debug/inc/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ uint32_t debug_get_version(void);
void debug_halt_error(THaltError reason);
void debug_reboot(TResetReason reason);

/* Enter the debug box from a privileged mode exception handler. This function
* requires the caller to have already switched the PSP to the debug box stack.
* We currently only call this on MPU faults and Hard Faults in
* vmpu_sys_mux_handler. If called from outside a privileged mode exception
* handler, this function does nothing. */
uint32_t debug_box_enter_from_priv(uint32_t lr);

#ifdef NDEBUG

#define DEBUG_INIT(...) {}
Expand Down
32 changes: 30 additions & 2 deletions core/debug/src/debug_box.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ static void debug_deprivilege_and_return(void * debug_handler, void * return_han
{
/* Source box: Get the current stack pointer. */
/* Note: The source stack pointer is only used to assess the stack
* alignment. */
* alignment and to read the xpsr. */
uint32_t src_sp = context_validate_exc_sf(__get_PSP());

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

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

/* Destination box: Forge the destination stack frame. */
/* Note: We manually have to set the 4 parameters on the destination stack,
Expand Down Expand Up @@ -142,3 +142,31 @@ void debug_register_driver(const TUvisorDebugDriver * const driver)
g_debug_box.box_id = g_active_box;
g_debug_box.initialized = 1;
}

/* FIXME This is a bit platform specific. Consider moving to a platform
* specific location. */
uint32_t debug_box_enter_from_priv(uint32_t lr) {
uint32_t shcsr;
uint32_t from_priv = !(lr & 0x4);

/* If we are not handling an exception caused from privileged mode, return
* the original lr. */
if (!from_priv) {
return lr;
}

shcsr = SCB->SHCSR;

/* Make sure SVC is active. */
assert(shcsr & SCB_SHCSR_SVCALLACT_Msk);

/* We had a fault (from SVC), so clear the SVC fault before returning. SVC
* and all other exceptions must be no longer active after the EXC RETURN,
* or else we cause usage faults when doing SVCs later (for example, to
* reboot via the debug_reboot SVC). */
SCB->SHCSR = shcsr & ~SCB_SHCSR_SVCALLACT_Msk;

/* Return to Thread mode and use the Process Stack for return. The PSP will
* have been changed already. */
return 0xFFFFFFFD;
}
5 changes: 2 additions & 3 deletions core/system/src/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ void UVISOR_NAKED UVISOR_NORETURN isr_default_sys_handler(void)
asm volatile(
"mov r0, lr\n"
"mrs r1, MSP\n"
"push {lr}\n"
"blx vmpu_sys_mux_handler\n"
"pop {pc}\n"
"bl vmpu_sys_mux_handler\n"
"bx r0\n"
);
}

Expand Down
26 changes: 20 additions & 6 deletions core/system/src/unvic.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,15 +579,29 @@ void unvic_init(void)
/* Verify that the priority bits read at runtime are realistic. */
assert(g_nvic_prio_bits > 0 && g_nvic_prio_bits <= 8);

/* check that minimum priority is still in the range of possible priority
* levels */
/* Check that minimum priority is still in the range of possible priority
* levels. */
assert(__UVISOR_NVIC_MIN_PRIORITY < UVISOR_VIRQ_MAX_PRIORITY);

/* by setting the priority group to 0 we make sure that all priority levels
/* Set the priority of each exception. SVC is lower priority than
* MemManage, BusFault, and UsageFault, so that we can recover from
* stacking MemManage faults more simply. */
static const uint32_t priority_0 = __UVISOR_NVIC_MIN_PRIORITY - 2;
static const uint32_t priority_1 = __UVISOR_NVIC_MIN_PRIORITY - 1;
assert(priority_0 < __UVISOR_NVIC_MIN_PRIORITY);
assert(priority_1 < __UVISOR_NVIC_MIN_PRIORITY);
NVIC_SetPriority(MemoryManagement_IRQn, priority_0);
NVIC_SetPriority(BusFault_IRQn, priority_0);
NVIC_SetPriority(UsageFault_IRQn, priority_0);
NVIC_SetPriority(SVCall_IRQn, priority_1);
NVIC_SetPriority(DebugMonitor_IRQn, __UVISOR_NVIC_MIN_PRIORITY);
NVIC_SetPriority(PendSV_IRQn, UVISOR_VIRQ_MAX_PRIORITY);
NVIC_SetPriority(SysTick_IRQn, UVISOR_VIRQ_MAX_PRIORITY);

/* By setting the priority group to 0 we make sure that all priority levels
* are available for pre-emption and that interrupts with the same priority
* level occurring at the same time are served in the default way, that is,
* by IRQ number
* for example, IRQ 0 has precedence over IRQ 1 if both have the same
* priority level */
* by IRQ number. For example, IRQ 0 has precedence over IRQ 1 if both have
* the same priority level. */
NVIC_SetPriorityGrouping(0);
}
4 changes: 3 additions & 1 deletion core/vmpu/inc/vmpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ extern void vmpu_arch_init_hw(void);
extern int vmpu_init_pre(void);
extern void vmpu_init_post(void);

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

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

0 comments on commit 2f23bf0

Please sign in to comment.