-
Notifications
You must be signed in to change notification settings - Fork 25
FreeRTOS-MPU: Read running task stack pointer from $sp register #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
During ISRs and other exception handlers, $sp uses one of the banked r13 registers (r13_irq, r13_fiq, etc.). Use $r13_usr if available instead.
Thanks for starting implementing this 👍. Please let me check some things during next week. We should still do some additional checks as discussed in the issue (interrupt). Also I currently do not see a need to only do it for the MPU enabled version. @haneefdm What do you think? |
If at all possible, we should do it for all cases. I just haven't finished thinking it through. But it does bring up another topic. Is this for FreeRTOS only? Ideally the non-MPU case applies to all and we can implement it uniformly. If we only have time to do it for FreeRTOS, fine. We should put it in a TODO list.
@malsyned, so this means I should remember not do a "Squash and merge" when accepting this PR? That is the default |
I'm late to thinking about this, it's only been on my mind since the MPU-enabled port I'm working with behaves so radically differently w.r.t. the stack. Here's where my head's at on this, though: On architectures that don't use a separate interrupt stack, However, on architectures with a separate interrupt stack and banked registers, like The MPU adds an additional wrinkle that makes MPU, not using MPU, using For myself, I'd rather have behavior that is consistent, and that always works when not halted in an ISR, than behavior that may or may not be correct depending on recent past events. That's why I created this PR that only uses On architectures with a dedicated ISR stack, I think any work-around would be necessarily platform-specific. My PR's second commit adds the platform-specific workaround for Cortex-A/R, which is to try The promised MPU gory details: In addition to possibly having separate hardware support for the ISR stack, FreeRTOS-MPU uses a separate per-task stack for system calls. Whenever a non-privileged task voluntarily relinquishes the CPU, the saved stack pointer (stored in |
My personal opinion is that it's better to have up-to-date Stack Top & Stack Used in regular code at the cost of surprising results on some architectures while in an ISR. However, I can easily see how reasonable people could disagree about this, especially since users may experience it as a regression. I created this more limited MPU-only PR in the hopes that you'll find it easier to get comfortable with merging, since the case for it being an improvement or even just a bug fix is more clear-cut.
For this PR, I'm thinking of the use of
If you all decide you don't want the second commit with the Cortex-A/R-specific fix for Stack Top reporting during ISRs, just let me know and I'll reset my PR branch to be just the first commit. Then you can squash and merge as normal. |
@malsyned Keep your PR the way it is. It serves as a reminder for me not to squash the commits. Lets give @PhilippHaefele a bit more time to put in his comments/concerns before I merge. Let's also document that stack may not be correct when stopped inside an ISR. |
I'm a little bit confused about this. I did a quick look and at least for most of the Cortex-M ports of FreeRTOS and uC/OS-II do use the PSP for the tasks and to my knowledge interrupts always use the MSP. And that's where we need the special handling. Something like this should be the way to go (at least for Cortex-M): Check if we're in an interrupt (e.g. via the CONTROL register) -> when so we either consider using the PSP or the last saved one (I don't think that someone will break in the SVC handler and do expect that our values are precise + old task shouldn't be running anymore) -> if not we can use the SP which in this case has the same value as the PSP. After writing this we maybe just consider using the PSP for the currently running task when available... 🤔 |
As I think that this handling mainly has architectural elements, we can easily adapt the other RTOS implementation too. There is a small chance that some ports e.g. do not use the PSP stuff from Cortex-M but I do not see a lot of reasons not to do this. Regarding the hint I also have something in mind. Maybe printing the architecture next to detected RTOS (we do have a function since the last MR now to check at least for some of them) and add a hint when we do not properly support/know the architecture somewhere (e.g. below the table) |
That's my mistake, I haven't worked with Cortex-M in a while, and I got it confused with some other architectures in my head. I'll go back and strike out the parts of my posts that relate to that mistake.
If I'm understanding this right, then I think always using PSP is the right move. The XRTOS tab is talking about the task's stack position and usage, not the stack as seen by ISR and other non-task frames. The regular debugger backtrace can tell you everything you need to know about the ISR's stack while it's executing. So (unless I'm still mistaken about PSP and MSP), PSP will always unambiguously give the currently running task's stack pointer regardless of whether an ISR is executing, and can be preferred to SP whenever it exists. Is my reasoning sound there? One thing we haven't talked about, and I don't know how to deal with, is multi-core. If there is more than one task in the RUNNING state, will rtos-views see the right value of SP / PSP / R13_USR for each of them by virtue of passing the correct frameId, or is there something more that has to be done? |
During ISRs and other exception handlers, $sp is linked to $msp. Use the task stack pointer $psp if available instead.
Just pushed a new commit that adds Cortex-M Note that none of this is using the architecture detection yet. The only real value to doing so would be the possibility of a slight speed-up under some circumstances by avoiding trying Another thing to note is that while the target description from JLinkGDBServer calls the Cortex-A/M register |
Thanks for adapting your comments and code. I will try to test the code with ARMv7-M & ARMv8.1-M, so we`re more confident about the new approach with PSP (e.g. as the 8 8.1 introduces additional safe contexts with additional stack pointers). Also not sure about multi core there was a discussion/MR regarding this for the FreeRTOS in the past. |
Very good question about multi-core. But this is a problem even within a gdb-server. I have no idea what OpenOCD/JLinkServer are actually telling GDB? Also when you are multi-core, then we may have multiple RUNNING threads. Now, if we evaluate the |
Was able to do some testing this week. It does in general work on ARMv7-M (M7) & ARMv8.1-M (M85). As I`m not yet into secure state stuff of the M85, I can't guarantee that it is still working properly when we have NON-Secure & Secure running. PSP works fine for both of them with Cortex Debug + an adapted version of the uC/OS-II support code (was quite easy to adapt). From my side we can merge this and I will try to get support into to other RTOS implementations I maintain soon |
When a non-privileged task voluntarily relinquishes the CPU,
ulContext
containsa pointer into the system call stack, rather than the task stack. While that
task is paused,
pulTaskStack
(pulTaskStackPointer
on some ports) will contain abackup of the task's stack pointer.
However, when that task returns to a RUNNING state,
pulTaskStack
gets zeroed andthe only way to get a stack top that bears any resemblance to reality is to read
directly from the stack pointer register.
Note that this can still have surprising results if the program is halted in an
ISR or system call on architectures which use dedicated exception stacks. The
second commit in this PR adds a Cortex-A/R-specific workaround for this. It's a
separate commit in case it proves to be controversial.