[转载]Pinczakko的AwardBIOS逆向工程指导
本来自己想写一个,但搜了一下网上,有一个现成的.关键词: Pinczakko Award BIOS 逆向工程 指导BIOS反汇编
来自:http://beiyu.bokee.com/
Pinczakko的AwardBIOS逆向工程指导
作者:Pinczakko
翻译:beiyu http://beiyu.bokee.com
Email: beiyuly@gmail.com
时间:2006.6.6
ida的使用和最后展望没有翻译,希望有兴趣的朋友能够补上。
目录
Pinczakko的AwardBios逆向工程指导1
1.序言2
2.准备工作2
2.1.PCI BUS3
2.2.ISA BUS4
3.一些硬件特性4
3.1. BIOS 芯片地址5
3.2. 晦涩的硬件接口(Port)6
3.3. "可重定位" 硬件Port8
3.4. Expansion ROM Handling9
4.一些软件特性10
4.1.call指令特性10
4.2. retn Instruction Peculiarity10
5. 用到的工具13
5.1. 我们的需求13
5.2. IDA Pro技术介绍13
5.2.1. IDA Pro介绍13
5.2.2. IDA Pro Scripting And Key Bindings19
6. Award BIOS 文件结构26
6.1.压缩部分26
6.2. 纯二进制部分27
6.3. 真实系统(Mainboard)中的内存印象27
7. 反汇编BIOS28
7.1. Bootblock29
7.1.1. "Virtual Shutdown" routine29
7.1.2. Chipset_Reg_Early_Init routine29
7.1.3. Init_Interrupt_n_PwrMgmt routine35
7.1.4. Call To "Early Silicon Support" Routine36
7.1.5. Bootblock Is Copied And Executed In RAM37
7.1.6. Call to bios decompression routine and the jump into decompressed system bios39
7.1.6.1. Enable FFF80000h-FFFDFFFFh decoding40
7.1.6.2. Copy lower 128KB of BIOS code from ROM chip into RAM40
7.1.6.3. Disable FFF8_0000h-FFFD_FFFFh decoding40
7.1.6.4. Verify checksum of the whole compressed BIOS image40
7.1.6.5. Look for the decompression engine41
7.1.6.6. Decompress the compressed BIOS components41
7.1.6.7. Shadow the BIOS code60
7.1.6.8. Enable the microprocessor cache then jump into the decompressed system BIOS60
7.2. System BIOS a.k.a Original.tmp61
7.2.1. Entry point from "Bootblock in RAM"61
7.2.2. The awardext.rom and Extension BIOS Components (lower 128KB bios-code) Relocation Routine62
7.2.3. Call to the POST routine a.k.a "POST jump table execution"64
7.2.4. The "segment vector" Routines68
7.2.5. "chksum_ROM" Procedure72
7.2.6. Original.tmp Decompression Routine for The "Extension_BIOS Components"72
7.2.7. Microcode Update Routine90
8. 激昂展望92
9. 结束语92
1.序言
我非常欢迎你能够来实践复杂的Award Bios的代码研究工作。本文不是一篇官方的Award Bios逆向工程的文章,也不是由Award公司内部人员编辑的。我只是一个好奇的普通人,我真的很喜欢搞清楚我的电脑的Bios是怎样工作的。我写这篇文章的是为了公开我的发现和研究,从而回报那些我所犯的错误,都是我在逆向工程进程当中所犯的。你有几个可能性来读这篇文章,也许你是一个老资格的黑客,也许你是一个像我一样的系统程序设计爱好者,也许你只是一个好奇的外行。只有一点是肯定的,你肯定可以从这篇文章有所收获,可以提高你的技巧。无论如何,我已经写了一个准备章节,来保证你吸收这篇文章所具备的知识。
除非你自己反汇编了Bios的文件,你是不会理解搞清楚BIOS的工作的。
这篇文章的目的是消除疑惑,定位好你自己,在开始对BIOS的逆向工程工作中,为你提供一个参考。
2.准备工作
1.我必须承认,这个工作需要x86的知识。
2.保护模式下的编成开发知识。你必须学会怎样让x86机器从实模式转移到保护模式。也就是说,你必须学会初步的x86保护模式OS开发。www.osdever.net是一个很好的学习这方面知识的网站。最重要的事情是保护模式的数据结构是怎样工作的。我的意思是GDT、IDT、x86控制寄存器和段寄存器是怎样工作的,特别是award bios用他们来实现他的奇妙的地方——稍后文章解释。
3.什么是x86的不真实模式。他是一个x86机器在真是模式和保护模式之间的的状态——稍后文章解释。
4.X86直接硬件编程开发。你需要知道怎样编程直接制硬件,特别是在你主板上面的。你可以联系这个,通过windows上的直接访问硬件程序开发练习。这个不是必需的,但是如果你懂的话,会给你带来很多方便。你也需要知道一些x86总线协议,比如PCI和ISA——稍后文章解释。
5.你必须理解大部分你的主板芯片的手册。比如北桥和南桥控制寄存器。
2.1.PCI BUS
官方的PCI总线标准系统是由PCISIG(PCI Special Interest Group)维持的。他可能是某种公司,他介于Intel和其他大公司,比如Microsoft。他将要被Arapahoe (PCI-Express a.k.a PCI-e) and Hypertransport代替。但是PCI曾经是在保持一种标准。Hypertransport向后兼容PCI。Arapahoe也是一样。只是这个PCI的标准是没有公开的。
首先,PCI BUS是一个32位宽度的总线。通讯需要32bit的地址模式。读写操作需要32位地址。64位PCI Bus不是天生就是,他使用了双重地址回路实现。所以你可以说PCI就是一个32位总线的系统。
其次,这个总线系统定义位置是,控制端口PORT CF8h – CFBh,数据端口CFCh – CFFh。这些端口用来配置相应的PCI芯片,比如读写PCI芯片的配置寄存器值。
第三,这个总线系统强制我们和PCI通讯需要遵守下面的法则(从用户CPU观点):
1.写目标总线号,设备号,功能号和偏移/寄存器号到配置地质端口,然后使能bit置1。通俗讲就是,写寄存器的地址到你想要写入的PCI地址端口。
2.从一个配置数据端口执行一个one-byte, two-byte, or four-byte I/O读操作或者写操作。通俗讲就是,读写数据从你想要读写的PCI端口。
作为一个提示,据我所知,每一个今天用到的BUS/通讯协议,使用简单的法则来使芯片互相通讯,而这些芯片有一个复杂的总线协议。
有了上面的定义,这里提供一个x86的汇编码片断,来说明怎样使用这些配置端口。
No.Mnemonic (masm syntax)Comment
1Pushad保存所有通用寄存器的值
2mov eax,80000064h把将要访问的PCI芯片寄存器的地址放入eax
(offset 64h device 00:00:00 or hostbridge)
3mov dx,0CF8h地址端口放入dx。因为是PCI,我们用CF8h作为端口,来打开访问这个设备。
4out dx,eax发送PCI地址端口到processor的I/O空间
5mov dx,0CFCh数据端口放入dx。因为是PCI,我们用CFCh作为端口,来和这个设备数据通信。
6in eax,dx将从这个设备读出的数据放入eax
7or eax, 00020202改变数据(this is only example, don't try this in your machine, it may hang or even destroy your machine)
8out dx,eax将数据发送回设备
9............-
10Popad出栈所有寄存器值
11Ret返回
我想上面的代码已经非常清晰了。这里有一个PCI寄存器地址格式例子:
mov eax,80000064h
the 80000064h is the address. The meaning of these bits are:
bit position313029282726252423222120191817161514131211109876543210
binary value10000000000000000000000001100100
hexadecimal value80000064
?Bit 31是一个使能标志。如果这个位置设置了,我们就给与PCI bus读写通信的权利了,否则就是禁止。那就是为什么我们在最左边有一个8的原因。
?Bits 30 - 24 保留 bits。
?Bits 23 - 16 是 PCI Bus 号。
?Bits 15 - 11是PCI 设备号。
?Bits 10 - 8 是PCI 功能号。
?Bits 7 - 0 是偏移地址。
80000064h的意思就是我们通讯的设备是bus 0, device 0, function 0, 偏移地址是64h。实际上这个是我们主板上面的北桥芯片中的存储控制配置寄存器。大多数环境下,bus 0, device 0, function 0是Hostbridge,你需要参考自己的芯片数据表来改变这个。大概来讲,他们要作如下工作:读取偏移地址,改写数据,写回设备。
2.2.ISA BUS
AFAIK(恕我直言),ISA bus 不是标准的总线。因此,实际上任何ISA设备可以存在于系统的16-bit I/O地址空间。我对ISA bus的经验很有限(CMOS chip ,mainboard's hardware monitoring chip- Winbond W83781D)。这两个芯片用了上面提到的PCI bus通用算法:
1.先送出你想要读写的设备的地址。只有那样,你才可以通过这个设备的数据端口发送接收数据。
2.通过数据端口,发送接收将要通过设备读写的数据。
我的硬件监视芯片用端口295h作为地址端口,296h作为数据端口。CMOS用70h作为地址端口,71h作为数据端口。
3.一些硬件特性
X86平台存在很多hack,特别是他的bios。这个要归功于向下兼容。这章要讨论一对在我BIOS反汇编中遇到的问题。
3.1. BIOS 芯片地址
最重要的负责bios代码处理的芯片是南桥和北桥芯片。由于这方面,北桥负责系统地址空间管理,比如bios shadowing,处理访问RAM和处理事务,用bios ROM作为南桥的目标,南桥最后积存bios rom。南桥主要负责使能rom解码控制,这将要寄存要访问的bios rom的存储地址。下面展示的地址可以存在于系统DRAM和bios rom芯片中的任何一个,这取决于在bios代码执行时,南桥和北桥寄存器的设置。
Physical AddressAlso Known AsUsed byAddress Aliasing Note
000F_0000h - 000F_FFFFh F_seg / F_segment 1 Mbit, 2 MBit, and 4 MBit BIOS alias to FFFF_0000h - FFFF_FFFFh in all chipset just after power-up
000E_0000h - 000E_FFFFhE_seg / E_segment1 Mbit, 2 MBit, and 4 MBit BIOSalias to FFFE_0000h - FFFE_FFFFh in some chipset just after power-up
上面的地址范围包含了bios代码和很多的系统特性。所以你不得不参考你的芯片数据表来理解它。而且,在bios代码运行后的时间里,注意上面的地址要被bios代码占据的是F_seg i.e. F_0000h - F_FFFFh。无论怎样,相当的操作系统可能会认为这段地址没有用,而且会把它用于自己的目的。上面提到的地址只是当bios代码访问或者其他代码直接访问bios rom的时候,反映了bios rom芯片到系统地址空间映射。就像我们要看到的一样,这个映射可以通过程序设计一些芯片寄存器来改变。
超过1m的Bios芯片,比如2m和4m的芯片有一个非常与众不同的低bios区域地址,i.e. C_seg, D_seg和其他低"segment(s)"。大多数情况,这个区域被映射到了靠近4GB地址范围。这个地址范围处理是从类似北桥到PCI地址范围来解决。这个配置下芯片行为如下:
?北桥作为一个地址传送装置:在不同方式和普通内存地址比较的状态下,它对这个特别的内存地址有反应,内存地址直接指向RAM。相反,这个特别的内存地址由北桥转到南桥,从而解码。
?南桥作为地址解码器:它解码这个特别的内存地址,这个地址指向正确的芯片,比如bios芯片。这方面,如果地址范围不被允许在南桥控制寄存器解码,南桥要返回“void”(bus地址周期结束)。
下面是一个例子:
Physical AddressAlso Known AsUsed byAddress Aliasing Note
000F_0000h - 000F_FFFFh F_seg / F_segment 1 Mbit, 2 MBit, and 4 Mbit BIOS alias to FFFF_0000h - FFFF_FFFFh in all chipset just after power-up
000E_0000h - 000E_FFFFhE_seg / E_segment1 Mbit, 2 Mbit, and 4 Mbit BIOSalias to FFFE_0000h - FFFE_FFFFh in some chipset just after power-up
FFFD_0000h - FFFD_FFFFhD_seg / D_segment2 Mbit, and 4 Mbit BIOS-
FFFC_0000h - FFFC_FFFFhC_seg / C_segment2 Mbit, and 4 Mbit BIOS-
FFF8_0000h - FFFB_FFFFh- 4 Mbit BIOS-
结论是:现代芯片组表现为效法F_seg and E_seg 处理。这是一个证据,证明现代x86系统保持着向下兼容。无论如何,卖主已经远离x86,这些“杂牌电脑(cludge)”往往被认为是过去的东西。
下面是在刚刚系统加电启动后,VIA693A芯片组(北桥)系统内存映射,根据芯片数据表。
Table 4. System Memory Map
Space Start SizeAddress Range Comment
DOS 0 640K00000000-0009FFFFCacheable
VGA 640K 128K000A0000-000BFFFFUsed for SMM
BIOS768K 16K 000C0000-000C3FFFShadow Ctrl 1
BIOS784K 16K 000C4000-000C7FFFShadow Ctrl 1
BIOS800K 16K 000C8000-000CBFFFShadow Ctrl 1
BIOS816K 16K 000CC000-000CFFFFShadow Ctrl 1
BIOS832K 16K 000D0000-000D3FFFShadow Ctrl 2
BIOS848K 16K 000D4000-000D7FFFShadow Ctrl 2
BIOS864K 16K 000D8000-000DBFFFShadow Ctrl 2
BIOS880K 16K 000DC000-000DFFFFShadow Ctrl 2
BIOS896K 64K 000E0000-000EFFFFShadow Ctrl 3
BIOS960K 64K 000F0000-000FFFFFShadow Ctrl 3
Sys 1MB ? 00100000-DRAM TopCan have hole
Bus D Top DRAM Top-FFFEFFFF
Init4G-64K 64K FFFEFFFF-FFFFFFFF000Fxxxx alias
最重要的要考虑到的东西是地址别名,比如你看到的FFFE_FFFFh- FFFF_FFFFh范围就是000Fxxxxh别名,这个就是bios rom芯片地址映射的地方(我得主板)。但是,我们不得不认为,这个是在启动阶段最初的时候(reset后)。在芯片重新被bios改编程序后,这个地址范围就会映射到了RAM中。我们认为这个是作为加电启动默认值。作为一个标记,主要的x86芯片用这个地址作为别名,至少是F-segment地址范围。
另外一个事实就是我们不得不考虑:大部分芯片组在加电后,寄存器中,只提供默认F-segment地址配置,其他bios rom段保持不可访问。这些段的地址配置将要少后由bootblock代码在改变了相关芯片组寄存器后配置(大部分是南桥寄存器)。这里研究的芯片属于这个组。
现代系统连接bios rom芯片和南桥芯片是通过LPC(Low Pin Count)接口。无论怎样,本文中的南桥没有这样的接口。它是一个老的芯片,使用ISA bus作为和bios rom的接口。
3.2. 晦涩的硬件接口(Port)
下面提到的一些晦涩的硬件接口没有在芯片数据文档提到。注意,这些信息是从Intel ICH5,VIA 586B和VIA596B的数据表中得到。
I/O Port address Purpose
92h Fast A20 and Init Register
4D0h Master PIC Edge/Level Triggered (R/W)
4D1h Slave PIC Edge/Level Triggered (R/W)
Table 146. RTC I/O Registers (LPC I/F桪31:F0)
I/O Port Locations If U128E bit = 0 Function
70h and 74h Also alias to 72h and 76h Real-Time Clock (Standard RAM) Index Register
71h and 75h Also alias to 73h and 77h Real-Time Clock (Standard RAM) Target Register
72h and 76h Extended RAM Index Register (if enabled)
73h and 77h Extended RAM Target Register (if enabled)
注意:
1.I/O位置的70h和71h是标准的服务于真实时间时钟的ISA接口。表格147所示。72h和73h作为访问扩展RAM。扩展RAM单元的访问依然通过索引配置。I/O地址72h作为地址指针,73h作为数据寄存器。索引地址127h以上不可用。如果不需要扩展RAM,它就变得不可用了。
2.软件比如保留地址70h的bit7。当顺序写入这个地址的时候,软件必须先读出这个位置的值,然后写入现同的值到bit7。注意70h不是可以直接读取的。唯一的方法是通过alt访问,读取相应寄存器的值。如果NMI#(不可屏蔽中断)使能没有在普通操作下改变,那么软件能够二者选一的读取这个bit一次,然后保留这个值,一边随后的所有写入端口70h操作。
RTC(通路控制)包含了两个索引寄存器配置,用于被两个分离索引和目标寄存器(70/71h or 72/73h)访问,如147表格所示。
Table 147. RTC (Standard) RAM Bank (LPC I/F桪31:F0)
Index Name
00h Seconds
01h Seconds Alarm
02h Minutes
03h Minutes Alarm
04h Hours
05h Hours Alarm
06h Day of Week
07h Day of Month
08h Month
09h Year
0Ah Register A
0Bh Register B
0Ch Register C
0Dh Register D
0Eh?Fh 114 Bytes of User RAM
3.3. "可重定位" 硬件Port
系统I/O空间中,有一些硬件端口种类可以重定位。在这个bios,那些端口包括smbus-related端口和电源管理相关端口。这些端口当然是基本地址。这些所谓的基本地址是通过可以编程的基址寄存器控制的。Smbus由smbus基址寄存器,电源管理由电源管理I/O基址寄存器。所以这些端口是可编程的,bootblock历程在bios历程执行开始的时候初始化这些地址寄存器的值。由于这些端口的可编程特性,就必需要开始bios bootblock的逆向工程来查出哪个端口地址用来这些可编程硬件端口。否则,就会搞不清楚稍后逆向工程中怪异端口的事件。例如:
Address Hex Mnemonic
F000:F604 BE C4 F6 mov si, 0F6C4h ; addr of chipset reg mask
F000:F607 next_PCI_reg: ; CODE XREF: Chipset_Reg_Early_Init+29
F000:F607 2E 8B 0C mov cx, cs:
F000:F60A BC 10 F6 mov sp, 0F610h
F000:F60D E9 F8 00 jmp Read_PCI_Byte
F000:F60D ; ---------------------------------------------------------------------------
F000:F610 12 F6 dw 0F612h
F000:F612 ; ---------------------------------------------------------------------------
F000:F612 2E 22 44 02 and al, cs:
F000:F616 2E 0A 44 03 or al, cs:
F000:F61A BC 20 F6 mov sp, 0F620h
F000:F61D E9 02 01 jmp Write_PCI_Byte
F000:F61D ; ---------------------------------------------------------------------------
F000:F620 22 F6 dw 0F622h
F000:F622 ; ---------------------------------------------------------------------------
F000:F622 83 C6 04 add si, 4
F000:F625 81 FE 04 F7 cmp si, 0F704h ; are we done yet?
.........
F000:F6F4 48 3B dw 3B48h ; B#0 D#7 F#3: PwrMngmt&SMBus - PwrMngmt IO Base Addr lo_byte
F000:F6F6 00 db 0 ; and mask
F000:F6F7 00 db 0 ; or mask
F000:F6F7 ;
F000:F6F8 49 3B dw 3B49h ; B#0 D#7 F#3: PwrMngmt&SMBus - PwrMngmt IO Base Addr hi_byte
F000:F6FA 40 db 40h ; and mask
F000:F6FB 40 db 40h ; PwrMngmt IO Base Addr = IO Port 4000h
.........
F000:F643 B9 90 3B mov cx, 3B90h ; B#0 D#7 F#3: PwrMngmt&SMBus - SMBus IO Base Addr lo_byte
F000:F646 B0 00 mov al, 0 ; set SMBus IO Base lo_byte to 00h
F000:F648 BC 4E F6 mov sp, 0F64Eh
F000:F64B E9 D4 00 jmp Write_PCI_Byte
F000:F64B ; ---------------------------------------------------------------------------
F000:F64E 50 F6 dw 0F650h
F000:F650 ; ---------------------------------------------------------------------------
F000:F650 B9 91 3B mov cx, 3B91h ; B#0 D#7 F#3: PwrMngmt&SMBus - SMBus IO Base Addr hi_byte
F000:F653 B0 50 mov al, 50h ; 'P' ; set SMBus IO Base hi_byte to 50h,
F000:F653 ; so, now SMBus IO Base is at port 5000h !!!
F000:F655 BC 5B F6 mov sp, 0F65Bh
F000:F658 E9 C7 00 jmp Write_PCI_Byte
F000:F658 ; ---------------------------------------------------------------------------
F000:F65B 5D F6 dw 0F65Dh
.........
F000:F66A BA 05 40 mov dx, 4005h ; access ACPI Reg 05h
F000:F66D B0 80 mov al, 80h ; '? ; setting reserved bit?
.........
当然,还有更多的可重定向硬件端口,但是至少你已经看到了这些提示。所以,一旦逆发现bios中的代码有点象访问怪异的端口,你将会知道它去哪里。
3.4. Expansion ROM Handling
有一对问题需要考虑到,比如video bios和其他扩展rom处理。这里是基本bios中PCI扩展rom处理run-down:
1.系统bios检测所有的系统中的pci芯片,初始化他们的BARs(基址寄存器)。一旦初始化结束,系统就拥有了一个可用的广阔的系统地址配置。
2.通过广阔的系统地址配置,系统bios一个接一个的拷贝需要的PCI扩展rom到RAM,这些扩展在(C000:0000h - D000:FFFFh),并且执行每一个模块或者初始化每一个模块。
至于ISA扩展rom,以后版本文章会讨论。
4.一些软件特性
在bios代码中有一些棘手的区域和rom中一些可执行部分有关。下面介绍:
4.1.call指令特性
Call指令在rom bios芯片内部的bios代码执行时不可用。这由于call指令使用桟,而我们不能在bios rom中写入来使用桟。这里使用桟是因为要压入call指令执行时写入保存的返回地址。我们很清楚的知道,这个时候地址指针ss:sp指向的时rom:我们不能写入。DRAM这个时候不能使用。它还没有被bios代码检测。我们根本就不知道有RAM存在!
4.2. retn Instruction Peculiarity
Retn指令特性,这里有ROM_call宏定义:
ROM_CALLMACRO RTN_NAME
LOCAL RTN_ADD
movsp,offset DGROUP:RTN_ADD
jmp RTN_NAME
RTN_ADD:dw DGROUP:$+2
ENDM
例子:
Address Hex Mnemonic
F000:6000 F000_6000_read_pci_byte proc near
F000:6000 66 B8 00 00 00 80 mov eax, 80000000h
F000:6006 8B C1 mov ax, cx ; copy offset addr to ax
F000:6008 24 FC and al, 0FCh ; mask it
F000:600A BA F8 0C mov dx, 0CF8h
F000:600D 66 EF out dx, eax
F000:600F B2 FC mov dl, 0FCh
F000:6011 0A D1 or dl, cl ; get the byte addr
F000:6013 EC in al, dx ; read the byte
F000:6014 C3 retn ; Return Near from Procedure
F000:6014 F000_6000_read_pci_byte endp
......
F000:6043 18 00 GDTR_F000_6043 dw 18h ; limit of GDTR (3 valid desc entry)
F000:6045 49 60 0F 00 dd 0F6049h ; GDT physical addr (below)
F000:6049 00 00 00 00 00 00 00 00 dq 0 ; null descriptor
F000:6051 FF FF 00 00 0F 9F 00 00 dq 9F0F0000FFFFh ; code descriptor:
F000:6051 ; base addr = F 0000h; limit=FFFFh; DPL=0;
F000:6051 ; exec/ReadOnly, conforming, accessed;
F000:6051 ; granularity=byte; Present; 16-bit segment
F000:6059 FF FF 00 00 00 93 8F 00 dq 8F93000000FFFFh ; data descriptor:
F000:6059 ; base addr = 00h; seg_limit=F FFFFh; DPL=0;
F000:6059 ; Present; read-write, accessed;
F000:6059 ; granularity = 4 KByte; 16-bit segment
......
F000:619B 0F 01 16 43 60 lgdtqword ptr GDTR_F000_6043 ; Load Global Descriptor Table Register
F000:61A0 0F 20 C0 mov eax, cr0
F000:61A3 0C 01 or al, 1 ; set PMode flag
F000:61A5 0F 22 C0 mov cr0, eax
F000:61A8 EA AD 61 08 00 jmp far ptr 8:61ADh ; jmp below in 16-bit PMode (abs addr F 61ADh)
F000:61A8 ; (code segment with base addr = F 0000h)
F000:61AD ; ---------------------------------------------------------------------
F000:61AD B8 10 00 mov ax, 10h ; load ds with valid data descriptor
F000:61B0 8E D8 mov ds, ax ; ds = data descriptor (GDT 3rd entry)
......
F000:61BCB9 6B 00 mov cx, 6Bh ; DRAM arbitration control
F000:61BFBC C5 61 mov sp, 61C5h
F000:61C2E9 3B FE jmp F000_6000_read_pci_byte ; Jump
F000:61C2 ; ------------------------------------------------------------------
F000:61C5C7 61 dw 61C7h
F000:61C7 ; ------------------------------------------------------------------
F000:61C70C 02 or al, 2 ; enable VC-DRAM
你看到的,必需要考虑retn指令被当前ss:sp寄存器值影响,ss寄存器还没有加载到正确的16-bit保护模式使用!这些代码怎么会执行?答案有点复杂。让我们看看ss寄存器的值,它在上述调用之前就巧妙的处理了。
Address Hex Mnemonic
F000:E060 8C C8 mov ax, cs
F000:E062 8E D0 mov ss, ax ; ss = cs (ss = F000h a.k.a F_segment)
F000:E064 assume ss:F000
Note: this routine is executed in real-mode
就如你看到的,ss寄存器装入了f000h(当前bios代码16-bit段在实模式)。这段代码说明隐藏的描述缓存寄存器(存在为每一个选择/段寄存器)被加载入ss*16 or F_0000h 的物理地址值。并且这个值会返回,尽管机器转变成了上述的16-bit保护模式,因为ss寄存器没有重载。Intel Software Developer Manual Vol.3片断:
8.1.4. First Instruction Executed
The first instruction that is fetched and executed following a hardware reset is located at physical address FFFFFFF0H. This address is 16 bytes below the processor抯 uppermost physical address. The EPROM containing the software-initialization code must be located at this address. The address FFFFFFF0H is beyond the 1-MByte addressable range of the processor while in real-address mode. The processor is initialized to this starting address as follows. The CS register has two parts: the visible segment selector part and the hidden base address part. In real address mode, the base address is normally formed by shifting the 16-bit segment selector value 4 bits to the left to produce a 20-bit base address. However, during a hardware reset, the segment selector in the CS register is loaded with F000H and the base address is loaded with FFFF0000H. The starting address is thus formed by adding the base address to the value in the EIP register (that is, FFFF0000 + FFF0H = FFFFFFF0H).
The first time the CS register is loaded with a new value after a hardware reset, the processor will follow the normal rule for address translation in real-address mode (that is, ). To insure that the base address in the CS register remains unchanged until the EPROM based software-initialization code is completed, the code must not contain a far jump or far call or allow an interrupt to occur (which would cause the CS selector value to be changed).
Ddj (Doctor Dobbs Journal)的一个小片断:
At power-up, the descriptor cache registers are loaded with fixed, default values, the CPU is in real mode, and all segments are marked as read/write data segments, including the code segment (CS). According to Intel, each time the CPU loads a segment register in real mode, the base address is 16 times the segment value, while the access rights and size limit attributes are given fixed, "real-mode compatible" values. This is not true. In fact, only the CS descriptor cache access rights get loaded with fixed values each time the segment register is loaded - and even then only when a far jump is encountered. Loading any other segment register in real mode does not change the access rights or the segment size limit attributes stored in the descriptor cache registers. For these segments, the access rights and segment size limit attributes are honored from any previous setting (see Figure 3). Thus it is possible to have a four giga-byte, read-only data segment in real mode on the 80386, but Intel will not acknowledge, or support this mode of operation.
现在,你知道重点在于描述缓存寄存器,特别是它的基地址部分。Ss可见部分只是一个“place holder”和“register-in-charge”,对于真实地址计算/变换是一个隐藏的描述缓存。无论你对这个描述缓存做什么, 当任何代码、栈或者数据值地址被转换计算的时候,它都要受到影响。在我们看来,我们不得不在16-bit保护模式使用基址是F_0000h的物理地址的“堆栈段”。这不是问题,因为ss描述缓存寄存器的基址已经在上面的代码中赋予了F_0000h值。这就解释了为什么上面的代码能够正确执行,下面是一个例子:
Address Hex Mnemonic
F000:61BFBC C5 61 mov sp, 61C5h
F000:61C2E9 3B FE jmp F000_6000_read_pci_byte ; Jump
F000:61C2 ; ------------------------------------------------------------------
F000:61C5C7 61 dw 61C7h
这段代码里面我们已经给ss:sp指向F_61C5h,为retn指令服务。实际上,我们已经做了,因为ss包含了F_0000h(它的描述缓存基址部分)和你看到(sp contains 61C5h)的物理地址,ss:sp是F_0000h+61C5h ,物理地址是F_61C5h。
5. 用到的工具
本节介绍逆向工程分析所需的工具。将有一节单独解释IDA Pro反汇编工具。
5.1. 我们的需求
开始进行之前,我们需要以下工具:
1、IDA Pro反汇编工具。我使用IDA Pro V4.3。你可以使用你喜欢的交互式反汇编工具。我觉得IDA Pro最适合我。我们之所以需要交互式反汇编工具,因为我们要反汇编的BIOS代码并不是普通的代码。当驻留在ROM中执行的一些时候并没有栈可用,而是使用了一些栈的技巧来进行过程/例程调用。
2、一个好的二进制编辑器。我使用HexWorkshop ver3.0b。该二进制编辑器最大的一个好处是它可以计算打开文件的所选范围内的校验和。
3、LHA2.55,用来修改BIOS二进制。如果你仅想解压缩并分析压缩的BIOS组件,也可使用winzip或其他可以处理LZH/LHA文件的压缩/解压缩工具。
4、BIOS修改工具,例如CBROM,我使用v2.08,v2.07和1.24。以及MODBIN,有两种:modbin6 for award bios ver. 6和modbin 4.50.xx for award bios ver. 4.5xPGNM。使用这些工具更容易查看BIOS组件。可从www.biosmods.com下载。
5、一些芯片集数据表,这取决于你要解剖的主板BIOS代码。www.com.by上有一部分pdf格式的数据表。我解剖的主板是VIA693A-596B,我当然有这个数据表。
6、Intel Software Developer Manual Volume 1, 2 and 3。BIOS有时使用一些外来指令集。另外有些很难记住的数据结构需要查询,如GDT、IDT等。
5.2. IDA Pro技术介绍
本小节介绍使用IDA Pro。如果抓住了这些概念,你可以方便地使用IDA pro。
5.2.1. IDA Pro介绍
逆向代码工程通过分析软件的可执行文件来实现对软件所使用算法的理解。在大多数情况下,软件仅发布它的可执行文件而没有源代码。BIOS也同样如此,我们可获得的仅仅是执行代码。逆向代码工程在以下工具的帮助下实现:调试器,反汇编工具,二进制文件编辑器即二进制编辑器,ICE()等。我们在本小节中仅讨论反汇编工具,例如IDA Pro反汇编工具。
IDA Pro是一款强大的反汇编工具。它支持插件和脚本组件支持50种以上的处理器结构。但功能强大的工具一般都有缺陷,就是难以掌握使用,IDA Pro也不例外。
IDA Pro有多个版本:免费版、标准版和高级版。最新的免费版为IDA Pro version 4.3 (AFAIK),可在http://www.dirfile.com/ida_pro_freeware_version.htm下载。
There are several editions of IDA Pro: freeware edition, standard edition and advanced edition. The latest freeware edition is IDA Pro version 4.3 (AFAIK) and it抯 available for download at http://www.dirfile.com/ida_pro_freeware_version.htm. It抯 the most limited of all IDA Pro version. It only supports x86 processor and doesn't come with plugin feature, but it comes at no cost, that's why it's presented here. Fortunately, it still comes with scripting feature. The standard and advanced editions of IDA Pro 4.3 of course differ from this freeware edition, they come with support for plugin and support for much more processor architecture. We are going to learn how to use the scripting feature in the next section.
Now, let抯 start to use IDA Pro freeware version to open a BIOS binary file. First, IDA Pro freeware version has to be installed. After the installation finished, one special step must be carried-out to prevent unwanted bug when this version of IDA Pro opens up a BIOS file with *.rom extension. To do so, one must edit the IDA Pro configuration file that抯 located in the root directory of the IDA Pro installation directory. The name of the file is ida.cfg. Open this file by using any text editor (such as notepad) and look for the following lines:
DEFAULT_PROCESSOR = {
/* Extension Processor */
"com" : "8086" // IDA will try the specified
"exe" : "" // extensions if no extension is
"dll" : "" // given.
"drv" : ""
"sys" : ""
"bin" : ""// Empty processor means the default processor
"ovl" : ""
"ovr" : ""
"ov?" : ""
"nlm" : ""
"lan" : ""
"dsk" : ""
"obj" : ""
"prc" : "68000" // PalmPilot programs
"axf" : "arm710a"
"h68" : "68000" // MC68000 for *.H68 files
"i51" : "8051" // i8051 for *.I51 files
"sav" : "pdp11" // PDP-11for *.SAV files
"rom" : "z80" // Z80 for *.ROM files
"cla*": "java"
"s19": "6811"
"o": ""
"*": "" // Default processor
}
Notice the line: "rom" : "z80" // Z80 for *.ROM files
This line must be removed or just replace the "z80" with "" in this line to disable the automatic request to load z80 processor module in IDA Pro upon opening a *.rom file. The bug occurred if the *.rom file is opened while this line is not changed ince freeware IDA Pro doesn't come with z80 processor module. Thus, opening *.rom file by default will terminate IDA Pro. Some motherboard BIOS files comes with *.rom extension by default, even though it's very clear that it won't be executed in z80 processor. Fixing this bug will ensure that we will be able to open motherboard BIOS file with *.rom extension flawlessly. Note that the steps needed to remove other file-extension to processor-type "mapping" in this version of IDA Pro is similar to the z80 processor that is just described.
Now let's proceed to open a sample BIOS file. This BIOS file is da8r9025.rom, BIOS file for Supermicro H8DAR-8 (OEM Only) motherboard. This motherboard used AMD-8131? HyperTransport? PCI-X Tunnel chip and AMD-8111? HyperTransport? I/O Hub chip. The dialog box below will be displayed when you start IDA Pro freeware version 4.3.
Just click OK to proceed. Then the next dialog box shown below will be displayed.
In this dialog box, you can try one of the three options, but we will just click on the Go button. This will start IDA Pro with empty workspace as shown below
Then locate and drag the file to be disassembled to the IDA Pro window (as shown above). In this case, IDA Pro will show the following dialog box.
In this dialog box, we will select Intel 80x86 processors: athlon as the Processor type in the drop down list box. Then click on the Set button to activate the new processor selection. Let the other option as it is. Code relocation will be carried out by using IDA Pro scripts in later section, then click OK. IDA Pro then shows the following dialog box.
This dialog box asks us to choose the default operating-mode of the x86 compatible processor during the disassembling process. AMD64 Architecture Programmer抯 Manual Volume 2: System Programming, February 2005 in section 14.1.5 page 417 states that:
"After a RESET# or INIT, the processor is operating in 16-bit real mode."
In addition, IA-32 Intel? Architecture Software Developer抯 Manual Volume 3: System Programming Guide 2004 section 9.1.1 states that:
"Table 9-1 shows the state of the flags and other registers following power-up for the Pentium 4, Intel Xeon, P6 family, and Pentium processors. The state of control register CR0 is 60000010H (see Figure 9-1), which places the processor is in real-address mode with paging disabled."
Thus, we can conclude that any x86 compatible processors start their execution in 16-bit real mode just after power-up and we have to choose 16-bit mode in this dialog box. It抯 accomplished by clicking No in the dialog box. Then the following dialog box pops up.
This dialog box told us that IDA Pro can抰 decide where the entry-point located. We have to locate it ourselves later. Just click OK to continue to the main window for the disassembly process.
Up to this point we are able to open the binary file within IDA Pro. This is not a trivial task for people new to IDA Pro. That's why it's presented in a step-by-step fashion. However, the output in the workspace is not yet usable. The next step is learning the scripting facility that IDA Pro provides to make sense about the disassembly database that IDA Pro generates.
5.2.2. IDA Pro Scripting And Key Bindings
Now we will proceed to try to decipher IDA Pro disassembly database shown in the previous sub-section with the help of the scripting facility. Before we proceed to analyze the binary, we have to learn some basic concepts about the IDA Pro scripting facility. IDA Pro scripts syntax are similar to C programming language. The syntax as follows:
1.IDA Pro scripts only recognize one type of variable, i.e. auto. There are no other variable types such as int, char, etc. The declaration of variable in an IDA Pro script as follows:
auto variable_name;
2.Every statement in an IDA Pro script ends with a semicolon (;), just like in the C programming language.
3.Function can return a value or not, but there抯 no return type declaration. The syntax as follows:
static function_name(parameter1, parameter2, parameter_n, ...)
4.Comment in an IDA Pro script starts with double-slash (//). The IDA Pro scripting engine ignores anything after the comment in the corresponding line.
5.// comment
6.statement; // comment
7.IDA Pro "exports" its internal functionality to the script that we build by using header files. These header files must be "included" in our script so that we are able to access that functionality. At least one header file must be included in any IDA Pro script, i.e. idc.idc. The header files are located inside a folder named idc in the IDA Pro installation directory. One must read the *.idc files inside this directory to learn about the functions that are exported by IDA Pro. The most important header file to learn is idc.idc. The syntax used to include a header file in an IDA Pro script is:
8.#include < header_file_name >
9.The entry point of an IDA Pro script is the main function, just as in the C programming language.
Now is the time to put the theory into a simple working example, an IDA Pro sample script.
#include
// relocate one segment
static relocate_seg(src, dest)
{
auto ea_src, ea_dest, hi_limit;
hi_limit = src + 0x10000;
ea_dest = dest;
for(ea_src = src; ea_src < hi_limit ; ea_src = ea_src + 4 )
{
PatchDword( ea_dest, Dword(ea_src));
ea_dest = ea_dest + 4;
}
Message("segment relocation finished (inside relocate_seg function)..\n");
}
static main()
{
Message("creating target segment (inside entry point function main)...\n");
SegCreate(, , 0xF000, 0, 0, 0);
SegRename(, "_F000");
relocate_seg(, );
}
The square bracket, i.e. [ ] in the script above is an operator used to form the linear address from its parameters by shifting the first parameter to left four bits and then adding the second parameter into the result, for example: means (0x7000 << 4) + 0 , i.e. 0x7_0000 linear address. This operator is just the same as MK_FP( , ) operator in previous versions of IDA Pro. One must read idc.idc file to see the "exported" function definition to understand this script completely, such as the Message, SegCreate and SegRename function. Another "exported" function that maybe of interest can be found in numerous *.idc file in the idc directory of IDA Pro installation folder. To be able to use the function, its definition have to be looked up in the exported function definition in the corresponding *.idc header file. For example, SegCreate function is defined in idc.idc as follows:
// Create a new segment
// startea- linear address of the start of the segment
// endea - linear address of the end of the segment
// this address will not belong to the segment
// 'endea' should be higher than 'startea'
// base - base paragraph or selector of the segment.
// a paragraph is 16byte memory chunk.
// If a selector value is specified, the selector should be
// already defined.
// use32 - 0: 16bit segment, 1: 32bit segment
// align - segment alignment. see below for alignment values
// comb- segment combination. see below for combination values.
// returns: 0-failed, 1-ok
success SegCreate( long startea,long endea,long base,long use32,
long align,long comb);
A 512KB BIOS binary file must be opened in IDA Pro with the loading address set to 0000h to be able to execute the sample script above. This loading scheme is the same as explained in the previous sub-section. In this case, we will just open the binary file of Supermicro H8DAR-8 motherboard as in the previous sub-section and then execute the script. First, we must type the script above in a plain text file. We can use notepad or another ASCII file editor for this purpose. We will name the file as function.idc. The script then executed by clicking on the File | IDC file... menu or by pressing F2, then the dialog box below will be shown.
Just select the file and click open to execute the script. If there抯 any mistake in the script, IDA Pro will warn you with a warning dialog box. Executing the script will display the corresponding message in the message pane of IDA Pro as shown below.
The script above relocates the last segment (64KB) of the Supermicro H8DAR-8 BIOS code to the right place. One must be aware that IDA Pro is only an advanced tool to help the reverse code engineering task, it抯 not a magical tool that抯 going to reveal the overall structure of the BIOS binary without us being significantly involve in the process. The script relocates/copies BIOS code from physical/linear address 0x7_0000-0x7_FFFF to 0xF_0000-0xF_FFFF. The logical reason behind this algorithm is explained below.
AMD-8111 HyperTransport IO Hub Datasheet chapter 4 page 153 says that:
Note: The following ranges are always specified as BIOS address ranges. See DevB:0x80 for more information about how access to BIOS spaces may be controlled.
SizeHost Address RangeAddress translation for LPC bus
64K bytesFFFF_0000h ?FFFF_FFFFhFFFF_0000h ?FFFF_FFFFh
64K bytes000F_0000h ?000F_FFFFhFFFF_0000h ?FFFF_FFFFh
In addition, AMD64 Architecture Programmer抯 Manual Volume 2: System Programming, February 2005 in section 14.1.5 page 417 says that:
"Normally within real mode, the code-segment base address is formed by shifting the CS-selector value left four bits. The base address is then added to the value in EIP to form the physical address into memory. As a result, the processor can only address the first 1 Mbyte of memory when in real mode. However, immediately following RESET# or INIT, the CS selector register is loaded with F000h, but the CS base-address is not formed by left-shifting the selector. Instead, the CS base address is initialized to FFFF_0000h. EIP is initialized to FFF0h. Therefore, the first instruction fetched from memory is located at physical-address FFFF_FFF0h (FFFF_0000h+0000_FFF0h). The CS base-address remains at this initial value until the CS selector register is loaded by software. This can occur as a result of executing a far jump instruction or call instruction, for example. When CS is loaded by software, the new base-address value is established as defined for real mode (by left shifting the selector value four bits)."
From the references above, we conclude that address 000F_0000h ?000F_FFFFh is an alias to address FFFF_0000h ?FFFF_FFFFh, i.e. they both points to the same physical address range. Whenever the host (CPU) accesses some value in 000F_0000h ?000F_FFFFh address range, it's actually accessing the value at FFFF_0000h ?FFFF_FFFFh range and the reverse is also true. From this fact, we know that we have to relocate 64KB of the uppermost BIOS code to address 000F_0000h ?000F_FFFFh for further investigation. This decision is made based on my previous experience with various BIOS binary files, they generally references address with F000h used as the segment value within the BIOS code. Also, note that the last 64KB of the BIOS binary file is mapped to last 64KB of the 4GB address space, i.e. 4GB-64KB to 4GB, that's why we have to relocate the last 64KB.
Simple script that is only several lines can be typed and executed directly within IDA Pro without opening a text editor. IDA Pro provides a specific dialog box for this purpose and it can be accessed by pressing Shift+F2. This is more practical for simple task, but as the number of the routine grows, one might consider coding the script as described in the previous explanation due to limitation of the number of instruction that can be entered in the dialog box. In this dialog box, enter the script to be executed and click OK to execute the script. Below is an example script.
Note that there is no need for #include statement in the beginning of the script, since by default all of the functions that are exported by IDA Pro in its scripts header files (*.idc) is accessible within the scripting dialog box shown above. The main function is also doesn抰 need to be defined. In fact, anything you write within the dialog box entry will behave as if it's written inside the main function in an IDA Pro script file.
Anyway, you might want to go to the IDA Palace for more IDA Pro script samples. It will take a while to grasp them, but IDA Palace is definitely the place to go if you're curious about IDA Pro scripting.
At present, we are able to relocate the binary within IDA Pro; the next step is to disassemble the binary within IDA Pro. Before that, we need to know how the default key binding works in IDA Pro. Key binding is the "mapping" between the keyboard button and the command carried-out when the corresponding key is pressed. The cursor must be placed in the workspace before any command is carried-out in IDA Pro. The key binding is defined in idagui.cfg file that's located in IDA Pro installation directory. An excerpt of the key binding (hot key) is provided below.
"MakeCode" = 'C'
"MakeData" = 'D'
"MakeAscii" = 'A'
"MakeUnicode" = 0 // create unicode string
"MakeArray" = "Numpad*"
"MakeUnknown" = 'U'
"MakeName" = 'N'
//"MakeAnyName" = "Ctrl-N"
"ManualOperand" = "Alt-F1"
"MakeFunction" = 'P'
"EditFunction" = "Alt-P"
"DelFunction" = 0
"FunctionEnd" = 'E'
One can alter idagui.cfg to change the default key binding, but we will only consider the default key binding. Now we have grasped the key binding concept, let's see how to use it in our binary. In the previous example, we are creating a new segment, i.e. 0xF000. Now, we will go to the first instruction that's executed in the BIOS within that segment, i.e. address 0xF000:0xFFF0. Press G, the dialog box below will be shown.
In this dialog box, enter the destination address. You must enter the address in complete form (segment:offset) as shown above, i.e. F000:FFF0. Then, click OK to go to the intended address. Note that you don't have to type the leading 0x character, since by default, the value within the input box is in hexadecimal. The result will be as shown below (inside IDA Pro workspace).
The next step to do is to convert the value in this address into a meaningful machine instruction. To do so, press C. The result is as shown below.
Then, we can follow the jump by pressing Enter. The result is as shown below.
We can return from the jump that we've just made by pressing Esc.
Up to this point, you've gained significant intuition to use IDA Pro. You just need to consult the key bindings in idagui.cfg in case want to do something and don't know what key to press.
________________________________________
Now we're armed. What we need to do next is to understand the basic stuff by using the hex editor before proceeding through the disassembling session.
6. Award BIOS 文件结构
6.1.压缩部分
内存映射16进制表:
1.0000h - 3AACh : XGROUP ROM (awardext.rom), Award扩展rom. 包含由system bios调用的例程,比如original.tmp。
2.3AADh - 97AFh : CPUCODE.BIN, bios的微代码。
3.97B0h - A5CFh : ACPITBL.BIN, acpi 表。
4.A5D0h - A952h : Iwill.bmp, BMP logo。
5.A953h - B3B1h : nnoprom.bin, I haven't know yet what this component's role。
6.B3B2h - C86Ch : Antivir.bin, bootsector 防病毒。
7.C86Dh - 1BEDCh : ROSUPD.BIN, 我得bios中的自定义部分,用于显示自定义的启动logo和提示符。
8.2_0000h - 3_5531h : original.tmp, 我得特殊的bios中的system BIOS部分。大多数的2m的bios在2_0000h - 3_xxxxh (if you look from within hex editor)都有original.tmp。 有一些4M的bios有original.tmp在bios二进制文件的最开始的部分,比如0000h。
注意:
a.在压缩的 ROSUPD.BIN 和 original.tmp 之间有填充 FFh bytes. 这些填充bytes 在压缩 original.tmp 和纯二进制BIOS 部分之后都有发现。一个例子:
AddressHex ASCII
00037D00 2A42 4253 532A 0060 0070 0060 0060 00A0 *BBSS*.`.p.`.`..
00037D10 3377 4670 8977 ACCF C4CF 0100 00FF FFFF 3wFp.w..........
00037D20 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ................
00037D30 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ................
b.这些压缩了的部分可以很容易的,通过拷贝和粘贴到新的二进制文件,通过Hexworkshop 。然后,解压这个新的文件,用LHA2.55或者winzip。如果我们使用winzip,那么改编扩展名为.lzh,这样winzip就可以自动识别了。识别我们剪切的部分非常简单,只要看到“-lh5-”字符串就可以了。2 bytes的“-lh5-”在文件的最前面,文件最后面总是00h,正好在下一个压缩了的文件前面,正好在填充bytes或者某些checksum前面。我要给你两个例子下面。高亮的bytes是要所的文件的最初和最后的标志。
我得bios中的压缩的CPUCODE.BIN:
AddressHex ASCII
00003AA0 4E61 19E6 9775 2B46 BA55 85F0 0024 382D Na...u+F.U...$8-
00003AB0 6C68 352D DC5C 0000 00A0 0000 0000 0140 lh5-.\.........@
00003AC0 2001 0B43 5055 434F 4445 2E42 494E BCAA..CPUCODE.BIN..
00003AD0 2000 0038 3894 9700 52C4 A2CF F040 0000..88...R....@..
00003AE0 4000 0000 0000 0000 0000 0000 0000 0000 @...............
........
000097A0 0E3C 8FA7 FFF4 FFFE 9FFF D3FF FFFB FF00 .<..............
000097B0 24D9 2D6C 6835 2DFA 0D00 00A6 2100 0000 $.-lh5-.....!...
我得bios中的压缩的 ORIGINAL.TMP:
AddressHex ASCII
0001FFF0 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ................
00020000 251A 2D6C 6835 2D09 5501 0000 0002 0000 %.-lh5-.U.......
00020010 0000 5020 010C 6F72 6967 696E 616C 2E74 ..P ..original.t
00020020 6D70 0CD9 2000 002D 7888 F0FD D624 A5BA mp.. ..-x....$..
........
00035510 019E 6E67 BF11 8582 88D9 4E7C BEC8 C34C ..ng......N|...L
00035520 401D 189F BDD0 A176 17F0 4383 1D73 BF99 @......v..C..s..
00035530 00C9 FFFF FFFF FFFF FFFF FFFF FFFF FFFF ................
00035540 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ................
6.2. 纯二进制部分
内存印象:
1.3_6000h - 3_6C4Ah : 这个例程初始化DRAM控制器(在host btidge中的),和我的bios中的DRAM时钟。
2.3_7000h - 3_7D1Ch : 解压缩例程部分。这个例程包含了LZH解压引擎,可以解压缩上面的bios压缩部分。
3.3_C000h - 3_CFE4h : 这个区域包含了不同的例程,低128KB是bios地址解码启动,默认的VGA初始化(如果系统bios错误执行),剩下的是Hostbridge初始化例程。
4.3_E000h - 3_FFFFh : 包含Boot Block代码。
注意:一些部分之间是填充. 一些是FFh bytes 一些是 00h bytes.
6.3. 真实系统(Mainboard)中的内存印象
我们已经注意到了内存映象,前面提到了bios二进制代码的。在主板bios芯片中,有一点不太一样,并且更加复杂。我得主板的映象如下(和你的可能不一样,参考芯片组文档):
1.Bios二进制文件中的0_0000h - 3_FFFFh映射到了系统内存中的FFFC_0000h - FFFF_FFFFh。由于我得系统中的北桥,地址FFFF_0000h-FFFF_FFFFh 只是F_0000h - F_FFFFh 的别名或者也可以说是在“实模式行话” F000:0000h - F000:FFFFh。注意这个映射适合在加电后,因为它是芯片组加电默认的值。在芯片组被bios重新编程后,不保证是否有效。有一些“kludge(杂牌电脑)”,它们是由系统决定的。你不得不参考Intel Software Developer Manual Volume 3(system programming)和你的芯片数据表。
2.归功于第一点的解释,bios中的纯二进制部分映射如下(加电后):
1)BootBlock : F000:E000h - F000:FFFFh
2)Decompression Block : F000:7000h - F000:7D1Ch
3)早期 DRAM 控制器 和 DRAM 初始化 : F000:6000h - F000:6C4Ah
3.压缩的bios部分在他们通过不同方式被释放后映射到系统内存空间。他们依靠这个解压模块例程,但是不同的bios文件中,他们的映射很少有看起来相同的。这些映射(我得如下,你的可能不一样,但是段地址很可能相同):
1)original.tmp a.k.a System BIOS : E000:0000h - F000:FFFFh
2)awardext.rom a.k.a Award 扩展 ROM : 4100:0000h - 4100:xxxxh。稍后被original.tmp重新部署到6000:0000h - 6000:xxxxh,比如在它执行之前。
在我们进行我们的旅途中,我们必需要注意这样的映射。
注意:
由于完全复杂的映射到真实系统bios二进制地址,我们很容易迷路。但是,有一个技巧可以方便我们的工作,在我们反汇编进程中,通过使用IDA Pro:
从纯二进制部分开始反汇编进程。在地址F000:FFF0h (3_FFF0h 从hex editor看二进制)开始反汇编。为了做到这个,用IDA Pro打开二进制文件(VD30728.BIN , i.e. Iwill VD133 BIOS binary),然后反汇编这个文件,通过设置它的地址映射到C000:0000h ,记住让段名无效,那样我们就可以在系统中,执行的时候看到实模式地址。通过IDA Pro的Scripts调整另外的段地址,记住调整地址配置来符合芯片数据表。
7. 反汇编BIOS
由于Intel system programming Guide,我们就要开始在f000:fff0h地址反汇编了(看看上面的内存映射,调整IDA Pro来适应它)。你可能会问:这怎么可能?Intel Software Developer Manual Vol. 3 (PROCESSOR MANAGEMENT AND INITIALIZATION - First Instruction Executed) 介绍:
在硬件reset后得到并执行的第一条指令所在的物理地址是FFFFFFF0H。
答案是:北桥芯片组使用000F_xxxxh 作为FFFE_FFFFh-FFFF_FFFFh 的别名。而且,注意在这个地址的转移之后南桥没有意义。它只是直接将地址传到Bios Rom芯片。因此,在加电reset后,地址FFFF_FFF0h 和 F_FFF0h (or F000:FFF0 in "real-mode lingo")没有什么困难。它是那么简单。这个是BootBlock区域。它总是有一个far jump跳入bootblock区域,主要的在F000:E05Bh 。从这点看,我们能够继续主要的纯二进制部分的反汇编。实际上,很多纯二进制部分代码没有执行,因为你的系统bios很少错误,并且Bootblock POST进程发生了,除非你把它搞糟了。 7.1. Bootblock
从这点看,我们可以返汇编bootblock例程了。现在,我要给你一些不明显的和重要的在已经反汇编了的bios代码区域。这个是关于我的bios,你的可能不同,但是恕我直言很相近。
7.1.1. "Virtual Shutdown" routine
Address Hex Mnemonic
F000:E07F BC 0B F8 mov sp, 0F80Bh ; ret from this jmp redirected to 0E103h (F000:E103h)
F000:E082 E9 7B 15 jmp Chipset_Reg_Early_Init
7.1.2. Chipset_Reg_Early_Init routine
Address Hex Mnemonic
F000:F600 Chipset_Reg_Early_Init proc near ; CODE XREF: F000:E082j
F000:F600 66 C1 E4 10 shl esp, 10h
F000:F604 BE C4 F6 mov si, 0F6C4h ; addr of chipset reg mask
F000:F607 next_PCI_reg: ; CODE XREF: Chipset_Reg_Early_Init+29j
F000:F607 2E 8B 0C mov cx, cs:
F000:F60A BC 10 F6 mov sp, 0F610h
F000:F60D E9 F8 00 jmp Read_PCI_Byte
F000:F60D ; ---------------------------------------------------------------------------
F000:F610 12 F6 dw 0F612h
F000:F612 ; ---------------------------------------------------------------------------
F000:F612 2E 22 44 02 and al, cs:
F000:F616 2E 0A 44 03 or al, cs:
F000:F61A BC 20 F6 mov sp, 0F620h
F000:F61D E9 02 01 jmp Write_PCI_Byte
F000:F61D ; ---------------------------------------------------------------------------
F000:F620 22 F6 dw 0F622h
F000:F622 ; ---------------------------------------------------------------------------
F000:F622 83 C6 04 add si, 4
F000:F625 81 FE 04 F7 cmp si, 0F704h ; are we done yet?
F000:F629 75 DC jnz next_PCI_reg
F000:F62B BA D0 04 mov dx, 4D0h ; Master PIC Edge/Level Triggered
F000:F62E 32 C0 xor al, al
F000:F630 EE out dx, al
F000:F631 FE C2 inc dl ; Slave PIC Edge/Level Triggered
F000:F633 EE out dx, al
F000:F634 B9 08 38 mov cx, 3808h ; Bus#0 Dev#7 Func#0 (PCI2ISA Bridge) reg 8h(revision id)
F000:F637 BC 3D F6 mov sp, 0F63Dh
F000:F63A E9 CB 00 jmp Read_PCI_Byte
F000:F63A ; ---------------------------------------------------------------------------
F000:F63D 3F F6 dw 0F63Fh
F000:F63F ; ---------------------------------------------------------------------------
F000:F63F 3C 10 cmp al, 10h ; is silicon revision > 10h
F000:F641 72 53 jb silicon_rev_lt_10h; in current mobo this jmp NOT taken (rev id = 12h)
F000:F643 B9 90 3B mov cx, 3B90h ; B#0 D#7 F#3: PwrMngmt&SMBus - SMBus IO Base Addr lo_byte
F000:F646 B0 00 mov al, 0 ; set SMBus IO Base lo_byte to 00h
F000:F648 BC 4E F6 mov sp, 0F64Eh
F000:F64B E9 D4 00 jmp Write_PCI_Byte
F000:F64B ; ---------------------------------------------------------------------------
F000:F64E 50 F6 dw 0F650h
F000:F650 ; ---------------------------------------------------------------------------
F000:F650 B9 91 3B mov cx, 3B91h ; B#0 D#7 F#3: PwrMngmt&SMBus - SMBus IO Base Addr hi_byte
F000:F653 B0 50 mov al, 50h ; 'P' ; set SMBus IO Base hi_byte to 50h,
F000:F653 ; so, now SMBus IO Base is at port 5000h !!!
F000:F655 BC 5B F6 mov sp, 0F65Bh
F000:F658 E9 C7 00 jmp Write_PCI_Byte
F000:F658 ; ---------------------------------------------------------------------------
F000:F65B 5D F6 dw 0F65Dh
F000:F65D ; ---------------------------------------------------------------------------
F000:F65D B9 D2 3B mov cx, 3BD2h ; B#0 D#7 F#3: PwrMngmt&SMBus - SMBus Ctrl
F000:F660 B0 01 mov al, 1 ; SMBus Controller Enable
F000:F662 BC 68 F6 mov sp, 0F668h
F000:F665 E9 BA 00 jmp Write_PCI_Byte
F000:F665 ; ---------------------------------------------------------------------------
F000:F668 6A F6 dw 0F66Ah
F000:F66A ; ---------------------------------------------------------------------------
F000:F66A BA 05 40 mov dx, 4005h ; access ACPI Reg 05h
F000:F66A ; (see chipset init above for init of port 4000h as ACPI IO)
F000:F66D B0 80 mov al, 80h ; '? ; setting reserved bit?
F000:F66F EE out dx, al
F000:F670 B9 41 3B mov cx, 3B41h ; general config
F000:F673 BC 79 F6 mov sp, 0F679h
F000:F676 E9 8F 00 jmp Read_PCI_Byte
F000:F676 ; ---------------------------------------------------------------------------
F000:F679 7B F6 dw 0F67Bh
F000:F67B ; ---------------------------------------------------------------------------
F000:F67B 0C 04 or al, 4 ; RTC Enable Signal Gated with PSON (SUSC#) in
F000:F67B ; Soft-Off Mode
F000:F67D BC 83 F6 mov sp, 0F683h
F000:F680 E9 9F 00 jmp Write_PCI_Byte
F000:F680 ; ---------------------------------------------------------------------------
F000:F683 85 F6 dw 0F685h
F000:F685 ; ---------------------------------------------------------------------------
F000:F685 reinit_SCI_interrupt: ; CODE XREF: Chipset_Reg_Early_Init+92j
F000:F685 B9 42 3B mov cx, 3B42h ; B#0 D#7 F#3: SCI Interrupt Configuration
F000:F688 BC 8E F6 mov sp, 0F68Eh
F000:F68B EB 7B jmp short Read_PCI_Byte
F000:F68B ; ---------------------------------------------------------------------------
F000:F68D 90 db90h ; ?
F000:F68E 90 F6 dw 0F690h
F000:F690 ; ---------------------------------------------------------------------------
F000:F690 A8 40 testal, 40h ; check SUSC State
F000:F692 74 F1 jz reinit_SCI_interrupt
F000:F694 EB 27 jmp short exit
F000:F696 ; ---------------------------------------------------------------------------
F000:F696 silicon_rev_lt_10h: ; CODE XREF: Chipset_Reg_Early_Init+41j
F000:F696 B9 80 3B mov cx, 3B80h
F000:F699 B0 00 mov al, 0
F000:F69B BC A1 F6 mov sp, 0F6A1h
F000:F69E E9 81 00 jmp Write_PCI_Byte
F000:F69E ; ---------------------------------------------------------------------------
F000:F6A1 A3 F6 dw 0F6A3h
F000:F6A3 ; ---------------------------------------------------------------------------
F000:F6A3 B9 81 3B mov cx, 3B81h
F000:F6A6 B0 50 mov al, 50h ; 'P'
F000:F6A8 BC AE F6 mov sp, 0F6AEh
F000:F6AB EB 75 jmp short Write_PCI_Byte
F000:F6AB ; ---------------------------------------------------------------------------
F000:F6AD 90 db90h ; ?
F000:F6AE B0 F6 dw 0F6B0h
F000:F6B0 ; ---------------------------------------------------------------------------
F000:F6B0 B9 84 3B mov cx, 3B84h
F000:F6B3 B0 07 mov al, 7
F000:F6B5 BC BB F6 mov sp, 0F6BBh
F000:F6B8 EB 68 jmp short Write_PCI_Byte
F000:F6B8 ; ---------------------------------------------------------------------------
F000:F6BA 90 db90h ; ?
F000:F6BB BD F6 dw 0F6BDh
F000:F6BD ; ---------------------------------------------------------------------------
F000:F6BD exit: ; CODE XREF: Chipset_Reg_Early_Init+94j
F000:F6BD 66 C1 EC 10 shr esp, 10h
F000:F6C1 C3 retn
F000:F6C1 Chipset_Reg_Early_Init endp
.........
F000:F6C4 Begin_Chipset_Reg_Val
F000:F6C4 47 38 dw 3847h ; bus#0 dev#7 func#0: PCI2ISA Bridge reg 47h
F000:F6C6 BF db 0BFh ; disable PCI delay transaction
F000:F6C7 A0 db 0A0h ; - Use INIT as CPU Reset
F000:F6C7 ; - Enable (ports 4D0-1 per EISA specification)
F000:F6C7 ;
F000:F6C8 50 00 dw 50h ; Host Bridge reg 50h Request Phase Control
F000:F6CA FF db 0FFh ; and mask
F000:F6CB 10 db 10h ; enable Defer Retry When HLOCK Active
F000:F6CB ;
F000:F6CC 51 00 dw 51h ; Host Bridge reg 51h Response Phase Control
F000:F6CE DD db 0DDh ; reset reserved bits
F000:F6CF 0D db 0Dh ; enable:
F000:F6CF ; - Non-Posted IOW
F000:F6CF ; - Concurrent PCI Master / Host Operation
F000:F6CF ;
F000:F6D0 52 00 dw 52h ; Host Bridge reg 52h Dynamic Defer Timer
F000:F6D2 E0 db 0E0h ; disable dynamic defer
F000:F6D3 08 db 8 ; snoop stall count = 8
F000:F6D3 ;
F000:F6D4 6B 00 dw 6Bh ; Host Bridge reg 6Bh DRAM Arbitration Control
F000:F6D6 00 db 0 ; - Park at last bus owner
F000:F6D6 ; - Disable Fast Read to Write turn-around
F000:F6D6 ; - Memory Module Configuration - Normal Operation
F000:F6D6 ; - MD Bus 2nd Level Strength Control = Normal Slew rate
F000:F6D6 ; - CAS Bus 2nd Level Strength Control = Normal Slew rate
F000:F6D6 ; - VC-DRAM disable
F000:F6D6 ; - Multi-Page Open disable
F000:F6D7 01 db 1 ; Enable Multi-Page Open
F000:F6D7 ;
F000:F6D8 71 00 dw 71h ; Host Bridge reg 71h CPU to PCI Flow Control 1
F000:F6DA 00 db 0 ; Disable:
F000:F6DA ; - Dynamic Burst
F000:F6DA ; - Byte Merge
F000:F6DA ; - PCI I/O Cycle Post Write
F000:F6DA ; - PCI Burst
F000:F6DA ; - PCI Fast Back-to-Back Write
F000:F6DA ; - Quick Frame Generation
F000:F6DA ; - 1 Wait State PCI Cycles
F000:F6DB 08 db 8 ; Enable PCI Burst
F000:F6DB ;
F000:F6DC 75 00 dw 75h ; Host Bridge reg 75h PCI Arbitration 1
F000:F6DE 00 db 0 ; - PCI has priority
F000:F6DE ; - REQ-based (arbitrate at end of REQ#)
F000:F6DE ; - Disable PCI Master Bus Time-Out
F000:F6DF 80 db 80h ; Fair arbitration between PCI and CPU
F000:F6DF ;
F000:F6E0 76 00 dw 76h ; Host Bridge reg 76h PCI Arbitration 2
F000:F6E2 CF db 0CFh ; and mask
F000:F6E3 80 db 80h ; or mask
F000:F6E3 ;
F000:F6E4 41 38 dw 3841h ; bus#0 dev#7 func#0: PCI2ISA Bridge reg 41h - ISA Bus control
F000:F6E6 FF db 0FFh ; and mask
F000:F6E7 01 db 1 ; ROM Write Enable
F000:F6E7 ;
F000:F6E8 43 38 dw 3843h ; bus#0 dev#7 func#0: PCI2ISA Bridge reg43h-ROM Decode Control
F000:F6EA 00 db 0 ; Disable ROMCS# decode for all ranges
F000:F6EB 30 db 30h ; Enable ROMCS# decode for the following ranges:
F000:F6EB ; 1. FFF00000h-FFF7FFFFh
F000:F6EB ; 2. 000E0000h-000EFFFFh
F000:F6EB ;
F000:F6EC 4A 38 dw 384Ah ; bus#0 dev#7 func#0: PCI2ISA Bridge reg4Ah-IDE Interrupt Routing
F000:F6EE FF db 0FFh ; and mask
F000:F6EF 40 db 40h ; Access ports 00-FFh via SD bus (applies to
F000:F6EF ; external devices only; internal devices such as
F000:F6EF ; the mouse controller are not effected)
F000:F6EF ;
F000:F6F0 5A 38 dw 385Ah ; bus#0 dev#7 func#0: PCI2ISA Bridge reg5Ah-KBC / RTC Control
F000:F6F2 F8 db 0F8h ; Disable:
F000:F6F2 ; - Internal RTC
F000:F6F2 ; - Internal PS2 Mouse
F000:F6F2 ; - Internal KBC
F000:F6F3 04 db 4 ; Internal RTC Enable
F000:F6F3 ;
F000:F6F4 48 3B dw 3B48h ; B#0 D#7 F#3: PwrMngmt&SMBus - PwrMngmt IO Base Addr lo_byte
F000:F6F6 00 db 0 ; and mask
F000:F6F7 00 db 0 ; or mask
F000:F6F7 ;
F000:F6F8 49 3B dw 3B49h ; B#0 D#7 F#3: PwrMngmt&SMBus - PwrMngmt IO Base Addr hi_byte
F000:F6FA 40 db 40h ; and mask
F000:F6FB 40 db 40h ; PwrMngmt IO Base Addr = IO Port 4000h
F000:F6FB ;
F000:F6FC 41 3B dw 3B41h ; bus#0 dev#7 func#3: PwrMngmt&SMBus - General Config
F000:F6FE FF db 0FFh ; and mask
F000:F6FF 80 db 80h ; enable: I/O for ACPI I/O Base
F000:F6FF ;
F000:F700 76 38 dw 3876h ; bus#0 dev#7 func#0: PCI2ISA Bridge reg76h-GPIO/Chip Select Control
F000:F702 00 db 0 ; Disable GPO 24-26
F000:F703 02 db 2 ; Enable GPO 25
F000:F703 End_Chipset_Reg_Val
7.1.3. Init_Interrupt_n_PwrMgmt routine
Address Hex Mnemonic
F000:E1A0 BF A6 E1 mov di, 0E1A6h ; ret addr below
F000:E1A3 E9 42 99 jmp Init_Interrupt_n_PwrMgmt
F000:E1A6 ; ---------------------------------------------------------------------------
F000:E1A6 B0 C1 mov al, 0C1h ; '+'
....
F000:7CDD delay: ; CODE XREF: Init_Interrupt_n_PwrMgmt:delay
F000:7CDD E2 FE loopdelay
F000:7CDF FF E7 jmp di ; jmp to F000:E1A6h
F000:7CDF Init_Interrupt_n_PwrMgmt endp
7.1.4. Call To "Early Silicon Support" Routine
Address Hex Mnemonic
F000:E1AD E9 47 02 jmp Search_BBSS_Signature
F000:E1AD ; ---------------------------------------------------------------------------
F000:E1B0 B2 E1 dw 0E1B2h
F000:E1B2 ; ---------------------------------------------------------------------------
F000:E1B2 0B F6 or si, si
F000:E1B4 74 38 jz short _BBSS_not_found
F000:E1B6 8B DE mov bx, si ;checksum start here
F000:E1B8 2E 8B 04 mov ax, cs:
F000:E1BB 25 00 F0 and ax, 0F000h
F000:E1BE C1 E8 04 shr ax, 4
F000:E1C1 05 00 F0 add ax, 0F000h
F000:E1C4 8E D8 mov ds, ax ; ds=base addr for calculation of BBSS checksum
F000:E1C6 assume ds:nothing
F000:E1C6 32 E4 xor ah, ah
F000:E1C8 33 F6 xor si, si
F000:E1CA B9 FF 0F mov cx, 0FFFh ; length of BBSS
F000:E1CD next_byte: ; CODE XREF: 000FE1D0 j
F000:E1CD AC lodsb
F000:E1CE 02 E0 add ah, al ; calc 8-bit chksum for BBSS
F000:E1D0 E2 FB loopnext_byte
F000:E1D2 3A 24 cmp ah,
F000:E1D4 75 18 jnz short _BBSS_not_found
F000:E1D6 2E 8B 07 mov ax, cs: ; chsum ok, jump to (exec) the BBSS engine
F000:E1D9 25 00 F0 and ax, 0F000h
F000:E1DC 8B F0 mov si, ax
F000:E1DE 81 C6 FC 0F add si, 0FFCh
F000:E1E2 2E 8B 34 mov si, cs:
F000:E1E5 BC EC E1 mov sp, 0E1ECh
F000:E1E8 FF E6 jmp si ; jmp to F000:60B4h (BBSS Engine), returns at F000:E1F8h
F000:E1E8 ; the BBSS engine is silicon support routine, used to
F000:E1E8 ; initialize PwrMgmt GPIO Ctlr, Host Ctlr and DRAM Ctlr
F000:E1E8 ; ---------------------------------------------------------------------------
F000:E1EA 87 db87h ; ?
F000:E1EB DB db 0DBh ; -
F000:E1EC F8 E1 dw 0E1F8h
.........
F000:E1F8 BBSS_exec_done:
F000:E1F8 B8 00 00 mov ax, 0
.........
这段代码在bootblock拷贝到RAM之前执行。万一RAM有错误,系统就要halt并且从扬声器输出错误代码。
7.1.5. Bootblock Is Copied And Executed In RAM
Address Hex Mnemonic
F000:E2AA ;----------- Enter 16-bit Protected Mode (Flat) ------------
F000:E2AA assume ds:_F000h
F000:E2AA 0F 01 16 F6 E4 lgdtqword ptr word_F000_E4F6
F000:E2AF 0F 20 C0 mov eax, cr0
F000:E2B2 0C 01 or al, 1
F000:E2B4 0F 22 C0 mov cr0, eax
F000:E2B7 EB 00 jmp short $+2 ; clear prefetch, enter 16-bit PMode. We're
F000:E2B7 ; using the "unchanged" hidden value of CS
F000:E2B7 ; register (descriptor cache) from previous
F000:E2B7 ; "PMode session" in memory_check_routine
F000:E2B7 ; for code segment desc
F000:E2B9 B8 08 00 mov ax, 8
F000:E2BC 8E D8 mov ds, ax ; init ds to 4GB-wide segment
F000:E2BE assume ds:nothing
F000:E2BE 8E C0 mov es, ax ; init es to 4GB-wide segment
F000:E2C0
F000:E2C0 There are two locations to access E0000H ROM space, one is 0E0000H
F000:E2C0 and another is 0FFFE0000H. Some chipsets can not access onboard ROM
F000:E2C0 space at 0E0000H if any device also use the space on ISA bus.
F000:E2C0 To solve this problem , we need to change address to 0FFFE0000H
F000:E2C0 to read BIOS contents at 0E0000H space.
F000:E2C0 assume es:nothing
F000:E2C0 66 BE 00 00 0E 00 mov esi, 0E0000h
F000:E2C6 67 66 81 7E 02 2D 6C 68+cmp dword ptr , '5hl-'
F000:E2CF 74 07 jz short LHA_sign_OK
F000:E2D1 66 81 CE 00 00 F0 FF or esi, 0FFF00000h
F000:E2D8
F000:E2D8 move entire BIOS (i.e. original.tmp and bootblock)
F000:E2D8 from ROM at E0000h-FFFFFh to RAM at 10000h-2FFFFh
F000:E2D8 LHA_sign_OK: ; CODE XREF: 000FE2CF
F000:E2D8 66 BF 00 00 01 00 mov edi, 10000h ; destination addr = 1000:0
F000:E2DE 66 B9 00 80 00 00 mov ecx, 8000h ; copy 128 KByte to buffer (original.tmp n Bootblock)
F000:E2E4 67 F3 66 A5 rep movs dword ptr es:, dword ptr
F000:E2E8 0F 20 C0 mov eax, cr0
F000:E2EB 24 FE and al, 0FEh
F000:E2ED 0F 22 C0 mov cr0, eax
F000:E2F0 EB 00 jmp short $+2 ; leave 16-bit protected mode (voodoo mode)
F000:E2F2 EA F7 E2 00 20 jmp far ptr _bootblock_in_RAM
.........
2000:E2F7 ; ---------------------------------------------------------------------------
2000:E2F7 Setup temporary stack at 0:1000H, at this point
2000:E2F7 Bios code (last 128 Kbyte) is still compressed
2000:E2F7 except the bootblock and decompression code
2000:E2F7
2000:E2F7 _bootblock_in_RAM:
2000:E2F7 33 C0 xor ax, ax
2000:E2F9 8E D0 mov ss, ax
2000:E2FB assume ss:nothing
2000:E2FB BC 00 10 mov sp, 1000h
最后128KB的bios代码(E000:0000h - F000:FFFFh)拷贝到RAM如下:
1.北桥加电的时候默认把F_0000h-F_FFFFh 放入空间FFFE_FFFFh-FFFF_FFFFh 这里也是bios rom芯片的地址空间映射。那也是下马面的代码能够安全运行的原因:
Address Hex Mnemonic
F000:FFF0 EA 5B E0 00 F0 jmp far ptr entry_point ; Northbridge is responsible for decoding
F000:FFF0 ; the target address of this jump into BIOS
F000:FFF0 ; chip through address aliasing. So, even if
F000:FFF0 ; this is a far jump (read Intel Software
F000:FFF0 ; Developer Guide Vol.3 for info)
F000:FFF0 ; we are still in BIOS chip d00d ;)
F000:FFF0 ; vi693A: FFFE_FFFF-FFFF_FFFF is 000F_xxxx alias.
并且,北桥加电默认禁止这段空间的DRAM shadowing。所以读写这段区域空间就不会送到DRAM。同时,在南桥没有控制寄存器控制这个地址空间的映射。所以,对这个地址空间的读操作就会直接指向了bios rom芯片,而没有被南桥转换地址。当然,这个读操作首先通过北桥,那样应用地址重名配置。
2.非常靠近bootblock执行的开始,例程Chipset_Reg_Early_Init开始执行。这个例程重新编程PCI-to-ISA桥(在南桥中),能够编码E_0000h-E_FFFFh 地址,比如促进这个地址的读操作到bios rom芯片。北桥加电默认禁止对这个地址空间的DRAM shadowing 。所以,读写这个空间就不会写入DRAM。
3.然后上面的例程,拷贝bios rom芯片最后128KB(E_0000h - F_FFFFh)内容到DRAM(1000:0000h - 2000:FFFFh)中去。这个可以实现,因为这个地址空间已经用芯片映射到了DRAM中,没有特别的地址翻译。
7.1.6. Call to bios decompression routine and the jump into decompressed system bios
Address Hex Mnemonic
2000:E3DC E8 33 01 callDecompress_System_BIOS
2000:E3DF EB 03 jmp short _sysbios_chksum_ok
2000:E3E1 ; ---------------------------------------------------------------------------
2000:E3E1 _sysbios_chksum_error: ; CODE XREF: 0002E347
2000:E3E1 ; 0002E350 ...
2000:E3E1 B8 00 10 mov ax, 1000h
2000:E3E4
2000:E3E4 _sysbios_chksum_ok: ; CODE XREF: 0002E3DF
2000:E3E4 8E D8 mov ds, ax ; ax = 5000h if decompression successful, otherwise ax = 1000h
2000:E3E6 assume ds:_1000h
2000:E3E6 B0 C5 mov al, 0C5h ; '+'
2000:E3E8 E6 80 out 80h, al ; manufacture's diagnostic checkpoint
2000:E3EA
2000:E3EA The source data segment is 5000H if checksum is good.
2000:E3EA the contents in this area is decompressed by routine "Decompress_System_BIOS".
2000:E3EA And segment 1000H is for shadowing original BIOS image if checksum
2000:E3EA is bad. BIOS will shadow bootblock and boot from it.
2000:E3EA E8 87 EB callCopy_Decomprssd_E_n_F_Seg ; relocate dcomprssed from decompression seg to
2000:E3EA ; E_n_F_seg in RAM (Shadow the system BIOS)
2000:E3ED B0 00 mov al, 0
2000:E3EF E8 C7 10 callSetup_Cpu_Cache
2000:E3F2
2000:E3F2 BIOS decide where to go from here.
2000:E3F2 If BIOS checksum is good, this address F80DH is shadowed by
2000:E3F2 decompressed code (i.e. original.bin and others),
2000:E3F2 And "BootBlock_POST" will be executed if checksum is bad.
2000:E3F2 EA 0D F8 00 F0 jmp far ptr loc_F000_F80D ; jump to decompressed system BIOS (F_seg) in RAM if decompression
2000:E3F2 ; successful, otherwise jump to bootblock at the same address if
2000:E3F2 ; decompression failed.
在执行例程Decompress_System_BIOS时,在RAM地址1000:0000h - 2000:FFFFh中的bios code(original.tmp)解压到了RAM中的5000:0000h - 6000:FFFFh 。这个解压了的system bios然后重新定位到了RAM中的E000:0000h - F000:FFFFh 。尽管如此,如果这个解压进程失败了,当前压缩的E_seg和F_seg定位到了RAM中的1000:0000h - 2000:FFFFh (包括在RAM中的bootblock)将要重新定位到RAM中的E000:0000h-F000:0000h ,然后bootblock错误处理代码就要运行了。注意那个问题是由于地址混淆,并且在重新定位时DRAM shadowing被通过设置一个适当的芯片寄存器而处理。下面是这个例程基本run-down:
7.1.6.1. Enable FFF80000h-FFFDFFFFh decoding
1.使能FFF80000h-FFFDFFFFh解码。对这个地址的访问就会通过PCI-to-ISA桥直接到bios rom芯片。PCI-to-ISA 桥rom解码控制寄存器在这里管理。这是必要的,所以我的256KB的bios芯片只有128KB是拷贝到RAM中的,比如original.tmp和bootblock目前正在地址1000:0000h-2000:FFFFh上。
7.1.6.2. Copy lower 128KB of BIOS code from ROM chip into RAM
2.拷贝低128KB的bios代码,从ROM芯片中的FFFC_0000h-FFFD_FFFFh到RAM中8000:0000h - 9000:FFFFh。
7.1.6.3. Disable FFF8_0000h-FFFD_FFFFh decoding
3.禁止FFF8_0000h-FFFD_FFFFh解码。这个地址的访问将不会通过PCI-to-ISA桥到bios rom芯片中去。
7.1.6.4. Verify checksum of the whole compressed BIOS image
4.改变整个bios映像的checksum。计算在内存RAM中的压缩的8bit的checksum(比如8000:0000h - 9000:FFFFh + 1000:0000h - 2000:7FFDh),并且和储存在2000:7FFEh的值比较结果。如果8bit不匹配,那么goto _sysbios_chksum_err ,否则继续解压缩例程。
7.1.6.5. Look for the decompression engine
5.在段2000h 通过搜索*BBSS*来查找解压引擎。
7.1.6.6. Decompress the compressed BIOS components
6.通过调用上面的解压引擎,解压缩压缩了的bios部分。注意这一步中,只有original.tmp和它的扩展(awardext.rom)被解压(其他的版本的awardext.rom也可能适用,我没有验证)。另外的部分通过其他方式处理。这个解压例程至处理他们自己的解压和压缩区域,并把他们放入RAM中的某些地方。我们需要一些预备信息,在深入研究这一步之前:
7.1.6.6.a. The format of the LZH level-1 compressed bios components
A.LAH level-1压缩bios部分格式。这些bios部分在解压缩之后的地址范围也是这样的结构。结构如下(适用于所有的压缩部分):
Offset from 1st byteOffset in Real HeaderContents
00hN/AThe header length of the component. It depends on the file/component name.
01hN/AThe header 8-bit checksum, not including the first 2 bytes (header length and header checksum byte).
02h - 06h00h - 04hLZH Method ID (ASCII string signature). In my BIOS it's "-lh5-" which means: 8k sliding dictionary(max 256 bytes) + static Huffman + improved encoding of position and trees.
07h - 0Ah05h - 08hcompressed file/component size in little endian dword value, i.e. MSB at 0Ah and so forth
0Bh - 0Eh09h - 0ChUncompressed file/component size in little endian dword value, i.e. MSB at 0Eh and so forth
0Fh - 10h0Dh - 0EhDecompression offset address in little endian word value, i.e. MSB at 10h and so forth. The component will be decompressed into this offset address (real mode addressing is in effect here).
11h - 12h0Fh - 10hDecompression segment address in little endian word value, i.e. MSB at 12h and so forth. The component will be decompressed into this segment address (real mode addressing is in effect here).
13h11hFile attribute. My BIOS components contain 20h here, which is normally found in LZH level-1 compressed file.
14h12hLevel. My BIOS components contain 01h here, which means it's a LZH level-1 compressed file.
15h13hcomponent filename name length in byte.
16h - 14h - component filename (ASCII string)
- - file/component CRC-16 in little endian word value, i.e. MSB at and so forth.
Operating System ID. In my BIOS it's always 20h (ASCII space character) which don't resemble any LZH OS ID known to me.
- - Next header size. In my BIOS it's always 0000h which means no extension header.
注意:
1.上面最左边的和在列中用到的地址是从部分的第一个字节计算的。这个“真正头部偏移”就像上面解释得的“便签RAM”使用。
2.每一个部分结束是EOFbyte,比如00h byte。
3.在我的bios中,有read_header例程,包含读写这个头部内容的例程。访问Calc_LZH_hdr_CRC16 有一个关键“procedure call”,它读出这个bios部分头部到“便签本”RAM中,从3000:0000h (ds:0000h)开始。这个便签本区域由"real-LZH-header value"填充,没有包含最前面的2bytes(头大小,头8bit校验和),但是包含了第三byte(offset 02h)直到HeaderSize+02h。
7.1.6.6.b. The location of various checksums
B.解压前和解压时的不同的checksum位置:
LocationCalculation Method
Right after compressed original.tmporiginal.tmp 8-bit checksum. This value is calculated after it's copied to RAM at segment 1000h and 2000h. The code as follows :
Address Assembly Code
2000:E307 ;verify System_BIOS checksum
2000:E307 mov ax, 1000h
2000:E30A mov ds, ax ; ds = E_seg_in_RAM
2000:E30C assume ds:_1000h
2000:E30C mov bx, cmprssd_size_hi_word
2000:E310 mov cx, cmprssd_size_lo_word
2000:E314 add cl, hdr_len ; cl = LZH hdrlen
2000:E318 adc ch, 0
2000:E31B adc bx, 0
2000:E31E add cx, 3
2000:E321 adc bx, 0
2000:E324 jz short hi_word_zero
2000:E326 mov bx, cx
2000:E328 xor cx, cx
2000:E32A hi_word_zero: ; CODE XREF: 0002E324
2000:E32A xor si, si
2000:E32C xor ah, ah
2000:E32E _next_byte: ; CODE XREF: 0002E331 0002E343
2000:E32E lodsb
2000:E32F add ah, al
2000:E331 loop_next_byte
2000:E333 or bx, bx ; compressed BIOS bigger than 64kb ?
2000:E335 jz short cmp_chksum
2000:E337 mov cx, bx
2000:E339 mov bx, ds
2000:E33B add bx, 1000h ; proceed to F_seg in RAM
2000:E33F mov ds, bx
2000:E341 assume ds:_2000h
2000:E341 xor bx, bx
2000:E343 jmp short _next_byte
2000:E345 ; ---------------------------------------------------------------------------
2000:E345 cmp_chksum: ; CODE XREF: 0002E335
2000:E345 cmp ah, ; cmp calc-ed original.tmp chksum with
2000:E345 ; chksum in BIOS image
2000:E347 jnz _sysbios_chksum_error
Right after the decompression engineThis is the 8-bit checksum of the decompression engine which starts at F000:7000h (2000:7000h after copied to RAM) in my BIOS. I guess this is the thing that some people call Decompression Block. The code as follows:
Address Assembly Code
2000:E35E ; Verify checksum of decompress engine
2000:E35E mov ds, ax ; ds = 2700h (2000:7000h)
2000:E360 assume ds:nothing
2000:E360 xor ah, ah
2000:E362 xor si, si
2000:E364 mov cx, 0FFFh ; cx = size of BBSS_engine (4KB-1)
2000:E367 __next_byte: ; CODE XREF: 0002E36A
2000:E367 lodsb
2000:E368 add ah, al
2000:E36A loop__next_byte
2000:E36C cmp ah, ; decompression engine chksum OK ?
2000:E36E jnz short _sysbios_chksum_error
1 byte before decompression engine checksum (that's explained above)This is the 8-bit checksum of all compressed BIOS plus the 8-bit checksum of the decompression engine (not including its previously calculated checksum above). The code :
Address Assembly Code
2000:E512 callCopy_C_seg_n_D_seg; copy lower 128 KByte bios code from ROM (at FFFC_0000h -
2000:E512 ; FFFD_0000h) to RAM (at 8000:0000h-9000:FFFFh)
2000:E515 xor ah, ah
2000:E517 xor cx, cx
2000:E519 mov bx, 8000h
2000:E51C mov ds, bx ; ds = 8000h, contains compressed
2000:E51C ; lower 128KB bios components (awdext,etc.)
2000:E51E assume ds:nothing
2000:E51E xor si, si
2000:E520 next_Cseg_Dseg_byte: ; CODE XREF: Decompress_System_BIOS+11
2000:E520 ; Decompress_System_BIOS+1F
2000:E520 lodsb
2000:E521 add ah, al ; calc 8-bit chksum of C_seg n D_seg
2000:E523 loopnext_Cseg_Dseg_byte
2000:E525 mov bx, ds
2000:E527 cmp bh, 90h ; '? ; are we in seg 9000h?
2000:E52A jnb short done
2000:E52C add bh, 10h ; move to next higher segment
2000:E52F mov ds, bx
2000:E531 assume ds:nothing
2000:E531 jmp short next_Cseg_Dseg_byte
2000:E533 ; ---------------------------------------------------------------------------
2000:E533 done: ; CODE XREF: Decompress_System_BIOS+18
2000:E533 mov bx, 1000h
2000:E536 mov ds, bx ; ds = start_addr_of E_seg n F_seg in RAM
2000:E536 ; (compressed original.tmp + bootblock)
2000:E538 assume ds:_1000h
2000:E538 xor si, si
2000:E53A cld
2000:E53B next_Eseg_Fseg_byte: ; CODE XREF: Decompress_System_BIOS+2C
2000:E53B ; Decompress_System_BIOS+3B
2000:E53B lodsb
2000:E53C add ah, al ; calc 8 bit chksum, contd from chksum above
2000:E53E loopnext_Eseg_Fseg_byte
2000:E540 cmp bh, 20h ; ' ' ; are we in seg 2000h?
2000:E543 jnb short chksum_done
2000:E545 add bh, 10h ; move to next higher segment
2000:E548 mov ds, bx
2000:E54A assume ds:_2000h
2000:E54A mov cx, 7FFEh ; amount of byte in last seg (F_seg in RAM) to calc
2000:E54D jmp short next_Eseg_Fseg_byte
2000:E54F ; ---------------------------------------------------------------------------
2000:E54F chksum_done: ; CODE XREF: Decompress_System_BIOS+31
2000:E54F cmp ah, ; cmp calc-ed chksum and chksum pointed to by .
2000:E54F ; this is the chksum for the bios binary
2000:E54F ; from 00000h to 37FFDh (C000:0h - F000:7FFDh)
2000:E551 jnz _sysbios_chksum_error ; jmp back and continue to bootblock error handling routine 7.1.6.6.c. The key parts of the decompression routine
C.解压例程的关键部分
Address Assembly Code
2000:E512 Decompress_System_BIOS proc near ; CODE XREF: 0002E3DC
.........
2000:E555 mov bx, 0
2000:E558 mov es, bx
2000:E55A assume es:nothing
2000:E55A mov word ptr es:7004h, 0FFFFh
2000:E561 xor al, al
2000:E563
2000:E563 ; System_BIOS Decompression started here
2000:E563 mov bx, 1000h
2000:E566 mov es, bx ; es = src_seg
2000:E568 assume es:_1000h
2000:E568 xor bx, bx ; bx = src_offset
2000:E56A callDecompress ; on ret, CF=1 if error occured
2000:E56D jb short sysbios_decomp_error
2000:E56F testecx, 0FFFF0000h ; compressed component size more than 64KB?
2000:E576 jz short sysbios_decomp_error ; jmp if compressed component size <= 64KB
2000:E578 mov bx, 2000h
2000:E57B mov es, bx ; proceed2next cmprssd componnt (in next segment)
2000:E57D assume es:_2000h
2000:E57D mov bx, 1 ; bx = index to be added to previous src_offset in cx
2000:E580 jmp short repeat_decompress ; decompress remaining component (1st pass jmp taken)
2000:E582 ; ---------------------------------------------------------------------------
2000:E582 sysbios_decomp_error: ; CODE XREF: Decompress_System_BIOS+5B
2000:E582 ; Decompress_System_BIOS+64
2000:E582 rcl al, 1
2000:E584 mov bx, 2000h
2000:E587 mov es, bx
2000:E589 xor bx, bx
2000:E58B callDecompress
2000:E58E rcl al, 1
2000:E590 cmp al, 3
2000:E592 jnz short decompress_successfull
2000:E594 mov ax, 1000h
2000:E597 stc
2000:E598 retn
2000:E599 ; ---------------------------------------------------------------------------
2000:E599 decompress_successfull: ; CODE XREF: Decompress_System_BIOS+80
2000:E599 or al, al
2000:E59B jnz short sys_bios_dcomprss_done
2000:E59D repeat_decompress: ; CODE XREF: Decompress_System_BIOS+6E
2000:E59D ; Decompress_System_BIOS+99
2000:E59D add bx, cx ; bx = point to next compressed component
2000:E59F callDecompress
2000:E5A2 jb short sys_bios_dcomprss_done ; 1st pass jmp taken (original.tmp)
2000:E5A4 testecx, 0FFFF0000h
2000:E5AB jz short repeat_decompress
2000:E5AD sys_bios_dcomprss_done: ; CODE XREF: Decompress_System_BIOS+89
2000:E5AD ; Decompress_System_BIOS+90
2000:E5AD callDecmprss_Sysbios_Extension
2000:E5B0 jz _sysbios_chksum_error
2000:E5B4 mov ax, 5000h
2000:E5B7 clc
2000:E5B8 retn
2000:E5B8 Decompress_System_BIOS endp
________________________________________
2000:E5B9 --- Decompress ---
2000:E5B9 in: es = component_seg
2000:E5B9 bx = component_offset
2000:E5B9 out: ecx = overall_compressed_component_length
2000:E5B9 edx = original_component_size
2000:E5B9 CF, set if failed, cleared if success
2000:E5B9 ; --------------- S U B R O U T I N E ---------------------------------------
2000:E5B9 Decompress proc near ; CODE XREF: Decmprss_Sysbios_Extension:not_awdext
2000:E5B9 ; Decmprss_Sysbios_Extension:not_awdext2 ...
2000:E5B9 cmp dword ptr es:, 40000000h ; is extension component?
2000:E5C2 jnz short not_xtension_component ; 1st pass jmp taken
2000:E5C4 mov si, 0
2000:E5C7 mov ds, si
2000:E5C9 assume ds:nothing
2000:E5C9 mov ds:7000h, bx
2000:E5CD mov si, es
2000:E5CF mov ds:7002h, si
2000:E5D3 lea si, ds:7789h
2000:E5D7 mov ds:7004h, si
2000:E5DB movzx ecx, byte ptr es:
2000:E5E0 add ecx, es:
2000:E5E5 add ecx, 3
2000:E5E9 retn
2000:E5EA ; ---------------------------------------------------------------------------
2000:E5EA not_xtension_component: ; CODE XREF: Decompress+9
2000:E5EA mov dx, 3000h ; dx = scratchpad_seg for decompression
2000:E5ED pushax
2000:E5EE pushes
2000:E5EF callFind_BBSS ; on ret, si contains offset right after BBSS sign
2000:E5F2 pop es
2000:E5F3 assume es:nothing
2000:E5F3 pushes
2000:E5F4 mov ax, es
2000:E5F6 shr ax, 0Ch
2000:E5F9 mov es, ax
2000:E5FB assume es:nothing
2000:E5FB mov ax, cs:
2000:E5FF callax ; call decompression engine at 2000:7789h
2000:E601 pop es
2000:E602 assume es:nothing
2000:E602 pop ax
2000:E603 retn
2000:E603 Decompress endp
________________________________________
2000:7789 --- Decomprssion_Ngine ---
2000:7789 in: dx = scratch-pad_segment_for_decompression
2000:7789 es = (compressed_segment_addr>>0xC)
2000:7789 bx = compressed_offset_addr
2000:7789
2000:7789 out: ecx = overall_compressed_component_length
2000:7789 edx = original_file_size
2000:7789 ; --------------- S U B R O U T I N E ---------------------------------------
2000:7789 Decompression_Ngine proc near
2000:7789 pusheax
2000:778B pushbx
2000:778C pushes
2000:778D mov ds, dx
2000:778F pushds
2000:7790 pop es
2000:7791 xor di, di
2000:7793 mov cx, 4000h
2000:7796 xor ax, ax
2000:7798 rep stosw ; zero-init 32KB starting at Scratchpad_Seg:0000h
2000:779A pop es
2000:779B pushes
2000:779C
2000:779C ;Setup GDT to be used to get src bytes (Fetch_Byte) later
2000:779C mov word ptr ds:100h, es ; ds:100h = compressed_seg_addr>>0xC
2000:779C ; 1st pass ds:100h = 1
2000:77A0 mov ds:102h, bx ; ds:102h = compressed_offset_addr
2000:77A0 ; 1st pass bx = 0
2000:77A4 xor ecx, ecx
2000:77A7 mov ds:57A8h, ecx
2000:77AC mov ds:57ACh, ecx
2000:77B1 lea cx, ds:57A8h
2000:77B5 ror ecx, 4
2000:77B9 mov ax, ds
2000:77BB add cx, ax
2000:77BD rol ecx, 4
2000:77C1 mov word ptr ds:57A2h, 18h
2000:77C7 mov ds:57A4h, ecx
2000:77CC mov dword ptr ds:57B0h, 0FFFFh
2000:77D5 mov ax, es
2000:77D7 movzx ecx, ah ; es = hi_word addr of desc_base
2000:77DB ror ecx, 8 ; ecx = base_24_31 << 24
2000:77DF mov cl, al
2000:77E1 or ecx, 8F9300h
2000:77E8 mov ds:57B4h, ecx
2000:77ED mov dword ptr ds:57B8h, 0FFFFh
2000:77F6 mov dword ptr ds:57BCh, 8F9300h
2000:77FF pushgs
2000:7801 mov di, 0
2000:7804 mov gs, di
2000:7806 assume gs:nothing
2000:7806 mov di, 6000h
2000:7809 mov word ptr gs:, 7789h
2000:780E
2000:780E ;check LZH header
2000:780E add bx, 12h ; LZH-header decomp_seg_addr_hi_byte index
2000:7811 callFetch_Byte
2000:7814 sub bx, 12h ; restore bx to point to first byte
2000:7817 cmp al, 40h ; '@' ; is extension component?
2000:7817 ; at 1st: al equ 50h (original.tmp)
2000:7817 ; at 2nd: al equ 41h (awardext.rom)
2000:7819 jnz short not_extension_component ; 1st-pass jmp taken
2000:781B add bx, 11h
2000:781E callFetch_Byte ; fetch "dest_seg_addr" lo_byte
2000:7821 sub bx, 11h ; restore bx to point to first byte
2000:7824 or al, al ; if extension component, jmp taken
2000:7826 jnz short extension_component
2000:7828 cmp dword ptr gs:, 0
2000:782E jnz short not_extension_component
2000:7830 extension_component: ; CODE XREF: Decompression_Ngine+9D
2000:7830 movzx dx, al ; dl = "dest_seg_addr" lo_byte
2000:7833 inc bx ; bx = LZH_hdr_chksum byte index
2000:7834 callFetch_Byte
2000:7837 sub al, dl ; LZH_hdr_chksum = LZH_hdr_chksum - "dest_seg_addr"_lo_byte
2000:7839 callPatch_Byte ; store new checksum
2000:783C dec bx ; restore bx
2000:783D xor al, al ; al = 00h
2000:783F add bx, 11h ; bx = "dest_seg_addr"_lo_byte index
2000:7842 callPatch_Byte ; patch "dest_seg_addr"_lo_byte to 00h
2000:7845 sub bx, 11h
2000:7848 inc dx ; dx = "dest_seg_addr"_lo_byte + 1
2000:7849 shl dx, 2 ; dx = 4*("dest_seg_addr"_lo_byte + 1)
2000:784C add di, dx ; di = 6000h + dx-- look above!
2000:784E mov gs:, bx ; 0000: = compressed_offset_addr
2000:7851 mov cx, es
2000:7853 mov gs:, cx ; 0000: = compressed_seg_addr>>0xC (hi_word of src phy addr)
2000:7857 callFetch_Byte ; al = LZH_hdr_len
2000:785A movzx ecx, al ; ecx = LZH_hdr_len
2000:785E add bx, 7
2000:7861 callFetch_Dword ; eax = compressed_file_size
2000:7864 sub bx, 7
2000:7867 add ecx, eax ; ecx = LZH_header_len + compressed_file_size
2000:786A add ecx, 3 ; ecx = total_compressed_component_size
2000:786E pop gs
2000:7870 assume gs:nothing
2000:7870 jmp exit
2000:7873 ; ---------------------------------------------------------------------------
2000:7873 not_extension_component: ; CODE XREF: Decompression_Ngine+90
2000:7873 ; Decompression_Ngine+A5
2000:7873 pop gs
2000:7875 callMake_CRC16_Table
2000:7878 callRead_Header ; fetch header component to scratchpad_seg, on error CF=1
2000:787B jb exit ; ret with error code set
2000:787F mov ax, ds:108h ; mov ax, decomprss_seg_addr
2000:7882 mov ds:104h, ax ; mov nu_decomprss_seg_addr, ax
2000:7885 mov ax, ds:10Ah ; mov ax, decomprss_offst_addr
2000:7888 mov ds:106h, ax ; mov nu_decomprss_offst_addr, ax
2000:788B mov ecx, ds:310h ; ecx = compressed_component_size
2000:7890 xor eax, eax
2000:7893 mov al, ds:571Ch ; al = LZH_hdr_len
2000:7896 add ecx, eax ; ecx = compressed_cmpnnt_size + LZH_hdr_len
2000:7899 add ecx, 3 ; ecx = compressed_cmpnnt_size + LZH_hdr_len +
2000:7899 ; sizeof(EOF_byte) + sizeof(LZH_hdr_len_byte) +
2000:7899 ; sizeof(LZH_hdr_8bit_chk_sum)
2000:7899 ; i.e. ecx = overall_component_len
2000:789D mov edx, ds:314h ; mov edx, original_file_size
2000:78A2 pushedx
2000:78A4 pushecx
2000:78A6 pushbx
2000:78A7 add bx, 5 ; point to LZH ID byte
2000:78AA callFetch_Byte
2000:78AD pop bx
2000:78AE cmp al, '0' ; is '-lh0-'?
2000:78B0 jnz short decompress_part
2000:78B2 pushds
2000:78B3 pushsi
2000:78B4 pushbx
2000:78B5 mov di, ds:10Ah
2000:78B9 movzx ax, byte ptr ds:571Ch
2000:78BE add ax, 2
2000:78C1 add bx, ax
2000:78C3 mov cx, ds:310h
2000:78C7 mov ax, ds:108h
2000:78CA mov es, ax
2000:78CC add cx, 3
2000:78CF shr cx, 2
2000:78D2 next_dword: ; CODE XREF: Decompression_Ngine+151
2000:78D2 callFetch_Dword
2000:78D5 add bx, 4
2000:78D8 stosd
2000:78DA loopnext_dword
2000:78DC pop bx
2000:78DD pop si
2000:78DE pop ds
2000:78DF jmp short LZH_hdr_OK
2000:78E1 ; ---------------------------------------------------------------------------
2000:78E1 decompress_part: ; CODE XREF: Decompression_Ngine+127
2000:78E1 pushword ptr ds:104h ; save destination seg addr
2000:78E5 pushword ptr ds:106h ; save destination offset addr
2000:78E9 pushlarge
2000:78EE callLzh_Expand ; Lzh_Expand capable of handling compressed
2000:78EE ; component bigger than 64KB (1 segment)
2000:78F1 pop dword ptr ds:314h
2000:78F6 pop word ptr ds:106h
2000:78FA pop word ptr ds:104h
2000:78FE LZH_hdr_OK: ; CODE XREF: Decompression_Ngine+156
2000:78FE callZero_Init ; zero init 32KB of scratchpad_seg
2000:7901 pop ecx
2000:7903 pop edx
2000:7905 clc
2000:7906 exit: ; CODE XREF: Decompression_Ngine+E7
2000:7906 ; Decompression_Ngine+F2
2000:7906 pop es
2000:7907 pop bx
2000:7908 pop eax
2000:790A retn
2000:790A Decompression_Ngine endp
________________________________________
2000:790B --- Make_CRC16_Table ---
2000:790B 1st pass, the base address for DS is 3_0000h
2000:790B in: ds = scratch_pad_segment for CRC table
2000:790B out: ds:10Ch - ds:11Bh = CRC-16 table
2000:790B ; --------------- S U B R O U T I N E ---------------------------------------
2000:790B Make_CRC16_Table proc near; CODE XREF: Decompression_Ngine+EC
2000:790B 51 pushcx
2000:790C 53 pushbx
2000:790D 50 pushax
2000:790E 56 pushsi
2000:790F BE 0C 01 mov si, 10Ch
2000:7912 B9 00 01 mov cx, 100h
2000:7915 next_byte: ; CODE XREF: Make_CRC16_Table+2B
2000:7915 B8 00 01 mov ax, 100h
2000:7918 2B C1 sub ax, cx
2000:791A 50 pushax
2000:791B BB 00 00 mov bx, 0
2000:791E is_bit: ; CODE XREF: Make_CRC16_Table+25
2000:791E A9 01 00 testax, 1
2000:7921 74 07 jz short not_bit
2000:7923 D1 E8 shr ax, 1
2000:7925 35 01 A0 xor ax, 0A001h ; CRC poly
2000:7928 EB 02 jmp short point_to_next_byte
2000:792A ; ---------------------------------------------------------------------------
2000:792A not_bit: ; CODE XREF: Make_CRC16_Table+16
2000:792A D1 E8 shr ax, 1
2000:792C point_to_next_byte: ; CODE XREF: Make_CRC16_Table+1D
2000:792C 43 inc bx
2000:792D 83 FB 08 cmp bx, 8
2000:7930 72 EC jb short is_bit
2000:7932 5B pop bx
2000:7933 89 00 mov , ax
2000:7935 46 inc si
2000:7936 E2 DD loopnext_byte
2000:7938 5E pop si
2000:7939 58 pop ax
2000:793A 5B pop bx
2000:793B 59 pop cx
2000:793C C3 retn
2000:793C Make_CRC16_Table endp
________________________________________
2000:79E8 --- Read_Header ---
2000:79E8 in: ds = scratchpad_segment
2000:79E8 ds:102h = LZH_hdr_byte_index
2000:79E8
2000:79E8 out:ds:102h = LZH_hdr_byte_index
2000:79E8 ds:108h = componnt_decomprrsion_seg_addr
2000:79E8 ds:10Ah = componnt_decomprrsion_offset_addr
2000:79E8 ds:310h = uncompressed_componnt_size
2000:79E8 ds:314h =component_seg:offset_decompression_addr
2000:79E8 ds:571Ch = LZH_hdr_len
2000:79E8 ds:571Dh = LZH_hdr_chksum
2000:79E8 ds:571Eh = LZH crc16 val
2000:79E8 ds:0 - ds:LZH_hdr_len = copy of current component LZH hdr
2000:79E8 ; --------------- S U B R O U T I N E ---------------------------------------
2000:79E8 Read_Header proc near ; CODE XREF: Decompression_Ngine+EF
2000:79E8 60 pusha
2000:79E9 06 pushes
2000:79EA 8B 1E 02 01 mov bx, ds:102h
2000:79EE E8 DA 00 callFetch_Byte
2000:79F1 FF 06 02 01 inc word ptr ds:102h
2000:79F5 A2 1C 57 mov ds:571Ch, al
2000:79F8 07 pop es
2000:79F9 80 3E 1C 57 00 cmp byte ptr ds:571Ch, 0
2000:79FE 75 04 jnz short read_LZH_hdr_ok
2000:7A00 error: ; CODE XREF: Read_Header+38
2000:7A00 ; Read_Header+71 ...
2000:7A00 F9 stc
2000:7A01 E9 86 00 jmp exit
2000:7A04 ; ---------------------------------------------------------------------------
2000:7A04 read_LZH_hdr_ok: ; CODE XREF: Read_Header+16
2000:7A04 06 pushes
2000:7A05 8B 1E 02 01 mov bx, ds:102h
2000:7A09 E8 BF 00 callFetch_Byte ; read LZH_hdr_chksum byte
2000:7A0C FF 06 02 01 inc word ptr ds:102h
2000:7A10 A2 1D 57 mov ds:571Dh, al ; 1st pass: 3000:571D = LZH_hdr_chksum
2000:7A13 07 pop es
2000:7A14 E8 26 FF callCalc_LZH_hdr_CRC16; fetch compressed component value to RAM,
2000:7A14 ; then calc its CRC16 checksum
2000:7A17 E8 88 FF callCalcHdrSum
2000:7A1A 3A 06 1D 57 cmp al, ds:571Dh ; is the stored LZH_hdr 8-bit chksum match the one that read?
2000:7A1E 74 02 jz short LZH_hdr_8bit_chksum_ok
2000:7A20 EB DE jmp short error
2000:7A22 ; ---------------------------------------------------------------------------
2000:7A22 LZH_hdr_8bit_chksum_ok: ; CODE XREF: Read_Header+36
2000:7A22 BB 05 00 mov bx, 5
2000:7A25 B9 04 00 mov cx, 4 ; bx+cx = compressed_component_size_index (Dword)
2000:7A28 E8 99 FF callGetFromHeader
2000:7A2B 66 A3 10 03 mov ds:310h, eax
2000:7A2F BB 09 00 mov bx, 9
2000:7A32 B9 04 00 mov cx, 4 ; bx+cx = original file size (Dword)
2000:7A35 E8 8C FF callGetFromHeader
2000:7A38 66 A3 14 03 mov ds:314h, eax
2000:7A3C BB 0D 00 mov bx, 0Dh
2000:7A3F B9 02 00 mov cx, 2 ; bx+cx = decompression_component_offset addr (Word)
2000:7A42 E8 7F FF callGetFromHeader
2000:7A45 A3 0A 01 mov ds:10Ah, ax
2000:7A48 BB 0F 00 mov bx, 0Fh
2000:7A4B B9 02 00 mov cx, 2 ; bx+cx = decompression_component_segment addr (Word)
2000:7A4E E8 73 FF callGetFromHeader
2000:7A51 A3 08 01 mov ds:108h, ax
2000:7A54 80 3E 11 00 20 cmp byte ptr ds:11h, 20h ; ' ' ; is LZH level 1 file attribute?
2000:7A59 75 A5 jnz short error
2000:7A5B 80 3E 12 00 01 cmp byte ptr ds:12h, 1; is LZH level 1 ?
2000:7A60 75 9E jnz short error
2000:7A62 0F B6 1E 1C 57 movzx bx, byte ptr ds:571Ch ; bx = lzh_hdr_len
2000:7A67 83 EB 05 sub bx, 5 ; bx = CRC16_byte_index
2000:7A6A B9 02 00 mov cx, 2
2000:7A6D E8 54 FF callGetFromHeader ; read CRC16 value
2000:7A70 A3 1E 57 mov ds:571Eh, ax ; ds:571Eh = CRC16_val
2000:7A73 BB 13 00 mov bx, 13h ; bx = filename_len byte index
2000:7A76 8A 9F 00 00 mov bl, ; bl = filename_len
2000:7A7A B8 14 00 mov ax, 14h
2000:7A7D 03 D8 add bx, ax ; bx = CRC16_byte_index
2000:7A7F C6 87 00 00 24 mov byte ptr , 24h ; '$'
2000:7A84 C6 87 01 00 00 mov byte ptr , 0
2000:7A89 F8 clc
2000:7A8A exit: ; CODE XREF: Read_Header+19
2000:7A8A 61 popa
2000:7A8B C3 retn
2000:7A8B Read_Header endp
________________________________________
2000:793D Calc_LZH_hdr_CRC16 proc near ; CODE XREF: Read_Header+2C
2000:793D 50 pushax
2000:793E 53 pushbx
2000:793F 51 pushcx
2000:7940 52 pushdx
2000:7941 0F B6 0E 1C 57 movzx cx, byte ptr ds:571Ch
2000:7946 06 pushes
2000:7947 56 pushsi
2000:7948 8B 1E 02 01 mov bx, ds:102h
2000:794C BE 00 00 mov si, 0
2000:794F next_byte: ; CODE XREF: Calc_LZH_hdr_CRC16+19
2000:794F E8 79 01 callFetch_Byte
2000:7952 88 04 mov , al
2000:7954 43 inc bx
2000:7955 46 inc si
2000:7956 E2 F7 loopnext_byte
2000:7958 8B C3 mov ax, bx
2000:795A 2B 06 02 01 sub ax, ds:102h
2000:795E 89 1E 02 01 mov ds:102h, bx
2000:7962 5E pop si
2000:7963 07 pop es
2000:7964 A2 1C 57 mov ds:571Ch, al
2000:7967 8B C8 mov cx, ax
2000:7969 01 06 14 03 add ds:314h, ax
2000:796D 41 inc cx
2000:796E BB 00 00 mov bx, 0
2000:7971 next_CRC_byte: ; CODE XREF: Calc_LZH_hdr_CRC16+5E
2000:7971 0F B6 07 movzx ax, byte ptr
2000:7974 49 dec cx
2000:7975 E3 26 jcxzshort exit
2000:7977 50 pushax
2000:7978 53 pushbx
2000:7979 56 pushsi
2000:797A 8B F0 mov si, ax
2000:797C A1 0C 03 mov ax, ds:30Ch
2000:797F 33 C6 xor ax, si
2000:7981 25 FF 00 and ax, 0FFh
2000:7984 8B F0 mov si, ax
2000:7986 D1 E6 shl si, 1
2000:7988 8B 9C 0C 01 mov bx,
2000:798C A1 0C 03 mov ax, ds:30Ch
2000:798F C1 E8 08 shr ax, 8
2000:7992 33 C3 xor ax, bx
2000:7994 A3 0C 03 mov ds:30Ch, ax
2000:7997 5E pop si
2000:7998 5B pop bx
2000:7999 58 pop ax
2000:799A 43 inc bx
2000:799B EB D4 jmp short next_CRC_byte
2000:799D ; ---------------------------------------------------------------------------
2000:799D exit: ; CODE XREF: Calc_LZH_hdr_CRC16+38
2000:799D 5A pop dx
2000:799E 59 pop cx
2000:799F 5B pop bx
2000:79A0 58 pop ax
2000:79A1 C3 retn
2000:79A1 Calc_LZH_hdr_CRC16 endp
________________________________________
2000:79A2 CalcHdrSum proc near ; CODE XREF: Read_Header+2F
2000:79A2 53 pushbx
2000:79A3 51 pushcx
2000:79A4 52 pushdx
2000:79A5 B8 00 00 mov ax, 0
2000:79A8 0F B6 0E 1C 57 movzx cx, byte ptr ds:571Ch
2000:79AD loc_2000_79AD: ; CODE XREF: CalcHdrSum+19 j
2000:79AD 0F B6 1E 1C 57 movzx bx, byte ptr ds:571Ch
2000:79B2 2B D9 sub bx, cx
2000:79B4 0F B6 97 00 00 movzx dx, byte ptr
2000:79B9 03 C2 add ax, dx
2000:79BB E2 F0 looploc_2000_79AD
2000:79BD 5A pop dx
2000:79BE 59 pop cx
2000:79BF 5B pop bx
2000:79C0 25 FF 00 and ax, 0FFh
2000:79C3 C3 retn
2000:79C3 CalcHdrSum endp
________________________________________
2000:79C4 --- GetFromHeader ---
2000:79C4 in: bx = byte_index of the "component" to read
2000:79C4 cx = length of "component" to read
2000:79C4
2000:79C4 out: eax = dword_read
2000:79C4 ; --------------- S U B R O U T I N E ---------------------------------------
2000:79C4 GetFromHeader proc near ; XREF: Read_Header+40
2000:79C4 ; Read_Header+4D ...
2000:79C4 53 pushbx
2000:79C5 66 52 pushedx
2000:79C7 56 pushsi
2000:79C8 66 33 C0 xor eax, eax
2000:79CB 4B dec bx
2000:79CC 41 inc cx
2000:79CD next_byte: ; CODE XREF: GetFromHeader+1D
2000:79CD 49 dec cx
2000:79CE E3 13 jcxzshort exit
2000:79D0 66 C1 E0 08 shl eax, 8
2000:79D4 8B F3 mov si, bx
2000:79D6 03 F1 add si, cx
2000:79D8 66 0F B6 94 00 00 movzx edx, byte ptr
2000:79DE 66 03 C2 add eax, edx
2000:79E1 EB EA jmp short next_byte
2000:79E3 ; ---------------------------------------------------------------------------
2000:79E3 exit: ; CODE XREF: GetFromHeader+A
2000:79E3 5E pop si
2000:79E4 66 5A pop edx
2000:79E6 5B pop bx
2000:79E7 C3 retn
2000:79E7 GetFromHeader endp
看完这些彻底的线索,我们成功的构建映射了bios解压部分:
Starting address of decompressed BIOS component in RAM Compressed SizeDecompressed SizeDecompression State (by Bootblock code)Component description
4100:0000h3A85h57C0hDecompressed to RAM beginning at address in column one.awardext.rom, this is a "helper module" for original.tmp
4001:0000h5CDChA000hNot decompressed yetcpucode.bin, this is the CPU microcode
4003:0000hDFAh21A6hNot decompressed yetacpitbl.bin, this is the ACPI table
4002:0000h35Ah2D3ChNot decompressed yetiwillbmp.bmp, this is the EPA logo
4027:0000hA38hFEChNot decompressed yetnnoprom.bin, explanation N/A
4007:0000h1493h2280hNot decompressed yetantivir.bin, this is BIOS antivirus code
4028:0000hF63Ah14380hNot decompressed yetROSUPD.bin, seems to be custom Logo display procedure
5000:0000h15509h20000hDecompressed to RAM beginning at address in column one.original.tmp, the system BIOS
注意:绿色覆盖的解压地址被另外的方法处理:
A.上面解释的部分不是真正的被解压区域。只是某种真正解压区域的占有区域,稍后由original.tmp处理。结论是:在bootblock中只有original.tmp和awardext.rom被Decompress_System_Bios解压缩。如果你想改变这个,那么试着计算被解压代码的大小总和,他不会合适的!
B.所有的这些被解压段地址部分被Decompression_Ngine procedure变换到4000h,就像你看到的在例程里面地址2000:7842h。
C.“(被解压)开始地址。。。”中的40xxh 实际上是一个ID,工作如下:40(高字节)是ID,标示它是一个扩展bios,将要在稍后的original.tmp执行时被解压缩。Xx是一个id,在original.tmp用到,标示要被解压缩的部分。这些在下面的original.tmp中会详细解释。
D.所有的这些部分都要在original.tmp执行时被解压缩。解压结果被放在地址4000:0000h,但是不会在同一时刻。有一些(也许所有的)部分也要从那个地址重新定向,在另外的部分在那个地址被解压缩后保留他们的内容。这些在下面的original.tmp中会详细解释。
7.1.6.7. Shadow the BIOS code
7.Shadow bios代码。假设解压例程成功的完成了,上面的例程接着拷贝被解压得system bios(original.tmp),从RAM中的5000:0000h - 6000:FFFFh到E_0000h - F_FFFFh。完成如下:
1)重新编程北桥shadow RAM控制寄存器,使能只写到地址E_0000h - F_FFFFh,促进写操作这个地址范围到DRAM(没有到bios rom芯片)。
2)进行一个字符串拷贝操作,拷贝被解压了的system bios(original.tmp),从5000:0000h - 6000:FFFFh到E_0000h - F_FFFFh。
3)重新编程北桥shadow RAM控制寄存器,使能只读到地址E_0000h - F_FFFFh ,促进读操作这个地址范围到DRAM(没有到bios rom芯片)。这个也是对system bios 代码写保护
7.1.6.8. Enable the microprocessor cache then jump into the decompressed system BIOS
8.使能微处理高速缓存,然后跳转到压缩的system bios。这一步是普通bootblock代码执行路径的最后一步。使能处理器高速缓存后,代就会跳转到RAM地址F000:F80Dh中的写保护的system bios(original.tmp),如上面看到的代码。这个跳转的目的地址好像在不同的award bios中都一样。
现在我要呈现在跳转到解压缩的original.tmp之前,压缩的和解压的bios部分的内存地图。这个很重要,因为这会在等会的分析解压缩了的original.tmp方便我们。现在我们不得不注意,所有的代码都在RAM中之行,在没有代码在bios rom芯片中执行了。
Address Range in RAMDecompression State (by Bootblock code)Description
0000:6000h - 0000:6xxxhN/AThis area contains the header of the extension component (component other than original.tmp and awardext.rom) fetched from the compressed BIOS at 8000:0000h - 9000:FFFFh (previously BIOS component at FFFC_0000h - FFFD_FFFFh in the BIOS chip). Note that this is fetched here by part of the bootblock in segment 2000h.
1000:0000h - 2000:5531hCompressedThis area contains the compressed original.tmp. It's part of the copy of the last 128KB of the BIOS (previously BIOS component at E000:0000h - F000:FFFFh in the BIOS chip). This code is shadowed here by the bootblock in BIOS ROM chip.
2000:5532h - 2000:5FFFhPure Binary (non-executable)This area contains only padding bytes.
2000:6000h - 2000:FFFFhPure binary (executable)This area contains the bootblock code. It's part of the copy of the last 128KB of the BIOS (previously BIOS component at E000:0000h - F000:FFFFh in the BIOS ROM chip). This code is shadowed here by the bootblock in BIOS ROM chip. This is where our code currently executing (the "copy" of bootblock in segment 2000h).
4100:0000h - 4100:57C0hDecompressedThis area contains the decompressed awardext.rom. Note that the decompression process is accomplished by part of the bootblock code in segment 2000h.
5000:0000h - 6000:FFFFhDecompressedThis area contains the decompressed original.tmp. Note that the decompression process is accomplished by part of the bootblock code in segment 2000h.
8000:0000h - 9000:FFFFhCompressedThis area contains the copy of the first/lower 128KB of the BIOS (previously BIOS component at FFFC_0000h - FFFD_0000h in the BIOS chip). This code is copied here by the bootblock code in segment 2000h.
E000:0000h - F000:FFFFhDecompressedThis area contains copy of the decompressed original.tmp, which is copied here by the bootblock code in segment 2000h.
最后要注意:这里解释的booblock只涉及到了normal Bootblock code execution path ,意思是没有解释一旦original.tmp崩溃时的bootblock POST。有时间的话,我将要涉及到。所有的bootblock如上,我们将要开始研究original.tmp。
7.2. System BIOS a.k.a Original.tmp
我们刚进行了上面的bootblock,我要高亮晦涩的代码执行路径。所以,现在,你正在看我的bios的解压了的original.tmp的反汇编代码。
7.2.1. Entry point from "Bootblock in RAM"
Address Hex Mnemonic
F000:F80D This code is jumped into by the bootblock code
F000:F80D if everything went OK
F000:F80D E9 02 F6 jmp sysbios_entry_point ;
这里是在重新定位和写保护system bios后,bootblock跳转的地方。
7.2.2. The awardext.rom and Extension BIOS Components (lower 128KB bios-code) Relocation Routine
Address Assembly Code
F000:EE12 sysbios_entry_point: ; CODE XREF: F000:F80D
F000:EE12 mov ax, 0
F000:EE15 mov ss, ax ; ss = 0000h
F000:EE17 mov sp, 1000h ; setup stack at 0:1000h
F000:EE1A call setup_stack ; Call Procedure
F000:EE1D call init_DRAM_shadowRW ; Call Procedure
F000:EE20 mov si, 5000h ; ds=5000h (look at copy_mem_word)
F000:EE23 mov di, 0E000h ; es=E000h (look at copy_mem_word)
F000:EE26 mov cx, 8000h ; copy 64KByte
F000:EE29 call copy_mem_word ; copy E000h segment routine, i.e.
F000:EE29 ; copy 64Kbyte from 5000:0h to E000:0h
F000:EE2C call j_init_DRAM_shadowR ; Call Procedure
F000:EE2F mov si, 4100h ; ds = XGroup segment decompressed, i.e.
F000:EE2F ; at this point 4100h
F000:EE32 mov di, 6000h ; es = new XGroup segment
F000:EE35 mov cx, 8000h ; copy 64KByte
F000:EE38 call copy_mem_word ; copy XGroup segment , i.e.
F000:EE38 ; 64Kbyte from 4100:0h to 6000:0h
F000:EE3B call Enter_UnrealMode ; jump below in UnrealMode
F000:EE3E Begin_in_UnrealMode
F000:EE3E mov ax, ds
F000:EE40 mov es, ax ; es = ds (3rd entry in GDT)
F000:EE40 ; base_addr=0000 0000h;limit 4GB
F000:EE42 assume es:nothing
F000:EE42 mov esi, 80000h ; mov esi,(POST_Cmprssed_Temp_Seg shl 4)
F000:EE42 ; relocate lower 128KB bios code
F000:EE48 mov edi, 160000h
F000:EE4E mov ecx, 8000h
F000:EE54 cld ; Clear Direction Flag
F000:EE55 rep movs dword ptr es:, dword ptr ; move
F000:EE55 ; 128k data to 160000h (phy addr)
F000:EE59 call Leave_UnrealMode ; Call Procedure
F000:EE59 End_in_UnrealMode
F000:EE5C mov byte ptr , 0 ; mov byte ptr
F000:EE5C ; POST_SPEED,Normal_Boot
F000:EE61 mov si, 626Bh ; offset 626Bh (E000h POST tests)
F000:EE64 push 0E000h ; segment E000h
F000:EE67 push si ; next instruction offset (626Bh)
F000:EE68 retf ; jmp to E000:626Bh
________________________________________
F000:7440 Enter_UnrealMode proc near ; CODE XREF: F000:EE3B
F000:7440 mov ax, cs
F000:7442 mov ds, ax ; ds = cs
F000:7444 assume ds:F000
F000:7444 lgdt qword ptr GDTR_F000_5504 ; Load Global Descriptor Table Register
F000:7449 mov eax, cr0
F000:744C or al, 1 ; Logical Inclusive OR
F000:744E mov cr0, eax
F000:7451 mov ax, 10h
F000:7454 mov ds, ax ; ds = 10h (3rd entry in GDT)
F000:7456 assume ds:nothing
F000:7456 mov ss, ax ; ss = 10h (3rd entry in GDT)
F000:7458 assume ss:nothing
F000:7458 retn ; Return Near from Procedure
F000:7458 Enter_UnrealMode endp
________________________________________
F000:5504 GDTR_F000_5504 dw 30h; DATA XREF: Enter_PMode+4
F000:5504 ; GDT limit (6 valid desc)
F000:5506 dd 0F550Ah ; GDT phy addr (below)
F000:550A dq 0 ; null desc
F000:5512 dq 9F0F0000FFFFh ; code desc (08h)
F000:5512 ; base_addr=F0000h;seg_limit=64KB;code,execute/ReadOnly
F000:5512 ; conforming,accessed;granularity=1Byte;16-bit segment;
F000:5512 ; segment present,code,DPL=0
F000:551A dq 8F93000000FFFFh ; data desc (10h)
F000:551A ; base_addr=0000 0000h;seg_limit=4GB;data,R/W,accessed;
F000:551A ; granularity=4KB;16-bit segment; segment present,
F000:551A ; data,DPL=0
F000:5522 dq 0FF0093FF0000FFFFh ; data desc 18h
F000:5522 ; base_addr=FFFF0000h;seg_limit=64KB;data,R/W,accessed;
F000:5522 ; 16-bit segment,granularity = 1 byte;
F000:5522 ; segment present, data, DPL=0.
F000:552A dq 0FF0093FF8000FFFFh ; data desc 20h
F000:552A ; base_addr=FFFF8000h;seg_limit=64KB;data,R/W,accessed;
F000:552A ; 16-bit segment,granularity = 1 byte;
F000:552A ; segment present, data, DPL=0.
F000:5532 dq 930F0000FFFFh ; data desc 28h
F000:5532 ; base_addr=F0000h;seg_limit=64KB;data,R/W,accessed;
F000:5532 ; 16-bit segment,granularity = 1 byte;
F000:5532 ; segment present, data, DPL=0.
________________________________________
注意:上面的代码执行以后,这个内存地图就再改变了一次。但是这个时候,只对于压缩BIOS扩展,比如低128KB的bios代码和解压缩了的awardext.rom,在上面bootblock解释到的内存地图部分的被覆盖了。
New Address Range in RAMDecompression StateDescription
6000:0000h - 6000:57C0hDecompressedThis is the relocated awardext.rom
160000h - 17FFFFhCompressedThis is the relocated compressed "BIOS extension", including the compressed awardext.rom. (i.e. this is the copy of FFFC0000h - FFFDFFFF in the BIOS rom chip.
7.2.3. Call to the POST routine a.k.a "POST jump table execution"
Address Assembly Code
E000:626B The last of the these POST routines starts the EISA/ISA
E000:626B section of POST and thus this call should never return.
E000:626B If it does, we issue a POST code and halt.
E000:626B
E000:626B This routine called from F000:EE68h
E000:626B
E000:626B sysbios_entry_point_contd a.k.a NORMAL_POST_TESTS
E000:626B mov cx, 3 ; mov cx,STD_POST_CODE
E000:626E mov di, 61C2h ; mov di,offset STD_POST_TESTS
E000:6271 call RAM_POST_tests ; this won't return in normal condition
E000:6274 jmp short Halt_System ; Jump
________________________________________
E000:6276 ; --------------- S U B R O U T I N E ---------------------------------------
E000:6276
E000:6276 RAM_POST_tests proc near ; CODE XREF: last_E000_POST+D
E000:6276 ; last_E000_POST+18 ...
E000:6276 mov al, cl ; cl = 3
E000:6278 out 80h, al ; manufacture's diagnostic checkpoint
E000:627A push 0F000h
E000:627D pop fs ; fs = F000h
E000:627F
E000:627F ;This is the beginning of the call into E000 segment
E000:627F ;POST function table
E000:627F assume fs:F000
E000:627F mov ax, cs: ; in the beginning :
E000:627F ; di = 61C2h ; ax = cs: = 154Eh
E000:627F ; called from E000:2489 w/ di=61FCh (dummy)
E000:6282 inc di ; Increment by 1
E000:6283 inc di ; di = di + 2
E000:6284 or ax, ax ; Logical Inclusive OR
E000:6286 jz RAM_post_return ; RAM Post Error
E000:6288 push di ; save di
E000:6289 push cx ; save cx
E000:628A call ax ; call 154Eh (relative call addr)
E000:628A ; ,one of this call
E000:628A ; won't return in normal condition
E000:628C pop cx ; restore all
E000:628D pop di
E000:628E jb RAM_post_return ; Jump if Below (CF=1)
E000:6290 inc cx ; Increment by 1
E000:6291 jmp short RAM_POST_tests ; Jump
E000:6293 ; ---------------------------------------------------------------------------
E000:6293
E000:6293 RAM_post_return: ; CODE XREF: RAM_POST_tests+10
E000:6293 ; RAM_POST_tests+18
E000:6293 retn ; Return Near from Procedure
E000:6293 RAM_POST_tests endp
________________________________________
E000:61C2 E0_POST_TESTS_TABLE:
E000:61C2 dw 154Eh ; Restore boot flag
E000:61C4 dw 156Fh ; Chk_Mem_Refrsh_Toggle
E000:61C6 dw 1571h ; keyboard (and its controller) POST
E000:61C8 dw 16D2h ; chksum ROM, check EEPROM
E000:61C8 ; on error generate spkr tone
E000:61CA dw 1745h ; Check CMOS circuitry
E000:61CC dw 178Ah ; "chipset defaults" initialization
E000:61CE dw 1798h ; init CPU cache (both Cyrix and Intel)
E000:61D0 dw 17B8h ; init interrupt vector, also initialize
E000:61D0 ; "signatures" used for Ext_BIOS components
E000:61D0 ; decompression
E000:61D2 dw 194Bh ; Init_mainboard_equipment & CPU microcode
E000:61D2 ; chk ISA CMOS chksum ?
E000:61D4 dw 1ABCh ; Check checksum. Initialize keyboard controller
E000:61D4 ; and set up all of the 40: area data.
E000:61D6 dw 1B08h ; Relocate extended BIOS code
E000:61D6 ; init CPU MTRR, PCI REGs(Video BIOS ?)
E000:61D8 dw 1DC8h ; Video_Init (including EPA proc)
E000:61DA dw 2342h
E000:61DC dw 234Eh
E000:61DE dw 2353h ; dummy
E000:61E0 dw 2355h ; dummy
E000:61E2 dw 2357h ; dummy
E000:61E4 dw 2359h ; init Programmable Timer (PIT)
E000:61E6 dw 23A5h ; init PIC_1 (programmable Interrupt Ctlr)
E000:61E8 dw 23B6h ; same as above ?
E000:61EA dw 23F9h ; dummy
E000:61EC dw 23FBh ; init PIC_2
E000:61EE dw 2478h ; dummy
E000:61F0 dw 247Ah ; dummy
E000:61F2 dw 247Ah
E000:61F4 dw 247Ah
E000:61F6 dw 247Ah
E000:61F8 dw 247Ch ; this will call RAM_POST_tests again
E000:61F8 ; for values below(a.k.a ISA POST)
E000:61FA dw 0
E000:61FA END_E0_POST_TESTS_TABLE
________________________________________
E000:247C last_E000_POST proc near
E000:247C cli ; Clear Interrupt Flag
E000:247D mov word ptr , 0
E000:2483 mov cx, 30h ; '0'
E000:2486 mov di, 61FCh ; this addr contains 0000h
E000:2489
E000:2489 repeat_RAM_POST_tests:; CODE XREF: last_E000_POST+10
E000:2489 call RAM_POST_tests ; this call immediately return
E000:2489 ; since cs:=0000h
E000:248C jb repeat_RAM_POST_tests ; jmp if CF=1; not taken
E000:248E mov cx, 30h ; '0'
E000:2491 mov di, 61FEh ; cs: contains 249Ch
E000:2494
E000:2494 repeat_RAM_POST_tests_2: ; CODE XREF: last_E000_POST+1B
E000:2494 call RAM_POST_tests ; this call should nvr return if
E000:2494 ; everything is ok
E000:2497 jb repeat_RAM_POST_tests_2 ; Jump if Below (CF=1)
E000:2499 jmp Halt_System ;
E000:2499 last_E000_POST endp
________________________________________
E000:61FC ISA_POST_TESTS
E000:61FC dw 0
E000:61FE dw 249Ch
E000:6200 dw 26AFh
E000:6202 dw 29DAh
E000:6204 dw 2A54h ; dummy
E000:6206 dw 2A54h
E000:6208 dw 2A54h
E000:620A dw 2A54h
E000:620C dw 2A54h
E000:620E dw 2A54h
E000:6210 dw 2A56h ; dummy
E000:6212 dw 2A56h
E000:6214 dw 2A56h
E000:6216 dw 2A58h
E000:6218 dw 2A64h
E000:621A dw 2B38h
E000:621C dw 2B5Eh ; dummy
E000:621E dw 2B60h ; dummy
E000:6220 dw 2B62h
E000:6222 dw 2BC8h ; HD init ?
E000:6224 dw 2BF0h ; game io port init ?
E000:6226 dw 2BF5h ; dummy
E000:6228 dw 2BF7h ; FPU error interrupt related
E000:622A dw 2C53h ; dummy
E000:622C dw 2C55h
E000:622E dw 2C61h ; dummy
E000:6230 dw 2C61h
E000:6232 dw 2C61h
E000:6234 dw 2C61h
E000:6236 dw 2C61h
E000:6238 dw 2C61h
E000:623A dw 2CA6h
E000:623C dw 6294h ; set cursor charcteristic
E000:623E dw 62EAh
E000:6240 dw 6329h
E000:6242 dw 6384h
E000:6244 dw 64D6h ; dummy
E000:6246 dw 64D6h
E000:6248 dw 64D6h
E000:624A dw 64D6h
E000:624C dw 64D6h
E000:624E dw 64D6h
E000:6250 dw 64D6h
E000:6252 dw 64D6h
E000:6254 dw 64D6h
E000:6256 dw 64D6h
E000:6258 dw 64D6h
E000:625A dw 64D6h
E000:625C dw 64D6h
E000:625E dw 64D8h ; bootstrap
E000:6260 dw 66A1h
E000:6262 dw 673Ch
E000:6264 dw 6841h ; issues int 19h (bootstrap)
E000:6266 dw 0
E000:6266 END_ISA_POST_TESTS
注意:
这个“POST jump table”例程在他们遇到一些执行错误的时候会设置Carry Flay(CF=1)。在POST例程返回,这个Carry Flag就要被测试,如果它被设置,然后这个“RAM_POST_TESTS”就会立刻返回,这样就会使系统崩溃,系统扬声器就会发出声音。:) 7.2.4. The "segment vector" Routines
下面只是一个它的用法例子。它有很多地方用得到。有一对这样的“段向量”。一些就要从段E000h跳转到F000h,一些从段F000h跳到E000h,一些从E000h到6000h(重新定位的解压了的awardext.rom),一些从F000h到6000h(重新定位的解压了的awardext.rom)。
a.First variant: jump from segment E000h to F000h
b.Address Assembly Code
________________________________________
E000:1553 Restore_Warm_Boot_Flag proc near ; CODE XREF: POST_1S
.........
E000:155A callF_Vect_Read_CMOS_Byte
.........
E000:156E Restore_Warm_Boot_Flag endp
________________________________________
Address Machine Code Assembly Code
E000:6CA2 F_Vect_Read_CMOS_Byte proc near ; CODE XREF: Restore_Warm_Boot_Flag+7 p
E000:6CA2 ; 000E1747 p ...
E000:6CA2 push0E000h
E000:6CA5 push6CB3h
E000:6CA8 push0EC31h
E000:6CAB push0E4FDh ; Read_CMOS_Byte
E000:6CAE jmp far ptr F000_Vector
E000:6CB3 ; ---------------------------------------------------------------------------
E000:6CB3 retn
E000:6CB3 F_Vect_Read_CMOS_Byte endp
________________________________________
F000:EC30 F000_Vector: ; CODE XREF: 000E1781 J 000E17AA J ...
F000:EC30 retn
F000:EC31 ; ---------------------------------------------------------------------------
F000:EC31 retf
________________________________________
F000:E4FD Read_CMOS_Byte proc near
F000:E4FD xchgbx, bx
F000:E4FF nop
F000:E500 out 70h, al ; CMOS Memory:
F000:E500 ; used by real-time clock
F000:E502 jcxzshort $+2
F000:E504 jcxzshort $+2
F000:E506 xchgbx, bx
F000:E508 in al, 71h ; CMOS Memory
F000:E50A jcxzshort $+2
F000:E50C jcxzshort $+2
F000:E50E retn
F000:E50E Read_CMOS_Byte endp
________________________________________
c.Second variant: jump from segment E000h to 6000h
d.Address Machine Code Assembly Code
________________________________________
.........
E000:1737 pushcs
E000:1738 push1743h ; ret addr below
E000:173B push1829h ; func addr in XGROUP ROM
E000:173E jmp far ptr loc_6000_2
E000:1743 ; ---------------------------------------------------------------------------
E000:1743 clc
E000:1744 retn
.........
________________________________________
6000:0000 locret_6000_0: ; CODE XREF: 00060017 j
6000:0000 retn ; jump to target procedure
6000:0001 ; ---------------------------------------------------------------------------
6000:0001 retf ; back to caller
________________________________________
6000:0002 loc_6000_2: ; push return addr for retn
6000:0002 push1 ; (addr_of retf above)
6000:0005 pushax
6000:0006 pushf
6000:0007 cli
6000:0008 xchgbp, sp
6000:000A mov ax, ; mov ax,1 ; look at 1st inst above
6000:000D xchgax, ; xchg ax,word_pushed_by_org_tmp
6000:0010 mov , ax ; = word_pushed_by_org_tmp
6000:0013 xchgbp, sp ; modify sp
6000:0015 popf
6000:0016 pop ax
6000:0017 jmp short locret_6000_0 ; jump into word_pushed_by_original.tmp
________________________________________
6000:1829 cli ; Clear Interrupt Flag
.........
6000:18B3 retn ; Return Near from Procedure
________________________________________
e.Third variant: jump from segment 6000h to F000h
f.Address Assembly Code
________________________________________
6000:4F60 reinit_chipset proc far
6000:4F60 push ds
6000:4F61 mov ax, 0F000h
6000:4F64 mov ds, ax ; ds = F000h
6000:4F66 assume ds:nothing
6000:4F66 mov bx, 0E38h ; ptr to PCI reg vals (ds:bx = F000:E38h)
6000:4F69
6000:4F69 next_PCI_reg: ; CODE XREF: reinit_chipset+3D
6000:4F69 cmp bx, 0EF5h ; are we finished ?
6000:4F6D jz exit_PCI_init ; if yes, then exit
6000:4F6F mov cx, ; cx = PCI addr to read
6000:4F72 call setup_read_write_PCI ; on ret, ax = F70Bh, di = F725h
6000:4F75 push cs
6000:4F76 push 4F7Fh
6000:4F79 push ax ; goto F000:F70B (Read_PCI_Byte)
6000:4F7A jmp far ptr 0E000h:6188h ; goto_seg_F000
6000:4F7F ; ---------------------------------------------------------------------------
6000:4F7F mov dx, ; reverse-and mask
.........
________________________________________
E000:6188 goto_F000_seg: ; CODE XREF: HD_init_?+3BD
E000:6188 ; HD_init_?+578 ...
E000:6188 68 31 EC push 0EC31h
E000:618B 50 push ax
E000:618C 9C pushf ; Push Flags Register onto the Stack
E000:618D FA cli ; Clear Interrupt Flag
E000:618E 87 EC xchg bp, sp ; Exchange Register/Memory with Register
E000:6190 8B 46 04 mov ax, ; mov ax, EC31h
E000:6193 87 46 06 xchg ax, ; xchg ret addr and EC31h
E000:6196 89 46 04 mov , ax ; mov ,
E000:6199 87 EC xchg bp, sp ; Exchange Register/Memory with Register
E000:619B 9D popf ; Pop Stack into Flags Register
E000:619C 58 pop ax
E000:619D EA 30 EC 00 F0 jmp far ptr F000_func_vector ; Jump
________________________________________
F000:EC30 F000_func_vector: ; CODE XREF: chk_cmos_circuit+3C
F000:EC30 C3 retn ; jump to target function
F000:EC31 ; -------------------------------------------------------------------
F000:EC31 CB retf ; return to calling segment:offset (6000:4F7F)
________________________________________
F000:F70B read_PCI_byte proc near ; CODE XREF: enable_ROM_write?+4
.........
F000:F724 retn ; Return Near to F000:EC31h
F000:F724 read_PCI_byte endp
7.2.5. "chksum_ROM" Procedure
这个例程是“E0_POST_TESTS”的一部分,“E0_POST_TESTS”是由POST例程通过使用“POST jump table”来调用的。这个例程没有立刻的返回。但是,一个调用到“Check_F_Next”的调用将会完成这个“near return”,这个近返回需要继续进行下一个“POST 进程”的执行。
________________________________________
E000:16D2 chksum_ROM proc near
.........
E000:16FF 74 1E jz Check_F_Next ; yes. This jump will return this routine
E000:16FF ; to where it's called
.........
E000:171D EB E6 jmp short spkr_endless_loop ; Jump
E000:171D chksum_ROM endp
________________________________________
E000:171F Check_F_Next proc near; CODE XREF: chksum_ROM+2D
.........
E000:1743 F8 clc ; signal successful execution
E000:1744 C3 retn ; retn to RAM_POST_TESTS, proceed to next POST proc
E000:1744 Check_F_Next endp ; sp = -6
________________________________________
7.2.6. Original.tmp Decompression Routine for The "Extension_BIOS Components"
这是一个在最开始的时候最会混淆的地方。但是,通过理解它,我们实际上的没有更多的需要对“bios 代码执行路径”担心的。我怀疑我们这里要解释的相同的技术适用于绝大部分的award bios。这个例程基本的run-down解释如下:
a.Decompress_System_BIOS 历程被“主bootblock执行路径”(在bootblock代码在地址段2000h执行期间)调用,保存了必需的对在RAM预先确定区域有用的标志,下面展示:
________________________________________
2000:E512 Decompress_System_BIOS proc near ; CODE XREF: 0002E3DC
2000:E512 E8 EB DA callCopy_C_seg_n_D_seg; copy lower 128 KByte bios code from ROM (at FFFC_0000h -
2000:E512 ; FFFD_0000h) to RAM (at 8000:0000h-9000:FFFFh)
2000:E515 32 E4 xor ah, ah
2000:E517 33 C9 xor cx, cx
2000:E519 BB 00 80 mov bx, 8000h
2000:E51C 8E DB mov ds, bx ; ds = 8000h, contains compressed
2000:E51C ; lower 128KB bios components (awdext,etc.)
2000:E51E assume es:nothing, ds:nothing
2000:E51E 33 F6 xor si, si
2000:E520 next_Cseg_Dseg_byte: ; CODE XREF: Decompress_System_BIOS+11
2000:E520 ; Decompress_System_BIOS+1F
2000:E520 AC lodsb
2000:E521 02 E0 add ah, al ; calc 8-bit chksum of C_seg n D_seg
2000:E523 E2 FB loopnext_Cseg_Dseg_byte
2000:E525 8C DB mov bx, ds
2000:E527 80 FF 90 cmp bh, 90h ; '?' ; are we in seg 9000h?
2000:E52A 73 07 jnb short done
2000:E52C 80 C7 10 add bh, 10h ; move to next higher segment
2000:E52F 8E DB mov ds, bx
2000:E531 assume ds:nothing
2000:E531 EB ED jmp short next_Cseg_Dseg_byte
2000:E533 ; ---------------------------------------------------------------------------
2000:E533 done: ; CODE XREF: Decompress_System_BIOS+18
2000:E533 BB 00 10 mov bx, 1000h
2000:E536 8E DB mov ds, bx ; ds = start_addr_of E_seg n F_seg in RAM
2000:E536 ; (compressed original.tmp + bootblock)
2000:E538 assume ds:_1000h
2000:E538 33 F6 xor si, si
2000:E53A FC cld
2000:E53B next_Eseg_Fseg_byte: ; CODE XREF: Decompress_System_BIOS+2C
2000:E53B ; Decompress_System_BIOS+3B
2000:E53B AC lodsb
2000:E53C 02 E0 add ah, al ; calc 8 bit chksum, cont'd from chksum above
2000:E53E E2 FB loopnext_Eseg_Fseg_byte
2000:E540 80 FF 20 cmp bh, 20h ; ' ' ; are we in seg 2000h?
2000:E543 73 0A jnb short chksum_done
2000:E545 80 C7 10 add bh, 10h ; move to next higher segment
2000:E548 8E DB mov ds, bx
2000:E54A assume ds:_2000h
2000:E54A B9 FE 7F mov cx, 7FFEh ; amount of byte in last seg (F_seg in RAM) to calc
2000:E54D EB EC jmp short next_Eseg_Fseg_byte
2000:E54F ; ---------------------------------------------------------------------------
2000:E54F chksum_done: ; CODE XREF: Decompress_System_BIOS+31 j
2000:E54F 3A 24 cmp ah, ; cmp calc-ed chksum and chksum pointed to by .
2000:E54F ; this is the chksum for the bios binary
2000:E54F ; from 00000h to 37FFDh (C000:0h - F000:7FFDh)
2000:E551 0F 85 8C FE jnz _sysbios_chksum_error ; jmp back and continue to bootblock error handling routine
2000:E555 mov bx, 0
2000:E558 mov es, bx
2000:E55A assume es:nothing
2000:E55A mov es:word_0_7004, 0FFFFh ; save signature to be used by original.tmp
2000:E55A ; (POST_8S) for decompression
2000:E561 xor al, al
2000:E563
2000:E563 ; System_BIOS Decompression started here
2000:E563 mov bx, 1000h
2000:E566 mov es, bx ; es = src_seg
2000:E568 assume es:_1000h
2000:E568 xor bx, bx ; bx = src_offset
2000:E56A callDecompress ; on ret, CF=1 if error occured
2000:E56D 72 13 jb short sysbios_decomp_error
2000:E56F 66 F7 C1 00 00 FF FF testecx, 0FFFF0000h ; compressed component size more than 64KB?
2000:E576 74 0A jz short sysbios_decomp_error ; jmp if compressed component size <= 64KB
2000:E578 BB 00 20 mov bx, 2000h
2000:E57B 8E C3 mov es, bx ; proceed2next cmprssd componnt (in next segment)
2000:E57D assume es:_2000h
2000:E57D BB 01 00 mov bx, 1 ; bx = index to be added to previous src_offset in cx
2000:E580 EB 1B jmp short repeat_decompress ; decompress remaining component (1st pass jmp taken)
2000:E582 ; ---------------------------------------------------------------------------
2000:E582 sysbios_decomp_error: ; CODE XREF: Decompress_System_BIOS+5B
2000:E582 ; Decompress_System_BIOS+64
2000:E582 D0 D0 rcl al, 1
2000:E584 BB 00 20 mov bx, 2000h
2000:E587 8E C3 mov es, bx
2000:E589 33 DB xor bx, bx
2000:E58B E8 2B 00 callDecompress
2000:E58E D0 D0 rcl al, 1
2000:E590 3C 03 cmp al, 3
2000:E592 75 05 jnz short decompress_successfull
2000:E594 B8 00 10 mov ax, 1000h
2000:E597 F9 stc
2000:E598 C3 retn
2000:E599 ; ---------------------------------------------------------------------------
2000:E599 decompress_successfull: ; CODE XREF: Decompress_System_BIOS+80
2000:E599 0A C0 or al, al
2000:E59B 75 10 jnz short sys_bios_dcomprss_done
2000:E59D repeat_decompress: ; CODE XREF: Decompress_System_BIOS+6E
2000:E59D ; Decompress_System_BIOS+99
2000:E59D 03 D9 add bx, cx ; bx = point to next compressed component
2000:E59F E8 17 00 callDecompress
2000:E5A2 72 09 jb short sys_bios_dcomprss_done ; 1st pass jmp taken
2000:E5A4 66 F7 C1 00 00 FF FF testecx, 0FFFF0000h
2000:E5AB 74 F0 jz short repeat_decompress
2000:E5AD sys_bios_dcomprss_done: ; CODE XREF: Decompress_System_BIOS+89
2000:E5AD ; Decompress_System_BIOS+90
2000:E5AD E8 AB DA callDecmprss_Sysbios_Extension
2000:E5B0 0F 84 2D FE jz _sysbios_chksum_error
2000:E5B4 B8 00 50 mov ax, 5000h ; set success flag
2000:E5B7 F8 clc
2000:E5B8 C3 retn
2000:E5B8 Decompress_System_BIOS endp
________________________________________
b.Decmprss_Sysbios_Extension 要保存段8000h或者9000h作为解压了的bios部分扩展的源段。这个是在RAM(seg 2000h)中的bootblock执行期间完成的,如下展示:
________________________________________
2000:C05B -- Decmprss_Sysbios_Extension --
2000:C05B in: es = src_seg
2000:C05B bx = src_offset
2000:C05B
2000:C05B out: ZF = 1 --> error occured
2000:C05B ZF = 0 --> execution succeeded
2000:C05B ; --------------- S U B R O U T I N E ---------------------------------------
2000:C05B Decmprss_Sysbios_Extension proc near
2000:C05B ; CODE XREF: Decompress_System_BIOS:sys_bios_dcomprss_done p
2000:C05B BB 00 80 mov bx, 8000h ; es = seg_addr of C_seg n D_seg copy in RAM
2000:C05B ; this seg_addr will be saved to RAM (0000:60XXh)
2000:C05B ; for extension component other than awdext.rom/awdeyt.rom
2000:C05E 8E C3 mov es, bx
2000:C060 assume es:nothing
2000:C060 33 DB xor bx, bx ; reset src_offset_addr
2000:C062 66 33 C9 xor ecx, ecx ; reset compressed src size
2000:C065 51 pushcx
2000:C066 repeat_decomprss: ; CODE XREF: Decmprss_Sysbios_Extension+30 j
2000:C066 03 D9 add bx, cx
2000:C068 72 09 jb short move_to_next_seg
2000:C06A 66 F7 C1 00 00 FF FF testecx, 0FFFF0000h ; is size more than 64KB?
2000:C071 74 0A jz short size_less_than_64KB
2000:C073 move_to_next_seg: ; CODE XREF: Decmprss_Sysbios_Extension+D j
2000:C073 8C C1 mov cx, es
2000:C075 81 C1 00 10 add cx, 1000h
2000:C079 8E C1 mov es, cx
2000:C07B assume es:nothing
2000:C07B EB 1A jmp short reset_byte_counter
2000:C07D ; ---------------------------------------------------------------------------
2000:C07D size_less_than_64KB: ; CODE XREF: Decmprss_Sysbios_Extension+16 j
2000:C07D 26 80 7F 12 41 cmp byte ptr es:, 41h ; 'A' ; is awardext.rom?
2000:C082 75 04 jnz short not_awdext
2000:C084 58 pop ax
2000:C085 0C 01 or al, 1
2000:C087 50 pushax
2000:C088 not_awdext: ; CODE XREF: Decmprss_Sysbios_Extension+27 j
2000:C088 E8 2E 25 callDecompress
2000:C08B 73 D9 jnb short repeat_decomprss
2000:C08D 8C C3 mov bx, es
2000:C08F 81 C3 00 10 add bx, 1000h
2000:C093 8E C3 mov es, bx
2000:C095 assume es:nothing
2000:C095 33 DB xor bx, bx
2000:C097 reset_byte_counter: ; CODE XREF: Decmprss_Sysbios_Extension+20 j
2000:C097 33 C9 xor cx, cx
2000:C099 repeat_dcomprss2: ; CODE XREF: Decmprss_Sysbios_Extension+4E j
2000:C099 03 D9 add bx, cx
2000:C09B 26 80 7F 12 41 cmp byte ptr es:, 41h ; 'A'
2000:C0A0 75 04 jnz short not_awdext2
2000:C0A2 58 pop ax
2000:C0A3 0C 01 or al, 1 ; set successful flag
2000:C0A5 50 pushax
2000:C0A6 not_awdext2: ; CODE XREF: Decmprss_Sysbios_Extension+45 j
2000:C0A6 E8 10 25 callDecompress
2000:C0A9 73 EE jnb short repeat_dcomprss2
2000:C0AB 58 pop ax
2000:C0AC 0A C0 or al, al ; al=0 indicate an error occured
2000:C0AC ; (awdext_rom doesn't exist)
2000:C0AE C3 retn
2000:C0AE Decmprss_Sysbios_Extension endp
________________________________________
c.Decompression_Ngine 例程被解压缩例程在RAM(在seg 2000h)中的bootblock改变头部时调用,它按需要改变头部,保存结果到RAM中重新定义区域,如下:
________________________________________
2000:7789 --- Decomprssion_Ngine ---
2000:7789 in: dx = scratch-pad_segment_for_decompression
2000:7789 es = (compressed_segment_addr>>0xC)
2000:7789 bx = compressed_offset_addr
2000:7789
2000:7789 out: ecx = overall_compressed_component_length
2000:7789 edx = original_file_size
2000:7789 ; --------------- S U B R O U T I N E ---------------------------------------
2000:7789 Decompression_Ngine proc near
.........
2000:77FF pushgs
2000:7801 mov di, 0
2000:7804 mov gs, di
2000:7806 assume gs:nothing
2000:7806 mov di, 6000h
2000:7809 mov word ptr gs:, 7789h ; save Decompression_Ngine offset
2000:780E
2000:780E ;check LZH header
2000:780E add bx, 12h ; LZH-header decomp_seg_addr_hi_byte index
2000:7811 callFetch_Byte
2000:7814 sub bx, 12h ; restore bx to point to first byte
2000:7817 cmp al, 40h ; '@' ; is extension component?
2000:7817 ; at 1st: al equ 50h (original.tmp)
2000:7817 ; at 2nd: al equ 41h (awardext.rom)
2000:7819 jnz short not_extension_component ; 1st-pass jmp taken
2000:781B add bx, 11h
2000:781E callFetch_Byte ; fetch "dest_seg_addr" lo_byte
2000:7821 sub bx, 11h ; restore bx to point to first byte
2000:7824 or al, al ; if extension component, jmp taken
2000:7826 jnz short extension_component
2000:7828 cmp dword ptr gs:, 0 ; cmp dword :0
2000:7828 ; 1st pass from original.tmp, =FFFFh
2000:7828 ; (programmed by POST_8S in original.tmp prior to calling this engine)
2000:782E jnz short not_extension_component
2000:7830 extension_component: ; CODE XREF: Decompression_Ngine+9D
2000:7830 movzx dx, al ; dl = "dest_seg_addr" lo_byte
2000:7833 inc bx ; bx = LZH_hdr_chksum byte index
2000:7834 callFetch_Byte
2000:7837 sub al, dl ; LZH_hdr_chksum = LZH_hdr_chksum - "dest_seg_addr"_lo_byte
2000:7839 callPatch_Byte ; store new checksum
2000:783C dec bx ; restore bx
2000:783D xor al, al ; al = 00h
2000:783F add bx, 11h ; bx = "dest_seg_addr"_lo_byte index
2000:7842 callPatch_Byte ; patch "dest_seg_addr"_lo_byte to 00h
2000:7845 sub bx, 11h
2000:7848 inc dx ; dx = "dest_seg_addr"_lo_byte + 1
2000:7849 shl dx, 2 ; dx = 4*("dest_seg_addr"_lo_byte + 1)
2000:784C add di, dx ; di = 6000h + dx-- look above!
2000:784E mov gs:, bx ; 0000: = compressed_offset_addr
2000:7851 mov cx, es
2000:7853 mov gs:, cx ; 0000: = compressed_seg_addr>>0xC (hi_word of src phy addr)
2000:7857 callFetch_Byte ; al = LZH_hdr_len
2000:785A movzx ecx, al ; ecx = LZH_hdr_len
2000:785E add bx, 7
2000:7861 callFetch_Dword ; eax = compressed_file_size
2000:7864 sub bx, 7
2000:7867 add ecx, eax ; ecx = LZH_header_len + compressed_file_size
2000:786A add ecx, 3 ; ecx = total_compressed_component_size
2000:786E pop gs
2000:7870 assume gs:nothing
2000:7870 jmp exit
2000:7873 ; ---------------------------------------------------------------------------
2000:7873 not_extension_component: ; CODE XREF: Decompression_Ngine+90
2000:7873 ; Decompression_Ngine+A5
2000:7873 pop gs
2000:7875 callMake_CRC16_Table
2000:7878 callRead_Header ; fetch header component to scratchpad_seg, on error CF=1
2000:787B jb exit ; ret with error code set
2000:787F mov ax, ds:108h ; mov ax, decomprss_seg_addr
2000:7882 mov ds:104h, ax ; mov nu_decomprss_seg_addr, ax
2000:7885 mov ax, ds:10Ah ; mov ax, decomprss_offst_addr
2000:7888 mov ds:106h, ax ; mov nu_decomprss_offst_addr, ax
2000:788B mov ecx, ds:310h ; ecx = compressed_component_size
2000:7890 xor eax, eax
2000:7893 mov al, ds:571Ch ; al = LZH_hdr_len
2000:7896 add ecx, eax ; ecx = compressed_cmpnnt_size + LZH_hdr_len
2000:7899 add ecx, 3 ; ecx = compressed_cmpnnt_size + LZH_hdr_len +
2000:7899 ; sizeof(EOF_byte) + sizeof(LZH_hdr_len_byte) +
2000:7899 ; sizeof(LZH_hdr_8bit_chk_sum)
2000:7899 ; i.e. ecx = overall_component_len
2000:789D mov edx, ds:314h ; mov edx, original_file_size
2000:78A2 pushedx
2000:78A4 pushecx
2000:78A6 pushbx
2000:78A7 add bx, 5 ; point to LZH ID byte
2000:78AA callFetch_Byte
2000:78AD pop bx
2000:78AE cmp al, '0' ; is '-lh0-'?
2000:78B0 jnz short decompress_part
2000:78B2 pushds
2000:78B3 pushsi
2000:78B4 pushbx
2000:78B5 mov di, ds:10Ah
2000:78B9 movzx ax, byte ptr ds:571Ch
2000:78BE add ax, 2
2000:78C1 add bx, ax
2000:78C3 mov cx, ds:310h
2000:78C7 mov ax, ds:108h
2000:78CA mov es, ax
2000:78CC add cx, 3
2000:78CF shr cx, 2
2000:78D2 next_dword: ; CODE XREF: Decompression_Ngine+151 j
2000:78D2 callFetch_Dword
2000:78D5 add bx, 4
2000:78D8 stosd
2000:78DA loopnext_dword
2000:78DC pop bx
2000:78DD pop si
2000:78DE pop ds
2000:78DF jmp short LZH_hdr_OK
2000:78E1 ; ---------------------------------------------------------------------------
2000:78E1 decompress_part: ; CODE XREF: Decompression_Ngine+127
2000:78E1 pushword ptr ds:104h ; save destination seg addr
2000:78E5 pushword ptr ds:106h ; save destination offset addr
2000:78E9 pushlarge
2000:78EE callLzh_Expand ; Lzh_Expand capable of handling compressed
2000:78EE ; component bigger than 64KB (1 segment)
2000:78F1 pop dword ptr ds:314h
2000:78F6 pop word ptr ds:106h
2000:78FA pop word ptr ds:104h
2000:78FE LZH_hdr_OK: ; CODE XREF: Decompression_Ngine+156
2000:78FE callZero_Init ; zero init 32KB of scratchpad_seg
2000:7901 pop ecx
2000:7903 pop edx
2000:7905 clc
2000:7906 exit: ; CODE XREF: Decompression_Ngine+E7
2000:7906 ; Decompression_Ngine+F2
2000:7906 pop es
2000:7907 pop bx
2000:7908 pop eax
2000:790A retn
2000:790A Decompression_Ngine endp
________________________________________
这个用红线标记的一行写入“signatures”到内存。比如,nnoprom.bin部分用id:4027h定义。这个例程中,nnoprom.bin的索引就要被保存。这个索引的计算方法如下(也是上面代码所看到的算法):
index = 4*(lo_byte(ID) + 1)
这个所引用来计算地址来保存信息或者签名。再nnoprom.bin里,索引是A0h(从)。所以,保存了信息的这个地址开始与60A0h。就像你上面看到的,第一个保存的信息是有压缩的“Extension_BIOS components”这个部分的偏移地址。它被保存在地址60A0h(for nnoprom.bin)。然后,临时“压缩/解压段地址”保存在60A2h(for nnoprom.bin)。对所有的“扩展bios部分”,这个临时的“压缩/解压段地址”经常是4000h,就像你上面看到的代码那样(这个临时的被解压段的值修改成了4000h,在被保存到RAM之前)。这个相同的进程就为其他的所有“扩展bios部分”执行完成了。 d.下一步,original.tmp(post执行期间)中的POST_8S负责准备为解压缩必须的签名,如下面你所看到的:
________________________________________
E000:17B8 POST_8S proc near
.........
E000:183F BE 00 00 mov si, 0
E000:1842 8E DE mov ds, si
E000:1844 assume ds:nothing
E000:1844 BE 00 70 mov si, 7000h
E000:1847 8B 44 04 mov ax, ; ax = FFFFh (0000:7004h filled before by Decompress_System_BIOS
E000:1847 ; during bootblock_in_RAM execution)
E000:184A BF 00 00 mov di, 0
E000:184D 8E C7 mov es, di
E000:184F assume es:nothing
E000:184F BF 00 60 mov di, 6000h
E000:1852 26 89 45 04 mov es:, ax ; = FFFFh --> signature to do LZH decompression
E000:1852 ; for extension components
E000:1856 3D FF FF cmp ax, 0FFFFh
E000:1859 74 10 jz short signature_ok
E000:185B 8B 04 mov ax,
E000:185D 26 89 45 04 mov es:, ax
E000:1861 8B 44 02 mov ax,
E000:1864 C1 E8 0C shr ax, 0Ch
E000:1867 26 89 45 06 mov es:, ax
E000:186B signature_ok: ; CODE XREF: POST_8S+A1
E000:186B E8 A2 6C call_init_Pwr_Mgmt_ctlr
E000:186E F8 clc
E000:186F C3 retn
E000:186F POST_8S endp
________________________________________
e.下一步,例程init_nnoprom_rosupd(这只是一个例子,其他部分可能会不同)解压缩nnoprom.bin和rosupd.bin,如下面代码:
________________________________________
E000:71C1 init_nnoprom_rosupd proc near ; CODE XREF: POST_11S
.........
E000:71CF BF A0 00 mov di, 0A0h ; 'a' ; nnoprom.bin index
E000:71CF ; nnoprom.bin-->4027h; A0h = 4h*(lo_byte(4027h)+1h)
E000:71D2 E8 74 FC callnear ptr decompress_BIOS_component ; decompress NNOPROM.BIN
E000:71D5 0F 82 ED 00 jb decompression_error
E000:71D9 68 00 40 push4000h
E000:71DC 1F pop ds ; ds = 4000h; decompression result seg
E000:71DD assume ds:nothing
E000:71DD 33 F6 xor si, si
E000:71DF 68 00 70 push7000h
E000:71E2 07 pop es ; es = 7000h
E000:71E3 assume es:nothing
E000:71E3 33 FF xor di, di
E000:71E5 B9 00 40 mov cx, 4000h
E000:71E8 FC cld
E000:71E9 F3 66 A5 rep movsd ; copy nnoprom decompression result from
E000:71E9 ; seg 4000h to seg 7000h
E000:71EC BF 03 00 mov di, 3
E000:71EF 66 26 81 3D 24 4E 4E 4F cmp dword ptr es:, 'ONN$' ; match (decompressed) nnoprom.bin signature
E000:71F7 0F 85 CB 00 jnz decompression_error
E000:71FB 68 F8 9F push9FF8h
E000:71FE 07 pop es ; es = 9FF8h
E000:71FF assume es:nothing
E000:71FF 33 FF xor di, di
E000:7201 B9 68 00 mov cx, 68h ; 'h'
E000:7204 32 C0 xor al, al
E000:7206 F3 AA rep stosb
E000:7208 BF A4 00 mov di, 0A4h ; 'a' ; ROSUPD.bin index
E000:720B E8 3B FC callnear ptr decompress_BIOS_component ; decompress ROSUPD.bin
E000:720E 0F 82 B4 00 jb decompression_error
E000:7212 1E pushds
E000:7213 06 pushes
E000:7214 0F A0 pushfs
E000:7216 0F A8 pushgs
E000:7218 9A DD 5F 00 F0 callds_es_fs_gs_flat_4GB
E000:721D 66 33 F6 xor esi, esi
E000:7220 8E DE mov ds, si
E000:7222 assume ds:nothing
E000:7222 8E C6 mov es, si
E000:7224 assume es:nothing
E000:7224 68 00 40 push4000h
E000:7227 5E pop si
E000:7228 66 C1 E6 04 shl esi, 4 ; esi = 4_0000h (decompressed ROSUPD.bin)
E000:722C 66 BF 00 00 10 00 mov edi, 100000h
E000:7232 66 8B CB mov ecx, ebx
E000:7235 66 C1 E9 02 shr ecx, 2
E000:7239 FC cld
E000:723A F3 67 66 26 A5 rep movs dword ptr es:, dword ptr es: ; copy decmprssd ROSUPD.BIN to 1MB
E000:723F 0F A9 pop gs
E000:7241 0F A1 pop fs
E000:7243 07 pop es
E000:7244 assume es:nothing
E000:7244 1F pop ds
E000:7245 assume ds:nothing
E000:7245 68 F8 9F push9FF8h
E000:7248 07 pop es
E000:7249 assume es:nothing
E000:7249 66 26 C7 06 00 00 00 00+mov dword ptr es:0, 100000h
E000:7253 66 26 C7 06 04 00 00 00+mov dword ptr es:4, 40000h
E000:725D 66 33 C0 xor eax, eax
E000:7260 B8 00 E0 mov ax, 0E000h
E000:7263 66 C1 E0 04 shl eax, 4
E000:7267 66 05 56 71 00 00 add eax, 7156h
E000:726D 66 26 A3 08 00 mov es:8, eax
E000:7272 B8 07 00 mov ax, 7
E000:7275 26 A3 0C 00 mov es:0Ch, ax
E000:7279 B8 00 70 mov ax, 7000h
E000:727C 26 A3 0E 00 mov es:0Eh, ax
E000:7280 66 33 C0 xor eax, eax
E000:7283 B8 00 E0 mov ax, 0E000h
E000:7286 66 C1 E0 04 shl eax, 4
E000:728A 66 05 AA 71 00 00 add eax, 71AAh
E000:7290 66 26 A3 10 00 mov es:10h, eax
E000:7295 66 BE 80 FF 09 00 mov esi, 9FF80h
E000:729B 66 81 C6 00 00 00 00 add esi, 0
E000:72A2 B0 36 mov al, 36h ; '6'
E000:72A4 0E pushcs
E000:72A5 68 B0 72 push72B0h
E000:72A8 68 FD E4 push0E4FDh ; read CMOS byte
E000:72AB EA 88 61 00 E0 jmp far ptr Fseg_vector
E000:72B0 ; ---------------------------------------------------------------------------
E000:72B0 8A D8 mov bl, al
E000:72B2 B8 00 00 mov ax, 0
E000:72B5 E8 41 FE callnear ptr call_nnoprom_at_7000h ; execute decompressed nnoprom.bin
E000:72B8 9C pushf
E000:72B9 9D popf
E000:72BA 72 0A jb short decompression_error
E000:72BC B8 00 00 mov ax, 0
E000:72BF 8E D8 mov ds, ax
E000:72C1 assume ds:nothing
E000:72C1 80 0E B7 04 03 or ds:byte_0_4B7, 3
E000:72C6 decompression_error: ; CODE XREF: init_nnoprom_rosupd+14
E000:72C6 ; init_nnoprom_rosupd+36 ...
E000:72C6 66 61 popad
E000:72C8 07 pop es
E000:72C9 assume es:nothing
E000:72C9 1F pop ds
E000:72CA assume ds:nothing
E000:72CA C3 retn
E000:72CA init_nnoprom_rosupd endp ; sp =2
________________________________________
E000:6E49 -- decompress_BIOS_component --
E000:6E49 in: di = index to compressed component (as written at 0000:6XXXh)
E000:6E49 ; --------------- S U B R O U T I N E ---------------------------------------
E000:6E49 decompress_BIOS_component proc far
E000:6E49 ; CODE XREF: EPA_Procedure+43
E000:6E49 ; EPA_Procedure+5E ...
E000:6E49 1E pushds
E000:6E4A 06 pushes
E000:6E4B 55 pushbp
E000:6E4C 57 pushdi
E000:6E4D 56 pushsi
E000:6E4E 81 E7 FF 3F and di, 3FFFh ; clear di's MSB
E000:6E52 FA cli
E000:6E53 B0 FF mov al, 0FFh ; enable cache
E000:6E55 E8 14 FE callF0_init_cpu_cache
E000:6E58 68 00 E0 push0E000h
E000:6E5B 68 69 6E push6E69h
E000:6E5E 68 31 EC push0EC31h
E000:6E61 68 D4 E3 push0E3D4h ; mod_A20_access_mode
E000:6E64 EA 30 EC 00 F0 jmp far ptr F000_Vector
E000:6E69 ; ---------------------------------------------------------------------------
E000:6E69 E8 2F 7D callds_ss_Enter_Voodoo_Mode
E000:6E6C 8C D8 mov ax, ds
E000:6E6E 8E C0 mov es, ax ; es = voodoo mode, base at 0000_0000h
E000:6E70 assume es:nothing
E000:6E70 E8 45 7D callss_Leave_Voodoo_mode
E000:6E73 5A pop dx ; dx = si
E000:6E74 58 pop ax ; ax = di --> compressed component index
E000:6E75 26 66 8B 9D 00 60 mov ebx, es:; ebx = compressed component physical addr ((seg>>0xC)+offset)
E000:6E7B 66 0B DB or ebx, ebx ; is compressd component exist?
E000:6E7E 0F 84 2E 01 jz no_cmprssd_component
E000:6E82 83 FB FF cmp bx, 0FFFFh
E000:6E85 0F 84 27 01 jz no_cmprssd_component
E000:6E89 F6 C4 40 testah, 40h
E000:6E8C 74 04 jz short exec_decompress ; for nnoprom.bin, jmp taken
E000:6E8E F8 clc
E000:6E8F E9 1F 01 jmp decomprss_BIOS_componnt_ret
E000:6E92 ; ---------------------------------------------------------------------------
E000:6E92 exec_decompress: ; CODE XREF: decompress_BIOS_component+43
E000:6E92 26 8B 3E 00 60 mov di, es:6000h ; di = Decompression_Ngine offset addr
E000:6E97 67 66 8B 35 00 00 16 00 mov esi, ds:160000h ; mov esi,
E000:6E9F 66 F7 D6 not esi
E000:6EA2 67 66 89 35 00 00 08 00 mov ds:80000h, esi ; modify ds:80000h value; restored below
E000:6EAA 66 81 FB 00 00 10 00 cmp ebx, 100000h ; compressed_component_phy_addr > 1MB ?
E000:6EB1 72 57 jb short above_1MB ; for nnoprom.bin, jmp _not_ taken
E000:6EB3 57 pushdi ; save Decompression_Ngine offset
E000:6EB4 66 BE 00 00 09 00 mov esi, 90000h
E000:6EBA 66 BF 00 00 14 00 mov edi, 140000h
E000:6EC0 66 B9 00 40 00 00 mov ecx, 4000h ; copy one segment
E000:6EC6 FC cld
E000:6EC7 67 F3 66 A5 rep movs dword ptr es:, dword ptr
E000:6ECB 66 BE 00 00 16 00 mov esi, 160000h
E000:6ED1 66 BF 00 00 08 00 mov edi, 80000h
E000:6ED7 66 B9 00 80 00 00 mov ecx, 8000h ; 2 segment (128KB)
E000:6EDD FC cld
E000:6EDE 67 F3 66 A5 rep movs dword ptr es:, dword ptr ; copy 2 segment (128KB) from 16_0000h to 8_0000h
E000:6EDE ; for decompression purposes
E000:6EE2 5F pop di
E000:6EE3 66 C1 CB 10 ror ebx, 10h
E000:6EE7 8E C3 mov es, bx ; es = HI_WORD(phy addr of compressed component)
E000:6EE9 66 C1 CB 10 ror ebx, 10h ; restore ebx
E000:6EED 26 8B 4F 11 mov cx, es: ; cx = decompression segment address.
E000:6EED ; The component will be decompressed into this segment address
E000:6EF1 51 pushcx ; push decompression segment addr
E000:6EF2 26 FF 37 pushword ptr es: ; push (LZH hdr len and LZH hdr chksum)
E000:6EF5 F6 C4 80 testah, 80h
E000:6EF8 74 36 jz short decompress ; all extension BIOS component-->jmp taken
E000:6EFA 26 89 57 11 mov es:, dx
E000:6EFE 02 CD add cl, ch
E000:6F00 02 D6 add dl, dh
E000:6F02 2A CE sub cl, dh
E000:6F04 26 28 4F 01 sub es:, cl
E000:6F08 EB 26 jmp short decompress
E000:6F0A ; ---------------------------------------------------------------------------
E000:6F0A above_1MB: ; CODE XREF: decompress_BIOS_component+68
E000:6F0A 66 81 C3 00 00 0E 00 add ebx, 0E0000h
E000:6F11 26 67 8B 4B 11 mov cx, es: ; cx = target segment addr (the component will be
E000:6F11 ; decompressed into this segmnt)
E000:6F16 51 pushcx
E000:6F17 26 67 FF 33 pushword ptr es:
E000:6F1B F6 C4 80 testah, 80h
E000:6F1E 74 10 jz short decompress
E000:6F20 26 67 89 53 11 mov es:, dx
E000:6F25 02 CD add cl, ch
E000:6F27 02 D6 add dl, dh
E000:6F29 2A CE sub cl, dh
E000:6F2B 26 67 28 4B 01 sub es:, cl
E000:6F30 decompress: ; CODE XREF: decompress_BIOS_component+AF
E000:6F30 ; decompress_BIOS_component+BF ...
E000:6F30 66 C1 CB 10 ror ebx, 10h
E000:6F34 8E C3 mov es, bx ; es = phy_addr>>0xC (hi_word of phy addr)
E000:6F36 66 C1 CB 10 ror ebx, 10h ; bx = compressed component offset
E000:6F3A 0E pushcs
E000:6F3B 68 49 6F push6F49h ; ret addr below
E000:6F3E 68 FF DF push0DFFFh
E000:6F41 BA 00 30 mov dx, 3000h ; scratch_pad_seg
E000:6F44 68 00 20 push2000h
E000:6F47 57 pushdi ; call Decompression_Ngine
E000:6F48 CB retf
E000:6F49 ; ---------------------------------------------------------------------------
E000:6F49 68 00 E0 push0E000h
E000:6F4C 68 5A 6F push6F5Ah
E000:6F4F 68 31 EC push0EC31h
E000:6F52 68 D4 E3 push0E3D4h ; disable_A20...
E000:6F55 EA 30 EC 00 F0 jmp far ptr F000_Vector
E000:6F5A ; ---------------------------------------------------------------------------
E000:6F5A E8 3E 7C callds_ss_Enter_Voodoo_Mode
E000:6F5D 8C D8 mov ax, ds
E000:6F5F 8E C0 mov es, ax ; es --> voodoo mode, base at 0000_0000h
E000:6F61 E8 54 7C callss_Leave_Voodoo_mode
E000:6F64 67 66 A1 00 00 08 00 mov eax, ds:80000h
E000:6F6B 67 66 3B 05 00 00 16 00 cmp eax, ds:160000h
E000:6F73 75 18 jnz short restore_header
E000:6F75 66 C1 CB 10 ror ebx, 10h
E000:6F79 8E C3 mov es, bx
E000:6F7B 66 C1 CB 10 ror ebx, 10h
E000:6F7F 26 8F 07 pop word ptr es:
E000:6F82 26 8F 47 11 pop word ptr es:
E000:6F86 26 66 8B 5F 0B mov ebx, es:
E000:6F8B EB 0F jmp short disable_A20
E000:6F8D ; ---------------------------------------------------------------------------
E000:6F8D restore_header: ; CODE XREF: decompress_BIOS_component+12A
E000:6F8D 26 67 8F 03 pop word ptr es:
E000:6F91 26 67 8F 43 11 pop word ptr es:
E000:6F96 26 67 66 8B 5B 0B mov ebx, es:
E000:6F9C disable_A20: ; CODE XREF: decompress_BIOS_component+142
E000:6F9C 68 00 E0 push0E000h
E000:6F9F 68 AD 6F push6FADh
E000:6FA2 68 31 EC push0EC31h
E000:6FA5 68 24 E4 push0E424h ; disable gate A20
E000:6FA8 EA 30 EC 00 F0 jmp far ptr F000_Vector
E000:6FAD ; ---------------------------------------------------------------------------
E000:6FAD F8 clc
E000:6FAE EB 01 jmp short decomprss_BIOS_componnt_ret
E000:6FB0 ; ---------------------------------------------------------------------------
E000:6FB0 no_cmprssd_component: ; CODE XREF: decompress_BIOS_component+35
E000:6FB0 ; decompress_BIOS_component+3C
E000:6FB0 F9 stc
E000:6FB1 decomprss_BIOS_componnt_ret:
E000:6FB1 ; CODE XREF: decompress_BIOS_component+46
E000:6FB1 ; decompress_BIOS_component+165
E000:6FB1 9C pushf
E000:6FB2 66 53 pushebx
E000:6FB4 68 00 E0 push0E000h
E000:6FB7 68 C5 6F push6FC5h
E000:6FBA 68 31 EC push0EC31h
E000:6FBD 68 D4 E3 push0E3D4h ; enable gate A20
E000:6FC0 EA 30 EC 00 F0 jmp far ptr F000_Vector
E000:6FC5 ; ---------------------------------------------------------------------------
E000:6FC5 E8 D3 7B callds_ss_Enter_Voodoo_Mode
E000:6FC8 8C D8 mov ax, ds
E000:6FCA 8E C0 mov es, ax
E000:6FCC E8 E9 7B callss_Leave_Voodoo_mode
E000:6FCF 67 66 A1 00 00 08 00 mov eax, ds:80000h
E000:6FD6 67 66 3B 05 00 00 16 00 cmp eax, ds:160000h
E000:6FDE 75 2B jnz short exit
E000:6FE0 66 BF 00 00 08 00 mov edi, 80000h
E000:6FE6 66 B9 00 40 00 00 mov ecx, 4000h
E000:6FEC 66 33 C0 xor eax, eax
E000:6FEF FC cld
E000:6FF0 67 F3 66 AB rep stos dword ptr es:
E000:6FF4 66 BE 00 00 14 00 mov esi, 140000h
E000:6FFA 66 BF 00 00 09 00 mov edi, 90000h
E000:7000 66 B9 00 40 00 00 mov ecx, 4000h
E000:7006 FC cld
E000:7007 67 F3 66 A5 rep movs dword ptr es:, dword ptr
E000:700B exit: ; CODE XREF: decompress_BIOS_component+195
E000:700B 68 00 E0 push0E000h
E000:700E 68 1C 70 push701Ch
E000:7011 68 31 EC push0EC31h
E000:7014 68 24 E4 push0E424h ; turn off Gate A20
E000:7017 EA 30 EC 00 F0 jmp far ptr F000_Vector
E000:701C ; ---------------------------------------------------------------------------
E000:701C 66 5B pop ebx
E000:701E B0 00 mov al, 0 ; disable CPU cache
E000:7020 E8 49 FC callF0_init_cpu_cache
E000:7023 9D popf
E000:7024 5D pop bp
E000:7025 07 pop es
E000:7026 1F pop ds
E000:7027 C3 retn
E000:7027 decompress_BIOS_component endp ; sp = -18h
其他部分的解压和处理与nnoprom.bin和rosupd.bin相似,如上。
通过上面的解释,我们只需要跟随“POST jump table execution”来知道在哪个环境下哪个“执行路径”被bios得到。做完了这个方法,我们就能够做我们喜欢做的hack award bios。不管怎样,我不准备在这里停止,下面的章节,我要给你呈现一些扩展部分的处理方法,他们很让我感兴趣。
7.2.7. Microcode Update Routine
微代码升级历程从POST_9S调用,如下所示:
________________________________________
E000:3BBE init_microcode proc near ; CODE XREF: POST_9S+52
E000:3BBE E8 4E 38 callis_intel_CPU
E000:3BC1 75 5F jnz short exit
E000:3BC3 66 B8 01 00 00 00 mov eax, 1
E000:3BC9 0F A2 cpuid
E000:3BCB BB 00 20 mov bx, 2000h
E000:3BCE 8E DB mov ds, bx
E000:3BD0 assume ds:_2000h
E000:3BD0 BB 00 90 mov bx, 9000h
E000:3BD3 3B 47 0C cmp ax,
E000:3BD6 75 05 jnz short decompress_microcode
E000:3BD8 E8 48 00 callget_cpu_microcode_ver
E000:3BDB 74 2C jz short update_microcode
E000:3BDD decompress_microcode: ; CODE XREF: init_microcode+18
E000:3BDD 66 50 pusheax
E000:3BDF BF 08 00 mov di, 8 ; compressed microcode index (4*(lo_byte(4001h)+1))
E000:3BE2 E8 64 32 callnear ptr decompress_BIOS_component
E000:3BE5 66 58 pop eax
E000:3BE7 72 39 jb short exit
E000:3BE9 66 C1 EB 0B shr ebx, 0Bh
E000:3BED 66 8B CB mov ecx, ebx
E000:3BF0 BB 00 40 mov bx, 4000h
E000:3BF3 8E DB mov ds, bx ; point to seg 4000h (microcode decompression rsult)
E000:3BF5 assume ds:nothing
E000:3BF5 33 DB xor bx, bx ; init bx
E000:3BF7 next_microcode: ; CODE XREF: init_microcode+47
E000:3BF7 3B 47 0C cmp ax,
E000:3BFA 75 05 jnz short microcode_not_match
E000:3BFC E8 24 00 callget_cpu_microcode_ver
E000:3BFF 74 08 jz short update_microcode
E000:3C01 microcode_not_match: ; CODE XREF: init_microcode+3C
E000:3C01 81 C3 00 08 add bx, 800h ; length of one microcode
E000:3C05 E2 F0 loopnext_microcode
E000:3C07 EB 19 jmp short exit
E000:3C09 ; ---------------------------------------------------------------------------
E000:3C09 update_microcode: ; CODE XREF: init_microcode+1D
E000:3C09 ; init_microcode+41
E000:3C09 66 B9 79 00 00 00 mov ecx, 79h ; 'y'
E000:3C0F 66 33 C0 xor eax, eax
E000:3C12 66 33 D2 xor edx, edx ; microcode update sign
E000:3C15 8C D8 mov ax, ds
E000:3C17 66 C1 E0 04 shl eax, 4
E000:3C1B 83 C3 30 add bx, 30h ; '0'
E000:3C1E 8B C3 mov ax, bx ; eax = linear addr of the microcode
E000:3C20 0F 30 wrmsr ; start microcode update
E000:3C22 exit: ; CODE XREF: init_microcode+3
E000:3C22 ; init_microcode+29 ...
E000:3C22 C3 retn
E000:3C22 init_microcode endp
8. 激昂展望
Hey, if you've read this article this far, you must be curious (^__^). Let's take a break a bit. I want to say some facts that are ridiculous. Well, at least to me. BIOS code is meant to be "twisted" so that code digger like us will find a hard time to figure it out. But, yeah here we are, understanding the big picture. Code digger rules my man! Nothing more dangerous than curiousity.
It's funny to see that the core LZH decompression routine that is used by award bioses (at least v4.51 that's dissected here) is just a complete "copy and paste" from Haruhiko Okumura's LZH code that anyone can find in the web. It's just the language that's different, Okumura's is in C while award's is in x86 assembly, the subroutines were exactly the same!
Another fact is, Phoenix code is very similar to award's code. I don't know who is "stealing" who, or perhaps there' s another source where both of them steal from (^__^). Oh no... I guess they are just doing reverse engineering like me with their tons of money. Unfortunately I don't have those tons of money he..he..he..
Well, let me stop ranting and continue my work on AMI BIOS. I guess we all waiting for it, right? It'll take sometime coz I'm very busy. If anyone of you who read this article have done it and had something to say or want to share your work with the world, I really keen to know. Why don't we join forces, right? my mail address is in the end of this article. I know some of us have done it.. we just haven't been in contact or perhaps it's better if we find our own way. Time will tell (-__-)
Greetz go to: Kris Kaspersky, Petr Soucek, Polaris, Havok, Zero, Mike Tedder a.k.a bpoint, apple_rom, Ilfak Guilfanov and many others who share their knowledge with the world.
9. 结束语
What I've explained above possibly far too premature to be ended here. But, I consider this article finished here as the Beta 5 version. If you follow this article from beginning to end, you'll be able to understand the "BIG Picture" of how the Award BIOS works. I think all of the issue dissected here is enough to do any type of modification you wish to do with award bios. If you find any mistake(s) within this article or have any suggestion, please contact me mamanzip@yahoo.com. Goodluck with your BIOS reverse engineering journey, I hope you enjoy it as much as I do (^__^) . Nothing more dangerous than curiousity. 好东西收藏起来了,明天发到公司好好研究~~~
谢谢斑竹~~~~~~~~:loveliness: thank you! 讲了点点皮毛?:lol
页:
[1]