EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
大家都知道linux的应用程序要想访问内核必须使用系统调用从而实现从usr模式转到svc模式。下面咱们看看它的实现过程。 系统调用是os操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的执行让用户程序陷入内核,该陷入动作由swi软中断完成。 7 u/ k5 z4 O9 l/ J
at91rm9200处理器对应的linux2.4.19内核系统调用对应的软中断定义如下:% f6 G3 y% _" t% R' Q
#if defined(__thumb__) //thumb模式; m, R' Q0 u( J% e
#define __syscall(name) /8 s, f. O6 i4 _
"push {r7}/n/t" /1 z5 t) Y6 t0 X: t3 x
"mov r7, #" __sys1(__NR_##name) "/n/t" /. t$ U' m& V' z3 y% d6 O- P( P
"swi 0/n/t" /
# `2 x3 P1 O2 J$ x8 V9 Y"pop {r7}"
% F- a( s' m; \#else //ARM模式
( ? G8 Y) g/ d+ e' t#define __syscall(name) "swi/t" __sys1(__NR_##name) "/n/t"
$ ?7 E$ i2 q) O" @" G#endif
; C1 q" W! z1 ~5 u0 p# u+ X
; p& s- u) J3 N I9 [4 C#define __sys2(x) #x) F3 q5 g. x' s% x* p
#define __sys1(x) __sys2(x)7 `6 V$ D5 x* @6 s
#define __NR_SYSCALL_BASE 0x900000 //此为OS_NUMBER << 20运算值- W2 {' D6 U2 \4 y# l2 \
#define __NR_open (__NR_SYSCALL_BASE+ 5) //0x900005 ! }; n0 v5 z- R, C1 y
举一个例子来说: 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在表中对应的顺序号为 B$ R% R4 q4 u5 s" ?
__syscall_start:
0 @! w+ B% `* |: x0 n& a2 x...6 m9 L8 m( ~9 C
.long SYMBOL_NAME(sys_open) //第5个
; B6 Q3 U) W; ~. ]4 ~... 将sys_call_table[5]中内容传给pc,系统进入sys_open函数,处理实质的open动作 注:用到的一些函数数据所在文件,如下所示 arch/arm/kernel/calls.S声明了系统调用函数 include/asm-arm/unistd.h定义了系统调用的调用号规则
- ^- C h: P ?7 Q/ nvector_swi定义在arch/arm/kernel/entry-common.S
* a G9 }: d, S! dvector_IRQ定义在arch/arm/kernel/entry-armv.S/ N5 b% v+ @% A0 d0 n
vector_FIQ定义在arch/arm/kernel/entry-armv.S1 @. s M$ p! a* P$ G6 y5 F
arch/arm/kernel/entry-common.S中对sys_call_table进行了定义:4 t$ B- k2 D" k ?" T
.type sys_call_table, #object# E" H1 {; F0 n5 w
ENTRY(sys_call_table)
' v' p' |: P" j8 ? R#include "calls.S" //将calls.S中的内容顺序链接到这里
$ u0 [- V. C( r; t! h9 W源程序:* e3 l! [ r% x4 \+ U+ B
ENTRY(vector_swi)0 y4 Q! y4 s9 }0 F' {. b
save_user_regs$ T* c+ ^, K1 Z* I6 e
zero_fp: N6 Z4 r6 g2 z& C1 t- l4 ^
get_scno //将[lr,#-4]中的中断号转储到scno(r7)/ C1 [# q4 b) l
arm710_bug_check scno, ip" k" e$ I# p, w
#ifdef CONFIG_ALIGNMENT_TRAP4 w* [3 P ?4 _- I) ~: A
ldr ip, __cr_alignment2 x! l! K, ~# z9 b4 l. K
ldr ip, [ip] a7 ~( {. c5 p3 }* U; |; C
mcr p15, 0, ip, c1, c0 @ update control register( z0 ] k& j/ g; s8 f0 j, X2 J
#endif
6 ^* R' }, b1 E) genable_irq ip
- ]3 F1 G5 b% Y. N9 K I" o! |; o9 m9 J9 N7 _; Y
str r4, [sp, #-S_OFF]! @ push fifth arg
3 Q, u- G7 r* H9 V! m* J; B# b, s6 v* P. b ?3 Z& b: x! I
get_current_task tsk
6 O' Y( h* y, D. @ [5 U+ q6 Zldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing
4 k4 Q- o, n% B+ mbic scno, scno, #0xff000000 @ mask off SWI op-code
2 E, m% _2 }$ ^3 G//#define OS_NUMBER 9[entry-header.S]
% s: m" m4 D0 b//所以对于上面示例中open系统调用号scno=0x900005
8 {6 o# @; F6 b# Q/ x//eor scno,scno,#0x9000007 f/ x) R3 q* j* S3 a- C; W
//之后scno=0x05
) h1 z: I: b( p& P+ [8 o6 `! Teor scno, scno, #OS_NUMBER << 20 @ check OS number
+ d6 U5 q9 R' [3 M+ _$ c7 s//sys_call_table项为calls.S的内容
0 z) v8 k) Q3 r; C3 Hadr tbl, sys_call_table @ load syscall table pointer
+ W% g1 G$ n! Z. _tst ip, #PT_TRACESYS @ are we tracing syscalls?
/ i2 I# y4 C qbne __sys_trace$ }8 O* `+ L/ `4 D6 M
: m9 v. f" ~3 u* K( U
adrsvc al, lr, ret_fast_syscall @ return address# _; i. d8 m/ x! u
cmp scno, #NR_syscalls @ check upper syscall limit' a* y7 `7 d. l$ T. H- Q. R; P3 D
//执行sys_open函数
+ q e& o. d/ ]* q. Q. Rldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine7 G- g% K/ _; d' \+ ^) y
add r1, sp, #S_OFF; }) m4 ]& R# u9 i
2: mov why, #0 @ no longer a real syscall$ a- M Y# d, V5 |
cmp scno, #ARMSWI_OFFSET0 C8 a+ p# y, Y( r# d
eor r0, scno, #OS_NUMBER << 20 @ put OS number back3 F) _/ g. }- H0 J8 Q, p
bcs SYMBOL_NAME(arm_syscall)
5 F7 {2 L9 a; j8 B8 ~3 Tb SYMBOL_NAME(sys_ni_syscall) @ not private func
8 C% @& y @1 ]! K/*! q s2 c7 j [8 J1 ^
* This is the really slow path. We're going to be doing
9 m$ ` {& r" g3 r Y2 M5 t1 j* context switches, and waiting for our parent to respond.- Q# l4 Z* Z0 P
*/( i, G$ p2 X9 }" s" o& H+ r
__sys_trace:
) r9 f. l; N& c) M* |7 d8 Q5 yadd r1, sp, #S_OFF
2 g$ s% O3 {; o3 G5 `2 P1 P A! Vmov r0, #0 @ trace entry [IP = 0]
$ K- N; g' r$ ^ Abl SYMBOL_NAME(syscall_trace)7 U2 E; q, A# g7 {# v; l% ]
/*
7 i# f: j: s$ Q2 [% j; ?4 T& m$ ~//2007-07-01 gliethttp [entry-header.S]' L8 J6 }1 V) f& r
//Like adr, but force SVC mode (if required)
! [! X4 @* U! s! @: f5 I( C.macro adrsvc, cond, reg, label8 ]( Z M2 l1 q
adr/cond /reg, /label
5 b+ L) l/ k! e.endm- \, x# p1 ~) l5 I8 I9 i+ u6 o* V
//对应反汇编:5 {1 C6 l, t; C. j) W
//add lr, pc, #16 ; lr = __sys_trace_return) F: r( F' j) z0 d8 q
*/
8 i6 M0 ^; ?4 n( g }adrsvc al, lr, __sys_trace_return @ return address+ |% f9 W/ Q6 |$ k
add r1, sp, #S_R0 + S_OFF @ pointer to regs' ?% n% k. _- @* u x; N
cmp scno, #NR_syscalls @ check upper syscall limit
6 t/ q3 b! V! R9 |% C, \! b+ [& Aldmccia r1, {r0 - r3} @ have to reload r0 - r3
X# e* J% } W( H7 ]$ Vldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine9 y& _$ | m% t* @5 C; e- w
b 2b
) G0 A! s/ Y! P4 g* n
' g3 b: |- V+ p) s# Z__sys_trace_return:2 v$ @/ }$ w) [3 s
str r0, [sp, #S_R0 + S_OFF]! @ save returned r0% f- n; U9 v5 @6 E+ ?+ G
mov r1, sp8 ~7 y7 S3 p- X9 ^9 A
mov r0, #1 @ trace exit [IP = 1]
6 ?6 P* g! Z% K2 Z6 S$ y5 y; Xbl SYMBOL_NAME(syscall_trace)
" L8 C' `! g# \b ret_disable_irq% s* [, i- s6 d2 r
/ W- m) r: w/ q0 U.align 5# u q3 h- _. R: D
#ifdef CONFIG_ALIGNMENT_TRAP: M% {! i d% l* \& {
.type __cr_alignment, #object: s3 P% s+ r* y
__cr_alignment:
0 @4 D* u- C* K& P) m& }.word SYMBOL_NAME(cr_alignment)# j7 Q" S! A E4 a, ?& i0 a6 g
#endif2 F! j) @8 s# m4 l1 B; i
.type sys_call_table, #object
; @( C' E6 U# [6 F, }ENTRY(sys_call_table) G. V# e/ q" C( O5 `8 q5 {
#include "calls.S" + d5 ]5 H2 N: j: y
|