Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this an overkill? The context_validate_exc_sf function does exactly the same check (reads with the t instruction).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the commit description spells it out as not really necessary, as a non-recoverable fault would happen in context_validate_exc_sf, preventing further progress. As currently written, the unprivileged access instruction is not technically necessary.

However, from the defensive coding perspective, it makes sense to use the unprivileged access instruction. Maybe the context_validate_exc_sf goes away on accident or has a bug introduced on accident. It's also nice to consistently have all places where uVisor accesses unprivileged memory using unprivileged access instructions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


/* 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