I'm studying an OS implemented in a stm32f103rb. I arrived at 02-ContextSwitch-1 chapter and found that the program crashes and throws this error.
qemu: fatal: Trying to execute code outside RAM or ROM at 0x681b4b14
R00=00000003 R01=00000000 R02=4000440c R03=00000000
R04=2000a000 R05=08000129 R06=08000191 R07=08000197
R08=af00b480 R09=681b4b17 R10=f0434a16 R11=60130305
R12=01000000 R13=00000024 R14=681b4b15 R15=681b4b14
PSR=00000173 ---- T svc32
FPSCR: 00000000
make: *** [Makefile:22: qemu] Aborted (core dumped)
After a little debugging I found that the problem is in function activate.
.thumb
.syntax unified
.global activate
activate:
/* save kernel state */
mrs ip, psr
push {r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}
/* switch to process stack */
msr psp, r0
mov r0, #3
msr control, r0
/* load user state */
pop {r4, r5, r6, r7, r8, r9, r10, r11, lr}
/* jump to user task */
bx lr
At the beginning of the function these are the register values
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0x20009bd0 0x20009bd0
lr 0x800011f 134218015
At the end of the function, after pop
has been executed, the register values where not restored.
r4 0x2000a000 536911872
r5 0x8000129 134218025
r6 0x8000191 134218129
r7 0x8000197 134218135
r8 0xaf00b480 -1358908288
r9 0x681b4b17 1746619159
r10 0xf0434a16 -264025578
r11 0x60130305 1611858693
r12 0x1000000 16777216
sp 0x24 0x24
lr 0x681b4b15 1746619157
This causes a jump to address 0x681b4b15 and the corresponding error.
Why did this happen?
Edit: registers R0-R3 don't seem to be corrupted.
At the beginning.
r0 0x0 0
r1 0x0 0
r2 0x4000440c 1073759244
r3 0x0 0
At the end.
r0 0x3 3
r1 0x0 0
r2 0x4000440c 1073759244
r3 0x0 0
The problem is that the stm32-p103 in qemu only has 20K of memory not 40K as the linker script expects. The stack therefore happens to be placed in non-existent memory. Change the linker script to say:
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
In case you are trying to match up the push
with the pop
, remember that the former is on the kernel stack and the latter is on the user stack. It is not supposed to restore the values pushed, it will get the values set in os.c. The kernel values are saved for future use.