Search code examples
assemblyoperating-systemarmcpu-registerscontext-switch

Why doesn't this pop instruction restore the register values?


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

Solution

  • 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.