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

ARM linux系统调用的实现原理

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
7 b7 G7 ^4 p5 D
大家都知道linux的应用程序要想访问内核必须使用系统调用从而实现从usr模式转到svc模式。下面咱们看看它的实现过程。
. e0 w( R3 E: y6 V3 R2 x# q8 ?- A# O9 B# j% M0 X5 L" A3 b
系统调用是os操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的执行让用户程序陷入内核,该陷入动作由swi软中断完成。) Y3 q* y# y9 T0 j4 R; E' Z7 Z4 v

' p. A! f- a5 q* Rat91rm9200处理器对应的linux2.4.19内核系统调用对应的软中断定义如下:( d) ^4 p0 x+ t2 P. ^; h9 n
#if defined(__thumb__) //thumb模式7 T+ [' t2 D2 Y
#define __syscall(name) /
; p) u7 q* s5 R"push {r7}/n/t" /6 M$ x4 R! U! c) v8 s, {  L4 s
"mov r7, #" __sys1(__NR_##name) "/n/t" /7 X2 Z4 L! y. T9 N+ [! ]4 a* X
"swi 0/n/t" /
$ L& _; E7 A  u) c"pop {r7}"( V7 O2 t9 I! P; }, ^
#else //ARM模式
4 S0 x# M+ `% _6 k( C#define __syscall(name) "swi/t" __sys1(__NR_##name) "/n/t"
9 d4 \3 W2 [: _#endif! ~. Y) J% y. M7 @: w* ?

2 l- V: s% P1 A+ `+ K& m' M#define __sys2(x) #x
$ N2 V* a" P8 o: @#define __sys1(x) __sys2(x)
. h4 ]1 `0 g* O1 K7 S#define __NR_SYSCALL_BASE 0x900000 //此为OS_NUMBER << 20运算值
# n! Z% s% n5 c4 `6 ]  F9 ]  d#define __NR_open (__NR_SYSCALL_BASE+ 5) //0x9000058 S4 `: z2 }( M9 T& b/ i
2 e3 }& z% c0 L( o

  p  N1 i1 e- `$ U$ r7 |  S9 C: b' k1 V
举一个例子来说: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在表中对应的顺序号为
2 b) N; Z* H6 s1 s0 {8 ^, ~# L__syscall_start:
! n+ Y2 `6 Q" v4 c% {( q...! H7 y$ x0 D, Z$ p+ K5 U1 a
.long SYMBOL_NAME(sys_open) //第5个
- H' h1 w! b5 y; ~...# D/ l, C9 S9 S/ p" Q% j5 J

# z- f5 u7 B9 k& A$ R将sys_call_table[5]中内容传给pc,系统进入sys_open函数,处理实质的open动作
$ i' g& N- N$ P" ?& ~
" p2 q1 z  M7 g注:用到的一些函数数据所在文件,如下所示* N, u+ _3 h+ Z' B6 t6 D
5 ?7 g$ v) J: G+ m/ o9 j- |2 g
arch/arm/kernel/calls.S声明了系统调用函数8 k3 I/ D8 w  s, j9 w% N- a1 n

5 q; u# @. o* y( ?% dinclude/asm-arm/unistd.h定义了系统调用的调用号规则
3 J+ t; V5 \! K# I4 r3 n% uvector_swi定义在arch/arm/kernel/entry-common.S  j1 o' y. X2 B+ |" y& |) O
vector_IRQ定义在arch/arm/kernel/entry-armv.S
0 |! h& K( a( D& ~! X  ^( Evector_FIQ定义在arch/arm/kernel/entry-armv.S
4 R  `" o1 X, s7 J5 ]* p! Yarch/arm/kernel/entry-common.S中对sys_call_table进行了定义:
$ K& ]! F' M& _0 _.type sys_call_table, #object
" G0 a! a3 B. L. q8 y  F. }% o5 ]ENTRY(sys_call_table)- ]5 ~/ ~' c9 [/ q
#include "calls.S" //将calls.S中的内容顺序链接到这里* a$ T; Q4 e, v- i7 D! b+ p& D
源程序:8 s( K: s! f5 i* A" N
ENTRY(vector_swi)+ K, O6 n, C  P/ V: {
save_user_regs) y" [' w. u! ]7 X3 Q( |, k
zero_fp& f/ a: {1 z( f: w& a
get_scno //将[lr,#-4]中的中断号转储到scno(r7)
5 n; |  q; ?: D; r9 o6 Z4 Parm710_bug_check scno, ip; X/ u* I. P1 O
#ifdef CONFIG_ALIGNMENT_TRAP7 b4 R  f) d4 ?% [% q  O+ C
ldr ip, __cr_alignment; c" M% M8 F& e( @% j3 C8 I
ldr ip, [ip]. z8 w0 F9 C, e) ]( f7 r2 h
mcr p15, 0, ip, c1, c0        @ update control register
/ h! X' S# ~6 j" M" X2 J6 d( y#endif+ b# Z3 ~. |- @9 _4 q
enable_irq ip
6 a* u$ R3 a% h( G. F( m8 H0 m+ M0 a; \# @4 }' ~. r
str r4, [sp, #-S_OFF]!        @ push fifth arg
+ ]$ [0 G! m7 [# d! s  U
/ N; y# B7 D- o# t- |+ Rget_current_task tsk2 D! p9 G' i7 Q$ }8 e/ j
ldr ip, [tsk, #TSK_PTRACE]        @ check for syscall tracing3 M' p* M% j; ~4 y
bic scno, scno, #0xff000000        @ mask off SWI op-code$ N/ T" F# X* A: t+ Y3 g
//#define OS_NUMBER 9[entry-header.S]
3 z3 ?1 q) @9 B; [. O$ X0 x//所以对于上面示例中open系统调用号scno=0x9000055 W7 Y) Z/ {$ e9 d
//eor scno,scno,#0x9000000 d) W; K# `) D' M% C) V
//之后scno=0x05. f5 J% \2 j9 w( \$ H
eor scno, scno, #OS_NUMBER << 20        @ check OS number
; c8 y3 H( ?9 J8 K2 n//sys_call_table项为calls.S的内容
. B; Q% y& u( Aadr tbl, sys_call_table        @ load syscall table pointer! \! r3 k5 W  T2 f+ d
tst ip, #PT_TRACESYS        @ are we tracing syscalls?
! r/ [1 o1 m2 P8 T' x1 i; `. g) Gbne __sys_trace8 s+ |+ A2 P' F! H1 i
/ \/ s4 w# G( |& L# l$ ]6 R
adrsvc al, lr, ret_fast_syscall        @ return address
- p( p# Z! l. x' M* D) vcmp scno, #NR_syscalls        @ check upper syscall limit0 k# n2 G7 y8 d3 d  ^( ~6 J
//执行sys_open函数7 g. `7 H6 U$ N' [0 ?
ldrcc pc, [tbl, scno, lsl #2]        @ call sys_* routine2 E# X. U3 m0 ~2 L
add r1, sp, #S_OFF. \% t: m2 W* R) H* A! h
2: mov why, #0        @ no longer a real syscall. B0 q# H* ~( y4 [3 c+ W
cmp scno, #ARMSWI_OFFSET/ t) l% l! P/ R! |  Y/ F
eor r0, scno, #OS_NUMBER << 20        @ put OS number back
. X" Q) N: [& T4 M% L% o( _. ?- Wbcs SYMBOL_NAME(arm_syscall)
- F$ S" M8 V- G0 L3 Cb SYMBOL_NAME(sys_ni_syscall)        @ not private func9 }/ z* n+ |9 x! ^& E8 v# ^
/*$ q8 _1 n: [; A& m3 U
* This is the really slow path. We're going to be doing) g; p: f) j9 V- l$ N8 y' A/ }$ _
* context switches, and waiting for our parent to respond.3 l- i" O" q4 l# R" o: K* I
*/4 i# Z. e3 P& y4 g  k
__sys_trace:! M1 M# {% l, O5 K9 i5 p8 q& N7 q
add r1, sp, #S_OFF+ @4 V2 c% a2 u1 t1 ?+ }$ X
mov r0, #0        @ trace entry [IP = 0]: k; L: P: k+ P) w$ s+ U* t
bl SYMBOL_NAME(syscall_trace)" w. s( @: h6 k. c$ I9 m" N6 Z
/*
" F* P% c8 X) g- X4 d0 Q//2007-07-01 gliethttp [entry-header.S]
) C6 y  o, h! U# i3 I//Like adr, but force SVC mode (if required); e* B/ n' f, l$ I& r& r
.macro adrsvc, cond, reg, label
8 h" c' Z3 a8 s5 o4 w( q( Padr/cond /reg, /label
  M% @/ G' |! H% `.endm: L7 \% e" G# }( J* }
//对应反汇编:" E" l, }6 B5 }- g! s' q- \
//add lr, pc, #16 ; lr = __sys_trace_return8 d/ s1 x! u6 y$ S9 i, r9 Q
*/
: [: p+ N$ M' h. e, V/ K7 tadrsvc al, lr, __sys_trace_return        @ return address& t4 b# K* X# ]3 I
add r1, sp, #S_R0 + S_OFF        @ pointer to regs
2 U9 H4 K( I* M2 w+ @cmp scno, #NR_syscalls        @ check upper syscall limit
& X  |' S  E+ q" a( t& g3 Cldmccia r1, {r0 - r3}        @ have to reload r0 - r3. g* S* J# \( l, E# P) L, f
ldrcc pc, [tbl, scno, lsl #2]        @ call sys_* routine
# ]8 J: ~# w" kb 2b3 m8 E: ^: D4 O7 U, C
$ r1 E+ ]9 H8 m  ~  Z- y) W
__sys_trace_return:
3 h6 L! \7 U/ ^% B+ K# lstr r0, [sp, #S_R0 + S_OFF]!        @ save returned r0
; P, y7 Y! f+ T. Z; Xmov r1, sp
, j" W! D% a- tmov r0, #1        @ trace exit [IP = 1]
& {8 r; ~2 |  vbl SYMBOL_NAME(syscall_trace)* e' N9 S1 B- `: H
b ret_disable_irq- S, e! H/ C2 t

  v- {/ M& Z& G* e  [$ y.align 5
/ X& J  J2 y! P: H% q% [0 r#ifdef CONFIG_ALIGNMENT_TRAP
7 f. [" N. ^8 N5 o9 |.type __cr_alignment, #object, z3 V, [! J# ~' p
__cr_alignment:
  M7 L  U* i7 Q+ ~0 P.word SYMBOL_NAME(cr_alignment)  h: [# X4 ?1 H$ ^8 I5 i
#endif
! x6 v( z0 Y0 P1 A6 j.type sys_call_table, #object
6 m; l1 E7 a; W/ a# i" wENTRY(sys_call_table)/ S" M& S9 z2 t0 E( L7 @
#include "calls.S"
. u2 O- g; ]# n! y
- q# ~0 X. p. ^8 s1 ]5 O" ?

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-24 22:05 , Processed in 0.156250 second(s), 24 queries , Gzip On.

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

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

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