找回密码
 注册
关于网站域名变更的通知
查看: 366|回复: 1
打印 上一主题 下一主题

ARM linux系统调用的实现原理

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-10-16 14:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x

( R# q5 q/ J- \! L大家都知道linux的应用程序要想访问内核必须使用系统调用从而实现从usr模式转到svc模式。下面咱们看看它的实现过程。. c, V  r& {( ~8 W+ Y% M  D1 B
8 I4 u5 ^: F& q: M8 W; Y
系统调用是os操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的执行让用户程序陷入内核,该陷入动作由swi软中断完成。( b( s8 ^5 |0 r
/ n6 `. q9 Y5 J3 `0 @* v7 ]0 \2 c
at91rm9200处理器对应的linux2.4.19内核系统调用对应的软中断定义如下:9 o, L: M0 M6 w& P+ e5 b7 j
#if defined(__thumb__) //thumb模式: x/ |+ A. o3 q) ]
#define __syscall(name) /
2 u. Q# r3 f* V"push {r7}/n/t" /
. k9 [8 u/ H% v3 k! P  k2 T* q"mov r7, #" __sys1(__NR_##name) "/n/t" /: N9 x2 D1 I2 x+ l2 J, E3 ~
"swi 0/n/t" /
0 _+ k. Z5 t6 x) L8 n& P. c8 p"pop {r7}"
6 N2 J. g3 x0 |$ t  D4 l#else //ARM模式& ]+ C% K4 y" v' \/ D# n
#define __syscall(name) "swi/t" __sys1(__NR_##name) "/n/t"( \8 S; Z8 {! Z  D* h5 _. ^
#endif1 L; g3 }. Y. ?" x+ y
$ h+ t+ K; T, F: u# M3 o. d
#define __sys2(x) #x
4 s& s+ ~5 Z. ~' y( k/ D. }#define __sys1(x) __sys2(x)
# u& u8 ]+ [# F( q1 b, }; ^: P#define __NR_SYSCALL_BASE 0x900000 //此为OS_NUMBER << 20运算值
: D0 G3 t9 H4 d* o#define __NR_open (__NR_SYSCALL_BASE+ 5) //0x900005
- m. m  L; X# h" a( m$ J' A$ H1 L
$ b. y: H) H& B2 x3 g- @/ W7 p9 r
' g2 x9 I8 f) b
/ C  s% V7 B3 q8 p- J1 K- ?. w举一个例子来说: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在表中对应的顺序号为
1 Y; _; r& o0 H" f( p__syscall_start:
- L/ g: l2 X5 b1 p6 |...
5 E! A1 t' {- P8 q+ U1 w* v.long SYMBOL_NAME(sys_open) //第5个
; z" m) U: Y  Z5 R9 k, G3 Q...2 u! J* A8 `% j8 g$ k& t% U
/ ~5 o, L( R  U7 k$ b
将sys_call_table[5]中内容传给pc,系统进入sys_open函数,处理实质的open动作9 X8 ?+ o+ @/ K' A

3 d" ~! V- s) O; N注:用到的一些函数数据所在文件,如下所示  \6 w/ r# F2 R; F* ?
- C+ g: E! _0 g/ m0 y  h( o' N0 A
arch/arm/kernel/calls.S声明了系统调用函数
% b- _7 N7 k5 p6 O$ Y( p, o
9 w% `0 ~: J9 J  Y3 R. W, O1 r2 L/ Winclude/asm-arm/unistd.h定义了系统调用的调用号规则4 W+ _. F% k0 E5 u  v; n
vector_swi定义在arch/arm/kernel/entry-common.S$ M  ]6 d# Y. _5 ?8 E" Z; X
vector_IRQ定义在arch/arm/kernel/entry-armv.S
1 V9 h7 A+ {& X* ^& U; M; Yvector_FIQ定义在arch/arm/kernel/entry-armv.S
4 J& q0 r! k* b. Z5 W" N8 ]arch/arm/kernel/entry-common.S中对sys_call_table进行了定义:! n4 @. m% R# _6 S& j: E/ b
.type sys_call_table, #object
3 ~, [# h! m9 _' G/ AENTRY(sys_call_table)1 a- A( q$ |# \, v$ n/ Z
#include "calls.S" //将calls.S中的内容顺序链接到这里
! F& p" N; ~6 g3 R) Y7 \2 ~! x源程序:2 \) v7 M; V- I( C: Z" I
ENTRY(vector_swi)3 \' O3 }" c& Q+ `" i
save_user_regs
% d9 A! A9 ]1 ]zero_fp3 d& f' W% `& t
get_scno //将[lr,#-4]中的中断号转储到scno(r7)
6 x9 j7 C! G) |* B( a% Darm710_bug_check scno, ip! i3 v/ w' ~6 u
#ifdef CONFIG_ALIGNMENT_TRAP
. M; P1 _  I" g# L# Y. m5 h0 Y+ f& ildr ip, __cr_alignment
, u# q& l! t! _ldr ip, [ip]
1 t6 D0 n* B8 I' \( M) R2 p" `mcr p15, 0, ip, c1, c0        @ update control register. J3 P# Q: O9 B' \$ J
#endif
1 d/ R  g6 j  N6 Y; ~; Lenable_irq ip9 G3 d) f) A9 I2 }
3 a, Q& e- Z' c7 H  w1 c" l  y* B
str r4, [sp, #-S_OFF]!        @ push fifth arg, V: k# C* h3 }
9 |1 O) h0 W1 L, R
get_current_task tsk1 [5 F& P' j. T' }( ^2 }
ldr ip, [tsk, #TSK_PTRACE]        @ check for syscall tracing
0 ^$ |9 a( U# p9 Ubic scno, scno, #0xff000000        @ mask off SWI op-code
; n& H4 V) P1 t- u% }//#define OS_NUMBER 9[entry-header.S]- t1 K2 B/ I% o3 p$ Q; l" X. o/ q
//所以对于上面示例中open系统调用号scno=0x900005. s1 M4 y1 t! R& N) J" A+ a0 b" K9 B
//eor scno,scno,#0x900000
0 J6 `# Y, p, ]+ G//之后scno=0x05
' T( S# W" L8 D- m% o; Z- ^eor scno, scno, #OS_NUMBER << 20        @ check OS number
  M) e7 I. Q$ _5 q, A# `% r1 {! {- z//sys_call_table项为calls.S的内容
: v. G  ~: e& [; a; ladr tbl, sys_call_table        @ load syscall table pointer' }) }8 E! y2 i4 \
tst ip, #PT_TRACESYS        @ are we tracing syscalls?
% P2 u$ K6 I5 f4 ?) z) ]bne __sys_trace# C* ^- [# K+ s4 E
" |* _3 A& ]9 u% [
adrsvc al, lr, ret_fast_syscall        @ return address
3 B  o( y5 N3 `5 Bcmp scno, #NR_syscalls        @ check upper syscall limit
9 ~6 g. N( Q3 L2 ~" ]# I( U//执行sys_open函数) j( A! ], X- x4 Q6 Y; o
ldrcc pc, [tbl, scno, lsl #2]        @ call sys_* routine) s& f/ F% P' M( P
add r1, sp, #S_OFF
8 l' f+ B4 U2 v7 S- y( M' f2: mov why, #0        @ no longer a real syscall5 M- C$ v" \0 I
cmp scno, #ARMSWI_OFFSET
- f/ q3 Y8 [, J7 G( Neor r0, scno, #OS_NUMBER << 20        @ put OS number back& R' M9 _/ w4 j3 C4 J3 G. K
bcs SYMBOL_NAME(arm_syscall) & `& k6 c' ~2 s1 M" c; |, l0 y$ W
b SYMBOL_NAME(sys_ni_syscall)        @ not private func8 B- l4 q- a$ Z6 s2 P8 Y/ S1 t# D
/*1 E' \. Z' _* G$ C7 A6 L8 B: t/ x
* This is the really slow path. We're going to be doing( G  i: W; V4 @+ S$ Q
* context switches, and waiting for our parent to respond.- N* x* T1 e  X! O3 u- C- M: q
*/
, q9 ~) J+ {& M* K. [__sys_trace:
, E+ f5 c! F' B, G& j( k& [% dadd r1, sp, #S_OFF
8 n* a- b+ i0 @! C. k& [, U+ R7 T7 smov r0, #0        @ trace entry [IP = 0]
/ O7 w* c2 k0 [; Jbl SYMBOL_NAME(syscall_trace)5 e% o1 S  e7 O! ^5 Y
/*
" o# j& g1 L8 q' P//2007-07-01 gliethttp [entry-header.S]
6 T' z! R* j; p/ c. |, |//Like adr, but force SVC mode (if required)5 N2 r- C% i2 S6 T# Y* g0 s
.macro adrsvc, cond, reg, label. C1 Y0 D. S& h) p, B
adr/cond /reg, /label
4 R/ S) e7 R4 _( c5 O' x2 P.endm4 |/ b/ S1 y' \% {7 {
//对应反汇编:8 Z# Y! L0 m9 w, O
//add lr, pc, #16 ; lr = __sys_trace_return
: }% F3 u4 V- ?*/4 l8 q; m) x0 J& z5 @' Z3 R
adrsvc al, lr, __sys_trace_return        @ return address' a* r8 g% L' E% x
add r1, sp, #S_R0 + S_OFF        @ pointer to regs" u6 S7 s" ~) L$ i# U& {
cmp scno, #NR_syscalls        @ check upper syscall limit
9 T5 V2 x/ |% g7 E* i% r3 P' Nldmccia r1, {r0 - r3}        @ have to reload r0 - r3
6 F: T# M/ S5 K. t* U2 ]4 I- ~ldrcc pc, [tbl, scno, lsl #2]        @ call sys_* routine
5 N# ^  l$ s! ]% O; _b 2b& s% K4 \, Q" }$ I7 m4 j& {/ A
3 q8 a* `6 `# U- Y+ O7 y
__sys_trace_return:
% S5 D/ b  ]: l& k9 s% u; Mstr r0, [sp, #S_R0 + S_OFF]!        @ save returned r0" h" m1 j% r+ T4 T0 {7 J5 ?
mov r1, sp" l, J1 D2 I6 n4 k: k  t9 t' r
mov r0, #1        @ trace exit [IP = 1]
7 E  G3 U  s9 ?# I+ ]  q: `* `bl SYMBOL_NAME(syscall_trace)
3 ~0 G, m+ M! ?# r/ J+ pb ret_disable_irq* Q6 X9 c' ^0 g" L
; ?0 [) Z2 Y+ ]
.align 5
* X. [. E, l* g3 n1 P/ N) K# P#ifdef CONFIG_ALIGNMENT_TRAP
" L6 v# C: i( w! ?1 m, J& d.type __cr_alignment, #object7 L, P' z6 ?9 {$ a- J
__cr_alignment:3 Y: }# j/ \/ F+ W+ Y4 e! u/ N" J+ Q
.word SYMBOL_NAME(cr_alignment)1 x; T: G4 ]) _' [
#endif
, K0 V8 l% m! ^+ h/ W& F.type sys_call_table, #object& {- F3 ~6 @' x0 N4 C) k
ENTRY(sys_call_table)7 |' ^/ K- r3 [$ X4 ?, i
#include "calls.S"
5 u9 b, s: h# O9 C$ Y% N( f5 e
: l5 o7 L3 D! V4 b4 x

该用户从未签到

2#
发表于 2020-10-16 15:21 | 只看该作者
ARM linux系统调用的实现原理
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-24 21:06 , Processed in 0.140625 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表