I am writing an operating system... I am working on context switching .. I can switch the kernel into user program and go back. but SVC call seems not work well.
syscall:
svc SYSCALL_SVC_NUMBER
bx lr
when calling svc it trigger interrupt, I can see the control flow go back to kernel. The hard fault arise when it gets back to user program.
around here --> bx lr
I've checked that all the registers are correctly loaded, except that xPSR lacks of thumb bit. That's why the hard fault comes.
But I have no idea why xPSR is clear to zero...
.global activate
activate:
/* save kernel state in ip register */
mrs ip, psr
push {r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}
/* switch to process stack */
msr psp, r0
mov ip, #2
msr control, ip
ldr ip, [sp, #0x38]
msr psr_nzcvq, ip
/* load user state */
pop {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
add sp, #0x8
ldr ip, [sp, #-0x8]
/* this line can branch correctly */
bx ip
Ahh, yes, you are right, but you dont need to modify anything at the same time.
Using this code for example
mov r1,#0x22
mov r2,#0x33
mov r3,#0x44
mov r0,#0x55
mov r12,r0
mov r0,#0x66
mov r14,r0
mov r0,#0x11
svc #1
The stack looks like this when it hits the svc handler
Fairly certain this is documented
20000FD4 FFFFFFF9 return address
20000FD8 00000011 r0
20000FDC 00000022 r1
20000FE0 00000033 r2
20000FE4 00000044 r3
20000FE8 00000055 r12
20000FEC 00000066 r14
20000FF0 0100009E r15
20000FF4 21000000 xPSR
On an exception on a cortex-m they behave in hardware in a way that can call a C function directly per their calling convention. Understand that the program counter itself has an lsbit of 0, the lsbit of 1 thing is for BX, BLX and POP, it is used by those instructions to determine ARM or THUMB mode, the bit is stripped then used as the PC.
The return from an SVC can/should look like the above. if you want to use svc or any other interrupt to do a context switch you need to build the stack to match.
there is a bit of a chicken and egg problem of course, for each thread you build a stack image like the above
20000FD4 FFFFFFF9
20000FD8 00000011
20000FDC 00000022
20000FE0 00000033
20000FE4 00000044
20000FE8 00000055
20000FEC 00000066
20000FF0 01001234
20000FF4 21000000
but you can put dont cares in the registers except for the pc which you set to the entry point of your thread. with the lsbit not set. Also you need some structure where you keep the state of the other registers.
then when you context switch you save the registers other than the above in a structure somewhere, which includes the sp, you then fill in those registers from the next thread including its sp. then you bx lr to return.
there is a little more to it than that, see atomthreads or chibios or other open source, functional OS.
You are correct the address that was interrupted or in this case the address after the svc, the program counter, is on the stack without the lsbit set, but at the same time that is correct. The actual lr used to return from the exception (svc or timer interrupt or whatever) is the special "exception return" 0xFFFFFFxx which has the lsbit set.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.