【我所認知的BIOS】->反彙編BIOS之Bootblock(2)

【我所認知的BIOS->反彙編BIOSBootblock(2)

--CPU micro code update

By Lightseed

5/12/2010

1CPU micro code的背景

先做個鋪墊爲什麼要在BIOS剛剛開始跑的時候就來講CPUmicro code

以下引用自網絡:

-------------------------------------

在十多年前的Pentium時代, INTEL曾經發布過有缺陷的CPU, 因爲浮點運算表邊界上有幾個數據錯誤, 導致在某些應用會出現錯誤, 這個錯誤概率很小, 出錯機率小於千萬分之一, 但在還是被捅出來了. INTEL爲此召回CPU.

Pentium Pro, INTEL決定給CPU留出一個補丁接口, CPU內部有缺陷的時候, 通過加載微碼(Microcode), 可以修復CPU的部分缺陷.

INTEL, 他們只測試過的CPU都是加載了微碼的, 如果沒有加載微碼, INTEL不保證會出現什麼問題.

現在的CPU有一個CPUID, 通過執行CPUID指令, 可以知道當前CPU的版本和Stepping. 根據這個信息, 再給CPU打相應的補丁.

下圖就是CPUID=06D2, Rev.A2

何時給CPU打補丁?

在給CPU初始化的時候, 就需要把INTEL提供的微碼寫進CPU, 因此, 加載CPU微碼就是系統BIOS的任務.

如果系統的CPU是可更換的, 那麼其微碼也需要更換. 因此, BIOD, 一般要包進若干個IDCPU微碼, 以便工廠安排不同的SKU出貨. 如果BIOS發佈是在CPU發佈之前, 那麼BIOS裏很可能就沒有包進最新的微碼, 這個系統要使用新CPU的時候, CPU微碼是無法加載的.

另外, BIOS ROM容量有限, 一個微碼補丁最小有2K, 如果平臺兼容的CPU很多, 則微碼數量是十分巨大的, 臺式機某些主板可能兼容20多個CPU版本, 那麼微碼的體積很大, BIOS里根本包不下這麼多東西, 於是, 廠商不得不縮水, 去掉一些不常用的微碼. 這些不常用的微碼一般都是早期的CPU, DOTHAN早期的A STEPPING就很可能沒有對應的微碼包進你的本本中去.

不打補丁會有什麼問題?

INTEL說他們沒測過不打補丁的CPU, 也就不知道會出什麼問題. 呵呵, 這顯然, 他們不想說太多技術細節而已. 以俺的經驗, 如果不打補丁, 99.99%的時候, 用戶是感覺不到的, 除非問題特別突出. 只是俺遇到過幾個明顯的例子, 爲此出了幾身汗. 有幾個案例:

1, Prescott CPU, 在臺式機上發熱量特別大, 超出Design Point, 後來發現沒加載微碼, 加上微碼就正常了;

2, Pentium D CPU, WINDOWS XP會藍屏, 以安全模式進去後, 安裝一個SP2補丁, 就正常了. 後來查出, 也是微碼沒加載;

3, Pentium M架構CPU, 在使用CPU內部TSC, 發現測出的CPU內部頻率高出實現的4, 2GHz CPU測出卻有8GHz, 後查, 也是沒加載微碼造成的異常.

此類案例很多, 特別是Core架構CPU, 不但微碼必須加載, 而且要求儘早加載, 否則, BIOS都跑不完, 系統就掛了. 但是INTEL但至今沒有任何官方對每個CPU微碼版本進行描述的文件.

怎麼檢查CPU微碼是否加載?

加載微碼後, CPUMSR(機器特定寄存器)裏可以讀出版本號. INTEL IA-32編程手冊上給出標準檢查方法:

 

MOV ECX, 008bh

XOR EAX, EAX

XOR EDX, EDX

WRMSR ;MSR 8BH0, 清除MSR中的信息

MOV EAX, 0001

CPUID ;CPUID, CPU查看微碼版本, 並把微碼版本送到MSR 8B

MOV ECX, 008bh

RDMSR ;讀出當前CPU微碼版本

執行上面的代碼後, 如果EDX的值爲0, 則說明你的CPU微碼是沒有沒加載的, 你的CPU運行在有缺陷的狀態. 如果不爲0, 則顯示的是當前微碼版本號

以上代碼可以在DOS環境下, DEBUG32調試界面執行.

----------------------------------------------------

2、來來來,動手反彙編了!!!

2.1 BIOS開始的代碼

如果您做了前兩篇的東西,那麼您會不難反彙編到這裏來,(F000_FFF0跳到F000:E05B,然後再一個near jmp到了F000:E1B0)也就是下面這段代碼。這段代碼也就是Award BIOS最開始的代碼部分了。

之前我們有研究過,當CPU 收到reset信號後它內部會做一系列的動作,而且當第一次從FFFF_FFF0H處取指令執行的時候,還會在對應的寄存器中保存一些相關的信息。在

http://blog.csdn.net/lightseed/archive/2009/10/27/4735101.aspx

中的圖1您可以看到DX裏面究竟存了什麼值。(其實就是CPUtype。)

在加註的時候,其實我個人更喜歡用英語註釋哈。但是在之前有人說想要我用中文註釋,想了又想,其實真的沒有必要。如果連這點英語都看不懂,那麼我想看datasheet也估計很困難。所以最後還是確定用English來註釋。註解有誤的話,還往各位諒解並指正,我會盡快修正。

_F000:E1B0

_F000:E1B0 loc_FE1B0:              ; CODE XREF:  _F000:E05BJ

_F000:E1B0       mov    gs, dx     ; Save CPU type to GS

_F000:E1B2       cli               ; Close interrupt

_F000:E1B3       cld

_F000:E1B4       mov    ax, cs

_F000:E1B6       mov    ss, ax     ; CS and SS use the same segment, that can use ROM_CALL

_F000:E1B8       mov    sp, 0E1BEh               ; First Use ROM_CALL

_F000:E1BB       jmp    BT_CPU_Init               ; Save esp (Return    Address)

這段代碼也就是BIOS開始兩個JMP後的代碼,應該說比較好理解。在E1B8這裏BIOS第一次用了上一節中提到的ROM_CALL這個宏。也遇到了第一個函數。BT_CPU_Init其實是在CPU開始跑code的最開始就針對特殊的CPUpatch。那麼我就來詳細和大家說說這個函數。

2.2 CPU micro code update

關於這個函數,原本我是有反彙編的源代碼的,代碼不復存在,但是原理卻能夠說清楚。(下面的說明,基本上就是這個函數所作的所有動作。反彙編出來的地址,其實我們可以暫且跳過,看原理就好。)

上面micro code update的全部函數。一些簡單的動作,我也在code中註釋了。我着重拎一些不太好懂的說說。

_F000:0036在這行中,主要是先對比一下CPU是否爲Cedar Mill B1,如果不是那麼這個函數就不用跑了。Patch當然也就不用做了。(如果你照着我之前做的動作,那麼這個行數應該是能對的上的,但是就算對不上也沒有關係。只看我的算法講解就可以了。)至於code的細節嘛,那你就自己慢慢體會吧。

_F000:0049在這行中,有一個對比的指令,其實很明顯可以猜到這就是CPU micro code的標誌。

_F000:0049       cmp    dword ptr [esi], '1SB*' ; Compare if it is CPU micro code?

讓我們用ultraedit打開之前說的那個BIOSBIN來看看,如圖1

1

從圖1中可以看出,“*BS1”是處於bin文件中的6000段的,也就是BIOS在實際跑中的E000段。所以和代碼中的段剛好符合。如果把整個E000段都找完了還是找不到的話,那麼就說明沒有這個部分的micro code,直接就return了。

_F000:005B這行是爲了得到CPU micro codebase address。這個地址是CBROM填入了,我們可以不用care它。只需要知道從這裏可以得到CPU micro code就好了。見圖2 bin文件中實際的micro code位置FFFE_57E0H

 

2

緊接着,我們可以從對應的地址處看到實際的CPU micro code。如圖3

 

3

而牽涉到CPUmicro code那麼就不得不提它的結構。從micro code的第0個字節算起,會有如下一個表。

CPU micro code開始幾個flag

HeaderVersion

;offset 00h

UpdateRevision

;offset 04h

UpdateData

;offset 08h

ProcessorVersion

;offset 0ch

Checksum

;offset 10h

LoaderRevision

;offset 14h

Platform_ID

;offset 18h

DataSize

;offset 1ch

TotalSize

;offset 20h

Reserved

;offset 24h

Update_Data

;offset 30h

有了這幾個說明,我想從Update_Micro_code_Start:開始的那些EBX+XX之類的比較就應該沒有什麼問題了哦。看看圖3中,我還給大家標了一些標誌出來。您可以追追看。

_F000:0080_F000:0086兩行操作的是MSR寄存器17H。它的說明在3 B裏面有說,以下是截圖。

_F000:0080       mov    ecx,    17h

_F000:0086       rdmsr

 

4

_F000:00A2這行主要是初始化MSR79H。關於它的說明也是在3B裏面見圖5所示。

_F000:009B       mov    eax,    ebx

_F000:009E       add    eax,    30h ; '0'

_F000:00A2       mov    ecx,    79h ; 'y'         ; MSR register to update micro code

_F000:00A8       xor    edx,    edx

_F000:00AB       wrmsr

 

5

經過那麼多的判斷後,最終只確定了一件事,那就是目前的CPU確實是應該update以下它的micro code了,於是在_F000:00AB        wrmsr命令執行後,CPU開始升級它的micro code

至此關於CPUBootblock的時候升級micro code的動作就做完了。其實在後面POST的時候,也會有這樣的動作,但是原理都是一樣的。(稍微有些些差別)我們理解原理就好啦。呵呵。。。希望大家喜歡。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章