如何从 IRQ 模式将用户堆栈指针的值保存到变量中
我正在尝试为 ARM 处理器构建简单且小型的抢占式操作系统(用于试验 ARM 架构)。
我的 TCB
具有指向正确线程堆栈的指针,我正在我的 dispatch()
方法中更新/读取该堆栈 - 像这样(混合 C 和汇编
asm("
ldr r5, =oldSP
ldr sp, [r5]
");
myThread->sp = oldSP;
myThread = getNewThread();
newSP = myThread->sp
asm("
ldr r5, =newSP
str sp, [r5]
");
)我从用户模式(显式调用)调用此 dispatch()
,一切正常 - 线程正在丢失并按其应有的方式获取处理器。
但是,我正在尝试构建抢占式操作系统,因此我需要计时器 IRQ 来调用调度 - 这就是我的问题 - 在 irq 模式下,r13_usr 寄存器是隐藏的,因此我无法访问它。我也无法更改为 SVC 模式 - 它也隐藏在那里。
我看到的一种解决方案是切换到用户模式(在我输入调度方法之后),更新/更改 sp 字段并切换回 irq 模式以继续我离开的地方。这可能吗?
另一个解决方案是尝试不要再次进入 IRQ 模式 - 我只需要处理硬件事务(在定时器外围设置适当的状态位),调用dispatch()(仍然处于 irq 模式),其中我将屏蔽定时器中断,更改为用户模式,进行上下文切换,取消屏蔽定时器中断并继续。恢复的线程应在其暂停处继续(在进入 IRQ 之前)。这是正确的吗? (如果在中断时,处理器将 r4-r11 和 lr 推入用户堆栈,这应该是正确的,但我认为我在这里错了......)
谢谢。
I am trying to build simple and small preemptive OS for the ARM processor (for experimenting with the ARM architecture).
I have my TCB
that have pointer to the proper thread's stack which I am updating/reading from in my dispatch()
method - something like this (mixed C and assembly)
asm("
ldr r5, =oldSP
ldr sp, [r5]
");
myThread->sp = oldSP;
myThread = getNewThread();
newSP = myThread->sp
asm("
ldr r5, =newSP
str sp, [r5]
");
When I call this dispatch()
from user mode (explicit call), everything works all right - threads are losing and getting processor as they should.
However, I am trying to build preemptive OS, so I need timer IRQ to call dispatch - and that is my problem - in irq mode, r13_usr register is hidden, so I can't access it. I can't change to the SVC mode either - it is hidden there, too.
One solution that I see is switching to the user mode (after I entered dispatch method), updating/changing sp fields and switching back to the irq mode to continue where I left. Is that possible?
Another solution is to try not to enter IRQ mode again - I just need to handle hardware things (set proper status bit in timer periphery), call dispatch() (still in irq mode) in which I will mask timer interrupt, change to the user mode, do context switch, unmask timer interrupt and continue. Resumed thread should continue where it was suspended (before entering IRQ). Is this correct? (This should be correct if on interrupt, processor pushes r4-r11 and lr into user stack, but I think I am wrong here...)
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我想我可能在这里回答了类似的问题:“ARM - 从管理员模式访问 R13 和 R14”
在您的情况下,只需使用“IRQ 模式”而不是“管理员模式”,但我认为同样的原则也适用。
长&除此之外,如果你从IRQ切换到用户模式,那就是一扇单向陷阱门,你不能简单地在软件控制下切换回IRQ模式。
但是通过操纵 CPSR 并切换到系统模式,您可以获得 r13_usr,然后切换回之前的模式(在您的情况下为 IRQ 模式)。
I think I might have answered a similar question here: "ARM - access R13 and R14 from Supervisor Mode"
In your case, just use "IRQ mode" instead of "Supervisor mode", but I think the same principle applies.
Long & short of it, if you switch from IRQ to user mode, that's a one-way trap door, you can't simply switch back to IRQ mode under software control.
But by manipulating the CPSR and switching to system mode, you can get
r13_usr
and then switch back to the previous mode (in your case, IRQ mode).通常,您在启动时设置所有这些,各种堆栈寄存器,处理程序等。如果有理由进入用户模式并退出它,您可以从用户模式使用 swi 并让 swi 处理程序执行任何操作你想在用户模式或任务切换到 svc 模式处理程序或类似的东西。
Normally you setup all of this on boot, the various stack registers, handlers, etc. If there is a reason to go to user mode and get out of it, you can use swi from user mode and have the swi handler do whatever it was you wanted to do in user mode or task switch to a svc mode handler or something like that.
您使用哪种 ARM 变体?在像 Cortex_M3 这样的现代变体上,您有 MRS/MSR 指令。这样,您可以通过将 MSP 和 PSP 寄存器移入/移出通用寄存器来访问它们。
CMSIS 甚至将 __get_MSP() 和 __get_PSP() 以及它们的 __set[...] 对应项定义为 C 函数。
编辑:这似乎仅适用于 Thumb-2。抱歉产生噪音。
Which ARM variant do you use? On modern variants like Cortex_M3 you have the MRS/MSR instruction. This way you can access the MSP and PSP registers by moving them to/from a general purpose register.
CMSIS even defines __get_MSP() and __get_PSP() as C functions, as well as their __set[...] counterparts.
EDIT: This seems to work in Thumb-2 only. Sorry for the noise.