【我所认知的BIOS】->反汇编BIOS之Bootblock(8)-- Memory initial函数的入口By Lightseed6/24/20101、BIOS的主流程为什么会有bootblock和非bootblock这么一说呢?其实就是因为有没有真正的内存可以用的区别。这个章节里我们一起来看看经过之前那些章节的讨论后,BIOS在初始化memory之前会做的一些动作。(稍微比较琐碎点,看起来比较枯燥。)图1 BIOS主流程2、怎么去找到Memory initial的函数入口2.1 Memory initial函数两套方案的必要性Memory对于一个计算机而言,很明显是非常非常重要的一个东西。没有他的话基本上电脑就要脑瘫了,(虽然也可以走路,但是和本山大叔小品里面的那些特殊人士差不多了,要么必须用拐,要么必须用轮椅。。。哈哈,扯远了。)在BIOS里面考虑的比较周全,为了能够万无一失地确保能够把memory初始化的工作做好,BIOS用了两套方案来初始化内存。一种方法非常严谨,校验和呀其他什么的都很齐全。另外一种方法就是直接进入到memory初始化的函数中去。前者确实是严谨,但是越严谨说明要求的条件就越多,条件越多就越有可能出错从而导致memory的初始化不能正常进行(当然一般情况下是不会这样的啦。)。假如是真的发生了这样的事情,那么BIOS就会马上启动第二备用方案直接进入到memory初始化的函数中去。2.2关于BBSS table在讲代码之前,有一个概念必须要和大家讲,否则后面就会看着晕了。在award的bios里面有一个table,在这个table中存着一些比较重要函数的入口地址呀什么的,这些重要的函数(暂时就卖过关子,因为说了也没啥用处,待我们研究完BIOS,您自然而然就知道这些函数是哪些函数了。)就会形成一个table,我们就叫它BBSS table。可是为什么叫BBSS呢?是因为这个table的开头是以“*BBSS*”字符串为开始的。那么在下面的代码中,Search_BBSS_label这个函数其实就是寻找“*BBSS*”这个特殊字符串的函数了。2.3实际代码详细阐述(原本这里有一大段代码,我想如果你自己动手反汇编的话,应该能找到的。介于某些原因,我就把这段代码删除了,毕竟这里的代码应该是比较核心的东西了。)我就用流程图来说明了。对于这段代码,我觉得有必要详细说明一下。虽然说我在代码的后面都做了注释,但是理解起来却仍然比较晦涩难懂。为了更明确地搞清楚上面这段代码的结构,我画了一个流程图,如图2 图2进入Memory initial函数的算法嘿嘿,有了上面这个算法,那么上面的代码就好讲多了。首先我们看主线,这条线就是我之前说的,那个比较严谨的路线。首先搜索BBSS table(如果连BBSS都没的话,那么内存初始化代码肯定也是不存在了,所以直接启动第二套方案来初始化内存,也就是图1中右边的那条副线。),找到了以后然后取得BOOTrom的扩展程序的入口,然后判断程序是否存在?存在的跑之,不存在跳过,从BBSS中去取得内存初始化代码的段地址。然后进一步做内存初始化代码的check sum。因为有可能这段代码被损坏了,那样的话直接跑起来就有可能计算机会死机。纵观上述过程,BIOS在这里还是考虑的很周到的吧?呵呵。。。后面的BIOS代码的技术含量就越来越高了。2.4换个思维再读代码由于这段代码包含了很重要的一个思想,所以我还要反复和大家说一下。(因为后面的BIOS源码很多时候都会用到这种算法。)之前那些都是我们从表面的代码来理解的,那么我们就不能有其他方法着手来看了么?当然有!那就是直接打开BIOS的bin文件来研究。来我们来看看BBSS table的截图,如图3 图3 BBSS table从图2中我们可以看出,BBSS table实际上是位于E000段的,(这和前面我们探讨的Search_BBSS_label这个函数中DS的值是一样的哦~~),不过会不会有人问,图上明明写的是6F8C0H的地址嘛,咋会是放在E000段的呢?(答案自己先去想,想不通,再来问我。)然后我们来看看BBSS table后面的offset为19h的地方是什么,红方框那里就是BBSS table + 19h的位置,很明显这说明BOOTROM的扩展代码的入口地址是0FFFFH,所以图1中的第一个判断直接跳走。然后,我们看看memory initial代码的segment是在BBSS table offset0处。正如图2中的阴影部分所示,这个segment是A00EH。但是由于BIOS在中间做了些处理,还要经过转换。_F000:E34E这行代码就是转换的过程,经过转换后的函数入口就出来了,地址是在EA00H处。在这里存放关于memory initial代码的一些相关信息。后面的我想我就不用多说了。(如果您不放心,大可买块板子来调试一下哦,呵呵。。。这些都是经过我详细验证过的。所以大家放心阅读吧~~)3、从思维的怪圈中跳出来如果我是你,我想经过上面的一番一番地读代码,我已经头大了。真的晕了~~难道看BIOS代码真的需要这么郁闷么,当然不是了。有时候我们偷偷懒,感觉反而更好。不信我们再试试看。不知道你认不认同,我们可以大胆地猜想,award bios在初始化内存的时候虽然是用了两套方案,但是两套方案的代码完全是一样的。(我也没验证,但是目前看来,没出错,呵呵。。。)所以既然第一套方案追其code很复杂,我们还不如直接拿第二套方案的code来研究。因为第二套方案的code直接就可以看到了。当然这种猜想也不是凭空而来的。让我们来看看反汇编出来的code吧,在_F000:E36C这行中是用FAR JMP去执行从BBSS table里面找出来的memory initial的函数。但是我们看看_F000:E369这行,它把SP指向了_F000:E370,不仅如此_F000:E370里面存的数据却又恰好指向_F000:E37C,这个地址与这行_F000:E377代码(第二套方案用的memory initial函数)的返回地址一样。_F000:E365 cmp ah, [si] ; check sum_F000:E367 jnz Ready_To_MEMORY_Init_F000:E369 mov sp, 0E370h_F000:E36C jmp dword ptr ds:2 ; execute memory detection_F000:E36C ;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?_F000:E370 dw 0E37Ch ; point to the same address_F000:E372 dw 0F000h_F000:E374 ;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?_F000:E374_F000:E374 Ready_To_MEMORY_Init: ; CODE XREF: _F000:E348j_F000:E374 ; _F000:E367j_F000:E374 mov sp, 0E37Ah_F000:E377 jmp CT_Memory_Init_F000:E377 ;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?_F000:E37A dw 0E37Ch ; point to the same address所以我们直接研究第二套方案的代码就好。不知道大家理解了么?4、小结在这一节中,我们第一次遇到了算法稍微复杂点的code,主要原因还是初始化内存这个步骤太重要了。所以才会反复地去做判断呀什么的。可想而知,真正的内存初始化代码有多重要。(由于那部分code是intel直接提供的,并且很多寄存器都是Confidential的,所以我暂时还不打算和大家详细注释MRC[memory reference code]的部分。)