2727#include "halt.h"
2828#include "vmpu.h"
2929
30+ /* Wrap a function call into an atomic section with IRQ state restoration. */
31+ #define atomic_call_wrapper (fn ) { \
32+ uint32_t primask = __get_PRIMASK(); \
33+ __disable_irq(); \
34+ fn; \
35+ if (!(primask & 0x01)) { \
36+ __enable_irq(); \
37+ } \
38+ }
39+
3040/* By default a maximum of 16 threads are allowed. This can only be overridden
3141 * by the porting engineer for the current platform. */
3242#ifndef UVISOR_EXPORT_TABLE_THREADS_MAX_COUNT
@@ -584,6 +594,18 @@ static void thread_switch(void * c)
584594 }
585595}
586596
597+ /* uVisor expects all calls to its API to be executed in the highest priority
598+ * interrupt (SVC) since they are not re-entrant.
599+ * If this is not the case, we need to make sure that no other interrupt can
600+ * preempt these calls by wrapping them in an atomic section.
601+ */
602+ static void thread_switch_atomic (void * c )
603+ {
604+ atomic_call_wrapper (
605+ thread_switch (c )
606+ );
607+ }
608+
587609static void boxes_init (void )
588610{
589611 /* Tell uVisor to call the uVisor lib box_init function for each box with
@@ -606,7 +628,7 @@ const TUvisorExportTable __uvisor_export_table = {
606628 .pre_start = boxes_init ,
607629 .thread_create = thread_create ,
608630 .thread_destroy = thread_destroy ,
609- .thread_switch = thread_switch ,
631+ .thread_switch = thread_switch_atomic ,
610632 },
611633 .pool = {
612634 .init = uvisor_pool_init ,
0 commit comments