您的位置:首页 > 运维架构 > Linux

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

2012-10-20 21:37 148 查看
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的内容为:



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

在这里跳到系统调用函数.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: