您的位置:首页 > 移动开发 > IOS开发

【我所认知的BIOS】->反汇编BIOS之Bootblock(9)

2010-06-24 20:39 369 查看
【我所认知的BIOS】->反汇编BIOS之Bootblock(9)
-- Memory initial 函数
By Lightseed
06/24/2010

1、BIOS的主流程

为什么会有bootblock和非bootblock这么一说呢?其实就是因为有没有真正的内存可以用的区别。这个章节里我们一起来看看经过之前那些章节的讨论后,BIOS在初始化memory之前会做的一些动作。(稍微比较琐碎点,看起来比较枯燥。)Memory initial这个函数里面,会再做一些前期的准备工作。比如8259的中断控制器的初始化,PCIE的初始化,等等然后进入到intel提供的MRC里面去。那么这节就讲讲这个函数里面具体接触的东西。



图1 BIOS主流程

2、CT_Memory_Init整个函数的架构

_F000:36E0 CT_Memory_Init:                         ; CODE XREF: _F000:E377j
 
Call Power_Managment_init;伪代码
 
_F000:370C Power_Managment_init_Exit:              ; CODE XREF: _F000:8850j
 
Call PCIExpressInit      ;伪代码
 
Call Memory_INIT       ; There are too many registers which intel do not release, so I have not plan to comment it.
                                                  ; We usually call these code "MRC", it means memory refrence code. As I know, Award and AMI
                                                  ; MRC are the same.
                           ;中间省略N行
Call     IGDDetect         ; 伪代码
 
Ret

上面是memory initial的整个函数反汇编出来的代码。架构也很清晰,正如之前说的那些,8259初始化好了后,继续Power management的初始化,然后再是PCIE的初始化,然后是真正进入到intel的MRC去detect和初始化内存。一条线,比较简单。

3、关于南桥那面Power management的初始化

从_F000:3709这行中可以看出,在8259初始化好了以后,程序就会进入到初始化power management的函数里去。那我们来看看这个函数里面具体都做了什么。

_F000:8834 Power_Managment_init:                   ; CODE XREF: _F000:3709j
_F000:8834                 mov     si, 880Ch
_F000:8837                 mov     dh, 40h ; '@'   ; PM IO
_F000:8839
_F000:8839 Power_Managment_init_loop:              ; CODE XREF: _F000:884Ej
_F000:8839                 mov     dl, cs:[si]     ; offset
_F000:883C                 mov     al, cs:[si+1]   ; get the value to store
_F000:8840                 out     dx, al          ; set
_F000:8841                 out     0EBh, al
_F000:8843                 out     0EBh, al
_F000:8845                 out     0EBh, al
_F000:8847                 add     si, 2
_F000:884A                 cmp     si, 8834h       ; Table end?
_F000:884E                 jnz     Power_Managment_init_loop

看到上面的函数是不是大家都有比较熟悉的感觉呀?一开始进来就是给SI找到一个table的offset,然后就是按照结构体的元素来初始化各个寄存器。而这个结构体就比较简单了,总共两个byte。第一个byte是在Power management base address(还记得么?在前面的文章里有讲,PM IO base address是4000H)上的偏移。关于table里面的东西,我就不多收了,我觉得我写的挺详细的,只要你对照ICH的datasheet一切都能查到对应的描述。

_F000:880C ;[]--------------------------------------------[]
_F000:880C This table is very easy, so I will not comment them one by one.
_F000:880C I choose the important register to comment. :)
_F000:880C ;[]--------------------------------------------[]
_F000:880C Power_Managment_init_table db    2 ;    ; Power Management 1 Enable Register Low byte
_F000:880D                 db    0 ;               ;
_F000:880D                                         ;
_F000:880E                 db    3 ;               ; Power Management 1 Enable Register High byte
_F000:880F                 db    0 ;               ;
_F000:880F                                         ;
_F000:8810                 db    0 ;               ; Power Management 1 Status Register low byte
_F000:8811                 db 0FFh ;               ; clear all status
_F000:8811                                         ;
_F000:8812                 db    1 ; 
_F000:8813                 db 0FFh ;               ; Power Management 1 Status Register high byte
_F000:8813                                         ;
_F000:8814                 db  11h ;               ; Processor Control Register
_F000:8815                 db    0 ;               ; No forced throttling, No clock throttling is occurring (maximum processor performance).
_F000:8815                                         ;
_F000:8816                 db  28h ; (             ; General Purpose Event 0 Status Register low byte
_F000:8817                 db 0FFh ;               ;
_F000:8817                                         ;
_F000:8818                 db  29h ; )             ; General Purpose Event 0 Status Register high byte
_F000:8819                 db 0FFh ;               ;
_F000:8819                                         ;
_F000:881A                 db  2Ah ; *
_F000:881B                 db 0FFh ;               ;
_F000:881B                                         ;
_F000:881C                 db  2Bh ; +
_F000:881D                 db 0FFh ;               ; clear all GPE0 status
_F000:881D                                         ;
_F000:881E                 db  2Ch ; ,             ; General Purpose Event 0 Enables Register the 1st byte
_F000:881F                 db    0 ;               ;
_F000:881F                                         ;
_F000:8820                 db  2Dh ; -
_F000:8821                 db    0 ;               ;
_F000:8821                                         ;
_F000:8822                 db  2Eh ; .
_F000:8823                 db    0 ;               ;
_F000:8823                                         ;
_F000:8824                 db  2Fh ; /
_F000:8825                 db    0 ;               ; all GPE0 disable
_F000:8825                                         ;
_F000:8826                 db  30h ; 0             ; SMI Control and Enable Register 1st byte
_F000:8827                 db  20h ;               ; Enables writes to the APM_CNT register to cause an SMI#.
_F000:8827                                         ;
_F000:8828                 db  31h ; 1
_F000:8829                 db    0 ;               ; Other function disable
_F000:8829                                         ;
_F000:882A                 db  34h ; 4             ; SMI Status Register 1st byte
_F000:882B                 db 0FFh ;               ;
_F000:882B                                         ;
_F000:882C                 db  35h ; 5             ; SMI Status Register 2nd byte
_F000:882D                 db 0FFh ;               ; clear all SMI status
_F000:882D                                         ;
_F000:882E                 db  41h ; A             ; I can not find the remark of this register in datasheet...:(
_F000:882F                 db  30h ; 0             ;
_F000:882F                                         ;
_F000:8830                 db  44h ; D             ; Device Activity Status Register low byte
_F000:8831                 db 0FFh ;               ;
_F000:8831                                         ;
_F000:8832                 db  45h ; E             ; Device Activity Status Register high byte
_F000:8833                 db 0FFh ;               ; clear all status

4、PCIE的初始化

关于这部分的说明,我觉得很惭愧,据我所了解,这部分的代码绝对多数是为了解决一些bug才放在这里的。而且这些bug应该还都是北桥那面的一些东西,intel也没公布相关的说明,所以我也不知道究竟这里面的寄存器是有啥用。这下这段代码就是PCIE初始化的函数被反汇编出来的源码。不过我把这个函数的地址贴出来,而且这里的基本上BIOS是不会动的,所以平时我也没有深入进去研究。

_F000:394A ;[]----------------------------------------[]
_F000:394A PCIExpressInit:
_F000:394A The function of this subrutine is to initial Northbridge
_F000:394A I think you can check with the datasheet by yourself.
_F000:394A Because some of the register, I do not research before .
_F000:394A What's more, we do not touch these code. If you are
_F000:394A interest into it, you can dig into.
_F000:394A ;[]----------------------------------------[]
_F000:394A
_F000:394A PCIExpressInit:                         ; CODE XREF: _F000:3745j
_F000:394A                 mov     cx, 54h ; 'T'   ; bus 0# dev 0# func 0# Reg 54h
_F000:3A90                 jmp     di              ; PCIExpressInit return

在PCIE初始化后面,还有关于北桥那面的寄存器操作,比如:MMIO base address的初始化(后面要用到的哦,尤其是intel的MRC也会频繁使用的。),MCHBAR的打开呀什么的,都比较简单啦。不过要提的一下是PCIE的访问方法:(我想网上应该有不少的说明,怎么去访问PCIE的配置空间。)

Register Location = PCI Express Base Address + Bus number* 100000h + device
number * 8000h + function * 1000h + Address Offset

 

5、进入到MRC

BIOS就真正进入到intel的MRC,有两点需要说明一下:
第一,我们再看看_F000:37A8之前有三个byte的数据是没有用到的(如果你反汇编了BIOS,如果没有,直接跳过具体的地址)。也许有人会很纳闷,为什么会这样呀?答案是在BIOS中,写code的时候用了aglin 4的动作。从而代指有三个byte是无意义的。所以我们应该跳过去看。
第二,正如我上面的注释里有说,Memory_INIT这个函数里面有太多的寄存器是intel没有release的了,所以我也不想挨着挨着深入。如果您有兴趣可以看看intel的一本橘皮书,好像是ICH BIOS spec吧。具体我不记得了。里面有详细的描述。

6、Memory初始化完了后

内存初始化完了以后,在award的bios里面还会继续detect IGD。代码很简单:
主要是操作北桥的相关寄存器(52H,详细的说明查一下北桥的datasheet)来做的。
都挺简单的,对照着北桥的datasheet就可以查清楚了。(你们查不到的寄存器,我也查不到了。。。。所以有些东西,我其实也不清楚,究竟某些寄存器有啥用。)

8、小结

至此关于BIOS的bootblock部分最最重要的目的就算是完成了。因为BIOS在rom里面跑而且还没有堆栈,真的很费事,而且速度还慢。所以才要尽快地把内存初始化好,然后把放在ROM里面的BIOS源码都copy到内存中来执行。这样的话不仅提高了BIOS初始化主板的速度,还显得让程序更好写。大致的过程可以看看图1所示。
 



图1 BIOS在不同时期的运行过程图
我要简单描述一下图1的意思。左边其实就是BIOS一直在ROM里面跑的过程。(由于北桥开关的原因,FFFF_0000会被映射到F_0000上去,之前有讲在这里再提一下。)所以在图上仍然以F000段开说明,不要混淆哦。然后到内存初始化好了以后,bootblock的解压缩函数就会把BIOS解压缩到内存中去,然后继续执行(这个时候的BIOS就是真的在实模式下执行的了哦,北桥的开关也就是真的把内存和实际的CPU低端寻址对应了。)。
Bootblock的这部分,我们基本就要结束了,后续我们会看到BIOS的copy呀什么的操作。让我们拭目以待吧!!
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息