EDA365电子论坛网
标题:
ARM linux系统调用的实现原理
[打印本页]
作者:
baqiao
时间:
2020-10-16 14:48
标题:
ARM linux系统调用的实现原理
4 g2 h. u& ~2 D+ V
大家都知道linux的应用程序要想访问内核必须使用系统调用从而实现从usr模式转到svc模式。下面咱们看看它的实现过程。
8 ?$ t' N# X) c$ W2 r
6 y$ l# W4 o G6 {
系统调用是os操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的执行让用户程序陷入内核,该陷入动作由swi软中断完成。
" @; ^ l# B8 b/ r: K
! T/ R, b/ w! C; i* d u- I) I
at91rm9200处理器对应的linux2.4.19内核系统调用对应的软中断定义如下:
5 i1 K( i# x0 A( S: \* y
#if defined(__thumb__) //thumb模式
, r& N. |) N }6 L6 @+ `
#define __syscall(name) /
! x+ O- a T( u0 X" |% P! z
"push {r7}/n/t" /
* s' e& T ?& b* a8 y
"mov r7, #" __sys1(__NR_##name) "/n/t" /
, l+ V. L- L# [2 z0 A# E
"swi 0/n/t" /
! q8 Z9 j% F& R5 k; E* g( @4 Q
"pop {r7}"
$ i$ R! B' G. F3 t- }8 \
#else //arm模式
6 K& _% u" i, ~9 n- {
#define __syscall(name) "swi/t" __sys1(__NR_##name) "/n/t"
+ g c1 _* ]" G
#endif
3 A. v+ z$ e3 B+ B
+ g+ a# @4 c8 s
#define __sys2(x) #x
5 i2 }9 b/ ]% X, c
#define __sys1(x) __sys2(x)
$ R! r! B( o* N7 K. B
#define __NR_SYSCALL_BASE 0x900000 //此为OS_NUMBER << 20运算值
- a" u, Y: u# d# J8 Z
#define __NR_open (__NR_SYSCALL_BASE+ 5) //0x900005
+ c" V" d: f( v7 u5 C1 a y2 L
- {. I, Q0 ^5 \3 |3 b, t
_6 I* T& o' M: f+ U5 c _
; d: R4 j7 |% a
举一个例子来说: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在表中对应的顺序号为
' o' |3 }) m, K* |- d1 W
__syscall_start:
: J( t+ ^$ N2 N6 h! x
...
: C) y6 V7 ~/ V# O5 @6 q5 W- X
.long SYMBOL_NAME(sys_open) //第5个
7 ~ ^* J* h3 u; y/ T0 S
...
5 L, w9 Q# ?& K6 L. L0 Q" E
K! M7 _ K$ L0 [; l
将sys_call_table[5]中内容传给pc,系统进入sys_open函数,处理实质的open动作
( R6 N1 }$ f4 s% p7 V3 Z1 g( x
$ p6 ~* B. m/ Y% z5 o1 M/ @
注:用到的一些函数数据所在文件,如下所示
0 Q+ _0 A6 h( z4 g8 k) c0 h
; i6 t- {! _+ N4 b+ F# Z% f0 H
arch/arm/kernel/calls.S声明了系统调用函数
: w5 H$ r$ Y( d2 W
0 t6 M8 ]' v! y5 _, d/ ]9 K
include/asm-arm/unistd.h定义了系统调用的调用号规则
% e1 m5 O1 g" V* K; y7 w3 D
vector_swi定义在arch/arm/kernel/entry-common.S
' D( a% Z4 V; ]( a$ b
vector_IRQ定义在arch/arm/kernel/entry-armv.S
: D; s# k! t3 S$ `+ @
vector_FIQ定义在arch/arm/kernel/entry-armv.S
1 m# ` A1 y! ?6 H# ^* ]4 t' Z
arch/arm/kernel/entry-common.S中对sys_call_table进行了定义:
4 E" @* O2 G. B) Y" G
.type sys_call_table, #object
q/ d) g& W& O# q% O
ENTRY(sys_call_table)
$ H* I+ P. c: ?, l6 ?/ g
#include "calls.S" //将calls.S中的内容顺序链接到这里
! d& Q' X$ y2 m$ ~9 Y% c
源程序:
; q! F$ Q* Z3 s$ v* h
ENTRY(vector_swi)
, W, }& N3 j, G( n
save_user_regs
+ o! f( f; n) S) v
zero_fp
% i# f& \1 n4 o8 B6 y5 M
get_scno //将[lr,#-4]中的中断号转储到scno(r7)
0 z: h% e( ~$ J- T8 n& i
arm710_bug_check scno, ip
) {$ y1 I3 M) t6 z
#ifdef CONFIG_ALIGNMENT_TRAP
7 j2 |' O/ y+ S
ldr ip, __cr_alignment
# y# W7 t( a' H1 Z9 I, d0 A
ldr ip, [ip]
5 \7 B0 m! h8 Q0 u" B
mcr p15, 0, ip, c1, c0 @ update control register
% x* k) L0 J6 J4 u) e5 b% A* E
#endif
# C$ s, y& b& [7 W
enable_irq ip
# h) C% ^7 j; F
6 [- A, `' ]/ w! K1 @- t4 R' j
str r4, [sp, #-S_OFF]! @ push fifth arg
1 M/ d0 s' @1 M4 @
y6 E& ~: T$ a; g5 R
get_current_task tsk
- z3 ~! d. G+ U% F7 Q0 @6 Y
ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing
( i+ p; K; e) @
bic scno, scno, #0xff000000 @ mask off SWI op-code
) f4 ]2 c5 R9 u) ]& E1 e
//#define OS_NUMBER 9[entry-header.S]
. l" {7 G! `- Q: m' k
//所以对于上面示例中open系统调用号scno=0x900005
8 y7 O$ ]6 f/ c/ u+ c
//eor scno,scno,#0x900000
& i+ h$ O2 }# l2 ?7 d I7 `
//之后scno=0x05
. P2 p; m% m6 w, n% n
eor scno, scno, #OS_NUMBER << 20 @ check OS number
6 ]9 s, n1 K- r7 t- v Z
//sys_call_table项为calls.S的内容
6 K( w! S, V4 z. R. h+ u
adr tbl, sys_call_table @ load syscall table pointer
% }% |. N7 b/ v6 d9 Y" h- ?& C
tst ip, #PT_TRACESYS @ are we tracing syscalls?
8 }* |# E+ G& K. R2 Z
bne __sys_trace
6 h- T& S1 D. k4 G! X' z
4 E5 V( p) z4 r/ K* T, w
adrsvc al, lr, ret_fast_syscall @ return address
1 k: C- W" D/ o; }; H
cmp scno, #NR_syscalls @ check upper syscall limit
0 z& d R% K% Y. `0 D$ X
//执行sys_open函数
1 L- N1 q9 i8 G9 D2 \
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
* x7 M, R+ g) ?3 x
add r1, sp, #S_OFF
- t, Q7 b( R K9 b7 }
2: mov why, #0 @ no longer a real syscall
. z5 o4 K) o1 |) k4 K! R C
cmp scno, #ARMSWI_OFFSET
! m; P& z5 @; t3 S( @
eor r0, scno, #OS_NUMBER << 20 @ put OS number back
2 J+ h9 l7 g4 A3 A
bcs SYMBOL_NAME(arm_syscall)
* M/ |/ k$ v/ Z5 ]& p _; x1 O6 W
b SYMBOL_NAME(sys_ni_syscall) @ not private func
2 Y" d# ^- E2 x4 \& X: K1 Q, m! B
/*
, h5 i/ ^; A, g/ M7 I
* This is the really slow path. We're going to be doing
4 X* q( O# h5 k2 I
* context switches, and waiting for our parent to respond.
5 W/ H7 b0 \7 P# o# L% G/ f
*/
, [' o l) R V7 @$ o7 i
__sys_trace:
8 ]* ~; T! U1 s) e. @
add r1, sp, #S_OFF
4 x+ J+ f z* s; I6 ^. f
mov r0, #0 @ trace entry [IP = 0]
, q- G1 E7 x/ @% ^) G. V1 G) X* X: H9 s4 \
bl SYMBOL_NAME(syscall_trace)
3 P6 I4 K; Q6 p7 K; }, P
/*
( ?2 N" k; j& Z; [* R/ U/ H
//2007-07-01 gliethttp [entry-header.S]
8 D. o2 g9 |0 _3 l. t
//Like adr, but force SVC mode (if required)
- p; R7 g. R) h( g( Y8 @6 D
.macro adrsvc, cond, reg, label
. V* O0 A- P+ \6 i* C$ A) K# Z& u
adr/cond /reg, /label
/ K! r% q4 w) b7 k& a7 A5 R% h% r: e
.endm
8 j; w5 p9 f3 n/ L
//对应反汇编:
$ o, q' h6 p3 |- U3 I
//add lr, pc, #16 ; lr = __sys_trace_return
. Y' A* Z( w# {
*/
( g2 K* \0 N) }5 H- R
adrsvc al, lr, __sys_trace_return @ return address
x* s4 b) N2 J" ?) k- |
add r1, sp, #S_R0 + S_OFF @ pointer to regs
# [5 m7 a" g u5 u7 w" C
cmp scno, #NR_syscalls @ check upper syscall limit
; I; U* ~8 } | }$ k3 ~
ldmccia r1, {r0 - r3} @ have to reload r0 - r3
" C+ e G1 H9 r, ^. h: J
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
9 e1 X6 }- g8 V4 u- }2 M
b 2b
1 `4 |/ ^9 s B; I8 v
+ r* t; x' m' _ l. Q
__sys_trace_return:
/ M: M/ U9 i) ?, g
str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
$ A- ?) m; g9 w' x0 m- [* d% p& y1 Z
mov r1, sp
2 }2 P0 B! F+ a, E3 ~
mov r0, #1 @ trace exit [IP = 1]
1 v2 D! M; f& }( W5 k
bl SYMBOL_NAME(syscall_trace)
9 V" G' I5 s" ~$ m u) l+ L* Q
b ret_disable_irq
* ]/ z' K- d1 f3 Q5 K9 ]9 i: B
5 J" Z4 _/ V3 |" u1 \+ _. S9 }
.align 5
: j/ Q/ |% O5 E6 S; A: C1 s2 B h
#ifdef CONFIG_ALIGNMENT_TRAP
8 t* i4 t: p8 Y/ V
.type __cr_alignment, #object
, T+ N; \3 \' ^
__cr_alignment:
& x6 R a4 R8 l8 |7 J
.word SYMBOL_NAME(cr_alignment)
8 g+ y/ p, F$ P( f2 F9 K
#endif
) R- j0 d6 I8 m3 T7 M
.type sys_call_table, #object
: l+ N$ w" }# a4 `. f( _
ENTRY(sys_call_table)
& e( d6 p0 D9 d# o7 n4 v( c
#include "calls.S"
# T3 ]3 {) c7 T6 `! @$ s0 K
3 K* |' ~% @5 L
作者:
NingW
时间:
2020-10-16 15:21
ARM linux系统调用的实现原理
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2