今天在測試EFI 的S3 Resume功能,看著C語言的寫法突然間把我原本在P廠商搞不清楚的問題都解決了,果然學BIOS還是從頭學會比較有感覺。
[學習紀錄]
1. ACPI Table的建立與放置的位址
2. 如何從F/E Segment 中找到ACPI Table
3. FACS中的Wake Vector 與OS、BIOS之間的互動
4. PM Register 與Sx State 的關係
將自己踏入BIOS領域中所學習到的知識做一些心得整理,像是Legacy BIOS、EFI BIOS、Windows Driver...etc. ※版權與智慧財產權聲明:保留所有法律權利。我在寫文章時如果有引用到其他人的地方我會盡量說明參考出處,如果有遺漏的地方請告訴我,我會馬上註明! 而轉貼我的文章時也請您註明出處!
星期四, 6月 21, 2007
星期二, 6月 19, 2007
星期四, 5月 31, 2007
EFI v.s #define
今天把EFI 的一些心得筆記整理的差不多了,所以開始去Trace 一些Source code,在追蹤的過程中發現了Intel 在寫EFI 的時候真的把所有的東西都模組化了,以後寫BIOS的時候可以很方便的去撰寫。
而在這些EFI Code之中,因為幾乎都是C (不是C++,但是Phoenix BIOS可以使用C++方式撰寫,不過我還沒接觸到他們的EFI,所以還不確定是否真的可以!)的語法去撰寫,所以在模組化的同時他也使用了很多巨集指令,也就是使用#define 的方式去宣告了很多不同的巨集指令,在這裡面發現了"##"這個東西,例如下面的範例:
#define MyMacro(a,b,c) {a ## b ##c}
MyMacro(A,B,C)
而##是用來連結字串的,所以展開後會變成ABC,所以在Blog 留下筆記心得的紀錄。
而在這些EFI Code之中,因為幾乎都是C (不是C++,但是Phoenix BIOS可以使用C++方式撰寫,不過我還沒接觸到他們的EFI,所以還不確定是否真的可以!)的語法去撰寫,所以在模組化的同時他也使用了很多巨集指令,也就是使用#define 的方式去宣告了很多不同的巨集指令,在這裡面發現了"##"這個東西,例如下面的範例:
#define MyMacro(a,b,c) {a ## b ##c}
MyMacro(A,B,C)
而##是用來連結字串的,所以展開後會變成ABC,所以在Blog 留下筆記心得的紀錄。
標籤:
EFI BIOS相關知識
星期二, 5月 29, 2007
EFI Protocol 觀念小筆記
C語言的宣告與定義:
1.C語言中只允許變數或函數的定義出現一次。
由於變數只有定義規則,沒有宣告規則,所以當你鍵入int a;時,代表此變數已經被定義了。我們如何宣告一個變數呢? 加上extern 變成exern int a;,告訴comipler,此變數a只是一個宣告,它的定義在別處。
2. C語言函數規則分成宣告與定義二種。當一個函數只有傳回值、名稱、傳入值, 沒有大括號{},compiler會把此種形式當成是函數宣告;如果加上了{}, 形成函數定義。所以你要宣告一個函數,只須鍵入int f(); compiler會自動把它示為函數宣告。
// EFI Protocol
------------------
EFI Protocol 可以看作是一個介面(Interface),透過這個Interface 去存取Data 或是函數,簡單說就是一個指標,指標指向的記憶體可能是Data,也可能是函數。
安裝一個 EFI Protocol 後會以 (GUID | Pointer) 的欄位格式存放在Handle DataBase中,然後就可以在其他地方利用LocateProtcol()方式去得到指標,然後使用他。
1.Data 型式的EFI Protocol
(a)宣告你的Sturcture與GUID在你的Protocol.h 與Protocol.c中
EFI_GUID gGuid=MY_GUID;
Extern gGuid;
typedef struct {
...
UINT8 Array[10];
...
} MY_PROTOCOL;
(b)在DXE Driver中使用使用MY_PROTOCOL "定義"一個變數Test
UINT16 i;
MY_PROTOCOL Test={......};
然後在呼叫InstallProtocol(&gGuid,&Test)去安裝一個Protocol到Handle Database,所以Handle Database中的Guid=gGuid,而指標Pointer=&Test。
2.Function 型式的EFI Protocol也是跟Data型式一樣作法,不同的地方在於宣告的是函數原型。
所以觀念在於如何去宣告Protocol與如何透過GUID+Pointer去做你要做的事情。
1.C語言中只允許變數或函數的定義出現一次。
由於變數只有定義規則,沒有宣告規則,所以當你鍵入int a;時,代表此變數已經被定義了。我們如何宣告一個變數呢? 加上extern 變成exern int a;,告訴comipler,此變數a只是一個宣告,它的定義在別處。
2. C語言函數規則分成宣告與定義二種。當一個函數只有傳回值、名稱、傳入值, 沒有大括號{},compiler會把此種形式當成是函數宣告;如果加上了{}, 形成函數定義。所以你要宣告一個函數,只須鍵入int f(); compiler會自動把它示為函數宣告。
// EFI Protocol
------------------
EFI Protocol 可以看作是一個介面(Interface),透過這個Interface 去存取Data 或是函數,簡單說就是一個指標,指標指向的記憶體可能是Data,也可能是函數。
安裝一個 EFI Protocol 後會以 (GUID | Pointer) 的欄位格式存放在Handle DataBase中,然後就可以在其他地方利用LocateProtcol()方式去得到指標,然後使用他。
1.Data 型式的EFI Protocol
(a)宣告你的Sturcture與GUID在你的Protocol.h 與Protocol.c中
EFI_GUID gGuid=MY_GUID;
Extern gGuid;
typedef struct {
...
UINT8 Array[10];
...
} MY_PROTOCOL;
(b)在DXE Driver中使用使用MY_PROTOCOL "定義"一個變數Test
UINT16 i;
MY_PROTOCOL Test={......};
然後在呼叫InstallProtocol(&gGuid,&Test)去安裝一個Protocol到Handle Database,所以Handle Database中的Guid=gGuid,而指標Pointer=&Test。
2.Function 型式的EFI Protocol也是跟Data型式一樣作法,不同的地方在於宣告的是函數原型。
所以觀念在於如何去宣告Protocol與如何透過GUID+Pointer去做你要做的事情。
標籤:
EFI BIOS相關知識
星期一, 5月 28, 2007
今天收到的新聞~~~
外傳廣達接獲新的iPhone訂單,廣達表示,廣達接單方向積極朝多元化產品發展,不會對單一客戶進行評論。據瞭解,開發一款手機約要六個月到九個月,隨著第一代iPhone推出,蘋果內部確實也在開發第二代iPhone,但訂單花落誰家,要視第一代產品銷售狀況才會決定。
看樣子我要去問問我那些做Apple代工的朋友們消息是否正確了....呵呵!
看樣子我要去問問我那些做Apple代工的朋友們消息是否正確了....呵呵!
星期三, 5月 09, 2007
Direct Hardware Access Under Windows 9x/NT/2000/XP/Vista
今天又多學一樣東西,就是呼叫Undocument API 去開啟I/O 存取權限,這樣子你就可以使用Ring3的應用程式直接存取硬體,例如下面的VC++範例程式中直接使用Assembly 或是IO Funcation call去存取硬體。
EX1: Read I/O Port
_asm {
pushf
mov al, ireg.h
mov dx,0x70
out dx,al
mov dx,0x71
in al, dx
mov mbid, al
popf
}
EX2: Read CMOS
_outp(0x70,ireg.h );
mbid=_inp(0x71);
使用的技巧是先進入Ring0 (也就是掛一個Driver),然後在DriverEntry 時去呼叫API去改變IO權限。
void Ke386SetIoAccessMap(int, IOPM *);
void Ke386QueryIoAccessMap(int, IOPM *);
void Ke386IoSetAccessProcess(PEPROCESS, int);
開剛始是利用修改TSS的來開啟IO存取權限方式,不過改完後DEBUG.COM會無法執行,所以才改成呼叫上面的API的方式,而直接修改TSS方式如下所示:
__asm {
cli // 遮罩中斷
sgdt gdtr // 得到 GDT 基底位址與段界限
str TSSseg // 得到 TSS 選擇子
movzx esi,TSSseg // 擴展到 ESI 中以便計算
add esi,gdtr.dwBase // 得到 TSS 在 GDT 中描述符
mov gdt,esi
}
不管是API還是修改TSS,都是在DriverEntery進去後去執行的。
因此實作部份分成三部份:
1.WDM Driver code(DriverEntery 的地方呼叫API)
2.InstallDriver code(應用程式執行時去動態載入驅動程式)
3.應用程式Application code(直接使用Assembly或是IO Function)
EX1: Read I/O Port
_asm {
pushf
mov al, ireg.h
mov dx,0x70
out dx,al
mov dx,0x71
in al, dx
mov mbid, al
popf
}
EX2: Read CMOS
_outp(0x70,ireg.h );
mbid=_inp(0x71);
使用的技巧是先進入Ring0 (也就是掛一個Driver),然後在DriverEntry 時去呼叫API去改變IO權限。
void Ke386SetIoAccessMap(int, IOPM *);
void Ke386QueryIoAccessMap(int, IOPM *);
void Ke386IoSetAccessProcess(PEPROCESS, int);
開剛始是利用修改TSS的來開啟IO存取權限方式,不過改完後DEBUG.COM會無法執行,所以才改成呼叫上面的API的方式,而直接修改TSS方式如下所示:
__asm {
cli // 遮罩中斷
sgdt gdtr // 得到 GDT 基底位址與段界限
str TSSseg // 得到 TSS 選擇子
movzx esi,TSSseg // 擴展到 ESI 中以便計算
add esi,gdtr.dwBase // 得到 TSS 在 GDT 中描述符
mov gdt,esi
}
不管是API還是修改TSS,都是在DriverEntery進去後去執行的。
因此實作部份分成三部份:
1.WDM Driver code(DriverEntery 的地方呼叫API)
2.InstallDriver code(應用程式執行時去動態載入驅動程式)
3.應用程式Application code(直接使用Assembly或是IO Function)
標籤:
Windows 程式相關
星期二, 5月 08, 2007
Windows 下的I/O存取
昨天我們Leader 請我幫忙寫一個Tools給對岸同胞的生產線使用,他們需要在Vista 底下去存取Panel ID.
所以自己留下個撰寫紀錄,讓自己下次修改自己的Source Code的時候有個依據。
目前Panel ID我們是使用跳線的方式去改變GPIO值來做辨別,所以只要去存取GPIO就可以了。
1.南橋ICH8會把GPIO 值 mapped 到某個IO Range...所以只要利用組合語言的IN/OUT 去存取他映對過去的IO 位址就可以知道GPIO的值。
2.查看主機板電路圖,看實際上被當成選擇Panel ID的GPIO是哪幾支接腳。
3.開發一個DOS版的Tools直接使用IN/OUT指令去存取,例如下面範例:
byte ReadGpioStatus(word OEM_GPIO_ADDR)
{
byte mbid;
...
_asm {
mov dx, OEM_GPIO_ADDR
in ax, dx
mov mbid, al
}
...
return mbid;
}
4.開發一個Windows 版的Tools也是使用IN/OUT指令,不過是由自己撰寫的I/O Driver所提供
byte ReadGpioStatus(word OEM_GPIO_ADDR)
{
byte mbid;
mbid=IN_B(OEM_GPIO_ADDR); //IN_B 會去呼叫Windows API然後送IRP給我自己寫的Driver
return mbid;
}
5.在Source code內做一個介面IN_B() 然後呼叫API去使用自己寫的I/O Driver所提供的服務
byte IN_B (WORD port)
{
ireg.x.DX = port;
...
bRc = DeviceIoControl (...); //送IRP給我自己寫的I/O Driver...
...
return (ireg.h.AL);
}
6.整個Windows版本的Source code架構與DOS版本差異不大,只是Windows版本需要去動態載入驅動程式,而這部分寫在if (!InitializeWinIo()) return 1 ;
上述這幾個部份是比較重要的地方,而整個DOS版與Windows版的程式架構如下:
int main(int argc,char *argv[])
{
modelString[]={
"000"," Reserved. ",
"001"," Vendor1. ",
"002"," Vendor2. ",
....
}
...
if (!InitializeWinIo()) return 1 ; // For Windows version only.
...
pStatus1=ReadGpioStatus(OEM_GPIO_DEFAULT_IO1); // Read Gpio
pStatus2=ReadGpioStatus(OEM_GPIO_DEFAULT_IO2);
...
panelid=(GetBit(pStatus1,2)<<2)+(GetBit(pStatus1,6)<<1)+GetBit(pStatus2,6);
...
if (strcmp(argv[2], modelString[panelid*2]))
{
...// if match...return passed!
}
return 0;
}
從上面範例可以知道其實DOS版與Windows版的Source code 寫法幾乎一樣,只是Windows版因為無法直接存取I/O,所以我自己多加了一個I/O Driver,然後做了兩個Function (IN_B()跟InitializeWinIo())來載入與使用這個Driver 。
所以自己留下個撰寫紀錄,讓自己下次修改自己的Source Code的時候有個依據。
目前Panel ID我們是使用跳線的方式去改變GPIO值來做辨別,所以只要去存取GPIO就可以了。
1.南橋ICH8會把GPIO 值 mapped 到某個IO Range...所以只要利用組合語言的IN/OUT 去存取他映對過去的IO 位址就可以知道GPIO的值。
2.查看主機板電路圖,看實際上被當成選擇Panel ID的GPIO是哪幾支接腳。
3.開發一個DOS版的Tools直接使用IN/OUT指令去存取,例如下面範例:
byte ReadGpioStatus(word OEM_GPIO_ADDR)
{
byte mbid;
...
_asm {
mov dx, OEM_GPIO_ADDR
in ax, dx
mov mbid, al
}
...
return mbid;
}
4.開發一個Windows 版的Tools也是使用IN/OUT指令,不過是由自己撰寫的I/O Driver所提供
byte ReadGpioStatus(word OEM_GPIO_ADDR)
{
byte mbid;
mbid=IN_B(OEM_GPIO_ADDR); //IN_B 會去呼叫Windows API然後送IRP給我自己寫的Driver
return mbid;
}
5.在Source code內做一個介面IN_B() 然後呼叫API去使用自己寫的I/O Driver所提供的服務
byte IN_B (WORD port)
{
ireg.x.DX = port;
...
bRc = DeviceIoControl (...); //送IRP給我自己寫的I/O Driver...
...
return (ireg.h.AL);
}
6.整個Windows版本的Source code架構與DOS版本差異不大,只是Windows版本需要去動態載入驅動程式,而這部分寫在if (!InitializeWinIo()) return 1 ;
上述這幾個部份是比較重要的地方,而整個DOS版與Windows版的程式架構如下:
int main(int argc,char *argv[])
{
modelString[]={
"000"," Reserved. ",
"001"," Vendor1. ",
"002"," Vendor2. ",
....
}
...
if (!InitializeWinIo()) return 1 ; // For Windows version only.
...
pStatus1=ReadGpioStatus(OEM_GPIO_DEFAULT_IO1); // Read Gpio
pStatus2=ReadGpioStatus(OEM_GPIO_DEFAULT_IO2);
...
panelid=(GetBit(pStatus1,2)<<2)+(GetBit(pStatus1,6)<<1)+GetBit(pStatus2,6);
...
if (strcmp(argv[2], modelString[panelid*2]))
{
...// if match...return passed!
}
return 0;
}
從上面範例可以知道其實DOS版與Windows版的Source code 寫法幾乎一樣,只是Windows版因為無法直接存取I/O,所以我自己多加了一個I/O Driver,然後做了兩個Function (IN_B()跟InitializeWinIo())來載入與使用這個Driver 。
標籤:
Windows 程式相關
星期一, 5月 07, 2007
SEGMENT與Public/Extern 用法
在BIOS Source code之中常常會看到一大堆的Segment,而有時候相同的Segment內去使用同一個Segment內的程序時,會在Segment 內去把他Extern進來,如下範例所示:
Test1.asm
AAA SEGMENT <--AAA Segment 裡面有一個BBB程序被共用(Public)
....
BBB PROC NEAR PUBLIC
...
BBB ENDP
....
AAA ENDS
Test2.asm內容如下
AAA SEGMENT <--AAA Segment內有一個CCC程序要去呼叫BBB程序,但是要在AAA Segment把BBB程式用Extern方式拉進來
EXTERN BBB:NEAR
....
CCC PROC
...
CALL BBB
...
CCC ENDP
AAA ENDS
Public 是把程序共用,而Extern 可看作要使用一個共用的程序
一般來說如果BBB程序與CCC程序都在同一個檔案內,那麼CCC程序可以直接呼叫BBB程序而不需要Extern
而不同"檔案"時就要這樣做,如上面範例是Test1.asm 跟Test2.asm
Test1.asm
AAA SEGMENT <--AAA Segment 裡面有一個BBB程序被共用(Public)
....
BBB PROC NEAR PUBLIC
...
BBB ENDP
....
AAA ENDS
Test2.asm內容如下
AAA SEGMENT <--AAA Segment內有一個CCC程序要去呼叫BBB程序,但是要在AAA Segment把BBB程式用Extern方式拉進來
EXTERN BBB:NEAR
....
CCC PROC
...
CALL BBB
...
CCC ENDP
AAA ENDS
Public 是把程序共用,而Extern 可看作要使用一個共用的程序
一般來說如果BBB程序與CCC程序都在同一個檔案內,那麼CCC程序可以直接呼叫BBB程序而不需要Extern
而不同"檔案"時就要這樣做,如上面範例是Test1.asm 跟Test2.asm
標籤:
組合語言Assembly
Strong/Weak 語法與"::"標籤表示法
組合語言中的Strong/Weak 語法簡單說就是如果A存在就跳躍過去A執行,如果A不存在就跳到B去執行
假如我有一段程式如下面所示:
PUBLIC BBB&Return
EXTERN AAA(BBB&Return):NEAR <--Strong/weak寫法
Test1 Proc
...
Jmp AAA
...
BBB&Return:: <--如果AAA不存在會跳到這邊執行
ret
Test1 EndP
AAA Proc <--如果AAA存在會跳到這邊執行
...
ret
AAA EndP
除了上面的Strong/Weak之外,還可以看到標籤是BBB&Return:: 而"::"代表的意思有兩種:
1.PUBLIC 出來的標籤,要把它標示成"::",簡單說就是不同程序間也可以跳躍
2."::"不同程序間的跳躍,如下面範例所示:
[註]功能還是跟 ":"一樣,只是表示方式不同而已。
Public Label2
Test1 proc near
Label1:
Label2::
ret
Test1 endp
Test2 proc near
jmp Label1 ; compiler 會錯誤, 因為該 label 找不到
jmp Label2 ; 正確, 該 label2 是可以找到的,因為有把他Public
ret
Test2 endp
假如我有一段程式如下面所示:
PUBLIC BBB&Return
EXTERN AAA(BBB&Return):NEAR <--Strong/weak寫法
Test1 Proc
...
Jmp AAA
...
BBB&Return:: <--如果AAA不存在會跳到這邊執行
ret
Test1 EndP
AAA Proc <--如果AAA存在會跳到這邊執行
...
ret
AAA EndP
除了上面的Strong/Weak之外,還可以看到標籤是BBB&Return:: 而"::"代表的意思有兩種:
1.PUBLIC 出來的標籤,要把它標示成"::",簡單說就是不同程序間也可以跳躍
2."::"不同程序間的跳躍,如下面範例所示:
[註]功能還是跟 ":"一樣,只是表示方式不同而已。
Public Label2
Test1 proc near
Label1:
Label2::
ret
Test1 endp
Test2 proc near
jmp Label1 ; compiler 會錯誤, 因為該 label 找不到
jmp Label2 ; 正確, 該 label2 是可以找到的,因為有把他Public
ret
Test2 endp
標籤:
組合語言Assembly
星期日, 5月 06, 2007
BIOS Code Entry point
前一篇說明了CPU如何去讀取第一條存在於BIOS ROM裡面的程式碼,現在就說明一下實際上BIOS Code是怎樣跑的。
這邊要重新說明一下觀念:
FFFF_FFF0 是第一條指令所存放的地方,而他是在4G頂端的地方,CPU在被重置(Reset)之後會去這邊讀取指令,而對CPU來說並不會在意Address FFFF_FFF0 是給BIOS ROM使用還是記憶體DRAM使用,而80386之後,這個位址是都給BIOS ROM使用。
000F_FFF0 (或表示成F000:FFF0),這個位址是在1M 頂端的地方,而這個位址是給BIOS ROM還是DRAM?
給誰使用則是去設定北橋,一般來說在POST 前(Power On-->BootBlock),這個地方應該是給BIOS ROM使用,而POST中途會去做Shadow動作,這個動作做完後,這個位址會給DRAM使用。
以前8088/8086 在1M頂端是給BIOS ROM使用,後來才變成BIOS ROM/DRAM 混用,所以以前CPU被重置的時候是去F_FFF0(F000:FFF0)讀取第一條指令,後來的CPU就不這樣做了。
上面觀念說明完之後我們就實際追蹤一下BIOS code的流程;在進入到OS之後,如果你去看000F_FFF0的資料,其實是看到DRAM裡面的資料,而這個資料是BIOS放進去的;而進入OS之前,這個位址的資料因為預設是給BIOS ROM使用,所以會跟FFFF_FFF0看到的資料一模一樣。
下面是實際上我們去追蹤P廠商BIOS code的範例:
1.我們先利用一些工具去在OS中去存取4G頂端的位址FFFF_FFF0 看到的資料如下所示:
FFFF_FFF0 E9 55 B2 ........... -->實際在BIOS ROM裡面的資料,因為這個位址是給BIOS ROM使用
上面看到的E9 55 B2 就是CPU讀取的第一條指令,而這個指令是一個Jmp 指令,他會跳到BootBlock Entry Point去執行,執行完畢後才會跳到POST Entry point.
2.下面也是在OS中利用工具去讀取1M頂端的資料,由於已經進入OS了,所以這些資料是BIOS填進去DRAM的資料(Shadow),也就是說這個000F_FFF0是被指向DRAM之中。
F000:FFF0 EA 5B E0 00 F0 ..... -->跳到F000:E05B
F000:E05B E9 FB A8 ........... -->跳到實際的POST Entry point....
A8FB+E05E=8959 (進位1 去掉)
F000:8959 FA ................. -->FA=CLI
這邊可以看到為了相容性問題,所以000F_FFF0是放著Jmp F000:E05B 位址,而這個位址裡面會放著POST Entry point指標(E9 FB A8),所以繼續追蹤過去後可以發現POST的第一條指令是CLI...
3.其實CPU第一條指令E9 55 B2 會跳到BootBlock去執行;而執行完畢後,BootBlock也會跳到跟F000:8959內一樣的BIOS code去執行所謂的POST。
所以簡單的描述上面所說的流程:
1.CPU去FFFF_FFF0 提取第一條指令執行(Jmp BootBlock)
2.執行BootBlock
3.執行完bootBlock後,跳到POST
4.執行POST (POST第一條指令一定是CLI)
5.POST過程中Shadow ,Shadow後000F_FFF0的資料就是Jmp F000:E05B
這樣子說應該很容易瞭解了吧! ^^Y
這邊要重新說明一下觀念:
FFFF_FFF0 是第一條指令所存放的地方,而他是在4G頂端的地方,CPU在被重置(Reset)之後會去這邊讀取指令,而對CPU來說並不會在意Address FFFF_FFF0 是給BIOS ROM使用還是記憶體DRAM使用,而80386之後,這個位址是都給BIOS ROM使用。
000F_FFF0 (或表示成F000:FFF0),這個位址是在1M 頂端的地方,而這個位址是給BIOS ROM還是DRAM?
給誰使用則是去設定北橋,一般來說在POST 前(Power On-->BootBlock),這個地方應該是給BIOS ROM使用,而POST中途會去做Shadow動作,這個動作做完後,這個位址會給DRAM使用。
以前8088/8086 在1M頂端是給BIOS ROM使用,後來才變成BIOS ROM/DRAM 混用,所以以前CPU被重置的時候是去F_FFF0(F000:FFF0)讀取第一條指令,後來的CPU就不這樣做了。
上面觀念說明完之後我們就實際追蹤一下BIOS code的流程;在進入到OS之後,如果你去看000F_FFF0的資料,其實是看到DRAM裡面的資料,而這個資料是BIOS放進去的;而進入OS之前,這個位址的資料因為預設是給BIOS ROM使用,所以會跟FFFF_FFF0看到的資料一模一樣。
下面是實際上我們去追蹤P廠商BIOS code的範例:
1.我們先利用一些工具去在OS中去存取4G頂端的位址FFFF_FFF0 看到的資料如下所示:
FFFF_FFF0 E9 55 B2 ........... -->實際在BIOS ROM裡面的資料,因為這個位址是給BIOS ROM使用
上面看到的E9 55 B2 就是CPU讀取的第一條指令,而這個指令是一個Jmp 指令,他會跳到BootBlock Entry Point去執行,執行完畢後才會跳到POST Entry point.
2.下面也是在OS中利用工具去讀取1M頂端的資料,由於已經進入OS了,所以這些資料是BIOS填進去DRAM的資料(Shadow),也就是說這個000F_FFF0是被指向DRAM之中。
F000:FFF0 EA 5B E0 00 F0 ..... -->跳到F000:E05B
F000:E05B E9 FB A8 ........... -->跳到實際的POST Entry point....
A8FB+E05E=8959 (進位1 去掉)
F000:8959 FA ................. -->FA=CLI
這邊可以看到為了相容性問題,所以000F_FFF0是放著Jmp F000:E05B 位址,而這個位址裡面會放著POST Entry point指標(E9 FB A8),所以繼續追蹤過去後可以發現POST的第一條指令是CLI...
3.其實CPU第一條指令E9 55 B2 會跳到BootBlock去執行;而執行完畢後,BootBlock也會跳到跟F000:8959內一樣的BIOS code去執行所謂的POST。
所以簡單的描述上面所說的流程:
1.CPU去FFFF_FFF0 提取第一條指令執行(Jmp BootBlock)
2.執行BootBlock
3.執行完bootBlock後,跳到POST
4.執行POST (POST第一條指令一定是CLI)
5.POST過程中Shadow ,Shadow後000F_FFF0的資料就是Jmp F000:E05B
這樣子說應該很容易瞭解了吧! ^^Y
標籤:
IA32 相關基礎知識
星期日, 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...等工具查看。
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...等工具查看。
標籤:
IA32 相關基礎知識
星期五, 4月 27, 2007
Extensible Firmware Interface ,EFI 簡介
Extensible Firmware Interface ,EFI 簡介 by Harrison
Extensible Firmware Interface (EFI) 是一個規範,他規範了一個介面,界於作業系統(例如: Windows)與平台韌體(Platform firmware)之間的一個橋樑。 EFI的改進被用來取代傳統BIOS的介面(這個傳統的介面被稱之為IBM PC compatible PC 的BIOS或稱之為Legacy BIOS).
最初EFI是由Intel 所主導發展,目前則由UEFI論壇(Unified EFI Forum) 的會員一起共同維護,這便是眾所皆知的UEFI (Unified EFI,統一的EFI).
發展歷史 History
最初EFI發展動機是為了在1990年中的Intel-HP Itanium 系統,當時的PC BIOS有一個限制(支援16 bit 的處理器模式,1MB 位址空間與AT 硬體架構),而這個限制使的他無法支援大型伺服器平台的系統Intel-HP Itanium。 最初的時候Intel 只是為了解決這些BIOS啟動時的限制,後來就乾脆改變它的名稱,且稱之為EFI。
EFI specification 1.02 在2000年12月的時候由Intel發行 (Version 1.01 則是Intel 最初發行的版本,但是它裡面有一些錯誤存在。)
EFI specification 1.10 在2002年12月1日發行,他包含了 EFI driver model 增強版。
到了 2005年, Intel 將這個版本貢獻給 UEFI Forum來幫助大家討論,藉以提升EFI開發環境以及提升他的功能。 所以將EFI改稱為 Unified EFI (UEFI)來代表這個改變。
而UEFI Forum 目前2007年1月7日的最新版本是UEFI specification version 2.1 。它增加了cryptography,network authentication, IPv6 support和User Interface 架構(簡稱 UEFI使用者介面,或稱HII)。
EFI specification 所定義的介面中包含platform information的Data tables還有啟動服務(Boot Services)與Runtime services (例如如何去啟動OS loader 或是啟動 ㄧ個EFI-aware OS)。
另外像是原本就存在於PC BIOS中的其他類型的增強型BIOS(像是SMBIOS或是ACPI )也都可以存在於EFI之中,因為他們並沒有使用16-bit runtime interface去服務他們。
Services
EFI 定義了啟動服務( boot services),這些服務包含了文字與圖形支援,這些支援可以針對不同的設備(device),匯流排(bus),檔案服務(file services),Block…等, 還有一些runtime services 就像是date, time 和 NVRAM services.
Device drivers
EFI針對標準設備驅動程式的增加部份,它提供了處理器-非依賴的設備驅動程式環境(Processor-independent device driver environment) 稱之為EFI Byte Code 或 EBC。依照UEFI 規範中的系統需求中提到,系統需要裝設一個翻譯器(interpreter)來提供EBC Image 的裝載(resides in)或是載入(Loaded into)進去這個環境。
因此,EBC會類似被模擬成Open Firmware的樣子。而這個Open Firmware(他是一個硬體-非依賴韌體,Hardware-independent firmware)是就像是使用在 PowerPC-架構的 Apple Macintosh 電腦或是 Sun Microsystems SPARC 電腦,或是其他也在使用Open Firmware的電腦。
一些非EBC(non-EBC architecture EFI device drivers types)架構的EFI 設備驅動程式型態則有一個介面來支援OS對他們的使用。
這些介面可以允許OS去依賴EFI所提供的一些基本設備驅動程式(像是圖形驅動程式,網路驅動程式的支援)來初始化一些設備,直到OS所需的驅動程式全被載入為止。
Boot Manager
EFI boot manager 也被使用來選擇和載入一個作業系統(Operating system),移除則需要決定一個Boot Loader的管理機制 (Boot Loader變成EFI 應用程式的類型),在Framework架構中是屬於Boot Device Select,BDS階段。
Disk Support
除了標準PC磁碟分割(Disk partition scheme)架構Master boot record (MBR)之外, EFI 還增加了一個新的支援 GUID Partition Table (GPT), 而這個新的支援則不受到標準MBR的侷限。 在EFI specification 並沒有描述你要使用哪一種的file system; 而典型的EFI在實作上則內定支援使用 FAT32 的檔案系統。
The EFI Shell
EFI 社群(community)建立了一個開放式源碼(Open Source)與介殼程式環境(Shell environment),是使用者與作業系統溝通的程式,負責解譯及執行使用者下達給作業系統的指令。
所以EFI Shell並不是直接的啟動進入到OS,因此在某些情況之下,使用者可以進入到EFI shell。而這個shell是一個EFI application,它可以直接存在於platform ROM(直接燒入在裡面),或是在有驅動程式的ROM的設備上面(透過驅動程式來載入EFI Shell)。
像在MacBook (Apple 的Intel CPU架構的筆記型電腦),你可以把EFI shell 應用程式放在USB隨身碟,而在開機的時候按著"Option",然後就會看到一個選擇開機項目的畫面,選擇你的USB隨身碟,那麼就可以看到一個長的很像DOS的畫面,而這個畫面就是EFI Shell。
而這個Shell可以被使用來執行一個EFI 的應用程式,像是 setup, OS install, diagnostic(診斷分析程式)或是Configuration utilities和System flash updates…等,他也能直接的播放CDs 或是DVDs 而不需要進入到一個完整的OS環境底下,它提供了一個適當的環境來開發EFI應用程式。另外Shell commands也可能可以用來複製,搬移檔案或是目錄(如果你的Shell 有支援),而設備驅動程式也可以利用他去載入或是卸載,而一個完整的TCP/IP 堆疊(TCP/IP 7層架構)也可以使用EFI Shell被完整的使用。
簡單說就是EFI Shell提供了一個不需要進入OS環境也可以處理你需要的工作的一個環境。最後EFI shell支援腳本,而他的副檔名是 .nsh files,他就像是DOS下的批次檔( batch files)。
Shell Command的指令名稱繼承了DOS command interpreter 或是 Unix shell(操作起來像是混合體,有時出現DOS指令的名稱,有時是Unix的名稱) ,而EFI Shell其實就是可以看作成在BIOS裡面的一個DOS環境。
Extensions
EFI延伸功能之中所描述,EFI可以從任何虛擬的非揮發性儲存設備載入並且連接到電腦之中,例如一個original equipment manufacturer (OEM) 廠商在賣系統的時候將EFI 分割區放硬碟中,而要將這些功能載入的程式則放在主機板上的ROM之中,簡單說就是BIOS ROM裡面的程式可以去硬碟把EFI 功能載入出來執行,例如一些測試程式放在硬碟,然後EFI開機的時候去硬碟讀取這些程式出來執行。
Intel Platform Innovation Framework for EFI
Intel 在其平台上為了EFI去建立了一個新框架(Framework),而這個框架的最初代號叫做Tiano,這個框架非常的完整,它包含了EFI對原本傳統韌體的所有支援,他也可以透過所謂的compatibility support module(CSM)來支援傳統的PC BIOS,簡單說就是傳統BIOS能做的EFI也能做,但是不是完整支援就要看CSM支援的程度。
特別是,這個框架包含了在Power-On後,所有必要的初始化步驟去初始化一個平台(Platform);但是這些步驟的運作並沒有被定義在EFI specification內,而是被定義在 Platform Initialization Specification內的某個章節。
Intel 並沒有將這個架構完整的開放給一般的End-User知道,他只有開放這些資訊給一些獨立的BIOS 廠商(稱之為IBV),像是安邁 (American Megatrends ,AMI) 或是系微(Insyde Software) …等的BIOS韌體供應商。
而在TianoCore project(也就是所謂的EFI Developer Kit ,EDK)的Open source之中,會提到如何去開發這個Framework。這個開發工具中含括了EFI的一些硬體初始化的程式碼(只針對一些硬體,但並不包含韌體本身) ,至於這些程式碼的授權包含BSD license 和 Eclipse Public License…等。
而Tiano是為了取代BIOS的一種框架,所以透過EFI可以讓PC的設備自己撰寫一個驅動程式來管理這個設備。而對於開放原始碼來說,這也代表大家可以從TianoCore.org 下載這個專案,然後以BSD(Berkley Software Distribution)的授權方式來生產你的產品。BSD的授權,你自己去修改它的軟體並且發展出屬於你自己的產品,但BSD並不會去要求你把修改的地方公開出來,而這種方法會有助於你去保護你的智慧財產權。
Platforms that use EFI or the Framework
最早使用EFI 的平台式 Intel的第一個Itanium 工作站和伺服器,他們支援EFI 1.02。 接著是Hewlett-Packard的第一個 Itanium 2 系統(2002年發表),支援EFI 1.10; 而這些系統都可以啟動 Windows, Linux, FreeBSD 和HP-UX。
不管是Itanium或是 Itanium 2 系統,他們在出貨的時候都是使用EFI compliant firmware,且須遵照DIG64 specifications。
在2003的11月, Gateway 介紹他們的Gateway 610 Media Center,第一個x86 Windows-based 的電腦系統使用了這個框架(Framework),而韌體供應商則是 Insyde Software's InsydeH2O。而這個韌體依舊是依靠賴傳統BIOS相容介面的方式去實作出這個框架來啟動微軟系統,簡單說就是EFI 的框架去模擬成傳統BIOS,因為Windows並不認識EFI,所以利用EFI框架做出模組(Module)方式去符合目前x86 架構。
在2006年1月,Apple Computer 販售了屬於他們第一次使用 Intel-based的Macintosh電腦, 這個系統使用了EFI和新框架Framework來取代了原本他們在Power PC-Based 一直以來都在使用的 Open Firmware,而在 2006年4月5日, Apple 公佈了一個 Boot Camp 應用程式,這是一個非破壞性的分割工具(non-destructive partitioning tool)去幫助Apple的使用這去安裝Windows XP驅動程式甚至是系統到麥金塔的電腦之中。
而同時,Apple的韌體的也做了更新支援,讓傳統的BIOS支援去它的EFI實作。在此之後,所有的麥金塔系統(Intel-Based)也都是使用使這種韌體(Firmware)出貨。 現在所有目前的Macintosh systems 也都可以啟動傳統的作業系統Windows XP,簡單說就是WindowsXP不認識EFI,而Apple機器內如果裝了Windows XP就必須使用Legacy BIOS方式去啟動Windows XP,因此Apple更新了EFI的Firmware支援,去模擬出一個傳統的BIOS介面來支援,應該也是叫做CSM。
從2005年之後,幾乎大多數的Intel 主機板都開始出貨這種支援新的框架架構的主機板的韌體(Framework-based firmware)。現在像是一些新的mobile,,desktop和 server 產品,在2006年起,也都開始使用這種框架。
自2005起,EFI也開始被實作在非PC架構的系統上,像是嵌入式系統,像是 embedded systems based 的 XScale cores。
而EDK 還包含了NT32 的目標(Target),也就是說它允許EFI Frimware和EFI Application 去執行一個Windows 應用程式。
Security and freedom concerns
According to Ron Minnich, the lead developer for LinuxBIOS, one of the stated goals of EFI is to protect hardware vendors "intellectual property"[15]. This raises security concerns and notably makes creating a free software BIOS impossible.
EFI could be used to create a "DRM BIOS", thus letting vendors build computers which limit what the user can do.
有關於自由軟體運動v.s EFI 請參考下列網站說明:
http://taiwan.cnet.com/enterprise/technology/0,2000062852,20098242,00.htm
Reference
維基百科
CNET
Extensible Firmware Interface (EFI) 是一個規範,他規範了一個介面,界於作業系統(例如: Windows)與平台韌體(Platform firmware)之間的一個橋樑。 EFI的改進被用來取代傳統BIOS的介面(這個傳統的介面被稱之為IBM PC compatible PC 的BIOS或稱之為Legacy BIOS).
最初EFI是由Intel 所主導發展,目前則由UEFI論壇(Unified EFI Forum) 的會員一起共同維護,這便是眾所皆知的UEFI (Unified EFI,統一的EFI).
發展歷史 History
最初EFI發展動機是為了在1990年中的Intel-HP Itanium 系統,當時的PC BIOS有一個限制(支援16 bit 的處理器模式,1MB 位址空間與AT 硬體架構),而這個限制使的他無法支援大型伺服器平台的系統Intel-HP Itanium。 最初的時候Intel 只是為了解決這些BIOS啟動時的限制,後來就乾脆改變它的名稱,且稱之為EFI。
EFI specification 1.02 在2000年12月的時候由Intel發行 (Version 1.01 則是Intel 最初發行的版本,但是它裡面有一些錯誤存在。)
EFI specification 1.10 在2002年12月1日發行,他包含了 EFI driver model 增強版。
到了 2005年, Intel 將這個版本貢獻給 UEFI Forum來幫助大家討論,藉以提升EFI開發環境以及提升他的功能。 所以將EFI改稱為 Unified EFI (UEFI)來代表這個改變。
而UEFI Forum 目前2007年1月7日的最新版本是UEFI specification version 2.1 。它增加了cryptography,network authentication, IPv6 support和User Interface 架構(簡稱 UEFI使用者介面,或稱HII)。
EFI specification 所定義的介面中包含platform information的Data tables還有啟動服務(Boot Services)與Runtime services (例如如何去啟動OS loader 或是啟動 ㄧ個EFI-aware OS)。
另外像是原本就存在於PC BIOS中的其他類型的增強型BIOS(像是SMBIOS或是ACPI )也都可以存在於EFI之中,因為他們並沒有使用16-bit runtime interface去服務他們。
Services
EFI 定義了啟動服務( boot services),這些服務包含了文字與圖形支援,這些支援可以針對不同的設備(device),匯流排(bus),檔案服務(file services),Block…等, 還有一些runtime services 就像是date, time 和 NVRAM services.
Device drivers
EFI針對標準設備驅動程式的增加部份,它提供了處理器-非依賴的設備驅動程式環境(Processor-independent device driver environment) 稱之為EFI Byte Code 或 EBC。依照UEFI 規範中的系統需求中提到,系統需要裝設一個翻譯器(interpreter)來提供EBC Image 的裝載(resides in)或是載入(Loaded into)進去這個環境。
因此,EBC會類似被模擬成Open Firmware的樣子。而這個Open Firmware(他是一個硬體-非依賴韌體,Hardware-independent firmware)是就像是使用在 PowerPC-架構的 Apple Macintosh 電腦或是 Sun Microsystems SPARC 電腦,或是其他也在使用Open Firmware的電腦。
一些非EBC(non-EBC architecture EFI device drivers types)架構的EFI 設備驅動程式型態則有一個介面來支援OS對他們的使用。
這些介面可以允許OS去依賴EFI所提供的一些基本設備驅動程式(像是圖形驅動程式,網路驅動程式的支援)來初始化一些設備,直到OS所需的驅動程式全被載入為止。
Boot Manager
EFI boot manager 也被使用來選擇和載入一個作業系統(Operating system),移除則需要決定一個Boot Loader的管理機制 (Boot Loader變成EFI 應用程式的類型),在Framework架構中是屬於Boot Device Select,BDS階段。
Disk Support
除了標準PC磁碟分割(Disk partition scheme)架構Master boot record (MBR)之外, EFI 還增加了一個新的支援 GUID Partition Table (GPT), 而這個新的支援則不受到標準MBR的侷限。 在EFI specification 並沒有描述你要使用哪一種的file system; 而典型的EFI在實作上則內定支援使用 FAT32 的檔案系統。
The EFI Shell
EFI 社群(community)建立了一個開放式源碼(Open Source)與介殼程式環境(Shell environment),是使用者與作業系統溝通的程式,負責解譯及執行使用者下達給作業系統的指令。
所以EFI Shell並不是直接的啟動進入到OS,因此在某些情況之下,使用者可以進入到EFI shell。而這個shell是一個EFI application,它可以直接存在於platform ROM(直接燒入在裡面),或是在有驅動程式的ROM的設備上面(透過驅動程式來載入EFI Shell)。
像在MacBook (Apple 的Intel CPU架構的筆記型電腦),你可以把EFI shell 應用程式放在USB隨身碟,而在開機的時候按著"Option",然後就會看到一個選擇開機項目的畫面,選擇你的USB隨身碟,那麼就可以看到一個長的很像DOS的畫面,而這個畫面就是EFI Shell。
而這個Shell可以被使用來執行一個EFI 的應用程式,像是 setup, OS install, diagnostic(診斷分析程式)或是Configuration utilities和System flash updates…等,他也能直接的播放CDs 或是DVDs 而不需要進入到一個完整的OS環境底下,它提供了一個適當的環境來開發EFI應用程式。另外Shell commands也可能可以用來複製,搬移檔案或是目錄(如果你的Shell 有支援),而設備驅動程式也可以利用他去載入或是卸載,而一個完整的TCP/IP 堆疊(TCP/IP 7層架構)也可以使用EFI Shell被完整的使用。
簡單說就是EFI Shell提供了一個不需要進入OS環境也可以處理你需要的工作的一個環境。最後EFI shell支援腳本,而他的副檔名是 .nsh files,他就像是DOS下的批次檔( batch files)。
Shell Command的指令名稱繼承了DOS command interpreter 或是 Unix shell(操作起來像是混合體,有時出現DOS指令的名稱,有時是Unix的名稱) ,而EFI Shell其實就是可以看作成在BIOS裡面的一個DOS環境。
Extensions
EFI延伸功能之中所描述,EFI可以從任何虛擬的非揮發性儲存設備載入並且連接到電腦之中,例如一個original equipment manufacturer (OEM) 廠商在賣系統的時候將EFI 分割區放硬碟中,而要將這些功能載入的程式則放在主機板上的ROM之中,簡單說就是BIOS ROM裡面的程式可以去硬碟把EFI 功能載入出來執行,例如一些測試程式放在硬碟,然後EFI開機的時候去硬碟讀取這些程式出來執行。
Intel Platform Innovation Framework for EFI
Intel 在其平台上為了EFI去建立了一個新框架(Framework),而這個框架的最初代號叫做Tiano,這個框架非常的完整,它包含了EFI對原本傳統韌體的所有支援,他也可以透過所謂的compatibility support module(CSM)來支援傳統的PC BIOS,簡單說就是傳統BIOS能做的EFI也能做,但是不是完整支援就要看CSM支援的程度。
特別是,這個框架包含了在Power-On後,所有必要的初始化步驟去初始化一個平台(Platform);但是這些步驟的運作並沒有被定義在EFI specification內,而是被定義在 Platform Initialization Specification內的某個章節。
Intel 並沒有將這個架構完整的開放給一般的End-User知道,他只有開放這些資訊給一些獨立的BIOS 廠商(稱之為IBV),像是安邁 (American Megatrends ,AMI) 或是系微(Insyde Software) …等的BIOS韌體供應商。
而在TianoCore project(也就是所謂的EFI Developer Kit ,EDK)的Open source之中,會提到如何去開發這個Framework。這個開發工具中含括了EFI的一些硬體初始化的程式碼(只針對一些硬體,但並不包含韌體本身) ,至於這些程式碼的授權包含BSD license 和 Eclipse Public License…等。
而Tiano是為了取代BIOS的一種框架,所以透過EFI可以讓PC的設備自己撰寫一個驅動程式來管理這個設備。而對於開放原始碼來說,這也代表大家可以從TianoCore.org 下載這個專案,然後以BSD(Berkley Software Distribution)的授權方式來生產你的產品。BSD的授權,你自己去修改它的軟體並且發展出屬於你自己的產品,但BSD並不會去要求你把修改的地方公開出來,而這種方法會有助於你去保護你的智慧財產權。
Platforms that use EFI or the Framework
最早使用EFI 的平台式 Intel的第一個Itanium 工作站和伺服器,他們支援EFI 1.02。 接著是Hewlett-Packard的第一個 Itanium 2 系統(2002年發表),支援EFI 1.10; 而這些系統都可以啟動 Windows, Linux, FreeBSD 和HP-UX。
不管是Itanium或是 Itanium 2 系統,他們在出貨的時候都是使用EFI compliant firmware,且須遵照DIG64 specifications。
在2003的11月, Gateway 介紹他們的Gateway 610 Media Center,第一個x86 Windows-based 的電腦系統使用了這個框架(Framework),而韌體供應商則是 Insyde Software's InsydeH2O。而這個韌體依舊是依靠賴傳統BIOS相容介面的方式去實作出這個框架來啟動微軟系統,簡單說就是EFI 的框架去模擬成傳統BIOS,因為Windows並不認識EFI,所以利用EFI框架做出模組(Module)方式去符合目前x86 架構。
在2006年1月,Apple Computer 販售了屬於他們第一次使用 Intel-based的Macintosh電腦, 這個系統使用了EFI和新框架Framework來取代了原本他們在Power PC-Based 一直以來都在使用的 Open Firmware,而在 2006年4月5日, Apple 公佈了一個 Boot Camp 應用程式,這是一個非破壞性的分割工具(non-destructive partitioning tool)去幫助Apple的使用這去安裝Windows XP驅動程式甚至是系統到麥金塔的電腦之中。
而同時,Apple的韌體的也做了更新支援,讓傳統的BIOS支援去它的EFI實作。在此之後,所有的麥金塔系統(Intel-Based)也都是使用使這種韌體(Firmware)出貨。 現在所有目前的Macintosh systems 也都可以啟動傳統的作業系統Windows XP,簡單說就是WindowsXP不認識EFI,而Apple機器內如果裝了Windows XP就必須使用Legacy BIOS方式去啟動Windows XP,因此Apple更新了EFI的Firmware支援,去模擬出一個傳統的BIOS介面來支援,應該也是叫做CSM。
從2005年之後,幾乎大多數的Intel 主機板都開始出貨這種支援新的框架架構的主機板的韌體(Framework-based firmware)。現在像是一些新的mobile,,desktop和 server 產品,在2006年起,也都開始使用這種框架。
自2005起,EFI也開始被實作在非PC架構的系統上,像是嵌入式系統,像是 embedded systems based 的 XScale cores。
而EDK 還包含了NT32 的目標(Target),也就是說它允許EFI Frimware和EFI Application 去執行一個Windows 應用程式。
Security and freedom concerns
According to Ron Minnich, the lead developer for LinuxBIOS, one of the stated goals of EFI is to protect hardware vendors "intellectual property"[15]. This raises security concerns and notably makes creating a free software BIOS impossible.
EFI could be used to create a "DRM BIOS", thus letting vendors build computers which limit what the user can do.
有關於自由軟體運動v.s EFI 請參考下列網站說明:
http://taiwan.cnet.com/enterprise/technology/0,2000062852,20098242,00.htm
Reference
維基百科
CNET
標籤:
EFI BIOS相關知識
星期二, 4月 24, 2007
菜鳥BIOS學習記之怎麼全身菜味篇 -BIOS 學習地圖
菜鳥之所以菜是因為全身都是菜味,學習擺脫菜味的學習過程中,你會發現......你真的很菜!
我是一個六年七班的BIOS菜鳥工程師為了生活而努力的一些心得筆記,如果你年紀輕輕就因為公司移往大陸而被優退的歷練,現在可能跟我一樣是個菜鳥,所以一起努力的擺脫菜味吧,菜鳥同志們!
剛開始進入BIOS行業的時候,由於自己已經有組合語言的基本底子,因此便開始從PC Architecture 跟BIOS Architecture開始學習。
我現在每天接觸的是Phoenix BIOS code 跟Insyde H2O EFI 所以學習起來感覺很充實,很多的東西都不懂,所以每天K Spec...到現在還是繼續K,KK相連到天邊,K到最高點,心中有KK,K才是王道,這也可能也是BIOS工程師的宿命吧...K就對了。
最早的時候我是看的是P廠商的PxxBIOS 4.0 Release 6.1 User Guide...
大概看到第8章的時候才開始看Source code....(Setup Menu那一章),前輩就叫我試著去修改一些畫面的設定...
接著就是看BIOS Source Code...(從BootBlock開始看到POST...) ,而這些組合語言裡面也沒有所謂的Phoenix 語法,都是組合語言的精華應用,像是Strong/Weak...(可以參考MASM Programmer's Guide)
而我目前比較頭痛的是P廠商用C去寫的一些Services...我到現在還是搞不太懂....像是Setup Menu Engine...PDM好像也是.....
而當我把POST source code看到一半的時候就,我們公司就有一些新案子在Run,也因此我就開始接一些東西做了...然後就一邊做案子一邊 K PCI Spec...SMBus Spec...MCH/ICH Spec...ACPI Spec...CPU Spec...然後就一直忙到現在...
我不太清楚其他人如何學習的,但至少我都是先去了解系統架構後才開始慢慢的看Source code...像是CPU 的工作模式(SMM/保護模式/真實模式),, IDA , Super LFM , EMTTM , EIST , 記憶體的管理(例如Big Realmode 或稱Flat Memory Mode或是分頁/虛擬記憶體...等), DDR,SPD,SMBus 如何存取,PCI與PCIE差異...等,還有一些工具的熟悉....
光這些入門課程我大概花了2個月的時間才摸出一點頭緒。
至今也做了7,8個月了,所以剛好整理一下一些心得;至於我開始學習BIOS時,則是依照下面的學習地圖去學習,也許不是最好的方式,但卻是我一路走來的方向的參考:
1.Hello Assembly
2.CMOS Dump
3.CMOS Read/Write
4.PCI Device Scan (CF8/CF9)
5.PCIE Device Scan (比較前面256 Bytes跟4KB Window的不同處)
6.Send EC/KBC Command
7.Access DMI/SMBIOS
8.SMBus Read/Write (認識一些Controller的控制方式及暫存器存取方式)
9.Send ATA/ATAPI Command (Spindown function/ Hdd password)
10.ACPI SCI/SMI (Gx State/Dx State/S3/S4...)
11.....未完待續....
BIOS 行業會不會又移去大陸我也不敢保證,我本身也去過上海住過好幾個月,雖然那邊沒啥不好的,但是競爭太激烈,文化差異大,重點是我吃東西會拉肚子(當你拉了一個月,拉到菊花都開了,你就會開始反感了! 印象中好像是7,8月去的,因為9月菊花盛開...^^),當時的我又沒技術又沒學歷(2專畢業),如果去那邊競爭,或許會成為沙灘前面的那群人,所以當時的我選擇了優退去充實學歷;但是去了對岸生活過一段時間後你會發現,對岸的同胞的目標是放眼全球的競爭,而台灣人的目標卻是"不要被大陸人取代",想法跟觀念大不同,所以我自己也該反省一下了。
我是系統端的BIOS,所以都是做一些OEM 的東西,但BIOS學問可深可淺。有前輩說,如果你只是要改改OEM的東西,大概就一年就可以了,還記得當初找工作的時候有去微星面試,有個實力堅強又很開朗的經理面試我的時候說他自己下去教,應該3個月就可以上手了! 但是如果要深入研究,那麼不混個5,10年,可能還是會覺得不夠。
像我除了會改改一些基本的OEM的東西,最近也學會撰寫WDM 的基本I/O Driver了,也懂得利用Windows XP內的Services Control Manager ,SCM 去動態載入驅動程式了,所以BIOS摸到的層面很廣,可以學到很多東西,也因此......為了等待機會的來臨(或是為了下一次又被優退後的挑戰),先好好提升自己的實力吧(雖然我只有兩粒......毅力跟努力)!
我是一個六年七班的BIOS菜鳥工程師為了生活而努力的一些心得筆記,如果你年紀輕輕就因為公司移往大陸而被優退的歷練,現在可能跟我一樣是個菜鳥,所以一起努力的擺脫菜味吧,菜鳥同志們!
剛開始進入BIOS行業的時候,由於自己已經有組合語言的基本底子,因此便開始從PC Architecture 跟BIOS Architecture開始學習。
我現在每天接觸的是Phoenix BIOS code 跟Insyde H2O EFI 所以學習起來感覺很充實,很多的東西都不懂,所以每天K Spec...到現在還是繼續K,KK相連到天邊,K到最高點,心中有KK,K才是王道,這也可能也是BIOS工程師的宿命吧...K就對了。
最早的時候我是看的是P廠商的PxxBIOS 4.0 Release 6.1 User Guide...
大概看到第8章的時候才開始看Source code....(Setup Menu那一章),前輩就叫我試著去修改一些畫面的設定...
接著就是看BIOS Source Code...(從BootBlock開始看到POST...) ,而這些組合語言裡面也沒有所謂的Phoenix 語法,都是組合語言的精華應用,像是Strong/Weak...(可以參考MASM Programmer's Guide)
而我目前比較頭痛的是P廠商用C去寫的一些Services...我到現在還是搞不太懂....像是Setup Menu Engine...PDM好像也是.....
而當我把POST source code看到一半的時候就,我們公司就有一些新案子在Run,也因此我就開始接一些東西做了...然後就一邊做案子一邊 K PCI Spec...SMBus Spec...MCH/ICH Spec...ACPI Spec...CPU Spec...然後就一直忙到現在...
我不太清楚其他人如何學習的,但至少我都是先去了解系統架構後才開始慢慢的看Source code...像是CPU 的工作模式(SMM/保護模式/真實模式),, IDA , Super LFM , EMTTM , EIST , 記憶體的管理(例如Big Realmode 或稱Flat Memory Mode或是分頁/虛擬記憶體...等), DDR,SPD,SMBus 如何存取,PCI與PCIE差異...等,還有一些工具的熟悉....
光這些入門課程我大概花了2個月的時間才摸出一點頭緒。
至今也做了7,8個月了,所以剛好整理一下一些心得;至於我開始學習BIOS時,則是依照下面的學習地圖去學習,也許不是最好的方式,但卻是我一路走來的方向的參考:
1.Hello Assembly
2.CMOS Dump
3.CMOS Read/Write
4.PCI Device Scan (CF8/CF9)
5.PCIE Device Scan (比較前面256 Bytes跟4KB Window的不同處)
6.Send EC/KBC Command
7.Access DMI/SMBIOS
8.SMBus Read/Write (認識一些Controller的控制方式及暫存器存取方式)
9.Send ATA/ATAPI Command (Spindown function/ Hdd password)
10.ACPI SCI/SMI (Gx State/Dx State/S3/S4...)
11.....未完待續....
BIOS 行業會不會又移去大陸我也不敢保證,我本身也去過上海住過好幾個月,雖然那邊沒啥不好的,但是競爭太激烈,文化差異大,重點是我吃東西會拉肚子(當你拉了一個月,拉到菊花都開了,你就會開始反感了! 印象中好像是7,8月去的,因為9月菊花盛開...^^),當時的我又沒技術又沒學歷(2專畢業),如果去那邊競爭,或許會成為沙灘前面的那群人,所以當時的我選擇了優退去充實學歷;但是去了對岸生活過一段時間後你會發現,對岸的同胞的目標是放眼全球的競爭,而台灣人的目標卻是"不要被大陸人取代",想法跟觀念大不同,所以我自己也該反省一下了。
我是系統端的BIOS,所以都是做一些OEM 的東西,但BIOS學問可深可淺。有前輩說,如果你只是要改改OEM的東西,大概就一年就可以了,還記得當初找工作的時候有去微星面試,有個實力堅強又很開朗的經理面試我的時候說他自己下去教,應該3個月就可以上手了! 但是如果要深入研究,那麼不混個5,10年,可能還是會覺得不夠。
像我除了會改改一些基本的OEM的東西,最近也學會撰寫WDM 的基本I/O Driver了,也懂得利用Windows XP內的Services Control Manager ,SCM 去動態載入驅動程式了,所以BIOS摸到的層面很廣,可以學到很多東西,也因此......為了等待機會的來臨(或是為了下一次又被優退後的挑戰),先好好提升自己的實力吧(雖然我只有兩粒......毅力跟努力)!
訂閱:
文章 (Atom)