/* Note: On ARMv7-M the return_handler is executed in NP mode. */ void debug_deprivilege_and_return(void * debug_handler, void * return_handler, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3) { /* Source box: Get the current stack pointer. */ /* Note: The source stack pointer is only used to assess the stack * 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 = 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, * so we will set the API to have nargs=0. */ uint32_t dst_sp = context_forge_exc_sf(src_sp, dst_id, (uint32_t) debug_handler, (uint32_t) return_handler, xpsr, 0); ((uint32_t *) dst_sp)[0] = a0; ((uint32_t *) dst_sp)[1] = a1; ((uint32_t *) dst_sp)[2] = a2; ((uint32_t *) dst_sp)[3] = a3; /* Suspend the OS. */ g_priv_sys_hooks.priv_os_suspend(); /* Stop all lower-than-SVC-priority interrupts. FIXME Enable debug box to * do things that require interrupts. One idea would be to provide an SVC * to re-enable interrupts that can only be called by the debug box during * debug handling. */ __set_BASEPRI(__UVISOR_NVIC_MIN_PRIORITY << (8U - __NVIC_PRIO_BITS)); context_switch_in(CONTEXT_SWITCH_FUNCTION_DEBUG, dst_id, src_sp, dst_sp); /* Upon execution return debug_handler will be executed. Upon return from * debug_handler, return_handler will be executed. */ return; }
static void thread_switch(void * c) { UvisorThreadContext * context = c; UvisorBoxIndex * index; /* Drain any outgoing RPC queues */ drain_outgoing_rpc_queues(); if (context == NULL) { return; } /* Only if TID is valid and the slot is used */ if (!thread_ctx_valid(context) || context->allocator == NULL) { /* This is a debug only assertion, not present in release builds, to * prevent a malicious box from taking down the entire system by * fiddling with one of its thread contexts. */ assert(false); return; } /* If the thread is inside another process, switch into it. */ if (context->process_id != g_active_box) { context_switch_in(CONTEXT_SWITCH_UNBOUND_THREAD, context->process_id, 0, 0); } /* Copy the thread allocator into the (new) box index. */ /* Note: The value in index is updated by context_switch_in, or is already * the correct one if no switch needs to occur. */ index = (UvisorBoxIndex *) *(__uvisor_config.uvisor_box_context); if (context->allocator) { /* If the active_heap is NULL, then the process heap needs to be * initialized yet. The initializer sets the active heap itself. */ if (index->active_heap) { index->active_heap = context->allocator; } } }