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.
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_usrand then switch back to the previous mode (in your case, IRQ mode).