Chip123 科技應用創新平台

標題: trace linux kernel source - ARM - 01 [打印本頁]

作者: gogojesse    時間: 2008-8-6 02:33 PM
標題: trace linux kernel source - ARM - 01
昨天下載了linux-2.6.26的kernel source
) E( p. C) ~4 c$ H) F打算trace一下 (以ARM為例子)9 w! `* w* ^' B7 E, T1 m$ ^" n3 Z- @
看看能不能多了解一下kernel booting時候的一些動作 . g  t) u6 i' H, ]% v! y
一些文章提到是從/arch/arm/boot/bootp/init.S開始
3 v) r: l- C. c8 L/ U& P$ [所以節錄了一些下來' ~; s5 i( C4 A  m- M/ |  \

3 o! f! E+ U! z8 t/ I% k     19         .section .start,#alloc,#execinstr+ e* D3 `3 t* F
     20         .type   _start, #function3 Q( L$ [( N7 \4 K8 t& O, w0 \
     21         .globl  _start
' h% P' e7 H; k* W  U2 j- R# X     224 }( M- v5 K0 Y. {) X; z
     23 _start:     add lr, pc, #-0x8       @ lr = current load addr
" [" W  D! {; Y     24         adr r13, data& p- p5 t5 q5 ^" o# z/ x" o! y
     25         ldmia   r13!, {r4-r6}       @ r5 = dest, r6 = length
% c- T' N8 j, O7 t     26         add r4, r4, lr      @ r4 = initrd_start + load addr
9 C- l! X0 C% ~8 C- ~6 {     27         bl  move            @ move the initrd& x0 {! t2 I: `7 [% J
     .....
/ }( R+ _/ U  R8 y     76         .type   data,#object1 V( c) o1 R! ~5 I- n
     77 data:       .word   initrd_start        @ source initrd address
; l7 A6 j6 ~7 @' N% F     78         .word   initrd_phys     @ destination initrd address
& R2 r4 D1 t7 e7 E$ N! B8 i. X     79         .word   initrd_size     @ initrd size5 _: a3 ^3 w# K' P2 I  ]
     80
2 E  Q) v( [* o0 d& r! m
3 H: \0 A: x# C; P2 Lline 19,宣告了叫做.start的section& j' A# g* L! e% n2 @
line 20,21宣告了一個叫做_start的function
- u& W3 Q  g: t程式碼似乎從line 23開始+ ?- ?5 e( c* {4 T1 k
line 23, 『add lr, pc, #-0x8』, Y6 z  q" g6 U8 X! G8 h- k" O6 F
add就是將pc+(-0x8)的結果放到lr之中,pc和lr都是ARM裡頭暫存器
: X: y  Z+ S  @pc就是program counter,CPU用來指著目前要執行的指令,執行完CPU就會自動把PC+1! f; ?4 h) g! O0 S- K6 q2 [# Y
這樣就會拿到下一道指令,lr通常是第14個register, r14,常被用來繼續function
% T* q6 S: f. |1 j' `. Zreturn時候的返回位置。奇怪的是為什麼要-0x8??
- V+ a/ v3 B0 r+ j. e( F8 U- i" ?! i原因應該是ARM本身有pipeline的設計,prefetch->decode->execution,當指令被執行! F7 |2 M8 c5 s# i+ v4 C
的時候,其實已經預先去偷偷抓下一道,所以PC值不是真的指在目前執行的地方,三級/ c1 q1 Q) Q/ a1 F# r/ F
pipeline剛好多了兩個cycle所以4 bytes x 2必須要-8才是正在執行指令的位址。
7 ^7 Y. l* w+ T! _! R4 l; W+ y0 [! J3 Z  w( i9 c
line 24, 『adr r13, data』
1 X0 u4 z3 F: d6 ladr會去讀取data所在的位址當作值,寫道r13裡頭。r13通常是用來放stack pointer,
5 h) q+ v  s1 V' a  I. {常縮寫成sp,所以現在r13就指到data所在的位置上去。# z" E8 o1 H& Y0 @

, O! W. U5 {6 C4 F* C. ?line 25, 『ldmia   r13!, {r4-r6}』
1 t; i1 i4 D' k9 Q7 i0 Qldmia, load multiple increment after,顧名思義就是可以做很多次load的動作,每此3 \6 c7 c; Z6 G3 p
load完就把位址+1,執行完之後- k7 I: l, n7 S6 I0 h1 f( S& z
r4 = initrd_start) O$ e. d3 ~& `* j" u( t: x) ?
r5 = initrd_phys' T7 |5 W5 }$ q" F) C
r6 = initrd_size
1 d* g" a. o0 g& v' p; z2 J4 b$ ], {9 s. g3 }
line 26, 『add r4, r4, lr』
7 n" `$ K6 A  y$ p! _- wr4 = r4+lr, lr是剛剛我們算過的,指到一開始執行指令的地方,看程式碼的解釋,被當  u9 D& L/ _9 S1 H. M
成載入的位址,所以執行完 r4 = initrd_start+程式被載入的位置,用途不明,看看之
2 M5 {/ n( G7 |( u, l後有沒有被用到。; p5 S' ]! s$ Z7 B9 k2 a

  F9 _  F: {7 U$ N  \line 27, 『bl  move』3 D, V+ Y) _1 ^% @! G4 a
bl, b是branch,相當於C語言goto的動作,l就是goto之前,先把目前位置存放到lr裡面,+ E1 t5 Y! d7 _8 Y/ _
所以bl除了goto之外,也改寫了lr,應該是有利於等一下返回的時候,可以用lr的值。
4 y! n( m" i5 C+ _
9 ?  m. c9 N! _) b. y; y! {5 ?以上,好像還沒開始什麼重點,有空再繼續,有想錯的地方或是需要補充的地方,多多指教~
作者: gogojesse    時間: 2008-8-6 06:23 PM
上面的 code 裡面出現了一些還沒定義的symbol
  a) `( p; ]3 I) a- k5 ?! v例如 initrd_start, initrd_size等等
. r9 A0 W+ p+ S3 d! Z其實是被定義在另外一個檔 ./arch/arm/boot/bootp/initrd.S/ n$ y4 S8 n4 \; T' P, Z6 x

% {8 w4 W9 R5 ~, R5 [1 Z      1     .type   initrd_start,#object' f) d: C6 p9 b, A1 y. f
      2     .globl  initrd_start
) k6 v+ p7 M* M      3 initrd_start:
: U9 S! a8 S2 v- l' [& g- K      4     .incbin INITRD
- r. [) C3 h+ L3 [1 c) Y      5     .globl  initrd_end
8 p" p: T- r$ N* N( h; r6 E9 {5 m      6 initrd_end:
. k  ^, z# y' g6 Q! O6 {# R* V" J5 x/ f% N. h, U
line 2, 3, 5, 6定義了兩個symbol initrd_start和initrd_end7 K/ v: Y) o6 q4 _
中間還用.incbin INITRD 將 ramdisk 的 image include進來
, U, L' i9 x. l7 D  J0 [這邊有點複雜
8 ~7 ]8 o4 j" A4 j! z. [! e假如compiler kernel的時候
, \4 H2 p: R3 }; v有選擇使用ramdisk當成boot device的話/ A% z: B8 q5 P, r  Y6 X
會對從環境變數去設置 INITRD 3 t/ R2 B+ O  {. G6 O  e
這個檔名會被帶入到MAKEFILE7 d: [  S8 @% X2 ]- G. U
並且在做assembler動作的丟進來/ [4 E9 R( v9 M: y; ], g5 h6 q. Y
假如沒有使用initrd
* y' j" ?7 D$ a那就.incbin應該就包不到東西2 i$ K; U1 X; X* X3 o5 H
initrd_start 和 initrd_end 就會相等
3 U( W6 t; s3 L# C" {
- ~* J3 @4 T, V' }* c另外有個 script ./arch/arm/boot/bootp/bootp.lds
- V3 b. A) v( t4 I' t它規範了所有link起來的object code裡面的section要怎麼編排# s8 l- x. x/ ?8 q/ _
這樣撰寫kernel的時候" d5 p3 ^1 N  S. Y( f: m: N
可以到特定的section取得想要的資料或是計算某個section的大小1 G" |1 g% S6 X  i$ [
+ o( L! t% ]$ f* @0 d+ {$ g! B
     10 OUTPUT_ARCH(arm)
' P7 P7 V' k; c5 e# p- J) Y     11 ENTRY(_start)
$ r% J) z9 k  |& F7 s7 ?' Q1 ^1 L- Z1 U     12 SECTIONS
- @2 _4 z! K) H- T  T     13 {# N1 i1 n* k- m  {9 ~( ~
     14   . = 0;9 R. y/ @( [1 @, X; i
     15   .text : {9 S3 G$ E: p* H  ?0 U1 }0 q- N* z2 ^* d
     16    _stext = .;9 {! d. d4 X1 ]% X* |* \7 ?9 q
     17    *(.start)
: F. H: L$ c8 W1 t+ `9 W1 J     18    *(.text)) k; T  I  j1 J& l3 p) W
     19    initrd_size = initrd_end - initrd_start;
+ y9 H, q" d- e     20    _etext = .;8 W7 \4 ]' V) W; i. D; B* s1 I
     21   }8 X5 m' P3 s% F, p: z( e! K
     22
+ K4 r; x9 N: e4 p7 u     23   .stab 0 : { *(.stab) }
/ [8 o( |1 Q+ {     24   .stabstr 0 : { *(.stabstr) }
  V1 a- V, \! _0 `! D     25   .stab.excl 0 : { *(.stab.excl) }0 {( c% T6 E6 H* K3 W/ |1 U
     26   .stab.exclstr 0 : { *(.stab.exclstr) }
  f6 B8 L) o2 A  ]1 l' v     27   .stab.index 0 : { *(.stab.index) }# q$ U7 @2 y4 F% N: g9 u  M; j
     28   .stab.indexstr 0 : { *(.stab.indexstr) }0 \' G, e8 }% e8 \4 j
     29   .comment 0 : { *(.comment) }8 m) c8 f, j" J9 n$ X
     30 }* p  S5 j' Z& y8 `% C' \( j
0 F9 ?8 \" d) z5 P' ^
對於object file的格式不熟悉的話7 \/ B) J5 B* ^  S; M; W3 d
可以參考ELF format的相關文件
作者: gogojesse    時間: 2008-8-6 07:50 PM
接著繼續看 init.S
: B$ ?' r  I7 k; x) s之前的code已經goto到move這邊來" G. A% R! y3 I( h  s
所以貼一些move的程式碼
' @, j! B& ?( [; L8 q" X
: m; Z  i* E3 t     66 move:       ldmia   r4!, {r7 - r10}     @ move 32-bytes at a time! W) @; _7 t+ P
     67         stmia   r5!, {r7 - r10}
3 u7 t0 u! Q! s" u. I     68         ldmia   r4!, {r7 - r10}
( A- ]! K  W$ H- s6 b3 m     69         stmia   r5!, {r7 - r10}
+ B: G2 F9 z, q# t( F9 B9 ~     70         subs    r6, r6, #8 * 4
. Q" @4 Z$ }2 Q) c, O9 F6 r% [) I# l     71         bcs move; T+ I5 @1 |1 O( ~8 U: C
     72         mov pc, lr  n  d/ K1 O7 H5 b$ i
3 I. v: r( C( m( Z2 @1 }
line 66, 將r4所指到的位置,分別將值讀出來放到r7, r8, r9, r10, 可以發現剛剛計算過的r4這邊被
* ]. ^9 ~$ g* U1 h用到了,但是為什麼r4不是用initrd_start,卻還要加上load addr??2 `+ {* x/ D# V6 s8 _. L" f: f
原因應該是bootp.lds的14行『. = 0;』表示最後被link好的address會從0x0開始
4 A  o! F( [# G$ F5 y所以 initrd_start 所記錄的位置可以當成是offset
* @/ d8 t, m4 ^2 x9 h加上load到DRAM或是擺在flash上的位址後* O( i1 {7 H) \( _" W( i8 c! _
就剛好是initrd所在的地方
# p0 Y3 S/ C/ g) N) l& \, {
. I% S6 _2 n/ _line 67, 『stmia   r5!, {r7 - r10}』
: c1 }8 @' @, `" L6 w' W; ~stmia, store multiple increment after, 和ldmia動作相同,只是用來寫資料。
7 _" J' e' @5 e9 G! M) M$ V+ R3 ^r5是存放著initrd要擺放的位置
6 \1 G3 ]8 G0 V: v  D# r猜測應該是為了一開始image放在flash上,但是可以將initrd拷貝到DRAM上+ x. `3 c! |6 v% H+ P/ Y2 f% }; F
r7寫到r5指到的位置
7 i& ?. I: a0 `! {3 D2 k2 l! pr8->r5+1" ~5 L- x3 S* \1 d) `8 s
r9->r5+2
3 @* o% L! t( B% r' ]5 ~: K& or10->r5+3
+ W* ?+ F2 A1 s, m所以我們發現,66,67行就是將r4所指的東西搬到r5。
2 N; M8 I# l, X  K0 \. o0 U. l
1 u- i7 Y6 n# B- Rline 68, 69也是一樣copy了4x4bytes,一共是32bytes。! d2 j/ [1 Z- c/ p# W5 L
line 70,『subs    r6, r6, #8 * 4』,將length - 32bytes) [" I* n; m3 c) M& Q  F
line 71,『bcs move』,b是branch的意思,cs是表示condition的條件,要是條件符合的話,$ u) z4 b) m% d: C4 U' X- `. T
就做branch的動作,這邊的用意是判斷前一個length是不是已經到0,如果不為零就繼續copy。: Q5 y' U, x$ C5 v+ g: M
line 72,『mov pc, lr』0 n# `3 n5 y0 D  c; t" h
接著就把剛剛bl指令預先存放好的lr 填入pc,這樣CPU就會跳回去原本的return address。7 d: A$ m8 a. k
/ r. {4 a7 }# K# \9 K6 r1 [2 j
以上的動作,慢慢看得出來有在做些什麼事
* \0 A2 V# T$ q) C5 X5 C2 Y1. 找出initrd的所在位置
$ E  a! @+ Z7 n0 t% ?. ~2. 將它copy到一個指定的destination去
作者: gogojesse    時間: 2008-8-7 11:25 AM
程式返回之後5 w& h. z" A. g; }. p5 K6 i
我們接著看下一行
  1.      33         ldmia   r13, {r5-r9}        @ get size and addr of initrd
    1 W) s; Y0 t) V) B. \! S: H: F
  2.      34                         @ r5 = ATAG_CORE) A3 z$ h7 ~, s# x
  3.      35                         @ r6 = ATAG_INITRD2
    ) x& W& w. q+ E' {* l
  4.      36                         @ r7 = initrd start
    4 _& }/ F* o/ n, h
  5.      37                         @ r8 = initrd end
    ( X( Z4 C$ ^' y' \+ N3 i
  6.      38                         @ r9 = param_struct address
    % G' `0 U2 T2 W" I# r8 P
  7.      39/ L# o' D8 k3 t0 @
  8.      40         ldr r10, [r9, #4]       @ get first tag. l* T: `  _, ~% M$ t
  9.      41         teq r10, r5         @ is it ATAG_CORE?
複製代碼
line 33, 繼續從r13的地方取出資料到r5, r6, r7 ,r8, r9,註解的說明有提到各個資料" O% l0 j8 K( `7 V7 d4 x
的意義,注意一下這邊的r7是initrd的destination address不是source address。
+ k5 e% R& d/ a' w' m6 N* M
$ p/ {7 ^! d, R" S7 yline 40, 讀入第一個tag,這邊的tag是指bootloader丟給kernel的一個boot arguments,
$ h8 ^! s/ y0 L! j: @. ~8 S6 u會被用一個叫做ATAG的structure包起來,並且放到系統的某個地方。然後kernel跑init.S,
' v% {; a$ G4 }0 P' `的時候就會去這個地方拿ATAG的資料,這些資訊包括記憶體要使用多大,螢幕的解析度多大等等。
  P& z% u- O, K) q1 p$ x1 C6 G. }# N2 D  v5 z- J9 \1 E
line 41, t是test, eq是equal, 判斷拿到的第一個tag是不是等於atag core. 應該是看 & t# w: b2 c9 Q7 X$ e9 K8 X
atag list 是不是成立的。7 ?7 _% N2 }  P5 h" F8 S3 M, V
. ~. j: g0 x6 X' x% m: Q. h6 W1 D
繼續接著看
  1.      45         movne   r10, #0         @ terminator
    # ^. a+ Z  a4 X0 J3 B6 Q  j/ z
  2.      46         movne   r4, #2          @ Size of this entry (2 words)+ A7 e, L# @1 P( z% {9 Z9 |' U5 O
  3.      47         stmneia r9, {r4, r5, r10}   @ Size, ATAG_CORE, terminator
複製代碼
發現45, 46, 47的指令都帶有condition "ne", not equal,表示是剛剛 line 41發現atag不成立
5 n, p1 J& O' S' r- [所做的事情,注釋是寫『If we didn't find a valid tag list, create a dummy ATAG_CORE entry.』$ F, o+ f3 w6 x8 I$ D
所以以上三行就是用來創造一個假的entry,假設一切順利這三行指令會bypass過去不會被執行到。
' E1 R% M9 g; L& c/ P" t  F/ x/ W3 W9 {0 m6 C+ M
接著來看init.S最後一段程式碼 (終於~)
  1.      54 taglist:    ldr r10, [r9, #0]       @ tag length7 ^0 ]6 {7 c, J9 \$ t* v
  2.      55         teq r10, #0         @ last tag (zero length)?$ E. I" I% M8 B5 B4 i
  3.      56         addne   r9, r9, r10, lsl #23 J! g* K( |( }2 {5 v; X
  4.      57         bne taglist* S, ]2 \' r9 N( f( G- y
  5.      58
    . B/ }  \" M# L% z8 N5 \
  6.      59         mov r5, #4          @ Size of initrd tag (4 words)
    " N) J5 H+ C+ {) e+ t0 U4 ?9 _
  7.      60         stmia   r9, {r5, r6, r7, r8, r10}
    - b5 C7 F% P( a8 _; i- ]9 S5 m
  8.      61         b   kernel_start        @ call kernel
複製代碼
line 54, 將r9指到的位址的offset 0x0的值載入到r10。看註解是tag length,所以這邊得要去翻翻atag的規範- }3 x6 o- [' H5 ^" [+ ]
這邊有個文章有提到 http://www.simtec.co.uk/products ... ooting_article.html ,一開! e2 _# \% p  l# i1 f9 A8 d5 M
始應該是去讀atag_header所看第一個欄位,確認一下是size,應該沒問題。
  1. struct atag_header {0 ~) }. E$ A  b6 h
  2.         u32 size; /* legth of tag in words including this header */
    . P% n) h3 b/ l) L2 L
  3.         u32 tag;  /* tag value */3 f: ]0 W/ S. W: x- O
  4. };
複製代碼
line 55,測試一下size是不是0。
1 w& P# f. M4 Fline 56, 57也有condition ne,表示是不為0的時候做的。將拿到的length(r10)乘以4,這邊的lsl是將r10往
, q7 I- }! l3 F/ U左shift的意思,因為一個欄位是4bytes,所以乘4之後就跳到下一個tag,一直跳到最後沒東西。! W8 k2 T1 f9 E) f) Y8 h

/ _1 i% `# F! {& w/ V' b8 s+ Kline 59, 將r5設成4
- n* ]- A  [6 Z% j+ y7 [line 60, 將r5, r6, r7, r8 ,r10存到r9所指到的位置,應該就是跟在atag list的後面。
& C9 v2 F5 y& Y) N4 O* p; f4 ]line 61, jump 到 kernel_start ,注意這邊是用b而不是bl,因為跳過去kernel就不需要返回了。BL會用到
- F) S  Z6 q7 ~; t# z/ X4 [" hlr紀錄返回位置。
- u3 ]3 {, |$ l- |
9 L- m0 O; u$ c& ?; b2 Q以上,走過一整個init.S,接著會跳到./arch/arm/boot/compressed/head.S。
1 J8 r9 v3 _# J" f# m* C& S/ K/ }1 ?' [1 g, N
kernel_start的定義方式跟initrd_start有點類似,中間有透過 kernel.S去用.incbin把kernel image包進來。
作者: jacky002    時間: 2008-8-9 07:44 AM
好一段時間沒有碰程式了,看到你的分析讓我想起年輕時候的我 ~~~~ 還是不要透漏年齡
作者: gogojesse    時間: 2008-8-9 11:31 AM
原帖由 jacky002 於 2008-8-9 07:44 AM 發表 ! Q% r8 M7 A' m% G: v. \+ A8 W' ]" t) X
好一段時間沒有碰程式了,看到你的分析讓我想起年輕時候的我 ~~~~ 還是不要透漏年齡

& S+ B4 k2 ^& S& _0 t1 ^  `! h6 z6 w+ \; K3 \. i& ^
  b, z' C2 i. I" B; u# U4 A0 [4 N; G
有些時候  東西是越陳越香啊~~; C6 Z& ^/ Z( B
...........
作者: gogojesse    時間: 2009-7-16 03:26 PM
剛剛發現一個大陸網站的blog貼了我的文章
8 m' N+ s+ z' }但是沒表明出處 = =
( r7 h) d. l8 l! }) O還把標題改過,感覺像是他自己寫的
( Q9 Y1 z- u; C真是麻煩~
7 T0 _' _( T. s% P+ o
* D+ v- f! Z6 S9 {) n  J已經好幾次這樣的經驗
% L' a; T4 P: Y  L) k) V以前幫忙有弄網站也是這樣& m0 d) i0 r+ E: a; Z
抄襲得很嚴重; |! |+ Z' J4 l1 T, `
內地那邊到底有沒有在管啊!!




歡迎光臨 Chip123 科技應用創新平台 (http://chip123.com/) Powered by Discuz! X3.2