arm linux中断向量注册分析,linu系统调用分析

2012-10-18 luoqindong


linux的中断向量从0xffff0000开始,该位置的内容在early_trap_init()函数中初始化:
/*
* Copy the vectors, stubs and kuser helpers (in entry-armv.S)
* into the vector page, mapped at 0xffff0000, and ensure these
* are visible to the instruction stream.
*/
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);


该函数调用过程:
start_kernel->setup_arch->early_trap_init
init/main.c   
arch\arm\kernel\setup.c  
arch\arm\kernel\traps.c


vectors的地址为0xffff0000, __vectors_start等几个标号在arch\arm\kernel\entry-armv.S中定义.


.globl __vectors_start
__vectors_start:
swi SYS_ERROR0
b vector_und + stubs_offset
ldr pc, .LCvswi + stubs_offset
b vector_pabt + stubs_offset
b vector_dabt + stubs_offset
b vector_addrexcptn + stubs_offset
b vector_irq + stubs_offset
b vector_fiq + stubs_offset


.globl __vectors_end
__vectors_end:


__vectors_start和__vectors_end之间保存的是arm的7个中断向量.
向量0是reset,但是这里被修改了,如果是cpu跑到了0地址,说明是系统出错,
用软件中断SYS_ERROR0来处理.


下来的几个标号vector_und 是通过宏vector_stub来产生的,
.macro vector_stub, name, mode, correction=0
.align 5


vector_\name:
.if \correction
sub lr, lr, #\correction
.endif


@
@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
@ (parent CPSR)
@
stmia sp, {r0, lr} @ save r0, lr
mrs lr, spsr
str lr, [sp, #8] @ save spsr


@
@ Prepare for SVC32 mode.  IRQs remain disabled.
@
mrs r0, cpsr
eor r0, r0, #(\mode ^ SVC_MODE)
msr spsr_cxsf, r0


@
@ the branch table must immediately follow this code
@
and lr, lr, #0x0f
mov r0, sp
ldr lr, [pc, lr, lsl #2]
movs pc, lr @ branch to handler in SVC mode
.endm


vector_und 等几个标号被定义在__stubs_start --- __stubs_end中间.
.globl __stubs_start
__stubs_start:


/*
 * Interrupt dispatcher
 */
vector_stub irq, IRQ_MODE, 4


.long __irq_usr @  0  (USR_26 / USR_32)
.long __irq_invalid @  1  (FIQ_26 / FIQ_32)
.long __irq_invalid @  2  (IRQ_26 / IRQ_32)
.long __irq_svc @  3  (SVC_26 / SVC_32)
.long __irq_invalid @  4
.long __irq_invalid @  5
.long __irq_invalid @  6
.long __irq_invalid @  7
.long __irq_invalid @  8
.long __irq_invalid @  9
.long __irq_invalid @  a
.long __irq_invalid @  b
.long __irq_invalid @  c
.long __irq_invalid @  d
.long __irq_invalid @  e
.long __irq_invalid @  f


.globl __stubs_end
__stubs_end:




每个cpu模式都定义的16个变量,但是只是第1个和第4个是有效的,因为linux只运行在
usr和svc模式下,它只会从这两个模式跳到异常向量地址.有16个变量是根据CPSR的低4位

来定义的,



虽然cpsr的cpu模式根据低5位来定,但是可以根据低4位区分开,所以只用了低4位.



只算低4位,usr是0,svc是3.


stubs_offset被定义为:
.equ stubs_offset, __vectors_start + 0x200 - __stubs_start


调用early_trap_init之后,0xffff0000的内容为:

arm linux中断向量注册分析,linu系统调用分析_第1张图片


b vector_irq + stubs_offset 
b     vector_irq + __vectors_start + 0x200 - __stubs_start
该语句的意思是b到vector_irq加上偏移量stubs_offset.
该语句的作用就是跳到vector_irq这个标号.


在entry-armv.S中,__stubs_start和__stubs_end定义在__vectors_start的前面,


__stubs_start:
vector_irq:
......
__stubs_end:


__vectors_start:  
......
b vector_irq + stubs_offset
__vectors_end:


以vector_irq为基点去算,先看成
b vector_irq
跳到了vector_irq标号处,再加上__vectors_start - __stubs_start,等于跳到了
__vectors_start处,再加上0x200,0x200开始的地方就是early_trap_init copy过去的
__stubs_start
...
__stubs_end
之间的内容.


b vector_dabt + stubs_offset
先跳到vector_dabt,加上__vectors_start - __stubs_start,如果__vectors_start处
也放有
__stubs_start
...
__stubs_end


那这时就跳到了__vectors_start处的vector_dabt,再加上0x200,0x200开始也是
__stubs_start
...
__stubs_end
所以跳到了正确的地址.




所有的系统调用接口都可以在arch\arm\kernel\call.S文件里边找到,
/* 0 */ CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)


CALL是宏,在arch\arm\kernel\entry-common.S文件里边定义,CALL被定义为两种情况.
第一次:
.equ NR_syscalls,0
#define CALL(x) .equ NR_syscalls,NR_syscalls+1
#include "calls.S"
#undef CALL
#define CALL(x) .long x


这里是为了计算有多少个NR_syscalls,后面重新定义CALL 为.long x


所有的系统调用号在arch\arm\include\asm\unistd.h中定义.
这里定义了系统调用表,所有的系统调用函数都在这表里边:
.type sys_call_table, #object
ENTRY(sys_call_table)
#include "calls.S"
#undef ABI
#undef OBSOLETE


这里取得系统调用号码:
#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
ldreq scno, [lr, #-4]
#else


ne就是结果不为0,eq就是结果为0.
在arm模式下,第2条语句不执行,第三条语句从swi指令中取得系统调用号.


swi指令的低24位是系统调用号:
#elif !defined(CONFIG_AEABI)
bic scno, scno, #0xff000000 @ mask off SWI op-code
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
#endif
__NR_SYSCALL_BASE在 arch\arm\include\asm\unistd.h里边定义为0.


cmp scno, #NR_syscalls @ check upper syscall limit
adr lr, ret_fast_syscall @ return address
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
在这里跳到系统调用函数.


你可能感兴趣的:(exception,linux,vector,include,wrapper,branch)