Lesson 1: 引导扇区
这一课我们将学习引导扇区的知识,这样我们就能写一个我们自己的引导程序了。
当计算机从软盘引导时, BIOS (Basic Input/Output System)将磁盘的第一个扇区读入以0000:7C00开始的内存。这个扇区称为DOS Boot Record (DBR)。然后,BIOS跳转到0x7C00开始执行那里的指令。正是那些指令(即“boot loader”)将把OS加载到内存中,并且开始启动处理。
我们要做的第一件事情是仔细看一看Boot Record。DOS的工具DEBUG非常有用,我们常常用它来查看内存或着是磁盘的内容。同样,我们将用DEBUG来看看软盘的Boot Record。
在DOS (或者Windows)的命令行方式下输入debug。于是提示符变成了连接线。如果你输入命令‘d’加上一个回车,它将显示一块内存的内容。如果你输入一个问号,将显示在DEBUG中可用的命令。(请仔细使用DEBUG。它可以用来覆盖磁盘上的内容,这有可能导致数据的丢失。)
请在软驱中放入一张新格式化的软盘。要载入你软盘上的Boot Record,请输入如下命令。
-l 0 0 0 1
(第一个字符是字母‘l’,而不是数字‘1’。)这个命令将磁盘扇区载入到内存中。‘l’后面的四个数字,依次表示你希望将数据载入到其中的那块内存的首地址,驱动器编号 (软驱的话,是0),以及扇区的编号和扇区的数目。输入这个命令将把磁盘的第一个扇区载入到内存以0开始的地方。
现在我们已经把Boot Record载入到内存里了,接下来我们想看看它的内容,输入下面的指令。
-d 0
你会看到8行数据,它们表示软盘引导记录最初的128(16进制的0x80)个字节。结果(我的软盘)如下:
0AF6:0000 EB 3C 90 4D 53 44 4F 53-35 2E 30 00 02 01 01 00 .<.MSDOS5.0.....
0AF6:0010 02 E0 00 40 0B F0 09 00-12 00 02 00 00 00 00 00 ...@............
0AF6:0020 00 00 00 00 00 00 29 F6-63 30 88 4E 4F 20 4E 41 ......).c0.NO NA
0AF6:0030 4D 45 20 20 20 20 46 41-54 31 32 20 20 20 33 C9 ME FAT12 3.
0AF6:0040 8E D1 BC F0 7B 8E D9 B8-00 20 8E C0 FC BD 00 7C ....{.... .....|
0AF6:0050 38 4E 24 7D 24 8B C1 99-E8 3C 01 72 1C 83 EB 3A 8N$}$....<.r...:
0AF6:0060 66 A1 1C 7C 26 66 3B 07-26 8A 57 FC 75 06 80 CA f..|&f;.&.W.u...
0AF6:0070 02 88 56 02 80 C3 10 73-EB 33 C9 8A 46 10 98 F7 ..V....s.3..F...
粗看一眼,仿佛什么都没有。我能够看出来这是张MS-DOS 5.0的软盘,有一个没有名字的FAT12文件系统。最左端的数字显示的是内存地址。中间的16进制码显示的是这段内存的全部字节,最右边显示的是16进制码所对应的ASCII字符(如果某字节不能被转换为一个可见的字符,就用一个句点来表示)。这部分引导记录中的一些字节是boot loader的指令,另一些存储了诸如每个扇区多少字节,每个磁道多少扇区这样的信息。
现在到看一看boot loader代码的时候了。输入下面的指令。
-u 0
这将执行“unassemble”操作。这将同样显示刚才的那些字节,(从地址0开始),只不过这一次DEBUG显示的是这些字节所表示的INTEL的指令。我的软盘结果如下:
0AF6:0000 EB3C JMP 003E
0AF6:0002 90 NOP
0AF6:0003 4D DEC BP
0AF6:0004 53 PUSH BX
0AF6:0005 44 INC SP
0AF6:0006 4F DEC DI
0AF6:0007 53 PUSH BX
0AF6:0008 352E30 XOR AX,302E
0AF6:000B 0002 ADD [BP+SI],AL
0AF6:000D 0101 ADD [BX+DI],AX
0AF6:000F 0002 ADD [BP+SI],AL
0AF6:0011 E000 LOOPNZ 0013
0AF6:0013 40 INC AX
0AF6:0014 0BF0 OR SI,AX
0AF6:0016 0900 OR [BX+SI],AX
0AF6:0018 1200 ADC AL,[BX+SI]
0AF6:001A 0200 ADD AL,[BX+SI]
0AF6:001C 0000 ADD [BX+SI],AL
0AF6:001E 0000 ADD [BX+SI],AL
第一个指令要求跳转到0x3E。这之后的指令是关于刚才我提到的软盘参数的,并没有对应的指令,但是DEBUG还是尽心尽责的为我们翻译了。
第一条指令跳过了这些数据,执行从地址0x3E开始的启动程序的代码。让我们看看那里的指令,输入:
-u 3E
在这里,你能看到负责加载DOS或者是WINDOWS的代码的开始部分。代码(就MS-DOS来说)将在磁盘上寻找IO.SYS和MSDOS.SYS。这些文件包含了操作系统的代码。boot loader的代码将把这些文件载入到内存中,并且开始执行它们。如果在磁盘上没有找到这些文件,boot loader将显示如下这条臭名昭著的错误信息:
Invalid system disk
Disk I/O error
Replace the disk, and then press any key
如果你看一下DOS引导记录的最后部分,你将会发现这条信息。你可以看看我磁盘上的:
-d 180
0AFC:0180 18 01 27 0D 0A 49 6E 76-61 6C 69 64 20 73 79 73 ..'..Invalid sys
0AFC:0190 74 65 6D 20 64 69 73 6B-FF 0D 0A 44 69 73 6B 20 tem disk...Disk
0AFC:01A0 49 2F 4F 20 65 72 72 6F-72 FF 0D 0A 52 65 70 6C I/O error...Repl
0AFC:01B0 61 63 65 20 74 68 65 20-64 69 73 6B 2C 20 61 6E ace the disk, an
0AFC:01C0 64 20 74 68 65 6E 20 70-72 65 73 73 20 61 6E 79 d then press any
0AFC:01D0 20 6B 65 79 0D 0A 00 00-49 4F 20 20 20 20 20 20 key....IO
0AFC:01E0 53 59 53 4D 53 44 4F 53-20 20 20 53 59 53 7F 01 SYSMSDOS SYS..
0AFC:01F0 00 41 BB 00 07 60 66 6A-00 E9 3B FF 00 00 55 AA .A...`fj..;...U.
这是引导记录的末尾。引导记录在磁盘上恰好占一个扇区(512字节)。如果从内存地址0开始加载它,那么最后那个地址应该是0x1FF。如果你看一看引导记录的这最后两个字节(0x1FE和0x1FF),你会发现它们是0x55和0xAA。引导记录的最后两个字节一定得是这个值,否则BIOS将不会加载这个扇区并且执行它。
概括起来说,DOS的引导记录以一个跳转指令开始,这个跳转指令讲跳过紧随其后的数据。这60字节的数据从0x02开始,至0x3D,之后是引导代码,从0x3E到0xFD,再之后是两个字节0x55和0xAA。下一课我们将利用我们的这些知识,来写一个我们自己的引导程序。