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 BUS  3
2.2.ISA BUS  4
3.一些硬件特性  4
3.1. BIOS 芯片地址  5
3.2. 晦涩的硬件接口(Port)  6
3.3. "可重定位" 硬件Port  8
3.4. Expansion ROM Handling  9
4.一些软件特性  10
4.1.call指令特性  10
4.2. retn Instruction Peculiarity  10
5. 用到的工具  13
5.1. 我们的需求  13
5.2. IDA Pro技术介绍  13
5.2.1. IDA Pro介绍  13
5.2.2. IDA Pro Scripting And Key Bindings  19
6. Award BIOS 文件结构  26
6.1.压缩部分  26
6.2. 纯二进制部分  27
6.3. 真实系统(Mainboard)中的内存印象  27
7. 反汇编BIOS  28
7.1. Bootblock  29
7.1.1. "Virtual Shutdown" routine  29
7.1.2. Chipset_Reg_Early_Init routine  29
7.1.3. Init_Interrupt_n_PwrMgmt routine  35
7.1.4. Call To "Early Silicon Support" Routine  36
7.1.5. Bootblock Is Copied And Executed In RAM  37
7.1.6. Call to bios decompression routine and the jump into decompressed system bios  39
7.1.6.1. Enable FFF80000h-FFFDFFFFh decoding  40
7.1.6.2. Copy lower 128KB of BIOS code from ROM chip into RAM  40
7.1.6.3. Disable FFF8_0000h-FFFD_FFFFh decoding  40
7.1.6.4. Verify checksum of the whole compressed BIOS image  40
7.1.6.5. Look for the decompression engine  41
7.1.6.6. Decompress the compressed BIOS components  41
7.1.6.7. Shadow the BIOS code  60
7.1.6.8. Enable the microprocessor cache then jump into the decompressed system BIOS  60
7.2. System BIOS a.k.a Original.tmp  61
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 Routine  62
7.2.3. Call to the POST routine a.k.a "POST jump table execution"  64
7.2.4. The "segment vector" Routines  68
7.2.5. "chksum_ROM" Procedure  72
7.2.6. Original.tmp Decompression Routine for The "Extension_BIOS Components"  72
7.2.7. Microcode Update Routine  90
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
1  Pushad  保存所有通用寄存器的值
2  mov eax,80000064h  把将要访问的PCI芯片寄存器的地址放入eax
(offset 64h device 00:00:00 or hostbridge)
3  mov dx,0CF8h  地址端口放入dx。因为是PCI,我们用CF8h作为端口,来打开访问这个设备。
4  out dx,eax  发送PCI地址端口到processor的I/O空间
5  mov dx,0CFCh  数据端口放入dx。因为是PCI,我们用CFCh作为端口,来和这个设备数据通信。
6  in eax,dx  将从这个设备读出的数据放入eax
7  or eax, 00020202  改变数据(this is only example, don't try this in your machine, it may hang or even destroy your machine)
8  out dx,eax  将数据发送回设备
9  ............  -
10  Popad  出栈所有寄存器值
11  Ret  返回 
  
  我想上面的代码已经非常清晰了。这里有一个PCI寄存器地址格式例子:
mov eax,80000064h

  the 80000064h is the address. The meaning of these bits are: 
bit position  31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10  9  8  7  6  5  4  3  2  1  0
binary value  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  1  0  0  1  0  0
hexadecimal value  8  0  0  0  0  0  6  4
  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 Address  Also Known As  Used by  Address 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_FFFFh  E_seg / E_segment  1 Mbit, 2 MBit, and 4 MBit BIOS  alias 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 Address  Also Known As  Used by  Address 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_FFFFh  E_seg / E_segment  1 Mbit, 2 Mbit, and 4 Mbit BIOS  alias to FFFE_0000h - FFFE_FFFFh in some chipset just after power-up 
FFFD_0000h - FFFD_FFFFh  D_seg / D_segment  2 Mbit, and 4 Mbit BIOS  - 
FFFC_0000h - FFFC_FFFFh  C_seg / C_segment  2 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    Size  Address Range      Comment
DOS   0        640K  00000000-0009FFFF  Cacheable
VGA   640K     128K  000A0000-000BFFFF  Used for SMM
BIOS  768K     16K   000C0000-000C3FFF  Shadow Ctrl 1
BIOS  784K     16K   000C4000-000C7FFF  Shadow Ctrl 1
BIOS  800K     16K   000C8000-000CBFFF  Shadow Ctrl 1
BIOS  816K     16K   000CC000-000CFFFF  Shadow Ctrl 1
BIOS  832K     16K   000D0000-000D3FFF  Shadow Ctrl 2
BIOS  848K     16K   000D4000-000D7FFF  Shadow Ctrl 2
BIOS  864K     16K   000D8000-000DBFFF  Shadow Ctrl 2
BIOS  880K     16K   000DC000-000DFFFF  Shadow Ctrl 2
BIOS  896K     64K   000E0000-000EFFFF  Shadow Ctrl 3
BIOS  960K     64K   000F0000-000FFFFF  Shadow Ctrl 3
Sys   1MB      ?    00100000-DRAM Top  Can have hole
Bus   D Top          DRAM Top-FFFEFFFF
Init  4G-64K   64K   FFFEFFFF-FFFFFFFF  000Fxxxx 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/F31: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/F31: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:[si]
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:[si+2]
F000:F616 2E 0A 44 03               or    al, cs:[si+3]
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_CALL  MACRO    RTN_NAME
      LOCAL    RTN_ADD
      mov  sp,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        lgdt  qword 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:61BC  B9 6B 00             mov   cx, 6Bh         ; DRAM arbitration control
F000:61BF  BC C5 61             mov   sp, 61C5h
F000:61C2  E9 3B FE             jmp   F000_6000_read_pci_byte ; Jump
F000:61C2                       ; ------------------------------------------------------------------
F000:61C5  C7 61                dw 61C7h
F000:61C7                       ; ------------------------------------------------------------------
F000:61C7  0C 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, [CS base address = CS segment selector * 16]). 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:61BF  BC C5 61             mov   sp, 61C5h
F000:61C2  E9 3B FE             jmp   F000_6000_read_pci_byte ; Jump
F000:61C2                       ; ------------------------------------------------------------------
F000:61C5  C7 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-11  for *.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 <idc.idc>    
// 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], [0x10000, 0], 0xF000, 0, 0, 0);  
  SegRename([0xF000, 0], "_F000");  
    
  relocate_seg([0x7000,0], [0xF000, 0]);  
}    
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: [0x7000, 0] 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. 
Size  Host Address Range[31:0]  Address translation for LPC bus
64K bytes  FFFF_0000h ?FFFF_FFFFh  FFFF_0000h ?FFFF_FFFFh
64K bytes  000F_0000h ?000F_FFFFh  FFFF_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 部分之后都有发现。一个例子: 
  Address  Hex                                     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: 
Address  Hex                                     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:
Address  Hex                                     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:[si]
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:[si+2]
F000:F616 2E 0A 44 03               or    al, cs:[si+3]
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                        db  90h ; ?
F000:F68E 90 F6                     dw 0F690h
F000:F690                         ; ---------------------------------------------------------------------------
F000:F690 A8 40                     test  al, 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                        db  90h ; ?
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                        db  90h ; ?
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                     loop  delay
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:[si]
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                     loop  next_byte
F000:E1D2 3A 24                     cmp   ah, [si]
F000:E1D4 75 18                     jnz   short _BBSS_not_found
F000:E1D6 2E 8B 07                  mov   ax, cs:[bx]         ; 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:[si]
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                        db  87h ; ?
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            lgdt  qword 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 [esi+2], '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:[edi], dword ptr [esi]
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                  call  Decompress_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                  call  Copy_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                  call  Setup_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 byte  Offset in Real Header  Contents
00h  N/A  The header length of the component. It depends on the file/component name.
01h  N/A  The header 8-bit checksum, not including the first 2 bytes (header length and header checksum byte).
02h - 06h  00h - 04h  LZH 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 - 0Ah  05h - 08h  compressed file/component size in little endian dword value, i.e. MSB at 0Ah and so forth
0Bh - 0Eh  09h - 0Ch  Uncompressed file/component size in little endian dword value, i.e. MSB at 0Eh and so forth
0Fh - 10h  0Dh - 0Eh  Decompression 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 - 12h  0Fh - 10h  Decompression 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).
13h  11h  File attribute. My BIOS components contain 20h here, which is normally found in LZH level-1 compressed file.
14h  12h  Level. My BIOS components contain 01h here, which means it's a LZH level-1 compressed file.
15h  13h  component filename name length in byte.
16h - [15h+filename_len]  14h - [13h+filename_len]  component filename (ASCII string)
[16h+filename_len] - [17h+filename_len]  [14h+filename_len] - [15h+filename_len]  file/component CRC-16 in little endian word value, i.e. MSB at [HeaderSize - 2h] and so forth.
[18h+filename_len]  [16h+filename_len]  Operating System ID. In my BIOS it's always 20h (ASCII space character) which don't resemble any LZH OS ID known to me. 
[19h+filename_len] - [1Ah+filename_len]  [17h+filename_len] - [18h+filename_len]  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位置:
Location  Calculation Method
Right after compressed original.tmp  original.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, [si]            ; cmp calc-ed original.tmp chksum with
2000:E345                             ; chksum in BIOS image
2000:E347   jnz   _sysbios_chksum_error
Right after the decompression engine  This 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, [si]            ; 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   call  Copy_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   loop  next_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   loop  next_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, [si]            ; cmp calc-ed chksum and chksum pointed to by [si].
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   call  Decompress          ; on ret, CF=1 if error occured
2000:E56D   jb    short sysbios_decomp_error
2000:E56F   test  ecx, 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   call  Decompress
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   call  Decompress
2000:E5A2   jb    short sys_bios_dcomprss_done ; 1st pass jmp taken (original.tmp)
2000:E5A4   test  ecx, 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   call  Decmprss_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:[bx+0Fh], 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:[bx]
2000:E5E0   add   ecx, es:[bx+7]
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   push  ax
2000:E5EE   push  es
2000:E5EF   call  Find_BBSS           ; on ret, si contains offset right after BBSS sign
2000:E5F2   pop   es
2000:E5F3   assume es:nothing
2000:E5F3   push  es
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:[si+0Eh]
2000:E5FF   call  ax                  ; 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) [hi_word of src phy addr]
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   push  eax
2000:778B   push  bx
2000:778C   push  es
2000:778D   mov   ds, dx
2000:778F   push  ds
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   push  es
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   push  gs
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:[di], 7789h
2000:780E
2000:780E ;check LZH header
2000:780E   add   bx, 12h             ; LZH-header decomp_seg_addr_hi_byte index
2000:7811   call  Fetch_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   call  Fetch_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:[di+4], 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   call  Fetch_Byte
2000:7837   sub   al, dl              ; LZH_hdr_chksum = LZH_hdr_chksum - "dest_seg_addr"_lo_byte
2000:7839   call  Patch_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   call  Patch_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:[di], bx         ; 0000:[di] = compressed_offset_addr
2000:7851   mov   cx, es
2000:7853   mov   gs:[di+2], cx       ; 0000:[di+2] = compressed_seg_addr>>0xC (hi_word of src phy addr)
2000:7857   call  Fetch_Byte          ; al = LZH_hdr_len
2000:785A   movzx ecx, al             ; ecx = LZH_hdr_len
2000:785E   add   bx, 7
2000:7861   call  Fetch_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   call  Make_CRC16_Table
2000:7878   call  Read_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   push  edx
2000:78A4   push  ecx
2000:78A6   push  bx
2000:78A7   add   bx, 5               ; point to LZH ID byte
2000:78AA   call  Fetch_Byte
2000:78AD   pop   bx
2000:78AE   cmp   al, '0'             ; is '-lh0-'?
2000:78B0   jnz   short decompress_part
2000:78B2   push  ds
2000:78B3   push  si
2000:78B4   push  bx
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   call  Fetch_Dword
2000:78D5   add   bx, 4
2000:78D8   stosd
2000:78DA   loop  next_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   push  word ptr ds:104h    ; save destination seg addr
2000:78E5   push  word ptr ds:106h    ; save destination offset addr
2000:78E9   push  large [dword ptr ds:314h]
2000:78EE   call  Lzh_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   call  Zero_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                        push  cx
2000:790C 53                        push  bx
2000:790D 50                        push  ax
2000:790E 56                        push  si
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                        push  ax
2000:791B BB 00 00                  mov   bx, 0
2000:791E                         is_bit:                     ; CODE XREF: Make_CRC16_Table+25
2000:791E A9 01 00                  test  ax, 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   [bx+si], ax
2000:7935 46                        inc   si
2000:7936 E2 DD                     loop  next_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                        push  es
2000:79EA 8B 1E 02 01               mov   bx, ds:102h
2000:79EE E8 DA 00                  call  Fetch_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                        push  es
2000:7A05 8B 1E 02 01               mov   bx, ds:102h
2000:7A09 E8 BF 00                  call  Fetch_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                  call  Calc_LZH_hdr_CRC16  ; fetch compressed component value to RAM,
2000:7A14                                                     ; then calc its CRC16 checksum
2000:7A17 E8 88 FF                  call  CalcHdrSum  
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                  call  GetFromHeader
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                  call  GetFromHeader
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                  call  GetFromHeader
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                  call  GetFromHeader
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                  call  GetFromHeader       ; 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, [bx+0]          ; 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 [bx+0], 24h ; '$'
2000:7A84 C6 87 01 00 00            mov   byte ptr [bx+1], 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                        push  ax
2000:793E 53                        push  bx
2000:793F 51                        push  cx
2000:7940 52                        push  dx
2000:7941 0F B6 0E 1C 57            movzx cx, byte ptr ds:571Ch
2000:7946 06                        push  es
2000:7947 56                        push  si
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                  call  Fetch_Byte
2000:7952 88 04                     mov   [si], al
2000:7954 43                        inc   bx
2000:7955 46                        inc   si
2000:7956 E2 F7                     loop  next_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 [bx]
2000:7974 49                        dec   cx
2000:7975 E3 26                     jcxz  short exit
2000:7977 50                        push  ax
2000:7978 53                        push  bx
2000:7979 56                        push  si
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, [si+10Ch]
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                        push  bx
2000:79A3 51                        push  cx
2000:79A4 52                        push  dx
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 [bx+0]
2000:79B9 03 C2                     add   ax, dx
2000:79BB E2 F0                     loop  loc_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                        push  bx
2000:79C5 66 52                     push  edx
2000:79C7 56                        push  si
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                     jcxz  short 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 [si+0]
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 Size  Decompressed Size  Decompression State (by Bootblock code)  Component description
4100:0000h  3A85h  57C0h  Decompressed to RAM beginning at address in column one.  awardext.rom, this is a "helper module" for original.tmp
4001:0000h  5CDCh  A000h  Not decompressed yet  cpucode.bin, this is the CPU microcode
4003:0000h  DFAh  21A6h  Not decompressed yet  acpitbl.bin, this is the ACPI table
4002:0000h  35Ah  2D3Ch  Not decompressed yet  iwillbmp.bmp, this is the EPA logo
4027:0000h  A38h  FECh  Not decompressed yet  nnoprom.bin, explanation N/A
4007:0000h  1493h  2280h  Not decompressed yet  antivir.bin, this is BIOS antivirus code
4028:0000h  F63Ah  14380h  Not decompressed yet  ROSUPD.bin, seems to be custom Logo display procedure
5000:0000h  15509h  20000h  Decompressed 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 RAM  Decompression State (by Bootblock code)  Description
0000:6000h - 0000:6xxxh  N/A  This 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:5531h  Compressed  This 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:5FFFh  Pure Binary (non-executable)  This area contains only padding bytes.
2000:6000h - 2000:FFFFh  Pure 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:57C0h  Decompressed  This 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:FFFFh  Decompressed  This 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:FFFFh  Compressed  This 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:FFFFh  Decompressed  This 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:[edi], dword ptr [esi] ; 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 [bp+214h], 0 ; mov byte ptr 
F000:EE5C                         ; POST_SPEED[bp],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 RAM  Decompression State  Description
6000:0000h - 6000:57C0h  Decompressed  This is the relocated awardext.rom
160000h - 17FFFFh  Compressed  This 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:[di]    ; in the beginning :
E000:627F                         ; di = 61C2h ; ax = cs:[di] = 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 [bp+156h], 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:[di]=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:[di] 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   call  F_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   push  0E000h
E000:6CA5   push  6CB3h
E000:6CA8   push  0EC31h
E000:6CAB   push  0E4FDh              ; 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   xchg  bx, bx
F000:E4FF   nop
F000:E500   out   70h, al             ; CMOS Memory:
F000:E500                             ; used by real-time clock
F000:E502   jcxz  short $+2
F000:E504   jcxz  short $+2
F000:E506   xchg  bx, bx
F000:E508   in    al, 71h             ; CMOS Memory
F000:E50A   jcxz  short $+2
F000:E50C   jcxz  short $+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   push  cs
E000:1738   push  1743h               ; ret addr below
E000:173B   push  1829h               ; 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   push  1                   ; (addr_of retf above)
6000:0005   push  ax
6000:0006   pushf
6000:0007   cli
6000:0008   xchg  bp, sp
6000:000A   mov   ax, [bp+4]          ; mov ax,1 ; look at 1st inst above
6000:000D   xchg  ax, [bp+6]          ; xchg ax,word_pushed_by_org_tmp
6000:0010   mov   [bp+4], ax          ; [sp+4] = word_pushed_by_org_tmp
6000:0013   xchg  bp, 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, [bx+1]         ; 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, [bx+3]         ; 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, [bp+4]     ; mov ax, EC31h
E000:6193 87 46 06               xchg ax, [bp+6]    ; xchg ret addr and EC31h
E000:6196 89 46 04               mov [bp+4], ax     ; mov [sp+4],[sp+6]
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                  call  Copy_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                     loop  next_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                     loop  next_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, [si]            ; cmp calc-ed chksum and chksum pointed to by [si].
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   call  Decompress          ; 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      test  ecx, 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                  call  Decompress
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                  call  Decompress
2000:E5A2 72 09                     jb    short sys_bios_dcomprss_done ; 1st pass jmp taken
2000:E5A4 66 F7 C1 00 00 FF FF      test  ecx, 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                  call  Decmprss_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                        push  cx
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      test  ecx, 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:[bx+12h], 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                        push  ax
2000:C088                         not_awdext:                 ; CODE XREF: Decmprss_Sysbios_Extension+27 j
2000:C088 E8 2E 25                  call  Decompress
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:[bx+12h], 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                        push  ax
2000:C0A6                         not_awdext2:                ; CODE XREF: Decmprss_Sysbios_Extension+45 j
2000:C0A6 E8 10 25                  call  Decompress
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) [hi_word of src phy addr]
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   push  gs
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:[di], 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   call  Fetch_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   call  Fetch_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:[di+4], 0 ; cmp dword [0000:6004]:0
2000:7828                         ; 1st pass from original.tmp, [0000:6004]=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   call  Fetch_Byte
2000:7837   sub   al, dl              ; LZH_hdr_chksum = LZH_hdr_chksum - "dest_seg_addr"_lo_byte
2000:7839   call  Patch_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   call  Patch_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:[di], bx         ; 0000:[di] = compressed_offset_addr
2000:7851   mov   cx, es
2000:7853   mov   gs:[di+2], cx       ; 0000:[di+2] = compressed_seg_addr>>0xC (hi_word of src phy addr)
2000:7857   call  Fetch_Byte          ; al = LZH_hdr_len
2000:785A   movzx ecx, al             ; ecx = LZH_hdr_len
2000:785E   add   bx, 7
2000:7861   call  Fetch_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   call  Make_CRC16_Table
2000:7878   call  Read_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   push  edx
2000:78A4   push  ecx
2000:78A6   push  bx
2000:78A7   add   bx, 5               ; point to LZH ID byte
2000:78AA   call  Fetch_Byte
2000:78AD   pop   bx
2000:78AE   cmp   al, '0'             ; is '-lh0-'?
2000:78B0   jnz   short decompress_part
2000:78B2   push  ds
2000:78B3   push  si
2000:78B4   push  bx
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   call  Fetch_Dword
2000:78D5   add   bx, 4
2000:78D8   stosd
2000:78DA   loop  next_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   push  word ptr ds:104h    ; save destination seg addr
2000:78E5   push  word ptr ds:106h    ; save destination offset addr
2000:78E9   push  large [dword ptr ds:314h]
2000:78EE   call  Lzh_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   call  Zero_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(从[4*(27h+1)])。所以,保存了信息的这个地址开始与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, [si+4]          ; 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:[di+4], ax       ; [0000:6004] = 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, [si]
E000:185D 26 89 45 04               mov   es:[di+4], ax
E000:1861 8B 44 02                  mov   ax, [si+2]
E000:1864 C1 E8 0C                  shr   ax, 0Ch
E000:1867 26 89 45 06               mov   es:[di+6], 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                  call  near ptr decompress_BIOS_component ; decompress NNOPROM.BIN
E000:71D5 0F 82 ED 00               jb    decompression_error
E000:71D9 68 00 40                  push  4000h
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                  push  7000h
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:[di], 'ONN$' ; match (decompressed) nnoprom.bin signature
E000:71F7 0F 85 CB 00               jnz   decompression_error
E000:71FB 68 F8 9F                  push  9FF8h
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                  call  near ptr decompress_BIOS_component ; decompress ROSUPD.bin
E000:720E 0F 82 B4 00               jb    decompression_error
E000:7212 1E                        push  ds
E000:7213 06                        push  es
E000:7214 0F A0                     push  fs
E000:7216 0F A8                     push  gs
E000:7218 9A DD 5F 00 F0            call  ds_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                  push  4000h
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:[edi], dword ptr es:[esi] ; 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                  push  9FF8h
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                        push  cs
E000:72A5 68 B0 72                  push  72B0h
E000:72A8 68 FD E4                  push  0E4FDh              ; 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                  call  near 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                        push  ds
E000:6E4A 06                        push  es
E000:6E4B 55                        push  bp
E000:6E4C 57                        push  di
E000:6E4D 56                        push  si
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                  call  F0_init_cpu_cache
E000:6E58 68 00 E0                  push  0E000h
E000:6E5B 68 69 6E                  push  6E69h
E000:6E5E 68 31 EC                  push  0EC31h
E000:6E61 68 D4 E3                  push  0E3D4h              ; mod_A20_access_mode
E000:6E64 EA 30 EC 00 F0            jmp   far ptr F000_Vector
E000:6E69                         ; ---------------------------------------------------------------------------
E000:6E69 E8 2F 7D                  call  ds_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                  call  ss_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:[di+6000h]  ; 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                  test  ah, 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,[awardext.rom 4Byte hdr]
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                        push  di                  ; 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:[edi], dword ptr [esi]
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:[edi], dword ptr [esi] ; 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:[bx+11h]     ; cx = decompression segment address.
E000:6EED                                                     ; The component will be decompressed into this segment address
E000:6EF1 51                        push  cx                  ; push decompression segment addr
E000:6EF2 26 FF 37                  push  word ptr es:[bx]    ; push (LZH hdr len and LZH hdr chksum)
E000:6EF5 F6 C4 80                  test  ah, 80h
E000:6EF8 74 36                     jz    short decompress    ; all extension BIOS component-->jmp taken
E000:6EFA 26 89 57 11               mov   es:[bx+11h], 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:[bx+1], 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:[ebx+11h]    ; cx = target segment addr (the component will be
E000:6F11                                                     ; decompressed into this segmnt)
E000:6F16 51                        push  cx
E000:6F17 26 67 FF 33               push  word ptr es:[ebx]
E000:6F1B F6 C4 80                  test  ah, 80h
E000:6F1E 74 10                     jz    short decompress
E000:6F20 26 67 89 53 11            mov   es:[ebx+11h], 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:[ebx+1], 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                        push  cs
E000:6F3B 68 49 6F                  push  6F49h               ; ret addr below
E000:6F3E 68 FF DF                  push  0DFFFh
E000:6F41 BA 00 30                  mov   dx, 3000h           ; scratch_pad_seg
E000:6F44 68 00 20                  push  2000h
E000:6F47 57                        push  di                  ; call Decompression_Ngine
E000:6F48 CB                        retf                       
E000:6F49                         ; ---------------------------------------------------------------------------
E000:6F49 68 00 E0                  push  0E000h
E000:6F4C 68 5A 6F                  push  6F5Ah
E000:6F4F 68 31 EC                  push  0EC31h
E000:6F52 68 D4 E3                  push  0E3D4h              ; disable_A20...
E000:6F55 EA 30 EC 00 F0            jmp   far ptr F000_Vector
E000:6F5A                         ; ---------------------------------------------------------------------------
E000:6F5A E8 3E 7C                  call  ds_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                  call  ss_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:[bx]
E000:6F82 26 8F 47 11               pop   word ptr es:[bx+11h]
E000:6F86 26 66 8B 5F 0B            mov   ebx, es:[bx+0Bh]
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:[ebx]
E000:6F91 26 67 8F 43 11            pop   word ptr es:[ebx+11h]
E000:6F96 26 67 66 8B 5B 0B         mov   ebx, es:[ebx+0Bh]
E000:6F9C                         disable_A20:                ; CODE XREF: decompress_BIOS_component+142
E000:6F9C 68 00 E0                  push  0E000h
E000:6F9F 68 AD 6F                  push  6FADh
E000:6FA2 68 31 EC                  push  0EC31h
E000:6FA5 68 24 E4                  push  0E424h              ; 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                     push  ebx
E000:6FB4 68 00 E0                  push  0E000h
E000:6FB7 68 C5 6F                  push  6FC5h
E000:6FBA 68 31 EC                  push  0EC31h
E000:6FBD 68 D4 E3                  push  0E3D4h              ; enable gate A20
E000:6FC0 EA 30 EC 00 F0            jmp   far ptr F000_Vector
E000:6FC5                         ; ---------------------------------------------------------------------------
E000:6FC5 E8 D3 7B                  call  ds_ss_Enter_Voodoo_Mode
E000:6FC8 8C D8                     mov   ax, ds
E000:6FCA 8E C0                     mov   es, ax
E000:6FCC E8 E9 7B                  call  ss_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:[edi]
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:[edi], dword ptr [esi]
E000:700B                         exit:                       ; CODE XREF: decompress_BIOS_component+195
E000:700B 68 00 E0                  push  0E000h
E000:700E 68 1C 70                  push  701Ch
E000:7011 68 31 EC                  push  0EC31h
E000:7014 68 24 E4                  push  0E424h              ; 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                  call  F0_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                  call  is_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, [bx+0Ch]
E000:3BD6 75 05                     jnz   short decompress_microcode
E000:3BD8 E8 48 00                  call  get_cpu_microcode_ver
E000:3BDB 74 2C                     jz    short update_microcode
E000:3BDD                         decompress_microcode:       ; CODE XREF: init_microcode+18
E000:3BDD 66 50                     push  eax
E000:3BDF BF 08 00                  mov   di, 8               ; compressed microcode index (4*(lo_byte(4001h)+1))
E000:3BE2 E8 64 32                  call  near 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, [bx+0Ch]
E000:3BFA 75 05                     jnz   short microcode_not_match
E000:3BFC E8 24 00                  call  get_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                     loop  next_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 (^__^) .