小華的部落格: 2007/4/29 - 2007/5/6

搜尋此網誌

網頁

星期日, 4月 29, 2007

x86 Intel CPU 的第一條指令~~~

一般CPU reset 後, 會預設跳躍至 0xffff_fff0 位址去執行, 這個位址是現行 BIOS ROM 映射的位址。而CPU被重置後的暫存器值為:

CS= F000h
EIP = 0000_FFF0h
Base Address= FFFF_0000h (隱含暫存器,不可見)

由於IA32 手冊中說明,IA32 CPU定址方式是利用Base Address+EIP,所以第一條指令讀取的位址是: Base Addr+EIP=FFFF_FFF0h,至於為什麼不是CS:IP的定址方式,則請參考IA32 手冊說明。

一般的做法是把 bootblock 的source code 放在這個區塊, 但是並不表示這個位址的 code 一定是 bootblock. 簡單說就是BIOS要不要做這一部分的功能就由你或是BIOS供應商決定.

一般而言,若有包 bootblock,則先跑 bootblock ; 之後才跳到 BIOS entry point ; 若沒包則直接跳到 BIOS entry point ( 這邊說的BIOS entry point 就是POST code一開始的地方,而他的第一條指令都是 cli ,而他的位址是固定的,也就是F000:E05B) !

Power on時 CPU 第一個 code read 一定是 0xFFFF_FFF0 ; 在那邊有放一個 jmp 指令 (因為 FFFFFFF0~FFFFFFFFh 只有 16-byte空間,無法放很多 code),如某個BIOS 在那個0xFFFF_FFF0的data 如下所示:

FFFFFFF0: E9 D3 E9 00 00 00 FE FF EA 39 EA ......

CPU讀取到E9 D3 E9 然後依照這個指令的描述 "轉跳" 到其他的地方 ,其中E9 是跳躍指令,jmp(E9)後面接的operand是相對位置,所以E9 "跳躍的位址"的計算方式:

"把現在的IP(*)加上operand就是target的IP "

0xFFF3 + 0xE9D3 = 0xE9C6(扣掉進位1,因為64k limit,範圍0000~FFFFh,會裁掉超出的部份)
(*當這到指令被CPU抓取時,IP就變成下一個指令的,所以目前的IP=0xFFF3);

若這 "跳躍的位址" 地方放的是 bootblock code,則先跑 bootblock。
所以由上面的範例可以知道,CPU讀取到第一行指令後會Jmp E9C6。
如果你是使用P廠商的BIOS,那麼這個位址就是指向BooBlock區塊的Entry point,因此可以證明他是有包BootBlock。

另外假設你的BIOS ROM大小為1MB ,那麼他會被映射到4G~(4G-1M)跟1M~640K的某幾個64K 的區域,簡單說就是4G~4G-1M 剛好就是對應到整顆BIOS ROM,而1M~640K則是某幾個64K會對應到BIOS ROM,例如E000h Segment(64K)或是F000h Segment(64k)=BIOS Data area,至於是誰要被映射過去就要看北橋的暫存器內的設定。

[註] 此篇文章整理自己在程式設計俱樂部的討論結果整理,感謝一些前輩指導。
[註] 如果要查看BIOS ROM的內容方式有下列幾種方式可以參考:
1.利用Debug dump 方式:利用OS自帶的Debug工具去將BIOS ROM資料讀到某個空閒的記憶體內查看
a. 在C:\> 鍵入 debug xxx.rom (以 256KB(3FFFFh)大小的BIOS ROM為例)
b. 在Debug提示"-"下鍵入"L 4000:0",其中L為Load意思,載入xxx.rom到記憶體4000:0的地方
所以40000~7FFFFh處為 xxx.rom的所有內容
c. 在Debug提示"-"下鍵入"D 7000:FFF0",其中D意思為Dump (查看記憶體資料)
此時會出現 7000:FFF0處的記憶體資料(也就是你載入的BIOS ROM資料)
2.若BIOS ROM size > 256KB,則使用 ultraedit 來看 ROM內容
3. 還可以使用反組譯工具Win32Dasm 或是IDA pro...等工具查看。