继续之前,先阅读一下硬盘的寻址方式文档。
随意Google一篇:
[url]http://storage.chinabyte.com/249/3444249.shtml[/url]
关联的Stage 1 代码如下:
0000001C 3CFF cmp al,0xff
0000001E 7402 jz 0x22
00000020 88C2 mov dl,al
00000022 52 push dx
00000023 BE7F7D mov si,0x7d7f
00000026 E83401 call word 0x15d
00000029 F6C280 test dl,0x80
0000002C 7454 jz 0x82
0000002E B441 mov ah,0x41
00000030 BBAA55 mov bx,0x55aa
00000033 CD13 int 0x13
00000035 5A pop dx
00000036 52 push dx
00000037 7249 jc 0x82
00000039 81FB55AA cmp bx,0xaa55
0000003D 7543 jnz 0x82
0000003F A0417C mov al,[0x7c41]
00000042 84C0 test al,al
00000044 7505 jnz 0x4b
00000046 83E101 and cx,byte +0x1
00000049 7437 jz 0x82
困了,明天再来:)
OK, Coming->
先看第一段:
0000001C 3CFF cmp al,0xff
0000001E 7402 jz 0x22
按照boot.S如下注释,0x7c3E起始的12个字节如下定义:
stage1_version:
.byte COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR
boot_drive:
.byte GRUB_INVALID_DRIVE /* the disk to load stage2 from */
force_lba:
.byte 0
stage2_address:
.word 0x8000
stage2_sector:
.long 1
stage2_segment:
.word 0x800
而我dd出来的对应数据区为:
0000030: 83c6 1049 7419 382c 74f6 a0b5 07b4 0302 ...It.8,t.......
0000040: ff00 0020 0100 0000 0002 ... ......
因此版本号为0302,这个与grub的0.9.6的关系我不清楚,暂时不管。
随后的0x40也就是mv al,[0x7c40]所load的内容为0xFF代表硬盘类型。引用如下文章的描述:
I'm coming {极端怀疑本文的可读性,不过作为一个过程挺好}[7C40] -> 80 ("Boot Drive") NOTE: For those of you with multi-OS
booting systems, if your Linux installation with GRUB's
remaining software (stage2, menu file, etc.) is located
somewhere other than on the Primary Master drive, this
value will be 81, 82, etc. depending upon which drive
that Linux OS's /boot/grub directory is located.
0XFF么,应该是只此一家,别无分店了。如下链接文章似乎可以印证这个说法。
Have a rest.//blog is good.
无论走那个分支,0x22处的push dx中的dl中已经包含了启动盘标识[0x80/0x81 ---]。
随后的
00000023 BE7F7D mov si,0x7d7f
00000026 E83401 call word 0x15d
0x7d7f - 0x7c00 = 17F
17F处的字符串数据为:”GRUB “
0000180: 5255 4220 0047 656f 6d00 4861 7264 2044 RUB .Geom.Hard D
0000190: 6973 6b00 5265 6164 0020 4572 726f 7200 isk.Read. Error.
0x15D处的代码为:
00000159 B40E mov ah,0xe
0000015B CD10 int 0x10
0000015D AC lodsb
0000015E 3C00 cmp al,0x0
00000160 75F4 jnz 0x156
00000162 C3 ret
//lunch,中秋就是好。
//Coming
显然,这段代码功能为利用int 10来显示字符串。
//废话比正文多。
//又是周末了,再来写。
先看lodsb功能:
LODSB∶ 指令助记符——字节装入(从字节串中取数)。它将DS段SI指出的字节数据送入AL寄存器中,并根据方向标志DF修改SI中的地址。即当DF=0时,地址加1 ;DF= 1 时,地址减1 。
这里的DF = 0 在这段代码中没有体现,也许是BIOS = STUB之间的一个约定。我理解,启动程序应该有一段CPU初始化代码才对。不知道GRUB为何这样,至少在以我所处理的嵌入式产品应该是初始化了CPU至少两次( Bootrom一次、 OS一次)。
至于int 10h的功能就很简明了,google到如下链接说明得很清楚:
AH = E
AL = char (7,8,10,13: special action)
BH = page(0)
BL = foreground color (graphic)
moves cursor
;Write command line:
mov si,82h ;parameters in PSP
mess: mov al,[si] ;each char
cmp al,0Dh ;until CR
jz quit
mov bh,0 ;page 0
mov ah,0Eh
int 10h
inc si ;next char
jmp mess
quit:
>INT 21.02: Display Character
由于前述dl = 0x80,因此
00000029 F6C280 test dl,0x80
0000002C 7454 jz 0x82
便将代码控制调整到0x82处了,在讨论0x82代码之前,先看本节关注的关键代码段:
00000030 BBAA55 mov bx,0x55aa
00000033 CD13 int 0x13
00000035 5A pop dx
00000036 52 push dx
00000037 7249 jc 0x82
00000039 81FB55AA cmp bx,0xaa55
0000003D 7543 jnz 0x82
0000003F A0417C mov al,[0x7c41]
00000042 84C0 test al,al
00000044 7505 jnz 0x4b
00000046 83E101 and cx,byte +0x1
00000049 7437 jz 0x82
如果,dl中存储的是stage2所在硬盘编号,0x8N。第一子段代码利用扩展int 13h的判断是否存在扩展服务调用(正如此链接描述):
则此驱动器不支持扩展功能. 如果进位标志为 0, 同时 BX = AA55h, 则
存在扩展功能. 此时 CX 的 0 位表示是否支持第一个子集, 1位表示是否
支持第二个子集.
随后的cmp bx 0xaa55确认是否存在合法的扩展,不存在直接跑到0x82(CHS),确实存在就将7c41(force_lba),就跑到0x4b去作LBA方式启动,否则依然0x82(CHS)方式读取stage2。我们的流程自然是0x82处的流程,下节我们来分析这个关键点。