分类:
2010-09-26 22:38:29
存放BIOS的設備從早期都放在EEPROM到現在的Flash ROM,一路上的演變已經可以寫成一部BIOS歷史課本。
在早期的
BIOS中,BIOS本身程式碼就是用來當成一個Boot
Loader,但是由於後來的晶片功能越來越強大且BIOS除了初始化硬體設備之外還要協助OS去支援一些功能,所以整個BIOS程式碼就已經變成了一個
龐然大物,而維護整個BIOS程式碼也非一個人的能力所及。
因此後來的BIOS程式碼都是由一些BIOS供應商來負責維護,各家BIOS供應商會有自己的撰寫方式與架構。正因為如此,開發BIOS的程式碼目前也都是使用各家廠商所提供的開發環境來建構。
而
這篇文章的目的在於如何在目前的PC架構下純手工打造一個屬於自己的BIOS環境以及撰寫一個簡單的BIOS程式碼可以讓系統輸出一個值到Port
80h,我同事問我為什麼不寫一個mini
BIOS可以開到DOS下去,因為如同我上述所說,寫是可以寫啦,要花很多的精力跟體力,這邊只是拋磚引玉說一個大概,然後描述一下如果自己真的要撰寫一
個BIOS 要如何做? 或許有些人有興趣可以找幾個朋友一起寫BIOS,或許哪一天就可以開ㄧ家台灣BIOS供應商...(呵呵,我自己在幻想啦!)
需要用到的工具以及相關知識:
1.MASM 6.15
2.Turbo C++ 3.0
3.基本組合語言撰寫能力
4.基本C語言撰寫能力
5.IA32 Spec vol 1~3
6.EC BIOS ROM(可以請EC BIOS Eng協助)
實驗目的與方法:
1. 建立一個BIOS 開發環境
2. 建立一個1MB BIOS ROM file
3. 利用組合語言撰寫一個64kb 大小的BIOS程式碼的 binary file
4. 利用C語言撰寫一個Build Tools,並將EC與64k BIOS塞進去1MB BIOS ROM
5.利用燒入器將1MB BIOS ROM燒入到MLB中,並且上電後檢查Port 80h是否有正確的輸出我們程式碼中撰寫的值。
上面的程式撰寫部分不需要很強的能力,只要基本的C或是組合語言語法就可以了,所以算是基本入門,重點還是在我ㄧ直強調的地方 "懂架構才是重點,程式語言只是工具而已"...。
電腦發展至今已經經過了很長的時間,許多遇到的問題也都被ㄧ些前輩解決了,因此目前學校或是市面上的書籍幾乎都是講解如何在一個"現成且成熟"的平台上發展。
例
如很多書會教你寫VC/.net/Java
,但是,說到如何去寫編譯器、作業系統及開發BIOS的書就不多了,也因此大家比較專注於如何在成熟的平台上能夠快速/有效率/有系統性的開發以及提出解
決問題的辦法,而像我因為興趣而去探討BIOS的本質的人就應該比較少吧,畢竟這些問題在之前的前輩都已經遭遇過,也提出了很好的解決方式,所以才會有目
前一些實力堅強的BIOS 供應商的存在,因此也沒必要像我這樣純手工打造。
在前ㄧ篇的文章中我已經大致上描述了一下我的實驗方式,這邊就針對整個流程作ㄧ些詳細的介紹。
在純手工打造你自己的x86 BIOS(1) 中有提到,你可以學習到的東西是比較基本的概念,所以我並不會把完整的Sample code貼上來,畢竟教釣魚比給魚吃還重要,因此請大家輕鬆看待我的拙作(小弟也只入行1年多 ,還請前輩還多多指導)。
前一篇文章中所提到的核心部份在於我撰寫了64K 的BIOS程式碼 (MyBIOS.asm),實際不到64k ,只是我利用了填00h的方式填滿到64k。
而
組譯與連結是透過ML.EXE ,輸出的是一個MyBIOS.exe ,而這個是一個DOS下的執行檔,所以裡面有MZ Header
,因為被多加了這個Header 因此MyBIOS.exe約65k ,而我會再利用Build tools取出裡面的64k
,然後變成MyBios.bin,當然這只是最簡單的方法而已,但不是唯一。
[註] EXE2BIN 只能轉換小於64k 的檔案,所以這邊不能使用它,所以我才自己轉換。
當取出了MyBios.bin 之後連同EC.bin 經由Build.exe 產生一個1MB 大小的BIOS ROM Image file,然後把位置固定住。
固定位址是因為:
1.
我的範例中的Platform 上面的EC Controller是採用Share ROM方式,也就是把EC BIOS包在System
BIOS中,因此我們需要固定住位址,這樣子EC Controller 才能去System BIOS中讀取EC BIOS的程式碼並且執行。
2.由於x86 CPU讀取第一條指令是在 FFFF_FFF0h,所以我們必須要把BIOS code固定在尾端往下算的64k 範圍內,如下圖所示:
圖 中可以看到整個BIOS ROM Image file是1MB ,其中64k是EC code另外64k是BIOS code,然後擺放在1MB 檔案中的位置就如上圖所示,其餘空白的地方我都是填00h/ffh (須看BIOS ROM Spec中說明空白是00h/ffh)
總結:
●MyBios.asm 負責CPU 第一條指令以及組態CPU 模式還有設定Port 80h的輸出並且輸出一個99h 到Port 80h
●EC.bin EC的BIOS Code,由EC BIOS工程師撰寫,我只是拿來用而已
●Build.exe 會先產生一個1MB 空白的BIOS ROM Image,然後把上面兩個bin file塞到先前產生的1MB 空白BIOS ROM Image,並固定其擺放位址,而擺放時並沒有考慮任何File System的架構問題,而是直接塞。
●MyBIOS.ROM 產生出的MyBIOS.ROM就是要用來燒入到BIOS part中的檔案,也就是類似一般大家在Flash BIOS時的那個檔案。
C:\> Flash.exe /all MyBIOS.ROM
上面是一般大家使用某個Flash Utiltity 時會打的一些指令,因為工具不同所以參數也不同,不過相同的是都會有一個BIOS ROM Image file(例如MyBios.ROM)
另 外這邊有點不ㄧ樣的地方在於我沒有自己寫Flash Utility(我們BIOS裝在EC Controller下,而我又懶的看EC Spec),所以沒辦法像上面方式使用某個工具去更新 BIOS ROM,況且你們如果要實驗相同的東西,Flash Utiltiy也不能共用,所以這部份有興趣的人就自己研究一下你們公司內是怎樣撰寫這部份的工具。
而我的燒錄方式是採用EC Controller提供的燒入器,所以直接點選我的MyBios.ROM就可以燒進去BIOS Part了,而這部份也不多做說明。
由於整個實驗我才花了1.5天時間(0.5天寫Build.exe + 1天寫MyBios.asm),所以很多地方沒考慮進去,希望各位有其他意見請告訴我,謝謝!
在前面兩篇文章中的描述中其實大家就應該可以知道我的實驗環境由幾個部份所組成,所以我這邊假設 "如果我是ㄧ個BIOS Vendor",我將會如何描述我前面所說的那些部分。
在我的實驗中,整個BIOS Build Environment 我們可以得知如同下圖的架構,我在後面將分別對這些部份做ㄧ個簡單的說明。
1.Source code : 這就是我的MyBios.asm,只有一個檔案,ㄧ般我會放在某個目錄內,大家可以想一下如果擴充成7000多個檔案的時候,你會放同一個目錄嗎? 如果分類你要如何分? 如果修改,你要直接改嗎? 還是採用什麼方式去覆蓋?
2. Build Settings : 我使用的是MASM,而他在我的C:\MASM,假如你是利用makefile產生結果,那麼你就會需要設定一些工具的路徑,組譯或是編譯的程式是哪ㄧ個,參數為何...等。
3.Build Tools : 像我提到的Build.exe就是我自己寫的,用來輔助建立BIOS Image時所使用,所以當你的環境越來越大的時候,所使用的Tools可能就不只一個。
4.Build : 當上面的部分都結合在一起後,就可以產生出結果,ㄧ般我們可以利用makefile 方式把上面步驟都結合在一起,然後就可以方便的產生出結果。
5.BIOS Image : 在我的實驗中,產生的結果就是MyBIOS.ROM。
結論:
實
驗中大家可以發現,其實BIOS
vendor所提供的環境基本的本質很簡單,只是當你在實做的時候你會遇到一些問題,而你在解決這些問題的時候不知不覺整個架構就會越來越複雜,因此當我
們接觸到一個成熟的BIOS Build environment時,就會需要了解更多的東西以便我們更能夠駕馭BIOS vendor所提供的環境。
前
面這幾篇文章大致上描述出BIOS Build
Environment的基本架構,所以當你想要寫一個BIOS然後提供給別人一個環境去撰寫BIOS時,其基本本質大概就是這樣,後面的文章中我會繼續
介紹實際上MyBIOS.asm 中我們該撰寫什麼後我們才能夠在Port 80h 的7段顯示器上顯示99h。
上ㄧ篇文章我已經針對我的實驗做了敘述,這裡我就針對實際上我的程式碼撰寫的內容做一個介紹。
在
程式碼的撰寫中,其實我只有使用了簡單的C語言跟組合語言語法,重點是要讓大家知道,其實BIOS跟一般的Boot
Loader寫法沒什麼不同,只是PC上面的BIOS需要考慮的事情比一般的Boot Loader還多很多,因此程式碼 size可以大
到1MB甚至是2MB (ㄧ般Boot Loader不可能這麼大),所以我有機會玩一個這麼大的Boot Loader也真是很榮幸的啦!
廢話不多說,我就先針對我前面提到的Build.exe 內的程式碼說明;
底
下是我的Build.c 內的程式碼片段,其實我就只有使用到fopen() 、fputc()
...等基本的函數去讀寫一個檔案,所以可以很容易的把我組譯好的MyBIOS.bin 跟EC.bin
塞進去同一個檔案內,做法其實很簡單,就是像我下面做法一樣,先利用fopen()開啟檔案,然後在把你要的資料寫進去檔案,只是寫的時候你要考慮
file offset 位置的問題,因為當你燒錄到BIOS
part中的時候,CPU是會固定重FFFF_FFF0h的位址讀取第一條指令,因此你要像我前面說的一樣,把MyBios.bin放在固定的位址中。
//建立一個空白的MyBIOS.ROM , 裡面資料都是00h
void show_help(void)
{
printf("Build.exe v1.0.0 by Harrison Hsieh \n");
printf("===========================================\n");
printf("/C Init MyBIOS.ROM \n");
printf("/B [EC] [BIOS] Add Rom \n");
printf("Output : MyBios.ROM \n");
}
void InitBiosROM(char *argv[])
{
FILE *fo;
long i;
if ((fo = fopen (BiosRom, "wb")) == (FILE *) NULL)
{
exit(1);
}
for(i=0 ; i<= BIOSSIZE ; i++) //1MB
{
fputc(0x00,fo);
}
/* All done, close the file */
fclose (fo);
}
在說明完Build.c內的做法後,接著說明MyBIOS.bin 內的程式碼撰寫;
其實在MyBios.asm 中,我只有做4 件事情:
1. 設定好FFFF_FFF0h的第一條指令
2.開啟BigReal Mode (因為我要設定ICH9的RCRB內的暫存器,所以要開啟)
3.設定ICH9內的暫存器,把所有Port 80h的訊號轉送到LPC介面(我的Post card走LPC界面,所以要設定)
4.輸出99h 到Port 80h(所以LPC介面上面的Post card就會顯示99h)
底下是我的MyBIOS.asm 內的程式碼片段:
COLDBOOT:
CLI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 1. Enable big real mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
JMPREG di,Make4GBSegmentDI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 2. Set RCRB base address
;; 3. Config ICH9 Register
;; 4. Out 99h to Port 80h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
....
mov dx, 0cfch
mov eax,RCRB_BaseAddr
out dx, eax
....
and BYTE PTR es:[esi], NOT (04h) ; RCRB+xxxxh bit 2=0 Output to LPC
....
fPostCode:
mov al,099h
mov dx,80h
out dx,al
jmp fPostCode ;無窮回圈ㄧ直顯示99h
...
...
wbinvd ; ...begins here on power up
PUBLIC POWER
POWER:
JMP COLDBOOT ; first jump
DB '11/14/07',00,00,00 ; My release marker
以上就是我撰寫的程式碼內容的說明,其實沒有用到什麼特別的東西,如果說比較難的部份大概就是如何把程式碼塞到正確的位址吧。
總結:
純手工打造你自己的x86 BIOS 文章(1)~(4)
在這邊就做一個結束,在這幾篇文章中的實驗我主要是要幫助剛入門的BIOS新手去了解整個BIOS
vendor提供的BIOS環境架構以及實際上BIOS code撰寫的第一步,因為很多東西都是入門的第一步比較難。
還記得ㄧ年前我剛入行的時候,我們學長跟我說寫BIOS最簡單的方式就是自己把一個BIOS寫到能開機你大概就已經學會了,雖然我離能自己寫到開機還有一
段距離,不過在學習的過程中也學到了很多東西,因此當初會想自己純手工寫一個能讓x86 CPU執行一段BIOS
code的環境也是希望能幫助更多BIOS入門時遇到挫折的朋友 ^^Y。
相关文章:
chulia200020012010-09-27 12:45:47
用C语言开发BIOS程序的实现方法 http://www.91linux.com/html/article/program/cpp/20071215/9106.html 1 BIOS开发语言分析 1. 1 汇编语言与C语言比较 传统BIOS程序的开发一般以汇编语言作为开发工具. 它的优点是:代码精简,时间效率与空间效率高,比较适合于BIOS程序开发. 缺点是:源程序代码冗长,使用大量标号,定义与区分工作量大,容易混淆,寄存器使用容易冲突,模块化设计功能差,软件的开发周期长. C语言具备如下优点:模块化的设计语言易于实现算法,缩短软件的开发周期,提高软件的开发质量,便于维护、升级,易于实现图形化用户界面,实现仿真Windows界面操作,比较适合于系统软件的开发. 其缺点是:对于Intel架构的C编译器,如Borland C + +等,代码的运行必须有操作系统的支持,因此,很难应用于BIOS程序开发. 目前,专门用于单片机及嵌入式系统开发的C语言已经成熟,然而还没有专门用于微机系统BIOS程序开发的C语言,使得BIOS程序的开发仍停留在使用汇编语言阶段. 然而, C语言产生的