买了一本于渊的《Orange'S: 一个操作系统的实现》,很是感谢作者的分享,正如作者所说的:OS From Scratch
于是想把学习过程中碰到的问题和心得记录下来...
好吧,直接进入主题,引导扇区,代码如下:
作者已经把扇区的引导说的很清楚了,我就不再赘述了,我们重点看看这段代码要干什么(其实就是在显示器上打印字符串“Hello OS world!”):
第1行 : 主要是告诉编译器,将来我们这段程序要被加载到内存偏移地址0x7c00h处
第2~4行: 很简单,将ds,es都指向cs段,这里,我们并没有将代码段和数据段明显的分开,所以都指向相同的地址
第5行 : 调用了函数DispStr,也就是显示字符串,我们后面会重点分析这个函数
第6行 : $表示当前行被汇编后的地址,所以jmp $,做的事情就是反复的跳转到第6行,也就是无限的循环,但什么也不做
我们重点分析函数DispStr:
首先我们看到14行,调用了BIOS的10h 中断,那BIOS的10h 中断是干什么的呢?我们先来了解一下:
我们在汇编语言程序中可使用软中断指令“INT n”调用BIOS程序,其中n是中断类型码。常用的BIOS程序的功能与其中断类型码对应关系如下:
中断类型码 BIOS中断调用功能
10H 显示器I/O中断调用(即显示器驱动程序)
16H 键盘驱动程序
17H 打印机驱动程序
13H 磁盘驱动程序
14H 通信驱动程序
因为我们这里要显示字符串,所以我们调用了显示器驱动程序(10H),但是显示器驱动程序也有很多功能,主要有寄存器AH来确定,我们注意到13行,将AX的值赋为:01301h,所以AH的值为:13,那么我们重点看看13号功能:
功能号:13H
功能:在Teletype模式下显示字符串
入口参数:AH=13H
BH=页码
BL=属性(若AL=00H或01H)
CX=显示字符串长度
(DH、DL)=坐标(行、列)
ES:BP=显示字符串的地址 AL= 显示输出方式
0—字符串中只含显示字符,其显示属性在BL中。显示后,光标位置不变
1—字符串中只含显示字符,其显示属性在BL中。显示后,光标位置改变
2—字符串中含显示字符和显示属性。显示后,光标位置不变
3—字符串中含显示字符和显示属性。显示后,光标位置改变
其他功能可以参考:http://www.programfan.com/blog/article.asp?id=16290
就像我们平时函数调用时要传参数一样,调用中断的驱动程序时,也要传递相应的参数,这些参数就存储在相应的寄存器里,跟据上面入口参数的描述,我们很容易理解8~13行所做的事情:
1)ES:BP=显示字符串的地址:bp --> BootMessage, 即字符串的偏移首地址,上面es已经等于cs了,es:bp就指向了我们的字符串
2)CX=显示字符串长度 : "Hello OS world!" 的长度为16,则:cx = 16
3)AL= 显示输出方式 :我们选择的输出方式为01H:字符串中只含显示字符,其显示属性在BL中。显示后,光标位置改变,同时 19:15:58AH=13h,故:ax = 01301h19:10:2719:10:38
4) BH=页码
5) BL=属性(若AL=00H或01H) : BH=0:页码为0, BL=0Ch:黑底红字,字符串中的字母都会以黑底红字的方式显示
6)(DH、DL)=坐标(行、列) : 我们 mov dx,00000h :就表示从第1行第1列开始显示,你要是mov dx, 00404h 就从第5行第5列始显示字符串
所以这个函数执行结束,就是在从显示器第1行第1列开始以黑底红字的方式显示字符串"Hello OS world!"
然后我们来到17行,作者已经解释了:$-$$ 表示本行距离程序开始处的相对位置,17行做的事就是,将剩下的到510字节为止的空间里填充0,最后在511,512个字节处填充AA55,表示扇区的结束。
其实我们可以做更多的事情,因为我们填充了 510-($-$$) 个0,故事的序幕也就是从这些荒芜的地方拉开了