lr holds user return address (location following swi instruction)
must be saved (as part of user context) for later return to user task
choices for getting user context:
enter system mode, or
use special version of stm instruction
choices for storing user context:
on user stack, or
in task descriptor
then restore kernel context
Kernel Exit
store kernel context (similar to voluntary stack switch)
restore given user context (next task to be run)
return to user mode, for example
movs pc, lr
variant of mov that changes processor mode
System Call Processing
these are suggestions - other implementations are possible...
SWI argument N can be retrieved as follows
lr points to instruction following swi ⇒ lr-4 points to swi instruction
read during context switch:
ldr r12, [lr, #-4] @ r12 just an example
or afterwards in kernel (lr stored in context)
mask low 24 bits to obtain N
kernel needs access to system call parameters
leave first four arguments in r0-r3: save during context switch
additional arguments on user stack; see ABI
Additional Information
An earlier document by Bill Cowan is available here.
This is certainly not the only way to write a context switch and I do not necessarily recommend (or not recommend) this particular approach, but I figure every bit of information can help.
Mixing C and Assembler
Coding
See various examples file in demo05. Take a look at the compiled .s source
main.c, adder.c - basic argument passing in r0, r1
adder6.c - beyond 4 arguments passed on stack
main.c, asm_adder.S - manual assembler routine working with C caller
main3.c, data_adder.c - memory-based data exchange between C and assembler
asm.c - embed assembler in C code; exchange data with local variables
special register access: msr/mrs for cpsr, spsr
special register access: mcr/mrc for co-process registers cp15
Recommendations
use embedded assembler via asm only for short code sequences that do not access sp
use assembler routine linked as C routine for context-switch code