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
#endif3 A. v+ z$ e3 B+ B
+ g+ a# @4 c8 s
#define __sys2(x) #x5 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 Dvector_swi定义在arch/arm/kernel/entry-common.S
' D( a% Z4 V; ]( a$ bvector_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' Zarch/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& iarm710_bug_check scno, ip) {$ y1 I3 M) t6 z
#ifdef CONFIG_ALIGNMENT_TRAP
7 j2 |' O/ y+ Sldr 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; F6 [- 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 Yldr 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=0x9000058 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 number6 ]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- ?& Ctst ip, #PT_TRACESYS        @ are we tracing syscalls?
8 }* |# E+ G& K. R2 Zbne __sys_trace6 h- T& S1 D. k4 G! X' z

4 E5 V( p) z4 r/ K* T, wadrsvc al, lr, ret_fast_syscall        @ return address
1 k: C- W" D/ o; }; Hcmp 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 xadd 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  Ccmp scno, #ARMSWI_OFFSET
! m; P& z5 @; t3 S( @eor r0, scno, #OS_NUMBER << 20        @ put OS number back2 J+ h9 l7 g4 A3 A
bcs SYMBOL_NAME(arm_syscall)
* M/ |/ k$ v/ Z5 ]& p  _; x1 O6 Wb 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_OFF4 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- Radrsvc 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: Jldrcc pc, [tbl, scno, lsl #2]        @ call sys_* routine9 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 Zmov r1, sp2 }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