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
- n" o. r- a7 h, Y0 J) f打算trace一下 (以ARM為例子)/ a6 T# ^% Z# P- r) ^" `
看看能不能多了解一下kernel booting時候的一些動作 4 T$ y) p) h; D/ N
一些文章提到是從/arch/arm/boot/bootp/init.S開始1 `$ v9 h# P" }+ b
所以節錄了一些下來- Q9 F* p* I8 O5 Y$ f' ^

& F7 m) F4 R# A0 p     19         .section .start,#alloc,#execinstr
" G4 p7 J% j. Y3 Z2 P     20         .type   _start, #function
( z+ t0 E; y* N     21         .globl  _start7 I) I5 }5 ^6 E: _+ h
     22
. n% f/ v/ [* E     23 _start:     add lr, pc, #-0x8       @ lr = current load addr
1 b9 a2 b- `/ P0 `' V$ E* }& X     24         adr r13, data
" ]& P$ J8 n! b  _; D     25         ldmia   r13!, {r4-r6}       @ r5 = dest, r6 = length1 @$ o- d9 _7 M% ?
     26         add r4, r4, lr      @ r4 = initrd_start + load addr
2 ^4 D2 Z# `9 ]: {4 v6 |     27         bl  move            @ move the initrd! [/ Z" @! v* h, T. n
     .....* h4 z. E# a2 ]
     76         .type   data,#object2 t. D( [2 B5 k. f5 ?
     77 data:       .word   initrd_start        @ source initrd address
) a. S( P9 u6 ~2 p& L( y0 [     78         .word   initrd_phys     @ destination initrd address
. L8 ?0 T: \$ p. G+ B% M     79         .word   initrd_size     @ initrd size! Z$ k) i, s; J5 L- K, G  g0 x
     80$ s; X& ?% m9 ]! \8 e9 h4 L3 \
% J: y3 C) V. f" V" g
line 19,宣告了叫做.start的section
! `) `, p6 M) I8 p5 yline 20,21宣告了一個叫做_start的function
3 D) |/ W3 N7 H1 R4 Y8 ~5 d程式碼似乎從line 23開始, |% F( O% C1 W1 a. h, c8 w- }
line 23, 『add lr, pc, #-0x8』- J+ k: J# G. i4 E. R2 _
add就是將pc+(-0x8)的結果放到lr之中,pc和lr都是ARM裡頭暫存器6 N$ x4 p% C2 C( d$ S
pc就是program counter,CPU用來指著目前要執行的指令,執行完CPU就會自動把PC+1! w! V* H, |1 s2 e
這樣就會拿到下一道指令,lr通常是第14個register, r14,常被用來繼續function; {8 g5 v* @1 i+ F8 P) y) K  t
return時候的返回位置。奇怪的是為什麼要-0x8??3 _  A3 E" G6 M7 Q
原因應該是ARM本身有pipeline的設計,prefetch->decode->execution,當指令被執行; t7 W! ^  B' t. k* h
的時候,其實已經預先去偷偷抓下一道,所以PC值不是真的指在目前執行的地方,三級# x& E4 O* K! n. N4 \4 I6 w4 Q/ e
pipeline剛好多了兩個cycle所以4 bytes x 2必須要-8才是正在執行指令的位址。
; f5 n9 }+ R! G6 h6 C! @( ]4 o. l$ j# V
line 24, 『adr r13, data』- G0 {: @; }' s( C& S2 \0 p
adr會去讀取data所在的位址當作值,寫道r13裡頭。r13通常是用來放stack pointer,
) w3 x9 @' d4 D/ u: n/ L' a6 L  W常縮寫成sp,所以現在r13就指到data所在的位置上去。8 ?) f& r3 X3 Y+ R
6 [% ]! C* u! i, o8 V: q3 n
line 25, 『ldmia   r13!, {r4-r6}』
% W/ {& B, p8 G1 S7 q! @ldmia, load multiple increment after,顧名思義就是可以做很多次load的動作,每此
# z) w+ x& n! Y, Eload完就把位址+1,執行完之後
+ D6 F& u6 V- Br4 = initrd_start8 i3 O/ {* F; V. d& z1 T/ K; s
r5 = initrd_phys5 r0 D7 J! h9 I6 u# o
r6 = initrd_size7 a* l# E( ~2 l( Q8 m/ f

: a' h: P" l+ B7 i- Eline 26, 『add r4, r4, lr』
5 ]! g7 o  w! {- kr4 = r4+lr, lr是剛剛我們算過的,指到一開始執行指令的地方,看程式碼的解釋,被當
$ C6 _- w6 A: Q成載入的位址,所以執行完 r4 = initrd_start+程式被載入的位置,用途不明,看看之
9 a# j) ^! n9 {! X, k$ c後有沒有被用到。
2 t* Y% V; h! y
! Z- m! a5 V# w8 r1 Nline 27, 『bl  move』
& l$ j$ ?2 T# l4 b! Z2 S% b& qbl, b是branch,相當於C語言goto的動作,l就是goto之前,先把目前位置存放到lr裡面,. x( d# Z- Q. J- f! j
所以bl除了goto之外,也改寫了lr,應該是有利於等一下返回的時候,可以用lr的值。  P6 E+ D: k5 o# }, [2 r

. B/ t4 H$ U  |- v! w# K$ n以上,好像還沒開始什麼重點,有空再繼續,有想錯的地方或是需要補充的地方,多多指教~
作者: gogojesse    時間: 2008-8-6 06:23 PM
上面的 code 裡面出現了一些還沒定義的symbol  Y6 D0 y- l4 V7 H+ e* y% i- ^0 f
例如 initrd_start, initrd_size等等
4 j& @8 h- E# B) {) e* z( ?其實是被定義在另外一個檔 ./arch/arm/boot/bootp/initrd.S5 z, M! U' ^: V2 B, A
3 S! C& C/ j9 D4 K7 s5 _
      1     .type   initrd_start,#object
& n1 \8 O2 I3 P' @* N3 i( {) q      2     .globl  initrd_start
# H3 X" b& q3 `; D5 w. @- X      3 initrd_start:
7 G5 M) }5 H: ~; [" w      4     .incbin INITRD
) ~! |" w" {9 G- y9 u/ E" h" ^+ \2 N      5     .globl  initrd_end
/ C1 q- k- Q+ U7 B! C( y      6 initrd_end:
* E5 Q1 ~9 n8 G# O1 _+ l& {; C* R# u, j! b
line 2, 3, 5, 6定義了兩個symbol initrd_start和initrd_end
  z4 o5 d) r9 _  x, K; n中間還用.incbin INITRD 將 ramdisk 的 image include進來
0 H+ w, ]/ N8 x( I這邊有點複雜
% O- z8 t; j; u6 E/ e$ c假如compiler kernel的時候+ N& N; @% }& L: O
有選擇使用ramdisk當成boot device的話, a' f. l- [3 Q
會對從環境變數去設置 INITRD
. U: v) _6 O# s$ g: j6 l這個檔名會被帶入到MAKEFILE/ D9 {9 h) t* e0 t
並且在做assembler動作的丟進來
! w( H( c# Q" t# d: t' f假如沒有使用initrd
8 ^; Y/ w+ M8 g+ L) G3 I" x那就.incbin應該就包不到東西( x- W1 G/ g8 |' V6 g% Z8 P) D
initrd_start 和 initrd_end 就會相等
$ C8 d6 V& ]7 A* l7 }. |9 x% V5 s6 A7 }6 j6 p& w
另外有個 script ./arch/arm/boot/bootp/bootp.lds
( T  ?: O- m9 N! b3 l它規範了所有link起來的object code裡面的section要怎麼編排* u. R+ Y$ Z# W% g5 i# C$ h
這樣撰寫kernel的時候
% Q- O. B5 ~7 e$ l- D1 h, L可以到特定的section取得想要的資料或是計算某個section的大小; T5 G. k' ^5 U- d! |) T3 [

# h7 N8 u2 Q% m; S) B% I     10 OUTPUT_ARCH(arm)
7 k# l2 ^) Y. V! r     11 ENTRY(_start)
- l/ u8 ?1 ~* o  m( @4 @; R6 S7 J5 N     12 SECTIONS
! [4 Z: O9 L9 s) y! N  ~# h9 e/ R     13 {4 X2 ^, b$ ]& f( u
     14   . = 0;2 D' |6 T3 s' g4 S' d4 L
     15   .text : {
/ [2 s1 q9 z5 o$ p* S( l5 k     16    _stext = .;0 R. \& O/ c, z( l$ R3 i( r# g
     17    *(.start)& K2 c* [5 R8 P) t% P
     18    *(.text); v2 D4 A  G# u
     19    initrd_size = initrd_end - initrd_start;" n8 B8 A. `1 Y1 q2 x6 Y, U! S; ]
     20    _etext = .;
' n' e4 K* `1 E: K5 c& Q     21   }
8 s8 R6 j. J. _% w; |; m/ g     22
' r& d) }/ u  H& p     23   .stab 0 : { *(.stab) }5 i) S$ W5 P, X9 p! N6 Q# }6 x
     24   .stabstr 0 : { *(.stabstr) }: c$ Z- V! f) ?3 N
     25   .stab.excl 0 : { *(.stab.excl) }' Y# }. Y; {  `6 `
     26   .stab.exclstr 0 : { *(.stab.exclstr) }, N; s. X3 I4 E) s9 p
     27   .stab.index 0 : { *(.stab.index) }) @4 `% @9 C7 v7 x& M
     28   .stab.indexstr 0 : { *(.stab.indexstr) }
# j& @+ r2 v" O4 S' n: E9 x$ J     29   .comment 0 : { *(.comment) }  R+ n9 s2 }) K1 E* @6 p! L1 I0 E
     30 }
6 ?! o7 h& l( o& d( H3 l! a- v5 F- V3 z8 c& o
對於object file的格式不熟悉的話2 g. D# {# i; M5 S( D! \
可以參考ELF format的相關文件
作者: gogojesse    時間: 2008-8-6 07:50 PM
接著繼續看 init.S1 K. b6 ]  U+ b# T
之前的code已經goto到move這邊來
( `1 |7 E! V! n; ^$ @; T所以貼一些move的程式碼
# ~, A( g6 N9 q: H- u* l) d1 V
" P0 Y9 ^7 Y2 i7 g     66 move:       ldmia   r4!, {r7 - r10}     @ move 32-bytes at a time
. A" i; x1 D) _, `     67         stmia   r5!, {r7 - r10}
# t3 C9 ~6 E" O     68         ldmia   r4!, {r7 - r10}
. y  {1 u( _) p2 {4 r8 [- s! G     69         stmia   r5!, {r7 - r10}8 e' o: u4 l4 G! Y
     70         subs    r6, r6, #8 * 4
! p2 n9 U7 @# O2 u     71         bcs move# [/ w) y2 K, \7 l6 R. W
     72         mov pc, lr6 X2 f, r& y& H
; A) W1 }: Y3 x3 g# c6 g
line 66, 將r4所指到的位置,分別將值讀出來放到r7, r8, r9, r10, 可以發現剛剛計算過的r4這邊被; p) ~0 G4 r. d0 _9 E
用到了,但是為什麼r4不是用initrd_start,卻還要加上load addr??1 L# Q6 Q- m  H( |' b) U8 ^+ c: |! B1 t
原因應該是bootp.lds的14行『. = 0;』表示最後被link好的address會從0x0開始3 f5 D3 k0 H& e) E3 S
所以 initrd_start 所記錄的位置可以當成是offset
' r9 x" R9 B* K. x加上load到DRAM或是擺在flash上的位址後( u# t" x$ G: c( `" K# P' ?! j
就剛好是initrd所在的地方
/ i% Z6 b- V/ I8 Y5 j
3 w; V! a7 c; o& a. M* ~line 67, 『stmia   r5!, {r7 - r10}』
. d3 ?4 P, a( t  {# W' ]6 Bstmia, store multiple increment after, 和ldmia動作相同,只是用來寫資料。/ ^: L! w+ o( O% q; y3 L4 W3 |
r5是存放著initrd要擺放的位置 ) c$ P2 K) X; s! t) K9 j
猜測應該是為了一開始image放在flash上,但是可以將initrd拷貝到DRAM上
- k! W! v4 K: k2 G$ f8 N' T( F/ ?, Mr7寫到r5指到的位置" j6 D+ o& }% C  X5 P1 b2 J% E" T
r8->r5+14 ]5 X8 [& O7 y- k5 s. G) n9 P) x3 g
r9->r5+2# n7 f  E  o! R- ~5 ?
r10->r5+3
$ r% n/ [3 t$ w' `5 |  Y; |所以我們發現,66,67行就是將r4所指的東西搬到r5。$ W4 S0 T& \1 _3 G1 d

/ g9 d( K/ J" z$ Sline 68, 69也是一樣copy了4x4bytes,一共是32bytes。
$ M% D/ ?# u% d% d+ U- rline 70,『subs    r6, r6, #8 * 4』,將length - 32bytes
8 o( V6 `. p- b+ i- m# vline 71,『bcs move』,b是branch的意思,cs是表示condition的條件,要是條件符合的話,# i/ ~: q1 A9 L5 ?
就做branch的動作,這邊的用意是判斷前一個length是不是已經到0,如果不為零就繼續copy。
, s; l: N' h7 K1 n+ b, M) n+ Gline 72,『mov pc, lr』
% `: p7 A8 W" M* ]1 ^- N8 p1 s接著就把剛剛bl指令預先存放好的lr 填入pc,這樣CPU就會跳回去原本的return address。+ U; g) }( `! B
* a/ l: x9 s& f" h, ^& `
以上的動作,慢慢看得出來有在做些什麼事$ f, L7 b" G8 Z
1. 找出initrd的所在位置. T- {" `4 y2 i6 i
2. 將它copy到一個指定的destination去
作者: gogojesse    時間: 2008-8-7 11:25 AM
程式返回之後
. V# n; T* Q& y1 g+ K我們接著看下一行
  1.      33         ldmia   r13, {r5-r9}        @ get size and addr of initrd
    5 ~; }( |, u" m# r# z5 `: [
  2.      34                         @ r5 = ATAG_CORE+ L1 C7 @! s0 }! B6 t$ B" u, K* H" J
  3.      35                         @ r6 = ATAG_INITRD2. U6 K  {4 u" M" `4 v
  4.      36                         @ r7 = initrd start
    ' p5 r7 z; z0 I# L8 b
  5.      37                         @ r8 = initrd end
    $ e! i2 D( j. W2 r
  6.      38                         @ r9 = param_struct address' w& _( u0 N+ {
  7.      39
    / |3 T# b6 {: [( ?# J5 ~
  8.      40         ldr r10, [r9, #4]       @ get first tag
    ( c; O0 w$ ~" l; b! m
  9.      41         teq r10, r5         @ is it ATAG_CORE?
複製代碼
line 33, 繼續從r13的地方取出資料到r5, r6, r7 ,r8, r9,註解的說明有提到各個資料* w0 _( [# `! w1 [2 Z
的意義,注意一下這邊的r7是initrd的destination address不是source address。1 u$ M1 z+ v2 s- f' I$ K
+ l) Z' j. m6 @4 e9 ~$ e& O
line 40, 讀入第一個tag,這邊的tag是指bootloader丟給kernel的一個boot arguments,
/ s+ _6 f( |' _) b4 m會被用一個叫做ATAG的structure包起來,並且放到系統的某個地方。然後kernel跑init.S,
$ Q5 F1 u! G9 g5 Z的時候就會去這個地方拿ATAG的資料,這些資訊包括記憶體要使用多大,螢幕的解析度多大等等。
( M" v2 \, N3 ^0 {7 \  m
1 r9 d; _1 J/ X& z2 v9 z% t8 zline 41, t是test, eq是equal, 判斷拿到的第一個tag是不是等於atag core. 應該是看
% a) a# `/ b& p) ^( xatag list 是不是成立的。1 Z" x, P, C7 N  Y. W% p: k# v
5 K& k0 B) u) |5 P+ K) H1 F$ z
繼續接著看
  1.      45         movne   r10, #0         @ terminator3 ]+ b; z! P5 z$ @1 I  a
  2.      46         movne   r4, #2          @ Size of this entry (2 words)9 {+ N. a( {4 O, i
  3.      47         stmneia r9, {r4, r5, r10}   @ Size, ATAG_CORE, terminator
複製代碼
發現45, 46, 47的指令都帶有condition "ne", not equal,表示是剛剛 line 41發現atag不成立
  s* H6 Q- j2 L/ C8 ~, {/ j所做的事情,注釋是寫『If we didn't find a valid tag list, create a dummy ATAG_CORE entry.』
+ O2 R: \; r  H8 a; M# h. n) C所以以上三行就是用來創造一個假的entry,假設一切順利這三行指令會bypass過去不會被執行到。
& v( {" q% y+ P+ I$ J' x: q
& h: c3 q8 S5 {' U( L- N接著來看init.S最後一段程式碼 (終於~)
  1.      54 taglist:    ldr r10, [r9, #0]       @ tag length, e8 j1 k+ _3 B7 M. e& M1 ]
  2.      55         teq r10, #0         @ last tag (zero length)?6 i& D- P+ P4 j& }  W1 s
  3.      56         addne   r9, r9, r10, lsl #25 B0 ^: K9 ~& e2 X5 l8 w, f& q
  4.      57         bne taglist9 U; m& \$ L, }$ _  c) N* O7 @
  5.      58+ g% P% t. G3 u% U
  6.      59         mov r5, #4          @ Size of initrd tag (4 words)
    # Z2 m- \$ @, Q# U7 M, E. ?
  7.      60         stmia   r9, {r5, r6, r7, r8, r10}
    5 i! Z- V/ H' @1 h: G7 Z2 j
  8.      61         b   kernel_start        @ call kernel
複製代碼
line 54, 將r9指到的位址的offset 0x0的值載入到r10。看註解是tag length,所以這邊得要去翻翻atag的規範
, D( X2 E* n' o8 O2 Z+ J這邊有個文章有提到 http://www.simtec.co.uk/products ... ooting_article.html ,一開) g* u$ R, k/ L, E+ ^
始應該是去讀atag_header所看第一個欄位,確認一下是size,應該沒問題。
  1. struct atag_header {
    # f$ A: G0 u7 E8 a% ~1 @
  2.         u32 size; /* legth of tag in words including this header */, ]9 J$ x0 L* O
  3.         u32 tag;  /* tag value */
    " K  w- p6 t- t. G0 K* J
  4. };
複製代碼
line 55,測試一下size是不是0。
) m) ]! k' P0 H4 Nline 56, 57也有condition ne,表示是不為0的時候做的。將拿到的length(r10)乘以4,這邊的lsl是將r10往/ Z, p9 d7 E4 m/ j2 `. Q. [" l6 F
左shift的意思,因為一個欄位是4bytes,所以乘4之後就跳到下一個tag,一直跳到最後沒東西。5 H/ P; L: _( w# Y4 t

4 ^" t+ S6 A: F0 Q$ T! pline 59, 將r5設成4+ g# u, w3 U! I. [7 O
line 60, 將r5, r6, r7, r8 ,r10存到r9所指到的位置,應該就是跟在atag list的後面。
4 V/ R1 R4 }, m7 lline 61, jump 到 kernel_start ,注意這邊是用b而不是bl,因為跳過去kernel就不需要返回了。BL會用到# R  a: W9 s& b. i2 y- L
lr紀錄返回位置。
" q- z; t# K5 N! c$ }5 u
" N/ I' J9 D4 ]/ t$ K: L以上,走過一整個init.S,接著會跳到./arch/arm/boot/compressed/head.S。) M! f4 ~0 X, K" y. l5 D5 N5 h
/ `5 g2 o$ s2 G/ s3 i" g
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 發表 * ]8 h3 |# n- Z7 D
好一段時間沒有碰程式了,看到你的分析讓我想起年輕時候的我 ~~~~ 還是不要透漏年齡
' u2 I2 L4 W2 e8 F+ z; h7 n' N

) q0 u  q' l$ Z- S0 z+ j
' k4 z+ V, I1 S: v  y! }有些時候  東西是越陳越香啊~~5 @( E* u. g* C2 r
...........
作者: gogojesse    時間: 2009-7-16 03:26 PM
剛剛發現一個大陸網站的blog貼了我的文章
. s  i( ], h6 v+ t9 {/ X0 v但是沒表明出處 = =
$ n! p1 T( X; Z還把標題改過,感覺像是他自己寫的
3 a* M" Q5 g% f+ M' h- z, L$ \* ~真是麻煩~% k! F  @) ?% @& e  r) u( E

) {" I( _% i% S4 M( `& @0 v3 Y& d' f已經好幾次這樣的經驗
& H# X- H6 N& e1 N0 y* r. e8 U以前幫忙有弄網站也是這樣# g; l) `; w1 A& G
抄襲得很嚴重7 C- L# j4 i( A: i  d2 U
內地那邊到底有沒有在管啊!!




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