【我所认知的BIOS】->反汇编BIOS之Bootblock(11)
-- 初识BIOS的解压缩
By Lightseed
8/24/2010
最近一段时间心态不太好,所以blog也没有更新。现在总算是调整过来了,目前我是这么打算,反汇编的文章暂时就写到bootblock这里了。至于如果还有兴趣研究POST部分的爱好者的话,我们可以私聊。后续文章准备写些比较深入点的文章,比较细节点的分析等等。希望大家给点建议,也希望我们BIOS ren共同进步~并且我准备把这个blog搬到BIOS联盟上去。毕竟那面比较专业一点。至此这篇文章也是bootblock反汇编的最后一篇文章了,其中还有一个问题没研究就是award bios的解压缩函数。这个函数用的LHA的压缩和解压缩算法,我没深入研究过。不过据说网上研究过的人比比皆是,再加上这段code一般都不会出错,所以我暂时也不打算深入研究了。如果你已经研究过了,可否和我share一下?
在bootblock的最后阶段,那当然就是把BIOS的压缩代码全部解压缩出来,然后进入到后续的BIOS初始化流程当中去。在这个章节中,我们就来简单探讨一下解压缩和解压缩以后BIOS的大致走向。(关于解压缩的细节,我们再议。)
图1 BIOS主流程
BIOS执行到现在,它本身已经被copy到了RAM中来,并且也正常RAM中跑了。不过为了能够让后续的BIOS跑的更快,更稳的话,我们还需要把内存的一些属性给初始化一下。这里要第一次接触到MTRR的初始化了哦。在前面的基础章节我曾经有和大家探讨过内存的属性的初始化。
http://blog.csdn.net/lightseed/archive/2009/09/28/4603383.aspx
如果您忘记的MTRR的一些东西,那么您可以从这里再回味一下。
_F000:E482 jmp far ptr 2000h:0E487h ; Here BIOS copy itself to RAM
_F000:E482 ; Althrough BIOS will use FAR JMP to run at 2000:0, but code is continuous.
_F000:E482 ; So we can go on disassembling in F0000
_F000:E487 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
_F000:E487 xor ax, ax
_F000:E489 mov ss, ax
_F000:E48B assume ss:seg000
_F000:E48B mov sp, 0E00h ; Stack init
_F000:E48E call Check_If_Intel_CPU
_F000:E491 jz Yes_its_IntelCPU
_F000:E493 cmp ebx, 'tneC' ; yuanhu+ ;Centaur CPU's identifier
_F000:E49A jnz loc_FE4DB
_F000:E49C
_F000:E49C Yes_its_IntelCPU: ; CODE XREF: _F000:E491j
_F000:E49C mov eax, 6060606h
_F000:E4A2 mov edx, eax
_F000:E4A5 mov ecx, 250h ; MTTR Address(250H) for 0-512K is WB
_F000:E4AB wrmsr ; Init memory type range register(MTTR)
_F000:E4AD mov cl, 58h ; 'X' ; Address(258H) for 512K-640K is WB
_F000:E4AF wrmsr
_F000:E4B1 xor eax, eax
_F000:E4B4 mov edx, eax ; Disable C0000 - FFFFFh Cacheable
_F000:E4B7 mov cl, 59h ; 'Y'
_F000:E4B9 wrmsr
_F000:E4BB mov cl, 68h ; 'h'
_F000:E4BD
_F000:E4BD EarlySetupMTRRLoop: ; CODE XREF: _F000:E4C4j
_F000:E4BD wrmsr
_F000:E4BF inc cl
_F000:E4C1 cmp cl, 6Fh ; 'o'
_F000:E4C4 jbe EarlySetupMTRRLoop
_F000:E4C6 mov eax, 0C00h
_F000:E4CC xor edx, edx
_F000:E4CF mov cl, 0FFh ; MTTR Address(2FFH), Enable cache
_F000:E4D1 wrmsr
_F000:E4D3 wbinvd ; Clear cache
_F000:E4D5 mov eax, cr3
_F000:E4D8 mov cr3, eax
_F000:E4DB
_F000:E4DB loc_FE4DB: ; CODE XREF: _F000:E49Aj
_F000:E4DB mov al, 0FFh
_F000:E4DD call CPU_Cache ; In order to speed up run bios
_F000:E4E0 mov al, 0Ch
_F000:E4E2 out 80h, al ; manufacture's diagnostic checkpoint
_F000:E4E4 call Search_BBSS_label
_F000:E4E7 mov ax, [si+0Eh] ; Get address of the decompress engine
_F000:E4EA mov si, 0
_F000:E4ED mov ds, si
_F000:E4EF mov si, 6000h ; Temp buffer for decompressing
_F000:E4F2 mov [si], ax ; Put Funcion address of decompress engine in 6000:0
_F000:E4F4 mov al, 0C3h ; '?
_F000:E4F6 out 80h, al ; manufacture's diagnostic checkpoint
_F000:E4F8 call Decompress_Whole_Bios
_F000:E4FB jmp short loc_FE51F
_F000:E4FD ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
_F000:E4FD
_F000:E4FD loc_FE4FD: ; CODE XREF: Expand_Bios+AEj
_F000:E4FD ; Expand_Bios+B9j
_F000:E4FD push 2000h
_F000:E500 pop ds
_F000:E501 assume ds:nothing
_F000:E501 mov dword ptr ds:0FFF4h, 2F3131F0h
_F000:E50A mov dword ptr ds:0FFF8h, 392F3131h
_F000:E513 mov dword ptr ds:0FFFCh, 0CFFC0039h
_F000:E51C mov ax, 1000h
_F000:E51F
_F000:E51F loc_FE51F: ; CODE XREF: _F000:E4FBj
_F000:E51F mov ds, ax ; BIOS is stiored in 5000h segment, now
_F000:E521 assume ds:nothing
_F000:E521 push ax
_F000:E522 mov al, 0C5h ; '?
_F000:E524 out 80h, al ; manufacture's diagnostic checkpoint
_F000:E526 call Shadow_System_Bios
_F000:E529 pop ax
_F000:E52A cmp ax, 5000h
_F000:E52D jz SumOk
_F000:E52F jmp far ptr loc_FF7D0
_F000:E534 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
_F000:E534
_F000:E534 SumOk: ; CODE XREF: _F000:E52Dj
_F000:E534 mov al, 0
_F000:E536 call CPU_Cache ;Turn cpu cache on to speed up
_F000:E539 jmp far ptr loc_FF80D ; Althrough this FAR JUMP is F000:F80D, but we must note that BIOS have been decompressed
_F000:E539 ; and store into E0000-FFFFFH. So we must change our bin file to go on disassembling BIOS.
对于上面的MTRR的初始化我就说一点,其他的应该都很明白了。初始化的这些寄存器都是cpu内存的寄存器,对应的特定的MSR会表征CPU在处理特定范围的内存做出对应的处理。其实BIOS做这个过程,目的都是为了让BIOS跑的更快更稳。
Bootblock跑了这么久,不就是为了解压缩么,到了现在我们终于见到了解压缩函数的真面目。真是“千呼万唤始出来”呀_F000:E4F8这个函数就是把整个压缩的BIOS bin文件给解压缩出来的函数了。(稍后我们再讨论,先飘过。。)
当BIOS被自己彻底解压缩了以后,在_F000:E526这行中就是把BIOS从5000H段copy到高端内存中去的函数。我要着重和大家探讨一下它。其实也很简单啦,只是觉得它比较重要,所以要单独拎出来说说。代码如下:
_F000:88C0 ; 圹圹圹圹圹圹圹?S U B R O U T I N E 圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹?
_F000:88C0
_F000:88C0
_F000:88C0 Shadow_System_Bios proc near ; CODE XREF: _F000:E526p
_F000:88C0 mov cx, 95h ; '? ; Programmable Attribute Map 5 E000-E800
_F000:88C3 mov al, 22h ; '"' ; Write Only: All writes are sent to DRAM. Reads are serviced by DMI
_F000:88C5 call Set_Pci_byte
_F000:88C8 mov cx, 96h ; '? ; Programmable Attribute Map 6 E800-F000
_F000:88CB mov al, 22h ; '"' ; Write Only: All writes are sent to DRAM. Reads are serviced by DMI
_F000:88CD call Set_Pci_byte
_F000:88D0 push ds
_F000:88D1 mov si, ds ; From 5000h segment
_F000:88D3 mov di, 0E000h ; To E000H segment
_F000:88D6 mov cx, 8000h ; 64 KB will be moved
_F000:88D9 call Move_code
_F000:88DC pop ds
_F000:88DD assume ds:nothing
_F000:88DD mov cx, 96h ; '? ; Programmable Attribute Map 6 E800-F000
_F000:88E0 mov al, 11h ; Read Only: All reads are serviced by DRAM. All writes are forwarded to the
_F000:88E0 ; DMI.
_F000:88E2 call Set_Pci_byte
_F000:88E5 mov cx, 95h ; '?
_F000:88E8 mov al, 11h ; Read Only: All reads are serviced by DRAM. All writes are forwarded to the
_F000:88E8 ; DMI.
_F000:88EA call Set_Pci_byte
_F000:88ED mov cx, 90h ; '? ; Programmable Attribute Map 0 F0000-FFFFFH
_F000:88F0 call Get_Pci_Byte
_F000:88F3 and al, 0Fh
_F000:88F5 or al, 20h ; Write Only: All writes are sent to DRAM. Reads are serviced by DMI.
_F000:88F7 call Set_Pci_byte
_F000:88FA mov si, ds
_F000:88FC add si, 1000h ; From 6000h segment
_F000:8900 mov di, 0F000h ; To F000h segment
_F000:8903 mov cx, 8000h ; 64 KB will be moved
_F000:8906 call Move_code
_F000:8909 mov cx, 90h ; '?
_F000:890C call Get_Pci_Byte
_F000:890F and al, 0Fh
_F000:8911 or al, 10h ; Read Only: All reads are serviced by DRAM. All writes are forwarded to the
_F000:8911 ; DMI.
_F000:8913 call Set_Pci_byte
_F000:8916 clc
_F000:8917 retn
_F000:8917 Shadow_System_Bios endp
看看上面的函数,算法其实也比较简单的,只是可能大家对北桥的寄存器不太了解。我在上面均加了详细的注释,如果还是不太明白的那就多查阅一下北桥的相关寄存器哦。
_F000:E539主要是这行,我需要强调一下。这里用了一个FAR jmp,而段地址是F000。用这个FAR jmp就是为了进入到当前被copy到了F000段的被解压缩出来的BIOS中去。到此应该Bootblock的使命就是彻底完成了。那么bootblock的系列文章也应该差不多要画上句号了。