跟著流程走(一):far jmp後發生什麼?
一、所需材料
1、主要BIOS :ex38dq6.f2 :技嘉主機板上Intel X38 MCH + ICH9 平臺。
備用BIOS:ma79xds4.f4 : 技嘉主機板上AMD 790X 北橋 + SB600 南橋平臺。
2、cbrom:這是一個BIOS編輯工具,這裡所用的是cbrom182版本
3、lha2.55:LHA格式的解壓工具。
4、awdbedit:award bios 的圖形化編輯工具,方便簡單。
5、hex workshop:一個十六進位編輯工具,簡單小巧。
6、IDA:一個反彙編工具,這裡使用的是IDA 5.2版本
二、所需知識
1、組合語言:這是必備的知識,彙編掌握的程度和理解能力成正比。
2、機器語言:這個不是必需的,但推薦能夠讀懂機器語言,某些場合下當組合語言也陷入窘境時,機器語言是唯一的解釋手段。
3、x86體系知識:具體可以查看相關的Intel 或 AMD 手冊
4、ISA/PCI 匯流排知識:可以查看相應的 ISA/PCI Specification
5、north/south bridge 知識:Intel 現在以MCH代稱north bridge,ICH代稱south bridge,可以查看相應的 datasheet
接下來用IDA pro打開ex38dq6.BIN觀察,這個是BIOS的主體檔,跟著流程走,看看far jmp後BIOS做什麼工作。
1、第一條指令 jmp far ptr F000:E05B 經過幾個跳轉,跳到F000:F46C處
2、以下是F000:F46C的代碼:
seg000:FF46C cli
seg000:FF46D cld
seg000:FF46E xchg bx, bx
seg000:FF470 smsw ax
seg000:FF473 test al, 1
seg000:FF475 jz short near ptr 0F480h
seg000:FF477 cli
seg000:FF478 mov al, 0FEh ; '?
seg000:FF47A out 64h, al ; AT Keyboard controller 8042.
seg000:FF47A ; Resend the last transmission
seg000:FF47C cli
seg000:FF47D hlt
--------------------------------------------------------------
取機器狀態字,也就是CR0寄存器,測試CR0.PE是否為1,判斷CPU是否處於真實模式狀態,若不是則停機。
若處於真實模式轉到F000:F480繼續處理。
3、轉到F000:F480又經過一道跳轉,來到F000:E043進行處理
4、下麵是F000:E043的代碼:
seg000:FE043 mov al, 8Fh ; '? ; disable NMI# and get 0Fh offset register
seg000:FE045 out 70h, al ; CMOS Memory:
seg000:FE045 ;
seg000:FE047 out 0EBh, al
seg000:FE049 in al, 71h ; get OFh offset register data
seg000:FE04B out 0EBh, al
seg000:FE04D or al, al ; is RESET ?
seg000:FE04F jmp near ptr 0F483h
在這裡,取 CMOS RAM 中位於0F處1個位元組的資料,通過測試這個位元組是否為0,判斷是否屬正常啟動。
5、正常啟動的話,調用F000:54DE這個子過程進行處理,否則跳到F000:3468。
二、下面看看F000:54DE的處理,以下是第二張流程圖:
下面proc_F54DE的代碼:
seg000:F54DE mov ax, 0
seg000:F54E1 mov es, ax
seg000:F54E3 cmp word ptr es:472h, 1234h
seg000:F54EA jnz short near ptr 54F8h
seg000:F54EC mov al, 8Fh ; '?
seg000:F54EE out 70h, al ; CMOS Memory:
seg000:F54EE ;
seg000:F54F0 out 0EBh, al
seg000:F54F2 mov al, 0AAh ; '?
seg000:F54F4 out 71h, al ; CMOS Memory:
seg000:F54F4 ;
seg000:F54F6 out 0EBh, al
seg000:F54F8 mov dx, 3C4h
seg000:F54FB mov al, 1
seg000:F54FD out dx, al ; EGA: sequencer address reg
seg000:F54FD ; clocking mode. Data bits:
seg000:F54FD ; 0: 1=8 dots/char; 0=9 dots/char
seg000:F54FD ; 1: CRT bandwidth: 1=low; 0=high
seg000:F54FD ; 2: 1=shift every char; 0=every 2nd char
seg000:F54FD ; 3: dot clock: 1=halved
seg000:F54FE inc dl
seg000:F5500 in al, dx ; EGA port: sequencer data register
seg000:F5501 or al, 20h
seg000:F5503 out dx, al ; EGA port: sequencer data register
seg000:F5504 call near ptr 76FBh
seg000:F5507 retn
1、在BIOS資料區的0472處存放著一個重定標誌:
seg000:F54E3 cmp word ptr es:472h, 1234h
通過比較 [0472] 是否1234h,標誌1234h是一個暖開機標誌位元,機器暖開機時,例如:按下CTRL+ALT+DEL 三個鍵時,由鍵盤中斷處理常式在[0472]處寫標誌1234h。
2、是暖開機的話,將寫入AA標誌到CMOS RAM 的0F處。
3、接著設置EGA相應的工作狀態。
4、在proc_F76FB過程裡置計時器1的狀態。
5、最後調用過程proc_F2941進行晶片組的初始化。
三、下面是本站節的重點,初始化某部分晶片組,下面是流程圖:
1、下面重點理解 write_pci_byte這個BIOS提供的rontine,代碼如下:
seg000:FF798 xchg ax, cx ; write_byte routine
seg000:FF799 shl ecx, 10h
seg000:FF79D xchg ax, cx
seg000:FF79E mov ax, 8000h ; Bus 0
seg000:FF7A1 shl eax, 10h
seg000:FF7A5 mov ax, cx
seg000:FF7A7 and al, 0FCh
seg000:FF7A9 mov dx, 0CF8h ; config_address register
seg000:FF7AC out dx, eax
seg000:FF7AE add dl, 4 ; config_data register
seg000:FF7B1 mov al, cl
seg000:FF7B3 and al, 3
seg000:FF7B5 add dl, al
seg000:FF7B7 mov eax, ecx
seg000:FF7BA shr eax, 10h
seg000:FF7BE out dx, al
seg000:FF7BF retn
將這個routine功能簡化為C代碼形式來看比較直觀:
void wirte_pci_byte(int offset_number, int mask)
{
if (number == -1)
jmp_7666();
do_wirte_pci_byte(offset_number, mask);
}
這段routine固定寫PCI的Bus0,Device0,Function0,offset 值放在cx中,由調用者傳來,置什麼值放在al寄存器,這是1個位元組的值。Bus0,Dev0,Fun0是hostbrige控制器(NorthBridge),也即是DRAM控制器的地址所在。這段代碼是典型的寫PCI設置的手法。PCI設置位址送入config_address_register中,然後往config_data_register裡寫資料,這個PCI設備位址將映射到PCI設備的寄存器,如前面介紹的位址空間圖所示,PCI設備位址範圍是E000_0000 ~ EFFF_FFFF,這段空間提交到相應的PCI設備。
2、現在回過頭來看調用者,cx=95,al=33 這個參數傳給 write_pci_byte。Offset是95,mask碼是33。Offset 95在write_pci_byte將被置為94,這將是DRAM控制器的PAM4寄存器,PAM4寄存器控制D_8000 ~ D_FFFF記憶體空間的屬性。寫入33,結果是:將這段空間置為read/write屬性,這將是所有訪問這段空間的操作會提交到DRAM。而不再是ROM。
3、Offset 96的結果和offset 95一樣,在write_pci_byte的遮罩中被置為offset 94。