How to run RTX threads in unprivileged mode, yet access privileged resources(e.g. SCB) when needed. Uses user-defined SVC calls.
In our example, the idler thread wants to put the CPU into low-power mode.
CPPFLAGS += -DOS_PRIVILEGE_MODE=0 __NO_RETURN void osRtxIdleThread (void *unused) { while(2) { __asm( "svc 1" ); /* Vendor-specific low-power mode api, likely writes to SCB->SCR, which is a privileged operation. Yet we are in thread mode here. */ EMU_EnterEM1(); __asm( "svc 2" ); } } static void svcThreadModePrivileged(void) { __set_CONTROL( __get_CONTROL() & ~CONTROL_nPRIV_Msk ); } static void svcThreadModeUnprivileged(void) { __set_CONTROL( __get_CONTROL() | CONTROL_nPRIV_Msk ); } void * const osRtxUserSVC[3] = { (void*)2, (void*)svcThreadModePrivileged, (void*)svcThreadModeUnprivileged, };
Of course the snag is that when the 'main' thread(s) are woken by some event (likely the event that returns from sleep), THEY get to run, and will run in PRIV mode. Only when the idler gets its next look in will it be able to switch back to nPRIV. Perhaps the idler's own priority could be bumped ??
Maybe, instead of "globally" enabling privileged mode with svcThreadModePrivileged and svcThreadModeUnprivileged, use an "svcEMU_EnterEM1" SVC call to call EMU_EnterEM1() from within there. Then only this code runs in privileged mode and does not confuse the rest of the system.
Yes, that would be a more disciplined way of doing things, just would take more code. For each block of code B you would want to run in priv mode, you'd need one slot in the SVC table, correct? But access to those entries is O(1) so no time impact.