简体   繁体   中英

arm cortex m4 xPSR change when branching

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM