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
在这里跳到系统调用函数.
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
在这里跳到系统调用函数.
相关文章推荐
- linux内核分析之系统调用
- 几个系统调用分析 glibc中的malloc调用和共享内存原理
- linux中mmap系统调用原理分析与实现
- Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质
- Linux--Sys_Read系统调用过程分析 http://blog.csdn.net/guopeixin/article/details/5962489
- linux中mmap系统调用原理分析与实现
- linux内核分析笔记----系统调用
- Linux内核分析——系统调用(上)
- 第4节 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用【Linux内核分析】
- Linux系统调用过程分析
- Android调用系统相机以及拉取本地相册的功能实现以及代码分析
- platform_device和platform_driver的注册过程,及probe函数何时调用的分析
- C#中调用API函数RegisterHotKey注册多个系统热键
- FUSE用户态文件系统中自己实现的highlevel接口函数从注册到调用完全追踪
- Linux系统调用的实现机制分析
- poll系统调用的内核态实现机制分析
- JNI注册调用源码分析完整过程-安卓4.4
- Linux内核分析--系统调用【转】
- linux内核分析——扒开系统调用的三层皮(下)
- Linux内核分析05-扒开系统调用的三层皮(下)