I'm currently doing some work to an RTOS to allow two kernels to be operating simultaneously on an M33 core, one in Secure flash/RAM and one in Non-Secure. I've got things *just* about working stably, but I'm having some trouble reading the banked Non-Secure ICSR register bits while in Secure mode.
Here is the register's documentation page: https://developer.arm.com/documentation/100235/0004/the-cortex-m33-peripherals/system-control-block/interrupt-control-and-state-register?lang=en)
The CMSIS headers indicate ICSR can be found at 0xE000ED04, and a specficially-Non-Secure version at 0xE002ED04.
The RTOS uses the standard approach to context switching by setting PendSV and using BASEPRI and whatnot to control synchronization. Everything has been working very well in that sense; the RTOS is reasonably mature, and this issue has only popped up when doing two kernels at once.
My approach is to make a few assumptions about what a Non-Secure "thread" means (i.e. it's the Non-Secure kernel) and I've replaced the Non-Secure kernel setting its PendSV interrupt with a Non-Secure Callable API that asks the Secure kernel to -- when it's ready -- pend the Non-Secure PendSV so the Non-Secure kernel can do its stuff.
What can also happen is that the thread for running the Non-Secure kernel can get swapped in with the Non-Secure PendSV getting set by the Secure kernel (since Non-Secure requested it), but then during the process someone else might have the Secure kernel swap in a different, Secure-based thread (which is entirely okay in the eyes of the RTOS; PendSV is the lowest-possible priority, and it specifically re-allows interrupts after it's swapped out a thread and picked up the thread to swap back in). Once this happens, the Secure PendSV should exit as normal but then fire again right away, since someone re-set the Secure PendSV when it requested a context change occur. Once the Secure PendSV comes back and swaps out the thread for the Non-Secure kernel, my hope was to be able to read the PENDSVCLR bit in ICSR and, if set, clear it and make sure to re-set the thread's request flag so that the next time the thread is swapped in, the Non-Secure PendSV is pended again.
BUT, what appears to happen is that the Secure PendSV read of the PENDSVSET bit in the Non-Secure ICSR register -- which should be available using 0xE002ED04 specifically to grab the Non-Secure version of the banked bits -- always returns 0, meaning I can't guarantee that, if I swap out the thread for the Non-Secure kernel before it is able to service its PendSV interrupt, it'll still get to have that interrupt the next time I swap it back in.
Is there a different way I can see that the Non-Secure PendSV interrupt is pending while in the Secure Handler mode of the M33 core?
Before realizing this was occurring, I was seeing integrity checks fail because the Non-Secure PendSV was being kept (since the Secure kernel didn't see it pending and thus wasn't clearing it), a Secure thread was being swapped in in the situation above, but then the Non-Secure kernel was getting its PendSV interrupt and doing context switching stuff, which includes manipulating EXC_RETURN's FTYPE bit before popping out and back to Secure Thread mode -- at which point the integrity check fails. If I just blindly clear the Non-Secure PendSV when swapping in a Secure thread, this problem goes away, and the two kernels are vastly more stable together. But, I still worry about consequences of missing a Non-Secure PendSV operation.
Hopefully someone has some input on an admittedly-niche problem. Thanks!
Oh boy, I sure do love making an account to ask a question, and then realizing I was just simply an idiot. Looks like my rusty ASM caused me to not actually read the register, but rather the address of it... Changing that fixes my fetching of the Non-Secure bit.
Now just mark the question as "answered" ;-)
View all questions in Cortex-M / M-Profile forum