推荐给好友 上一篇 | 下一篇

/sys/i386/i386/locore.s分析笔记

QzR Uf7Nw ikernel的入口地址是/sys/i386/i386/locore.s中定义的btext:
{%Rj(A \;d)l'\
V[ QOJ,Q O200  /**********************************************************************
8Wat,B6ny/Z1l201   *BSD爱好者乐园%M/MD%m0AU l)v
202   * This is where the bootblocks start us, set the ball rolling...BSD爱好者乐园f&O _T ln7C
203   *
U&w2IX/s1L!EE%[?204   */
8tW4P];K)c@to205  NON_GPROF_ENTRY(btext)BSD爱好者乐园fa \8\HsQ

1V'ri6R:w从/boot/kernel/kernel中可以读出btext的链接地址:BSD爱好者乐园Af$[j \9ovG h+j

)TO{j K.O;n# readelf -a /boot/kernel/kernel | grep btext
Qg L:QP Z!t  6870: c0458a30     0 FUNC    GLOBAL DEFAULT    5 btext
j.g2iw'v5t)s5A26381: c0458a30     0 FUNC    GLOBAL DEFAULT    5 btext
^ Zc/z_BHBSD爱好者乐园 K-Caut
因此,在物理地址0x458a30处设置断点,单步跟踪locore.s中的初始化代码。程序运行至此
s;@G+seQMNJ)c6e的cpu主要寄存器的内容如下:
|'d7UN1o m8o@
:?/{4p~R7X oG6Q+xrax: 0x00000000:00458a30 rcx: 0x00000000:a0200000
jT H:N!O&}Srdx: 0x00000000:000488a0 rbx: 0x00000000:00458a30
\B'h(nKrsp: 0x00000000:0009e844 rbp: 0x00000000:00094884BSD爱好者乐园nu9\(w:hA_R:~ T9b
rsi: 0x00000000:000610e4 rdi: 0x00000000:0005b9cc
H] R.gz5e(\!c$nr8 : 0x00000000:00000000 r9 : 0x00000000:00000000BSD爱好者乐园 wuc_:X'w]
r10: 0x00000000:00000000 r11: 0x00000000:00000000
-`vg*];Btx'p7Rr12: 0x00000000:00000000 r13: 0x00000000:00000000
c#t~!gf&r7F-dKPr14: 0x00000000:00000000 r15: 0x00000000:00000000
5]5NO m`+J%arip: 0x00000000:00458a30BSD爱好者乐园JD s8rf Q
eflags 0x00000002BSD爱好者乐园[t CaeA)C@(A$g

5L] SrMb+y首先是向0x472写入0x1234,告知bios下次为热引导:BSD爱好者乐园 z$T*l bg;ur}2o
BSD爱好者乐园7@2}T\!g2C6|O/s'^%w1|
216  /* Tell the bios to warmboot next time */
\8yH0| UY5^7PO217          movw    $0x1234,0x472
2yI0[u8U Fe/B5SCBSD爱好者乐园+ib{ jXG#T
构建一个新的帧:BSD爱好者乐园5~6l*^:Vmc` i

+Q0yt;d!])ovx220  /* Set up a real frame in case the double return in newboot is executed. */BSD爱好者乐园P*_G4A7t{)UhP
221          pushl   %ebpBSD爱好者乐园;{,f%K5P0R0E
222          movl    %esp, %ebpBSD爱好者乐园|ubc7@A7^B
BSD爱好者乐园_L;^ _8Z(Da0X+f
此时cpu主要寄存器的内容如下:BSD爱好者乐园#B _3a6[ L

y#FN:N9A6_rax: 0x00000000:00458a30 rcx: 0x00000000:a0200000BSD爱好者乐园H,j:A_S(K
rdx: 0x00000000:000488a0 rbx: 0x00000000:00458a30BSD爱好者乐园V ] t8E DK-sh4Ia^ q
rsp: 0x00000000:0009e840 rbp: 0x00000000:0009e840BSD爱好者乐园wX j2O/g
rsi: 0x00000000:000610e4 rdi: 0x00000000:0005b9ccBSD爱好者乐园&\(e[7k_)ua1tp2Q
r8 : 0x00000000:00000000 r9 : 0x00000000:00000000BSD爱好者乐园Bc uO$lzD1gj T
r10: 0x00000000:00000000 r11: 0x00000000:00000000
m:j+M%Xd6e Q5?r12: 0x00000000:00000000 r13: 0x00000000:00000000BSD爱好者乐园]%L)^H!t{
r14: 0x00000000:00000000 r15: 0x00000000:00000000BSD爱好者乐园|6aVc%x3R
rip: 0x00000000:00458a3cBSD爱好者乐园i-B;pFX)q
eflags 0x00000002
\-G|7i-G*_
9V&`:VoXw将PSL_KRENEL赋给eflags:
f&S|*I;}f%q |
+Uz)h5\_224  /* Don't trust what the BIOS gives for eflags. */
\ep#r @Qb@8D(@.]+M225          pushl   $PSL_KERNELBSD爱好者乐园u#WKZU
226          popflBSD爱好者乐园RV w j;v2|2Z

|qET4C?4m&q3dPSL_KERNEL是在/sys/i386/include/psl.h中定义的:
(X!E~y~{
|;XX0|"ZX,e-k'L:F60  /*
kGb lJXy61   * The i486 manual says that we are not supposed to change reserved flags,
&V5r&Xs5Z#bE|}]&`62   * but this is too much trouble since the reserved flags depend on the cpuBSD爱好者乐园8x_ Mj2C
63   * and setting them to their historical values works in practice.BSD爱好者乐园L-XGDBhdP5[ c gr
64   */
iv0y0e@jy[65  #define PSL_RESERVED_DEFAULT    0x00000002BSD爱好者乐园%J:H_~5Iw2\U4d
66BSD爱好者乐园+XdGq)H.t-xa
67  /*
4Ph7_$`d1i68   * Initial flags for kernel and user mode.  The kernel later inheritsBSD爱好者乐园 WNI1g3I0Lb5eM
69   * PSL_I and some other flags from user mode.BSD爱好者乐园nMt/l3x6`
70   */BSD爱好者乐园lt#V.aB3u1Sf M
71  #define PSL_KERNEL      PSL_RESERVED_DEFAULT
3NdH A#K D72  #define PSL_USER        (PSL_RESERVED_DEFAULT | PSL_I)
2lE-k-}n*z
A Rs:|?+pfE将ds的内容赋给fs和gs:
(J'BwLUh5k)bXBSD爱好者乐园U-rf SH/e E gM
228  /*
},B^0P%_T229   * Don't trust what the BIOS gives for %fs and %gs.  Trust the bootstrap
2Qw2__G230   * to set %cs, %ds, %es and %ss.
|0eQf[F VcR231   */BSD爱好者乐园MFaGq'fXm"x
232          mov     %ds, %ax
h)d/CF,Da233          mov     %ax, %fsBSD爱好者乐园s)[K!X j
234          mov     %ax, %gsBSD爱好者乐园%r+e8z Qfu q
BSD爱好者乐园5t?oBe(e H3r%c

E5j'xM Ow5tI;Mw236  /*BSD爱好者乐园!r(X3@1\0VY3F
237   * Clear the bss.  Not all boot programs do it, and it is our job anyway.BSD爱好者乐园YHBw2lM`/WS
238   *
~%i-L x"VRiv239   * XXX we don't check that there is memory for our bss and page tablesBSD爱好者乐园$D3sJT [2M
240   * before using it.BSD爱好者乐园*\Eu&X9HA~Q
241   *
qn"TQ6D_"?R242   * Note: we must be careful to not overwrite an active gdt or idt.  TheyBSD爱好者乐园U9k}d X+t8H
243   * inactive from now until we switch to new ones, since we don't load any
3yk!Eh7j |244   * more segment registers or permit interrupts until after the switch.
7Hj{N7\2tI245   */BSD爱好者乐园HpyR9o&?1i
246          movl    $R(end),%ecx
$S`)i:{Q._3\247          movl    $R(edata),%ediBSD爱好者乐园,o(d hn8bB
248          subl    %edi,%ecx
]7o9tVitk8M249          xorl    %eax,%eax
0] Hs4n/As250          cldBSD爱好者乐园@K~~8OV
251          rep
5m8} O:D)z |252          stosb
N6n(U'U/e2U@%i
z*t,Y n)t B根据readelf -a kernel的结果,end的地址是0xc0c06020,由于KERNBASE是BSD爱好者乐园'n-|\1M cfe o2O|
0xc0000000,此处赋给ecx的就是0xc06020。edata的地址是0xc0bab9a0,这实际上就是
W'g1R'ayB;?.bss段的起始地址,此处赋给edi的就是0xbab9a0。ecx减去edi之后的内容是0x5a680,BSD爱好者乐园5~l#^Dw;n.{#GO
这是从.bss段起始地址到end地址之间的字节数。随后将eax清0,作为后续清0操作的
Q\1}HM#hzekM写入值。cld保证edi递增变化。stosb将al的内容写入edi指向的位置。这段代码从
$g.qj L%^Kh3I/Wy0xc0bab9a0开始连续写入0x5a680个字节的0,从而实现将.bss段清0的目的。BSD爱好者乐园+wa nss/s

B L {.R's5O253
ovMm*sZKm[254          call    recover_bootinfo
H ]d.gg5{z:a;oT,H255
o9[kTZ2n eBSD爱好者乐园7\ P$LBg
调用recover_bootinfo获取由loader传入的引导信息。BSD爱好者乐园9O${$CK6Bb'? zg;f

p `8x4eWyG7G487          movl    28(%ebp),%ebx           /* &bootinfo.version */
X ~M7T o%{488          movl    BI_VERSION(%ebx),%eaxBSD爱好者乐园6P"y,t[/V~k
489          cmpl    $1,%eax                 /* We only understand version 1 */BSD爱好者乐园CB |8~O${4d4m
490          je      1fBSD爱好者乐园AKrb:R
491          movl    $1,%eax                 /* Return status */BSD爱好者乐园-Hmob!g
492          leave
S'H[8B%`;K493          /*BSD爱好者乐园D Onf(? s
494           * XXX this returns to our caller's caller (as is required) sinceBSD爱好者乐园R^C"I%L!}1Lx
495           * we didn't set up a frame and our caller did.BSD爱好者乐园 aN;J@)C*iS!q^2BH
496           */BSD爱好者乐园-M iboM8N
497          ret
bD-mQ:c.bEq-~BSD爱好者乐园CW$M/z5k L
locore.s入口btext的调用格式为(*btext)(howto, bootdev, 0, 0, 0, &bootinfo),在bootinfoBSD爱好者乐园*X,_V YX\
之后压栈的有5个参数,占20个字节,在加上返回地址和在调用recover_bootinfo之前压栈的ebp,BSD爱好者乐园8pG&Nfu^ep}
一共有28个字节,因此从当前ebp位置上溯28个字节就是bootinfo结构体的起始地址。上述代码BSD爱好者乐园@&b L P&F#S"cU
从bootinfo结构体中取出bi_version字段的内容,判断其是否为1,仅当版本为1时才继续处理。
E3H*]GjEZ9@CBSD爱好者乐园Cri'gs%v(`
500          /*
V2i;GR|6Wb501           * If we have a kernelname copy it inBSD爱好者乐园MH l`9[*W,S ~ X
502           */
Gp(?j R~503          movl    BI_KERNELNAME(%ebx),%esiBSD爱好者乐园7s4eI0E!`is8`6_6X
504          cmpl    $0,%esi
1Y.sp/xv` b505          je      2f                      /* No kernelname */BSD爱好者乐园*Q1J(C|#Fi
506          movl    $MAXPATHLEN,%ecx        /* Brute force!!! */BSD爱好者乐园9q;M0\ bD F&Y)~F
507          movl    $R(kernelname),%ediBSD爱好者乐园8_I(]5^6Y$o1m&W}p
508          cmpb    $'/',(%esi)             /* Make sure it starts with a slash */BSD爱好者乐园!de'ESw4a`
509          je      1fBSD爱好者乐园U"]J2n6t?aY
510          movb    $'/',(%edi)
&A+K,oW?:D^ yu511          incl    %edi
/}*CH"qJm)H2Q9Y B512          decl    %ecxBSD爱好者乐园[,RO/W/E w(fmdN
BSD爱好者乐园R/u |Z;`u#T
从bootinfo结构体中取出bi_kernelname字段,写入esi。MAXPATHLEN是最大路径长度,定义为1024,BSD爱好者乐园:[g!n n.y n e
这是kernel中的kernelname数组的尺寸。将该数组相对于KERNBASE偏移地址写入edi,并判断由
.I-V&cy k1]*J:uGbootinfo传入的bi_kernelname是否以"/"开始,若是,则将剩余部分拷入kernelname数组。
kV\.|$u"uBSD爱好者乐园V:qs!e4kR
519          /*
C;G1oWBIs\W5H520           * Determine the size of the boot loader's copy of the bootinfo
1oK/~.B ?M521           * struct.  This is impossible to do properly because old versions
qd8P%W#Y9x0m8y522           * of the struct don't contain a size field and there are 2 oldBSD爱好者乐园f _.g.zj D
523           * versions with the same version number.BSD爱好者乐园Y\j iKN,S
524           */BSD爱好者乐园 F1Ryx.`2| @ UV
525          movl    $BI_ENDCOMMON,%ecx      /* prepare for sizeless version */
u7z8[$rEU/[;izc/R526          testl   $RB_BOOTINFO,8(%ebp)    /* bi_size (and bootinfo) valid? */BSD爱好者乐园8P7CW:r%wbJq^
527          je      got_bi_size             /* no, sizeless version */BSD爱好者乐园B2M/XAc
528          movl    BI_SIZE(%ebx),%ecx
^k5u} Fk`+B
sa'ABE;` G将bootinfo中肯定会存在的字段的结束位置取出,写入ecx,实际上就是前三个字段,12个字节。
;}+C4SPL3a9}Q1~_]yRB_BOOTINFO在/sys/sys/reboot.h中定义为0x80000000,是一个表示是否传入了完整的bootinfoBSD爱好者乐园PV K!B{_9Y
结构体信息的标志。若传入了完整的bootinfo结构体信息,则将bi_size字段的内容赋给ecx。BSD爱好者乐园 F!kg4Av*? h
BSD爱好者乐园`w9N5I'}
531          /*BSD爱好者乐园%@-LB;xB#h#k,\$H:Mk
532           * Copy the common part of the bootinfo struct
,b/PuC PQ'@i533           */BSD爱好者乐园4Z6dKl.C!Jx
534          movl    %ebx,%esiBSD爱好者乐园W#YTHC0w
535          movl    $R(bootinfo),%edi
1e"E2Q:C zT.}lPs536          cmpl    $BOOTINFO_SIZE,%ecxBSD爱好者乐园2e} A%b8Ht
537          jbe     got_common_bi_sizeBSD爱好者乐园\v SV4V,I3J!|
538          movl    $BOOTINFO_SIZE,%ecxBSD爱好者乐园(qv#gkbxrPI
539  got_common_bi_size:
`(f9|o A$~540          cldBSD爱好者乐园H3I,k-eW3J,xfJ,pp
541          rep
.T B&gvK&v/n542          movsb
K7B#L@x
J.Ld|#n~,z比较传入的bi_size字段的内容与bootinfo结构体的大小是否一致,若传入bi_size小于等于bootinfoBSD爱好者乐园iY6L]:s V AI
结构体的大小,则以bi_size为准,否则以bootinfo结构体的大小为准。将传入的bootinfo信息拷贝BSD爱好者乐园2l-J6OD8KxKY)M
到bootinfo结构体中。BSD爱好者乐园``c9y)^x
BSD爱好者乐园.iat!YVUL
562          /*BSD爱好者乐园 XZ)H3h8H9~p
563           * The old style disk boot.BSD爱好者乐园nj? \7A9v~Y y
564           *      (*btext)(howto, bootdev, cyloffset, esym);BSD爱好者乐园ih'l.~G#shUy
565           * Note that the newer boot code just falls into here to pickBSD爱好者乐园V6`tn-Lq
566           * up howto and bootdev, cyloffset and esym are no longer used
+m-[ XE5[e567           */BSD爱好者乐园x2IK`N5MM0H's+p*f
568  olddiskboot:
:A*H&Y V2E m569          movl    8(%ebp),%eaxBSD爱好者乐园CzB0l?(RwQe
570          movl    %eax,R(boothowto)BSD爱好者乐园Cp a?+l`
571          movl    12(%ebp),%eax
mm Z| s8E572          movl    %eax,R(bootdev)BSD爱好者乐园:lvQ!z Q4x/{vx2q
573BSD爱好者乐园 ^p;J ^ d1m+e
574          ret
AOpG9a,k;GtBSD爱好者乐园$RGjBV@2dz
分别从入参中取出相关信息存入boothowto和bootdev变量。返回btext。
|+|+~Qr~
&x"nI$ZBt whrT@}4H256  /* Get onto a stack that we can trust. */
2X.QY6k,?2f0} G257  /*BSD爱好者乐园 a3mS~ b!r
258   * XXX this step is delayed in case recover_bootinfo needs to return via
KU6[ yi }u u259   * the old stack, but it need not be, since recover_bootinfo actuallyBSD爱好者乐园 {T,s/?\7Z QNV
260   * returns via the old frame.
UO9Z'Po)P j261   */
hDxV!@^262          movl    $R(tmpstk),%esp
o7wo+K[ag/D
#_W T Tnatmpstk是在本文件中定义的一块8192字节的连续空间,此处将esp指向这块空间。BSD爱好者乐园(?+?,T&I F9k?*E
实际上,这块空间就紧邻在bootinfo结构体的下面。BSD爱好者乐园2t A4n @"]q

q9x!I,O2U t'`291          call    identify_cpu
+q)c*Oky7}d+C u9aBSD爱好者乐园gP Nt ycVJ-Q
获取cpu识别信息。
KoUOk?!wBSD爱好者乐园,^n#_VL B
292          call    create_pagetablesBSD爱好者乐园#Qh6W7?3N

5N M b'm+?创建第一个页面目录及其页表。BSD爱好者乐园^j1PC+L F-s X

6@B'o0nJ'e

i8i,d]!C i|
[重要提醒]对本篇资料有疑问,请到论坛讨论,尽量使文章准确无误>>>
[版权声明]BSD爱好者乐园站内文章,如来源不是互联网,则均系原创或翻译之作,可随意转载,或以此为基础进行演译,但务必以链接形式注明原始出处和作者信息,否则属于侵权行为。另对本站转载他处文章,俱有说明,如有侵权请联系本人,本人将会在第一时间删除侵权文章。
TAG: 分析 源代码

61/6123456>
 

评分:0

我来说两句

seccode