本文主要解析MINIX中引导程序的源文件masterboot.s(1.9版本),而文章从http://www.os-forum.com/minix/boot/masterboot.php中参考了大量资料,也非常感谢作者(被参考文章)的大量注释。当是由于原作的解析是在于对代码的注释,没有很系统的折分和系统的讲解代码的工作原理。基于这个原因,作者(被参考文章)在注释中留了一些疑问;所以我决定从宏观上来讲解代码,这样能够更清楚的看清原理(不会太过于陷入细节而忽略原理),也解答了注释留下的疑问。
基于尊重和鼓励原创,如要转帖,请注明原处,谢谢。
如果对本文有任何疑问或纠正,欢迎留言,我会第一时间尽快的解答和修改。
这里我提供下masterboot.s(1.9版本)的源代码:http://www.cppblog.com/alister/archive/2011/02/26/masterboot-1_9_s.html
首先,根据源代码的结构,可以转化为如下的图示:
其中,虚线是代码中采用call的指令,实线是顺序运行或跳转指令(jmp,jl,jg...)。红色是表明该段代码是被call而不是跳转过去的。这里要注意的是fix没有与其他段代码进行跳转,而是其他代码引用fix区域内的数据。
读者可能没想到一个masterboot的汇编代码就如此的复杂,其实不是这样的;只要再看清楚就可以发现其实这个图示所表现得块可以分类成十一个分类。
第一分类是:master,over,migrate,key,getkey,keyok,override和noalt。
第二分类是:error0,error1和error。
第三分类是:sort,bubble,order,inuse和exchg。
第四分类是:loadpart。
第五分类是:bootstrap。
第六分类是:load0。
第七分类是:load,retry,ok,bad和nosig。
第八分类是:print,prnext和prdone。
第九分类是:findactive,nextdisk,nexthd,find和nextpart。
第十分类是:hang。
第十一分类是:fix。
现在我们再把这十一个分类构成图来看下分类与分类之间的依赖关系,如下图所示:
现在这个图很明显没有第一个图那么复杂了,同样的红字表明是被call的,而箭头上的蓝字就是分类与分类之间的依赖关系。下面,我将说明这些关系是什么,但是在此之前需要先说明下每个大类的功能简述。
第一分类:这个类中,主要是把LOADOFF(0x7C00)开始的512字节复制到BUFFER(0x0600),检查ALT键,若按下ALT键获取用户的输入(分区)。
第二分类:这个主要是错误处理。
第三分类:这个就是根据lowsec和sysind把分区进行排序。
第四分类:这个用于把用户的选项或默认选项加载扇区到LOADOFF(0x7C00)。(通过调用第七大类,这个类别可以理解成只是一个接口)
第五分类:直接运行地址0x7C00(LOADOFF),运行后可能是另一个masterboot或bootblock。
第六分类:设置要加载的lowsec(最小扇区号)为0,然后加载扇区到LOADOFF(0x7C00)。(通过调用第七大类)
第七分类:这个用于加载扇区到LOADOFF(0x7C00),若加载成功还检查LOADOFF+MAGIC处是否是0xAA55(目的在于检查是否是合法的引导扇区),若是合法扇区就运行地址0x7C00(LOADOFF),运行后可能是另一个masterboot或bootblock。
第八分类:这个是打印特定的字符串到标准输出(也就是显示器)。
第九分类:这是在ALT键没按下并且fix下的值是0(fix是第十一大类,用于存数据;数据关于是否绑死某个分区)的情况下,寻找一个active的分区。
第十分类:这个是所有错误最终导向的目标位置,其作用就是死机(让用户自己手动去关机或重启)。
第十一分类:这个是保存关于是否绑死某个分区来启动(0的话为不绑死,其余数字表示某分区)。
现在我已经把每个分类的大概功能都概述完毕,接着我要开始说明分类与分类之间的依赖关系。
1:第一分类与第二分类的关系;在override中,当调用load0(在第六分类中)读取所选项的第一个扇区时出现错误,就会过渡到第二分类。
2:第一分类与第三分类的关系;在override中,若用户所选的分区不是硬盘(不一定是第一个硬盘,可以是第二、第三等等)中的第一个分区时,就会过渡到第三分类。
3:第一分类与第五分类的关系;在override中,若用户所选的分区是硬盘(不一定是第一个硬盘,可以是第二、第三等等)中的第一个分区时,就会过渡到第五分类。
4:第一分类与第九分类的关系;在noalt中,若fix为0(也就是不绑死某个分区启动)时,就会过渡到第九分类。
5:第一分类与第六分类的关系;在override中,存在已绑死的分区(fix不为0)时,就会调用第六分类,然后无论成功与否都返回第一分类。
6:第一分类与第八分类的关系;在key中,若用户按了ALT键,就会调用第八分类来打印"/dev/hd?\b"到标准输出(显示器);还有一个调用存在于keyok中,调用第八分类来打印用户所选的分区选项到标准输出(显示器)。以上两个调用完后,都会返回第一分类中。
7:第九分类与第二分类的关系;在nexthd中,若在加载下个硬盘的第一个扇区(通过调用第六分类)时出现错误,就会过渡到第二分类。
8:第九分类与第八分类的关系;在nextpart中,若在寻找不到下个active的分区(相对于当前的硬盘)时,就调用第八大类来打印"None active\r\n\0"到标准输出(显示器),然后再返回第九分类。
9:第三分类与第二分类的关系;在order中,分区经过排序后,若所选的分区不是正在使用(sysind项要为0)时,就会过渡到第二分类(交给错误处理)。
10:第四分类与第二分类的关系;在loadpart中,加载分区的最小扇区(lowsec项)到LOADOFF(0x7C00)出现失败并返回时,就会过渡到第二分类(交给错误处理)。
11:第二分类与第十分类的关系;在error中,所有的错误处理最终都会过渡带第十分类(就是死机)。
12:第三分类与第四分类的关系;在order中,分区经过排序后,若所选的分是正在使用(sysind项要为非0)时,就会过渡到第四分类。
13:第四分类与第五分类的关系;在loadpart中,加在分区的最小扇区(lowsec项到LOADOFF(0x7C00)成功并返回时,就会过渡到第五分类(程序直接运行LOADOFF地址{0x7C00})。
14:第九分类与第四分类的关系;在find中,若当前所选的分区是active的话,就会过渡到第四分类。
15:第九分类与第六分类的关系;在nexthd中,通过调用第六分类来加载下个硬盘的第一个扇区,并返回第九分类。
16:第六分类与第七分类的关系;在load0中,先是把被加载分区的最小扇区(lowsec项)修改为0,然后通过渡到第七分类来完成后面实际的加载工作。
17:第四分类与第七分类的关系;在loadpart中,通过调用第七分类来加载分区的最小扇区(lowsec项)到LOADOFF(0x7C00),然后再返回第四分类。
18:第七分类与第十分类的关系;在nosig中,当前面加载成功后,若此时所加载的扇区的LOADOFF+MAGIC处的值不是0xAA55的话,就会过渡到第十分类(就是死机)。
19:第七分类与第八分类的关系;在nosig中,当前面加载成功后,若此时所加载的扇区的LOADOFF+MAGIC处的值不是0xAA55的话,就会通过调用第八分类来打印"Not bootable \0"到标准输出(显示器),然后再返回第七分类;再接下来就是第18的关系了。
本人的讲解也到此为止,读者可以去阅览http://www.os-forum.com/minix/boot/masterboot.php里详细注释,我就不在这里列出来。虽然原文是英文,但还是很好懂的。如果认为有翻译的必要就请在下面留言吧,我会根据人数的多少来决定是否有这个必要。