EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
大家都知道linux的应用程序要想访问内核必须使用系统调用从而实现从usr模式转到svc模式。下面咱们看看它的实现过程。 系统调用是os操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的执行让用户程序陷入内核,该陷入动作由swi软中断完成。 4 E/ `" k1 Y; E# j1 G
at91rm9200处理器对应的linux2.4.19内核系统调用对应的软中断定义如下:
6 R. o0 `3 h3 Q: H/ r* Q7 F8 s' z#if defined(__thumb__) //thumb模式* Q& d B, H" u" G
#define __syscall(name) /
/ J- w) `" R/ U1 e! f3 e"push {r7}/n/t" /+ N1 F" i) |/ I( z) [% U
"mov r7, #" __sys1(__NR_##name) "/n/t" /
9 r- ]( y6 e `' U. ]$ m"swi 0/n/t" /* e/ Y$ X4 N. e% ]! e1 T; Y7 V& w' q
"pop {r7}" x1 y* e$ m7 x. V# T" u
#else //ARM模式
7 s/ l, B0 ?3 e8 _8 o8 D5 z#define __syscall(name) "swi/t" __sys1(__NR_##name) "/n/t") M& B) B# Y ^, P$ g$ N, w
#endif
6 |4 f0 r ]# ^9 ~( p0 C- Q' L: t9 \- G+ H- e
#define __sys2(x) #x
, {) t1 r- z8 C, O) v4 i! ^#define __sys1(x) __sys2(x)
2 S4 w5 K/ n% x& r#define __NR_SYSCALL_BASE 0x900000 //此为OS_NUMBER << 20运算值
' d# l6 M4 e" L) m#define __NR_open (__NR_SYSCALL_BASE+ 5) //0x900005 5 Z( d- o+ p' H
举一个例子来说: open系统调用,库函数最终会调用__syscall(open),宏展开之后为swi #__NR_open,即,swi #0x900005触发中断,中断号0x900005存放在[lr,#-4]地址中,处理器跳转到arch/arm/kernel/entry-common.S中vector_swi读取[lr,#-4]地址中的中断号,之后查询arch/arm/kernel/entry-common.S中的sys_call_table系统调用表,该表内容在arch/arm/kernel/calls.S中定义,__NR_open在表中对应的顺序号为
/ x' i2 e8 @9 Q3 _* M0 ]; v- m__syscall_start:! l4 K* ]8 c& n# P7 ^; I
...
- h d! ^' [& B9 h.long SYMBOL_NAME(sys_open) //第5个" u3 y2 z9 N& ]% r: j% H2 `( `
... 将sys_call_table[5]中内容传给pc,系统进入sys_open函数,处理实质的open动作 注:用到的一些函数数据所在文件,如下所示 arch/arm/kernel/calls.S声明了系统调用函数 include/asm-arm/unistd.h定义了系统调用的调用号规则
& o) z' t8 l, D2 k9 `vector_swi定义在arch/arm/kernel/entry-common.S7 V% `5 W3 G" N J
vector_IRQ定义在arch/arm/kernel/entry-armv.S# ]6 C- y, u$ e; }2 o/ ?2 N
vector_FIQ定义在arch/arm/kernel/entry-armv.S4 F5 G( a' F# N1 a. {
arch/arm/kernel/entry-common.S中对sys_call_table进行了定义:
: `+ w- K2 P: n1 }4 H.type sys_call_table, #object
, h; l0 j- L+ }7 ]2 {- S, _5 s8 C ZENTRY(sys_call_table)
" U( A r, G# h* j! ~#include "calls.S" //将calls.S中的内容顺序链接到这里" j1 d0 z0 B# q0 M0 I* I) G
源程序:+ j2 c. A$ R: F) h$ p8 h
ENTRY(vector_swi)
! I' b E; ?* j5 j6 Z7 k9 wsave_user_regs! E2 C: x E% \* u2 P
zero_fp
' P( ~6 g3 i% Cget_scno //将[lr,#-4]中的中断号转储到scno(r7) i, R0 N9 B: e7 L0 i" i+ B+ p
arm710_bug_check scno, ip$ l" _6 L0 D( }9 o+ g3 b8 s& m
#ifdef CONFIG_ALIGNMENT_TRAP+ U( g; F4 S) I$ A# V L
ldr ip, __cr_alignment
8 O$ y% N1 R" Z+ hldr ip, [ip]
R' Q/ W( J7 o$ ^3 h4 n6 |mcr p15, 0, ip, c1, c0 @ update control register; w" U( M/ e; c% }
#endif
$ j* G( f$ r; S! ^8 ]$ Z" Kenable_irq ip
; u5 K. P9 B5 b2 i
, ]8 a5 Y2 ?, t" E3 r- Zstr r4, [sp, #-S_OFF]! @ push fifth arg
* v! |. q, P) ^: H E" ~1 j/ I* T/ ]6 G
get_current_task tsk( |: V: C8 J4 N J' I% l& [! Q
ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing
2 {5 i( `" m, J `5 K5 lbic scno, scno, #0xff000000 @ mask off SWI op-code- T& N; ~: a1 D$ {7 W6 ^& y8 u
//#define OS_NUMBER 9[entry-header.S]! |" A1 Z. l- B j& z' \; R
//所以对于上面示例中open系统调用号scno=0x900005( G& d. t# { c; X5 }
//eor scno,scno,#0x900000
* W8 \& J$ G: w$ m- X4 `//之后scno=0x053 N, {7 l+ [- w# I' d' B, B% D$ j3 O
eor scno, scno, #OS_NUMBER << 20 @ check OS number4 z0 d% G* | i3 W& N
//sys_call_table项为calls.S的内容) v) W# y* @+ z5 l
adr tbl, sys_call_table @ load syscall table pointer! U) w( i& E7 }+ f( i3 B; I+ s. j
tst ip, #PT_TRACESYS @ are we tracing syscalls?
$ I) A- P+ P! }$ M% U! U; zbne __sys_trace; r7 U2 v$ c! ^
& Q" \! e m: g6 Sadrsvc al, lr, ret_fast_syscall @ return address
2 q: H: ]: h1 zcmp scno, #NR_syscalls @ check upper syscall limit( L n# r* d4 j2 B
//执行sys_open函数
* ]6 U0 L& B6 A6 Bldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine$ B0 Q: ]7 d2 a( u* k1 |3 o% K/ r
add r1, sp, #S_OFF2 {. K+ o) s R! I
2: mov why, #0 @ no longer a real syscall( ]/ P8 e1 h7 m: f
cmp scno, #ARMSWI_OFFSET: w6 `, P* n* K5 l& k5 R
eor r0, scno, #OS_NUMBER << 20 @ put OS number back
! u, s7 ?, q! o% d1 z1 J1 gbcs SYMBOL_NAME(arm_syscall) + y a1 R% X* ]- w! B9 a( V
b SYMBOL_NAME(sys_ni_syscall) @ not private func
* g/ P! T; u1 q/*0 `' D c; L/ ~& e3 m& d0 x' }
* This is the really slow path. We're going to be doing1 Q) K/ d9 P: E( ?; D- y& z
* context switches, and waiting for our parent to respond." L6 t1 X: r: }" D9 o* a/ |" ^
*/1 o0 m) j: d V R$ O
__sys_trace:' I. M/ Q; x+ z0 \8 }
add r1, sp, #S_OFF. k( W# D7 t( } y5 ]7 i6 v+ G' K$ U% n' g
mov r0, #0 @ trace entry [IP = 0]
' T9 w# u' O8 W6 Pbl SYMBOL_NAME(syscall_trace)
* ?- P. u8 T5 X/*
# c' x* D$ ^+ E8 y//2007-07-01 gliethttp [entry-header.S]
7 J' ^8 o9 \- ]7 `//Like adr, but force SVC mode (if required)$ n' e' T% P, u! s
.macro adrsvc, cond, reg, label0 W8 ^. O0 v* ?' [" o2 T2 }
adr/cond /reg, /label
: ]" ?6 `9 H }.endm
6 F& p- ]4 e" C& p//对应反汇编:$ U6 c( C# L' m1 y; ]2 m% {
//add lr, pc, #16 ; lr = __sys_trace_return
% s W: `( B: |) I. A*/3 n0 o/ `# L l' \/ o
adrsvc al, lr, __sys_trace_return @ return address
8 F5 j" B8 w$ d/ v( o- Z. X" Zadd r1, sp, #S_R0 + S_OFF @ pointer to regs# b% _4 Z0 ^# k
cmp scno, #NR_syscalls @ check upper syscall limit
) W6 c9 K6 S$ Y) j5 x* eldmccia r1, {r0 - r3} @ have to reload r0 - r37 b p6 ~' s( k3 s% w# L
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
) {) ]( Z1 q1 V! Hb 2b- [0 y! c! }* A% ^# F, w) N$ ~
; r" i4 z9 h; E* I( r__sys_trace_return:
" s2 V$ ?. D% [str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
" _: P0 c: b, J N3 j# C* emov r1, sp$ `+ {$ t5 s; ?
mov r0, #1 @ trace exit [IP = 1]. u. p0 a% c% G9 Y
bl SYMBOL_NAME(syscall_trace)
. G/ |' J1 ]+ j! @0 ?3 Eb ret_disable_irq
: Z4 B% E" V% T4 Z: w4 E+ P: s; v% E+ |( _
.align 5
( Y B* v# r! o$ ]: g- b' s#ifdef CONFIG_ALIGNMENT_TRAP
8 h( J/ Q b6 X5 e" c8 F.type __cr_alignment, #object
2 g. E5 ?) U( v a, I! n; k+ B p9 K, d__cr_alignment:
* j1 B) ^* t M) u.word SYMBOL_NAME(cr_alignment)
9 c; {% X* E# G: F0 Q1 P% U. J, Z#endif- ]9 i- q; v) a7 P# Z
.type sys_call_table, #object
" }4 r: C: U* x" j. q' G. d" @% gENTRY(sys_call_table)
! r* j& S# v* b#include "calls.S" 5 _0 C, Y2 G8 @0 N
|