引导程序
1:概述
计算机在开始启动的时候,首先运行BIOS程序,BIOS程序检测当前硬件。
完成后,根据CMOS中的关于驱动器启动顺序的设置,找到一个可用的驱动器来启动。
这里的驱动器包括软盘、光盘、硬盘等设备,但是为了简化问题,下面只讨论软盘驱动器或者硬盘驱动器的启动。
在软盘(硬盘)启动的过程中,最先是BOIS将软盘的首扇区(也就是0柱面,0头、1扇区)的512个字节的内容读到内存的7C00H的地方,然后CPU跳到7C00H(CS:IP=0000:7C00H?)处运行。
由于只有512个字节的大小,不可能放下一个操作系统的代码。
因此,这512个字节的代码一般是一个过渡性的代码,它主要由读软盘扇区指令构成,用来实现这样的一个功能:将操作系统的代码都读到内存中去,读完后再通过JMP指令跳到操作系统代码的入口地址,进一步运行程序。
习惯上,我们把保存在首扇区中的程序称为引导程序。
虽说引导程序一般是用来实现操作系统的引导的,的是但这并不是必要的;它可以是任何形式的代码,只要符合的一个条件:代码对应的机器代码不超过512个字节。
下面的引导程序演示代码就没有任何的读软盘指令,它只是不断的循环一个过程:接受并显示字符。
在最后,交代一下程序的运行软件环境:程序在XP编写、编译,在虚拟机下测试。
2:引导程序演示代码
2.1演示代码BOOT.ASM
.MODEL SMALL ;这个可以不用管
CODE SEGMENT
ASSUME CS:CODE,DS:CODE ; 数据段和代码段混合在一起了
ORG 7C00H
START: JMP START1
INFO DB 'A:\',0 ;提示信息
STR1 DB 80 DUP (0) ;接受键盘输入缓冲区
START1:
MOV AX,CODE
MOV DS,AX
;设置光标的位置,在屏幕的最后一行,屏幕行号范围0—24,列号范围0-79
MOV DH,24 ;行号
MOV DL,0 ;列号
MOV AH,2 ;子功能号
INT 10H
L1: MOV SI,OFFSET INFO
CALL DISP_STR ;显示提示信息
CALL GET_STR ;输入字符串,以回车结束输入
CALL CRLF ;换行
MOV SI,OFFSET STR1
CALL DISP_STR ;输出刚才从键盘中接受到的字符串
CALL CRLF
MOV SI,OFFSET STR1
CMP BYTE PTR [SI],0 ;如果直接回车,那么就退出程序
JZ EXIT
JMP L1
EXIT:
MOV AH,4CH
INT 21H
DISP_STR PROC ;显示字符串
CLD ;设置DF=0,给后面的串指令用
.WHILE BYTE PTR [SI] != 0 ;.while是汇编伪指令,功能和高级语言的while一样LODSB
MOV AH,0EH ;输出字符
INT 10H
.ENDW
RET
DISP_STR ENDP
CRLF PROC ;实现回车功能
;屏幕上卷一行
MOV CH,0
MOV CL,0
MOV DH,24
MOV DL,79
MOV AL,1
MOV AH,06H
MOV BH,7
INT 10H
;获得光标位置
MOV BH,0
MOV AH,3
INT 10H
;设置光标位置
MOV BH,0
MOV DL,0
MOV AH,02H
INT 10H
RET
CRLF ENDP
GET_STR PROC ;从键盘输入字符串
MOV SI,OFFSET STR1
GETS: MOV AH,0
INT 16H
.IF AL != 0DH ;如果输入的字符不是回车,就显示字符,并继续输入MOV [SI],AL
INC SI
MOV AH,0EH
INT 10H
JMP GETS
.ENDIF
MOV [SI],0
RET
GET_STR ENDP
CODE ENDS
END START
2.2说明
1)我们首先将上面的BOOT.ASM文件编译、连接为BOOT.EXE文件。
2)该程序可以在控制台上运行预览结果,按回车结束程序。
下面为运行的结果。
程序只处理字母、数字和回车的输入,对于控制字符、退格等并没有处理。
3.写引导程序
引导程序完成了,现在我们就要将引导程序boot.exe写入软盘的首扇区。
3.1 EXE的文件结构
EXE文件由2部分构成:一部分是头部信息,一部分是汇编代码对应的机器代码。
下面我们用Ultra Edit打开BOOT.EXE,查看EXE的结构
头部信息一般都是512个字节,以4D5A开始,包含了CS、DS、SS、SP等基本信息。
操作系统在加载的EXE程序的时候,根据这些信息进行重新定位。
Boot.exe程序的数据头部如下:
对于EXE头部说明,就讨论到这里,更具体的说明再另外讨论
机器代码部分是从200H处开始的,我们发现,在200H~~7DFFH中的
7C00H个字节的数据都是0,这是因为编译ORG 7C00H这个指令的时候
,后面的代码从7C00H处开始,前面的数据都没有定义,就用0来填充。
7E00H后面的数据才是我们要写入首扇区的数据,这些数据都是和START:标号后的汇编指令一一对应的,这些数据如下,图中圈起来的数据是由DB ‘A:\’,0和DB 80 dup(‘0’)生成的。
我们用DEBUG来查看boot.exe的内容,并和上面的对比一下.
对比DEBUG中的反汇编的结果,它是和上面的7E00H中的数据以及和BOOT.ASM中的代码是一致的。
在认真对比一下,还是有一个地方不同的。
在DEBUG中,如上图所示,二进制代码是B8D313H,而用Ultra Edit查看的是B80000H,这个区别是因为DEBUG是对BOOT.EXE重定位的结果,这个重定位是由操作系统来完成的。
我们在把boot.ex e7E00H后面的数据写入软盘首扇区。
然后设置从软盘引导,由BOIS读到将该内容读并跳到7C00H处,运行到7C56H 处的时候,CPU执行的机器代码是B80000,也就是运行MOV AX,0000这样一个指令,而不是DEBUG中显示的MOV AX,13D3H。
3.2写引导程序
简单来说,把boot.exe写入到首扇区只要经过下面几步就可以了
1: 打开boot.exe文件
2: 把文件指针移动到7E00H的地方
3: 把boot.exe后面的内容读出来
4: 关闭文件
5: 把读出来的内容写到软盘的首扇区去.
具体的代码可以自己实现,也可以查看WRBOOT。
ASM文件,对于这个文件,我就不做具体的解释了。
编译完成后,运行WRBOOT.EXE,在从软盘启动,就可以看到结果了。
要注意以下两点:
1.在编译连接WRBOOT。
ASM的时候,在注意你的BOOT.EXE程序放
置的路径,在程序中做相应调整。
2.在测试程序的时候,不要直接回车,因为那时侯系统还不可以处理mov
ax,4ch int 21h这样的一个DOS中断
3.3 一些细节问题
1:ORG 7C00H 的作用
在这个程序中,ORG 7C00H是一个非常重要、却经常会忽略的指令。
假如没有这个指令,程序可能可以运行,却得不到所希望的结果。
ORG 7C00H在程序中的影响体现在两个地方:
MOV SI,OFFSET INFO
MOV SI,OFFSET STR
我们由前面的DEBUG知道,这两个指令在原来的程序中实际上是MOV SI,7C02H
MOV SI,7C06H
如果少了ORG 7C00H,就变成了
MOV SI,02H
MOV SI,06H
这样的区别是很明显的。
但是ORG 7C00H对JMP 指令是没有影响的,JMP在这里的短跳转,它的机器语言的意思是(新的IP)<-当前IP+相对偏移。
2:关于55AAH
一般的引导程序最后的两个字节是55AAH,以用来给BOIS检测该扇区的代码否是引导程序(就象EXE的开始2个字节是4D5AH),然后BOIS才将控制权转到7C00H处。
但有些BOIS没有首先检测这两个字节,而首先运行代码的程序,就想我的程序的测试环境中,就没有把这两个字节写上,也可以运行。
但建议还是不要省略这两个字节。
关于BOIS、CMOS
计算机在启动的时候,首先由BOIS检测当前硬件,然后与CMOS存储器中的设置比较;如果结果正确,则将控制权交给硬盘主引导记录,启动操作系统。
BOIS检测和设置程序放在BOIS芯片中,而BOIS设置后的硬件参数等放在CMOS存储器中。
BOIS设置也包括因盘参数的设置。
有关BOIS和CMOS的一些基本概念,对写操作系统非常重要。
BOIS是指放在ROM芯片中的软件,CMOS是只可读写的RAM存储器。
一、CMOS的基本概念
CMOS是微机主板上的一快可读写的RAM芯片,一般有128字节或者256字节的容量,存放微机系统的时钟信息和硬盘配置等信息,它依靠系统电源供电,系统掉电后,储存的信息不会丢失。
CMOS存储器是作为一种I/O设备来实现与CPU交换信息的,CMOS占有两个I/O地址,70H为地址口,71H。