系统调用的处理分为两部分。
- 从系统调用开始到进行
处理器异常进入 previllege 模式。
对于 ARM,此模式将是 SVC(主管)模式。
这部分涉及用正确的系统调用号填充通用寄存器,要在系统调用中传递的参数,
并将处理器的状态触发为特权模式。
- 第二部分(比第一部分复杂一点)涉及在特权模式下处理系统调用,并从特权模式返回。
2a。在 ARM 的异常表中,控件由异常向量(在本例中为 SVC)引导到异常的公共处理程序。
以下是 SVC 的异常向量:
[文件:arch\arm\kernel\entry-armv.S]
W(ldr) pc, __vectors_start + 0x1000
以下是异常处理程序的入口:
[文件:arch\arm\kernel\entry-armv.S]
vector_\name:
.if \correction
sub lr, lr, #\correction
.endif
2b。在这个公共处理程序结束时,r0,lr 和 spsr 分别保存在堆栈上的 [SP]、[SP+4] 和 [SP+8] 地址。
[文件:arch\arm\kernel\entry-armv.S]
stmia sp, {r0, lr} @ save r0, lr
mrs lr, spsr
str lr, [sp, #8] @ save spsr
2c。然后,通用处理程序将控制器转移/分支到 SVC 特定处理程序:
[文件:arch\arm\kernel\entry-armv.S]
mrs lr, spsr
...
and lr, lr, #0x0f
...
ARM( ldr lr, [pc, lr, lsl #2] )
movs pc, lr @ branch to handler in SVC mode
...
.word vector_swi
在公共处理程序结束时,控制器被转移到SVC处理程序vector_swi。
2d。现在让我们看看如何在 SVC 处理程序中处理 syscall。
将 SP 按以下顺序在新的 FRAME 处推进后,调用者的上下文保存如下:
[文件:arch\arm\kernel\entry-common.S]
ENTRY(vector_swi)
...
(r0-r12,sp,lr)_usr_mode, lr_exp(本例中为exp=svc)
此上下文将用于通过存储 r0-r12,sp,lr,pc 通过此上下文的值从 SVC 模式返回到用户模式。
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0 - r12
ARM( add r8, sp, #S_PC )
ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr
...
mrs r8, spsr @ called from non-FIQ mode, so ok.
str lr, [sp, #S_PC] @ Save calling PC
2e。系统调用号根据过程调用标准获取,最终存储在scno(r7 register)中。
[文件:arch\arm\kernel\entry-common.S]
elif defined(CONFIG_AEABI)
/*
* Pure EABI user space always put syscall number into scno (r7).
*/
#elif defined(CONFIG_ARM_THUMB)
/* Legacy ABI only, possibly thumb mode. */
tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs
addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in
...
2f。然后,sys_call_table的地址存储在tbl register(r8)中。
[文件:arch\arm\kernel\entry-common.S]
adr tbl, sys_call_table @ load syscall table pointer
sys_call_table 包含根据其编号的系统调用列表。
文件 call.S 包含列表。
[文件:arch\arm\kernel\entry-common.S]
ENTRY(sys_call_table)
#include "calls.S"
#undef ABI
...
2g。然后,正确的系统调用处理程序将通过分支到具有系统调用编号偏移量的 sys_call_table 来参与。
重发地址设置在标签“ret_fast_syscall”处。
[文件:arch\arm\kernel\entry-common.S]
adr lr, BSYM(ret_fast_syscall) @ return address
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
...
2 小时。然后,以这样一种方式恢复用户模式寄存器,即 (r0-r12,sp,lr,pc)_usr_mode 从步骤 2d 中存储的值中存储。
这是在宏“restore_user_regs”中完成的。
[文件:arch\arm\kernel\entry-common.S]
ret_fast_syscall:
...
restore_user_regs fast = 1, offset = S_OFF
...
[文件:arch\arm\kernel\entry-header.S]
macro restore_user_regs, fast = 0, offset = 0
mov r2, sp
...
.if \fast
ldmdb sp, {r1 - r12} @ get calling r1 - r12
.else
ldmdb sp, {r0 - r12} @ get calling r0 - r12
.endif
add sp, sp, #S_FRAME_SIZE - S_SP
movs pc, lr @ return & move spsr_svc into cpsr
.endm