4
\$\begingroup\$

In the ARM documentation it is stated that:

The processor supports two operation modes, Thread mode and Handler mode. Thread mode is entered on reset and normally on return from an exception. When in Thread mode, code can be executed as either Privileged or Unprivileged.

Handler mode will be entered as a result of an exception. Code in Handler mode is always executed as Privileged, therefore the core will automatically switch to Privileged mode when exceptions occur.

But it doesn't specify if I can just switch back to unprivileged mode inside an interrupt handler, or if the processor will just ignore that. I don't have an M3 handy with me to test at the moment so I am wondering if anyone knows the answer or is able to test?

Basically my scenario is I would like to be able to implement asynchronous "event handlers" from user code that are triggered by some hardware activity, but I want these to run in unprivileged mode, the obvious way to do this is to just have a loop like this in thread mode after setting up the kernel:

while (true) {
    __WFI();
    if (event_triggered) {
        run_event_handler();
    }
}

But the downside is that this code will be constantly running and doing the check whenever any interrupt happens, even if no event handler actually needs to run!

Whereas instead I could simply have a purely interrupt-driven design where whenever the kernel does something that (it knows) will trigger a user event, it can raise, say, a low-priority PendSV which then runs them as needed... but of course that would then run in a privileged context. So can I switch back to unprivileged here?

\$\endgroup\$
  • \$\begingroup\$ Deferring processing from interrupts (to keep the handlers as small as possible) to a main event loop (or background tasks if you have an RTOS) is good practice, regardless of privilege. \$\endgroup\$ – Brian Drummond Jan 7 '18 at 11:52
  • \$\begingroup\$ @BrianDrummond Yes, all other hardware interrupts would be very short and have a higher priority than PendSV (and be able to preempt it) in this scenario. \$\endgroup\$ – Thomas Jan 7 '18 at 11:55
2
\$\begingroup\$

So can I switch back to unprivileged here?

Yes. The simplest method would be to set up another stack for the unprivileged "thread".

Now you can simply switch stacks in the interrupt handler and use the standard "exception return" by moving a special value into the PC.

\$\endgroup\$
  • \$\begingroup\$ Although how do I make this work with sleep-on-exit, if I do a standard "exception return" then this would cause the processor to go back to sleep according to the documentation. And if I disable SLEEPONEXIT before doing that, then I can't turn it back on at the end of the unprivileged code? (I could WFI at the end and then re-enable SLEEPONEXIT at the beginning of any ISR, I suppose...) \$\endgroup\$ – Thomas Jan 8 '18 at 1:41
  • \$\begingroup\$ You cannot run unprivileged code with SLEEEPONEXIT, as the MCU is always in handler mode. \$\endgroup\$ – Turbo J Jan 8 '18 at 2:26
  • \$\begingroup\$ That sucks. I will reconsider whether code privilege is worth losing this feature. \$\endgroup\$ – Thomas Jan 8 '18 at 2:57
0
\$\begingroup\$

CONTROL.nPRIV Defines the Thread mode privilege level:

0 = privileged

1 = unprivileged.

There is no control register for Handler mode privilege level.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.