2008年6月28日 星期六

BIOS for VGAint

(轉貼於"小華的部落格http://biosengineer.blogspot.com/")

一般而言,BIOS會在POST時 locate 3 devices:
- Input device(Ex. Keyboard)
- Output device(Ex. Display device)
- IPL(Initial Program Load, Ex. HDD)

這次要提到的是 Display device,即 VGA !

在PCI_SCAN之後,BIOS會在記憶體中建立一個data structure,代表整個系統的 PCI architecture.
Ex. Ponter-> NB->P2P->SB->IDE->AUDIO->LAN->USB 2.0->USB 1.1->...->VGA->...->End

在VGA_init的階段,BIOS會去 go-through this list,一個個的問:"有沒有人需要shadow Option ROM的 ?"

-------------------------------
*1 在此,先break,並說明一些觀念:
1. Option ROM是 for H/W的 firmware;像BIOS一樣是 for MB.有可能直接在硬體上 ,or 包在BIOS image中
2. 有Option ROM的 H/W可能有: VGA card,Lan card, RAID card,...etc
3. VGA's Option ROM 也就是 VBIOS ! 專門處理 screen I/O operation(主要是int10h)
4. VGA "shadow" 即代表: 將 VBIOS copy 到 shadow RAM, Ex. C0000h~C7FFFh處(32K)
5. VGA init這個階段只 consider "VGA device" ! for 其他 device,之後再考慮其 shadow的事宜
-------------------------------

(承接前面的 flow):此時,VGA device會舉手說:"我要" !此時,BIOS會去尋找VGA device's Option ROM(即VBIOS)在哪裡;此時,VBIOS有可能在card上 or "當初" 被包在 BIOS image中(*2)

一但找到,則會先 作一些 checks:Ex.
- Option ROM signature is 0xAA55 ?
- 比較 Option ROM內的 Vendor ID/Device ID = H/W's IDs ?
- class code and sub-class code correct ?
- length = 0 ?
...etc...

若都符合,則視它為 VGA Option ROM(VBIOS) ! 之後,利用 memory2memory copy將之 copy到 shadow memory,從 C0000h處開始存放...

複製完後,再 check "checksum"是否正確;if yes then jump to "entry of initialization code",控制權自此轉移至 VGA Option ROM,由它去做 initialize VGA的工作 ! ( 若是CRT螢幕,user會聽到ㄉ一ㄤ的一聲 ! 即代表 initialize VGA成功 !!! )

<- 此為 VGA_init的工作 !!! *2 說"當初"的原因是: VGA BIOS若包在BIOS image中,在 BIOS shadow時,也會被一併 copy到記憶體的某處放著;當然,會記住存放處 ! [Note] 一般遇到 VGA init fail的issue時,可以先 check:是否 VGA BIOS已被 copy 至 C0000h處;若有,則check是否已經 jump to VBIOS or NOT;若否,則可以往前 check是否前面所列的一些 "關卡"沒過 (Ex. ID不 match, or checksum 不相等...etc ) VGA 若 ok,電腦就是彩色的 ^_^ ---------------------------
- 相關討論 -----------------
---------------------------


通常都是板子一來就會去開始Debug VGA...
VBIOS 若壞,螢幕是黑ㄟ
VBIOS若好,螢幕是彩色ㄟ
沒螢幕的情況下要繼續Porting BIOS就比較麻煩一點

[Q]Option ROM是 for H/W的 firmware;像BIOS一樣是 for MB.有可能直接在硬體上 ,or 包在BIOS image中。前者我叫它SW ROM,後者叫legacy ROM,您已經提到sw rom的load方式,那麽legacy rom load方式是否應該有所不同呢?一但找到OpROM,則BIOS 會先作一些 checks:
Ex.
- Option ROM signature is 0xAA55 ?
- 比較 Option ROM內的 Vendor ID/Device ID = H/W's IDs ?
- class code and sub-class code correct ?
- length = 0 ?
...etc...

兩种rom都是通過這種方式嗎?

Ans: 我所說的都是 rough flow,而這兩種ROM的"處理方式"不同,但"檢查的機制"大同小異...建議去trace BIOS code比較清楚

[補充1]
1.可以查看PCI ROM Spec... 裡面有詳細說明如何Load OpROM 的方式,而檢查項目就各家BIOS不同...

2.可以用HEX編輯器直接開啟ROM File,例如VBIOS.bin or OpROM.dat ...etc 來查看內容(Binary file),例如某VBIOS.DAT 的內容如下:

00000 55 AA 80 E9 4B ....
00010 30 30 00 22 E9 19 21 5F 40 00
.......................................
00040 50 43 49 52 86 80 42 2A ..............

其中:
a)55AA是這個ROM的Signature <--代表他是符合規範的ROM b)80 這個ROM的Code size <--需查閱Spec確定一下 c) 接著是EntryPoint Address <--實際上會執行的程式碼進入點的位址,所以一般都是講 Jmp OpRomBaseAddr+3 <-- 你如果trace BIOS 程式碼,這就是 +3 的由來 d) 000018h=40 代表另一個PCI Header在Offset 00040h的地方 所以 50 43 49 52 是Signature,如果用ACSII 來看就是"PCIR" 其他更多資訊可以查看PCI ROM Spec說明..... e) "PCIR"後面緊跟著這個OpRom的VID與DID ...即8086 2A42 <--Intel=8086 3.如果想要改OpRom裡面的Code,可以使用反組譯工具去修改或是用Debug去修改 如果比較簡單的OpROM要做實驗的話我都用Debug.com 把OpROM 載入到Mem,接著利用T /P 指令單步執行去追蹤與修改,修改好之後再查看機器碼,再利用Hex編輯器 or 反組譯工具寫回去OpROM (找Bug時可以嘗試這樣寫啦,不過違反智慧財產權,最好還是叫Vendor幫你改,而且光看懂OpROm的流程就需要一點時間了 ^^!) 如果要用組合語言寫一個Dummy OpRom的做法就像下面範例去模擬一個OpROM... 至於你BIOS端可不可以run 就要看你的檢查機制嚴謹程度或是你自己修改你的BIOS code來達到模擬的目的 : .586p .code YourCodeStart: ORG 0 db 55h, 0AAh TotalCodeSize db (offset YourCodeEnd) - (offset YourCodeStart) ORG 3 jmp entrypoint entrypoint: ........ YourCodeEnd: END 組譯完之後可以利用微軟工具EXE2BIN.EXE 把他轉成xxx.bin (binary file)然後你就可以包進去BIOS測試。 [補充2]
當VGA init時,那時VGA BIOS的放置處可能有:
case 1: 在 memory中(當初在 shadow stage時被 copy 到 memory)
case 2: 在 card上(Ex. 一般的 external VGA card上都有一顆小rom)

因此,這兩種case的處理方式便不同.
Ex. In case 2 若VGA card在 bridge後面,則還需要 config 該 bridge's resource window使Option(in card)可以被正確的 accessed...<- 所以處理方式有所不同 !

至於檢查機制;因為Option ROM不管放哪裡,其 content都是一樣 ! 因此檢查機制大同小異...還有,不同家BIOS的 "checks" 也未必完全相同 !!!

BIOS for PCI

(轉貼於"小華的部落格http://biosengineer.blogspot.com/")

[About PCI device]
1. 每一個PCI device都有其 unique PFA(PCI Function Address). PFA由 bus number,device number & function number所組成.

Ex. USB device PFA is (0,6,0) <- USB is a PCI device and its bus/dev/function is 0/6/0 2. 有了PFA,就可以存取其 PCI configuration registers. Ex. write USB PCI register 43h bit1 = 1 =>
mov eax, 80003040h
mov dx, 0cf8h
out dx, eax

mov dx, 0cffh
in al, dx
or al, 00000010b
out dx, al

* IO port 0cf8/0cfc 為 PCI config address port & data port,意即:將 address(80003040h)送到config port(0cf8h),然後從 data port(0cfch + 3)來存取 data(al)

* 注意: 32-bit address(80003040h) 中 bit[1:0] = 00b(固定的),所以雖然存取的是 43h,但還是寫成40h ! 而要存取到 43h,則從 0cfch+3來達成 (因為: 0cfch<-> 40h,0cfdh<->41h,0cfeh<->42h, 0cffh<->43h)

3. 基本的PCI device的 config registers可分成 2 parts:

A. header region(offset 00h~3Fh)
B. device specific region(40h~FFh)

在BIOS's PCI_SCAN stage中,會touch到 part A. Ex. command byte, BARs, Interrupt line, latency timer,...etc. 而Part B是製作 or design這個device的廠商所附加的 function/feature.

4. 每個PCI device都可以 request 之前所提的 4 resources:
A. memory resource:透過 Base Address Register(BAR)
B. IO resource:透過 Base Address Register(BAR)
C. Interrupt: 透過 interrupt pin
D. DMA: 這需要 device本身即具有 bus master function(status byte會indicate)


[Why need PCI SCAN]
現在的computer system泰半由許多PCI devices所組成,因此,BIOS POST中另一個重要的 task is : PCI_SCAN !!!

它代表的是: BIOS會掃瞄 whole system,找出所有的PCI devices; initial them and build a linked list of PCI devices.在此list中的每一個node都代表一個PCI device,且含有其 characteristics !

Ex. Vendor ID,Device ID, PFA,Option ROM exist or NOT,...etc.

一旦建好此表,以後的 tasks 隨時都可以參考 !!!

所以, after PCI_SCAN,有兩件事完成了:
1. PCI device initialization;device config registers(Part A) are correctly set ...
2. One data structure is built to describe the PCI devices in whole system(建在memory中)

這也是屬於kernel code part ^_^ ( system 一般很少 hang at this stage...)


符合PCI spec的device即稱為........PCI device ^_^

[補充] PCIe device

PCIe device => 符合PCIe spec的device(...廢話...)

對軟體而言,它仍是PCI device. 因此,基本的 header region and device specific region也有. 不過,PCIe新定義了 extended config space,即 offset 100h(含)以上,直到 FFFh( 所以, 最大可以至 4096 bytes )

存取 PCI config space的方式,用原來 0cf8/0cfc的方式依然可行,但只能 access offset 00h~FFh. 要 access 100h(含)以上的 extended config space,則必須用 memory transaction的方式 !

Ex. mov ax, [50400000h] <- read device (4,0,0)'s register 0;2 bytes here 50000000h: PCIe extended base address. 可以從 chipset register得知 bit[27:20]: Bus information [19:15]: Device information [14:12]: Function information [11: 8]: Extended Register [7:2]: DW number [1:0]: Byte enable 因此,只要知道 PCIe extended base address,就可以像以前一樣,可以任意存取 PCIe config registers, even > 0FFh !

除此之外, PCIe device可以由其 Capability pointer(points to a linked list of capabilities)辨認出來. 因為,在眾多的 capabilities中,會有一個 PCIe capability;其 ID value = 10h.

Note: PCIe extended base address 要 reserve and report to OS. Size is 256MByte. 這是BIOS需要做的. (當然,BIOS也要將此 base address寫入 chipset register,讓 chipset 知道:有這樣的 cycle時,是給PCIe device的 ! )

[補充] For P2P bridge

P2P bridge = PCI-to-PCI bridge. 其存在可以 introduce 另一 new PCI bus,可以容納更多的 PCI device.

P2P bridge亦有其 PCI config space,但是 lauout 與 PCI device有點不同,大家可以參閱P2P spec並與PCI device's config space比較一下.

在 P2P config space中,我常遇到的 issue是和下列 register有關的:
- Primary bus register: offset 18h
- Secondary bus register: offset 19h
- Subordinate bus register: offset 1Ah

----------------------------------------
Notes:
這三個 registers是BIOS在 PCI_SCAN時會決定的;所代表的意義是:這個 P2P bridge的上面 PCI bus number is ? 下面的PCI bus number is ? 及包含此 P2P bridge的 "branch" 最深的 PCI bus number is ?

Ex. 18/19/1Ah of one P2P bridge is 0/2/3
=> 此 P2P bridge 是 "bridge" PCI bus 0 and 2的(橋接在 PCI bus 0 and 2之間);而包含此P2P bridge的 PCI branch(想像成 tree structure) 最大(深)的PCI bus number is 3
----------------------------------------


- memory base/limit
- IO base/limit

----------------------------------------
Notes:
這兩個是 BIOS 在 PCI_SCAN時所 assign的. 所代表的是: resource "window" for devices behind this bridge.意即:若P2P bridge下面(就上例言:是 Bus 2上)有 PCI devices,則他們的 BARs 必須被包含在此 window 之內 !!!
----------------------------------------

[Practice]
[Q]假設有一個 P2P bridge ,下面有一PCI device;現在必須要去 accessPCI device's Device ID/Vendor ID(that is, PCI config read). 但是,問題是:做這事的"點"要在 PCI_SCAN之"前"....那要如何做到呢 ^_^ ?


Ans:假如要在很早前(Ex. PCI SCAN之前)去 access P2P bridge後面的 device,照理是做不到的,因為: P2P bridge沒有被正確的 configed...

在此例中,P2P bridge的 primary/secondary/subordinate bus要被 set,後面的device才能被 accessed到 !

所以,假如要在 PCI SCAN前就 access,則BIOS必須手動去 set 此 3 bytes;然後,PCI config access才能被 forward to 其後的 PCI devices...

[Q] 如何 disable memory or IO resource window ?
Ans: 只要將 base設成比 limit "大" 即可 !!!


---------------
- 相關討論 Part1 -
---------------

前輩已經提到P2P Bridge我就直接問我的問題了

[Q1] Bridge 是用來擴充PCI Bus,在PCI Bus Spec與PCI-PCI Bridge Spec中定義,PCI Device是透過IDSEL來決定他的身分,其中PCI Bus Spec定義AD[31:11],而PCI Bridge Spec定義AD[31:16] 當做IDSEL,這中間差異為何? 為什麼一個要從Bit 11開始當作是Dev 0 ,而另一個由Bit 16 才當作是 Dev 0 ?

Ans: 1. IDSEL對PCI device而言是 input,是用來當作 device's "chip-select"訊號. 而且,IDSEL "如何連接" 是 H/W決定的,BIOS無法決定.

假如將板子上某個device's IDSEL "割斷",則此 device將無法接受 PCI configuration read/write(以 ru.exe來說,就是按F6後,是看不到它的...)

那要如何決定 device's IDSEL ? 一般而言, board designer會將 "unused AD lines"拿來做 IDSEL,以連接至 PCI device.

在 configuration access時,所下的 Ex. "o cf8 80001020"(看起來是 I/O transaction)會被 host bridge轉成 configuration transaction;此時, host bridge即可判斷此 transaction 要 access的 device是否在該 PCI bus上;if YES 轉成 Type 0 transaction;If NO 轉成 Type 1 transaction,並往下發送...(host bridge只要 check latched "bus information"即可完成此判斷 !)

以 Type 0言,AD bus上的 format as follows:
bit[1:0] = 00 ( indicates "Type 0" )
bit[7:2] indicates register number
bit[10:8] indicates function number

那 Bus number ? Device number ?
=> Bus number不必知道 ! 因為:Type 0產生即代表 bus number = 現在的 bus #
=> Device number呢 ? 因為,此時(Config transaction && address phase) AD bus bit[31:11]沒人用 !!! 因此, board designer會把此 21 bits拿來做 IDSEL用 !

因此, AD bus bit11 <-> device 0
12 <-> device 1
.......

當然,不可能 21 bits都拿來接 PCI devices;因為電路上的現實考量...

.................以上為:我所知為何從 bit11開始來當作 IDSEL................

以 Type 1言,PCI-PCI bridge收到後,會將其 bus information與自己的 secondary bus number比較;若是 addressed device是在 secondary bus上,則將 Type 1 -> Type 0;若否,繼續包成Type 1往下一層送...

在P2P spec v1.1 page 22 有一張表,說明 IDSEL generation(from primary address -> secondary address),其中有提到: if primary address bit[15:11] =0,則 secondary address AD [31:16] = 0000 0000 0000 0001;以此類推.

所以,我覺得為什麼 for P2P bridge 其 IDSEL可由 bit[31:16] 來決定的原因在此 !!!(表的關係...)

.................以上為:我推論為何從 bit16開始來當作 IDSEL................
[補充]
PCI config index register裡面的資料其實和硬體解出configuration cycle是相關的.
一.轉換出來是type 0 cycle的話. 硬體只要做以下兩件事.
1. mask 掉bus number(bit 16 ~ 31)以上的部份.
2.解碼 device number的部份即可到對應的 AD bit. 所以其最低可以使用的就是AD11.也就是說一個bus上最多只能有 21個 devices(只是由於推動力問題, 往往是做不到的).
Note:其實也可以設計成其他大於AD 11開始, 這要看chip設計者決定了.
二. 轉換出來是type 1 cycle的話. 只要做
1. mask 掉reserved以上的部份(bit 24 ~31)
2. bit 0 = 1
由於P2P跟其他device不同的地方就是, 除了type 0 clcye以外, 還必須處理 type 1 cycle. 這也是分成兩部份
一. type 1 -> type 0. 當 bus number 等於 secondary bus number 時候出現.
1. 解碼 device number 到對應的 AD. spec中有提到轉換的表. dev 0 = AD16....etc
2. 把 bit 0 由1 變成 0
二. type 1-> type 1. 當 bus number 介於 secondary bus number和 subordinate bus number
1. 直接往下一層送即可.交給其他的P2P 處理.

[Q2] 在IA32下,CONFIG_ADDRESS 會被轉成Configuration Cycles,當Bus Number <>0 時,NB會轉成Type 1 然後往 DMI送到SB,當P2P Bridge收到後,然後定址到Slot上面的PCI Device,這樣說法對嗎?

Ans: 總而言之, 是自己local bus上的,就會轉成 Type 0,然後打在AD bus上,等待認領;若否就轉成 Type 1,往下一個bridge送,繼續尋找...對的人...for each bridge,都是一樣...
[補充]
對 PCI spec是, 如果以Intel PCI express架構來說. 那個已經被封裝成 pci express的 package了.沒有所謂的 type 0, type 1 cycle了.


[Q3]PCI Device透過IDSEL來決定身分,那PCIE Device呢? 我查過資料,好像PCIE不需要IDSEL那他是如何決定Device Number ?

Ans: 我所遇的 PCIe device也是由 AD bit[31:11]中找線拉至 device's IDSEL決定的.不知其他家 chipset是如何 implement.
[補充]
PCI express 是internal routing. PCI express是個跟PCI 完全不同的架構. 只是為了軟體相容性的關係, 把software架構做的跟PCI bus一樣. PCI express是point-to-point架構, 一個link 只會連接一個device. 跟PCI 這種可以多個device在同一bus上是不一樣的. 所以 device number對PCI express是完全不重要的.
Note. AMD的Hyper transport 也是基於一樣的心態來設計軟體架構的.

※ PCIe 的device是 internal routing. 以規格來看,下一層的 device number都是為0.

------------------
- 相關討論 Part 2 -
------------------

DMI指的是 Intel 南北橋中間的通道 ! 之前也是不知P2P bridge部份關於IDSEL的配置,查了表才知道原來有這樣的 mapping(primary address<->secondary address). 其實,可以說 "unused AD bus 會被拿來當 IDSEL用"就是了吧 ^_^
[補充]
是的, 只要軟體能夠知道routing 關係.怎麼接都可以. 只要bus controller控好實際的IDSEL即可. P2P之所以會有嚴格規定(兩項, 1. IDSEL&device number表, 2. secondary bus IRQ routing)是因為P2P 不一定是在板子上. 包含卡都可以有P2P bridge. 在板子上的P2P 可以靠BIOS來建立正確的 routing, 但是插卡不行. 所以必須把這些定義好. 這樣 PnP software(BIOS or OS)才能正確的完成IRQ 分配.讓卡正常工作. 所以如果觀察某些板廠. 就算是真的p2p 沒有存在在板子上, 很多PCI slot的IRQ routing都是依據p2p spec裡面的規定做(因為SB的PCI bus還是落在P2P之後).


在 PCI scan時,BIOS會掃描整個系統的PCI architecture(包含 device & bridge);其掃描方式由BIOS's PCI kernel來決定 !
[補充]
其實了解PCI spec. 要寫PCI scan其實可以效率好又正確. 常見的新進工程師寫法大概就是 3個 loop來處理. bus:0~255, device:0~31, function:0~7. 掃個 256*32*8次, 反正都是程式做, 結果往往也看來正確.這種寫法其實是不對的. (其實,若是多了解硬體的架構,就可以寫出有效率的code了 ! 這也是F/W工程師的價值...)


Ex. Assume 系統架構是這樣的: NB,P2Px3, PCIe bridge x2;其中:
A. 3 P2Ps的配置 is: P2P0下面接P2P1;P2P下面接P2P2
B. PCIe x 2 & P2P0都在 bus 0;其PFA為
NB(0,0,0)
P2P0(0,1,0)
PCIE0(0,4,0)
PCIE1(0,5,0)

=> 最後的 PCI achitecture is:

Bus 0----------------------
NB(0,0,0),P2P0(0,1,0),PCIE0(0,5,0),PCIE1(0,6,0)

*下面 Bus 1/2/3由 P2P0/1/2所 introduce:
Bus 1----------------------
P2P1(1,0,0)
Bus 2----------------------
P2P2(2,0,0)
Bus 3----------------------

*下面 Bus 4由 PCIE0所 introduce:
Bus 4----------------------

*下面 Bus 5由 PCIE1所 introduce:
Bus 5----------------------

所以,Bus number 是由BIOS's scanning "algorithm"所決定的;假如採用 depth-first,則會產生上述的結果 ! 決定後的值會填到 bridge的 Primary/secondary/subordinate bus number registers !

[Q]順便問個問題好了. 其實function number不應該是永遠需要scan的, 為什麼?什麼時候才需要scan function number?
Ans: 我想,對於 function number的問題,應該是: PCI header region offset 0Eh bit7代表: milti-function or NOT ! 因此,可以先 check此bit,再決定要不要往下掃了...這樣又少做了許多虛工...^_^

Ex. PFA (0,3,0) 有回應(that is, Vendor ID/Device ID != 0xFFFFFFFF),則先check (0,3,0)'s PCI Reg0Eh bit7; if "1" then 此device為 multi-function device,還要再往下找 Ex. (0,3,1~7) 有無回應;if "0" then try next device number...!


[補充,加快速的的方式]
檢查multi function bit是正確的, 但是不只是因為效率問題. 而是PCI 規格中, single function裝置可以不解碼 config cycle type 0 bit[8~10], 也就是說 一個 single function裝置, 會對 所有的function number回應, 也就是會出現 8 個相同的device.

順便說一下我的scan加速法. 其實我不是使用 vandor ID & device ID來判斷裝置存在與否. 我是用 class/subclass/interfae ID來作判斷. default 只scan bus 0, 遇到 P2P bridge才會把taget bus number+1, 如果遇到multi host(host bridge 數量> 1)的板子才會完整掃描 255個 bus. ^_^



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

~轉貼自艾克索夫實驗室~
Rootkit in PCI Option ROM


「Rootkit」一字來自 UNIX 界;但目前通常用於描述 Windows 木馬程式作者所運用的隱形技術。
起初,Rootkit指的是一組程式,可讓駭客躲過偵測。 為達成此目的,可執行的系統檔案 (如 login、ps、ls、netstat 等) 或系統程式庫 (libproc.a) 會遭到更換,或安裝核心模組。 這兩種動作只有一個相同目的;防止使用者收到正確資訊,知道電腦上發生了什麼事。

首先介紹PCI的基本常識, PCI Bus是在約1990年由Intel發展出來, 用來連接主機板上的各項裝置的匯流排標準, 後來成為業界的標準之一, Spec可以在PCI-SIG註冊會員之後下載, 架構上簡單的說, 就是一個Host bridge, 在一般的PC上通常指的就是North Brdige, 這個brdige後面就是bus#0(當然也有Multi Host-Bridge的狀況, 這邊舉例的是最單純的情況), 然後接到South Bridge, South Bridge之後可能接的是ISA Bus, IDE Controller, USB, IDE, DMA Controller等等, 如果bus#0上還有別的PCI Bridge, 這個Bridge後面就是bus#1, 如果有多個Bridge存在(PCI最多可以有256個bus), bus#就不一定是固定的了, 一個PCI Bus上可以有32個device, 每個device可以有8個function, 每個function都有屬於自己的256個register. 在PCI的規範裡, 256個register中的前0×40個是公定的功能, 從0×40到0xff則由各家廠商自行實作, 存取這些register的方法, 一般的PC上是透過IO port 0xCF8~0xCFF, 如果是新的PCI-Express則是直接透過Memory Mapped IO, 以存取記憶體的方式直接進行存取, 例如我們想要讀取一個在bus#0 dev#1 func#0的register#40~43, 透過IO的方式如下:

mov eax, (0x01 <<>mem decode), Command Register(0×04~0×05)的Memory Space Bit打開, 在0xFE000000的地方你就可以找到這個rom, 開頭是0×55AA(這當然也是規範之一, 用來辨視是否為一個PCI rom), BIOS在POST過程中, 會逐一掃描位於主機板上所有的PCI Device, 假如device上有rom, 就會把它給拷貝到memory中, 然後用jmp指令跳到ROM開頭offset 0×02(別忘了開頭offset 0×00是0×55AA)的地方開始執行PCI ROM, 執行完後ROM會再把控制權交回到BIOS手上, 一般而言, 在傳統記體空間中, 0xC0000~0xCFFFF是給VGA ROM用的, 0xD0000~0xEFFFF則是留給一般的PCI ROM使用, 當然各種情況下還是會有些許差異, 例如有些BIOS會保留0xE0000~0xFFFFF給自己使用, 像是BIOS的interrupt service, DMI data….等等雜七雜八的東西, 執行完的ROM仍然會保留在記憶體中, 因為有些ROM會修改IVT(Interrupt Vector Table), 將某些interrupt service導向自己的code, 像是VGA ROM可能就會hook int 0×10, 這是很合理的, 因為int 0×10是BIOS所提供用來控制螢幕的service, 聰明的你看到這裡應該就知道前面所提的那篇文章想說什麼了, 如果有個”惡意”的程式被埋在PCI ROM裡面, 只要一開機就會自動被執行, 它的運作並不是一時的, 它可以hook某個OS一定會用到的BIOS Interrupt Service, 然後在這個interrupt service被呼叫的時候動作就可以了, 而且麻煩的是即使你format你的HDD也沒用, 除非你把有問題的PCI Device從你的主機板上移除, 嗯….聽起來蠻炫的, 但是, 有可能嗎?

要回答這個問題之前, 需要知道一些基本的常識, 在保護模式下, 因為IO動作受到限制的關係, 要存取IO並不像在DOS那樣容易, 但如果想嘗試Re-flash一顆PCI ROM, 勢必得進行IO動作, 所幸在Windows下這並不是不可能的事, 有些人可能知道利用SeTcbPrivilege和使用ProcessUserModeIOPL structure呼叫undocumented Native API NtSetInformationProcess()就可以達成目的. 一旦攻擊者有辦法修改PCI ROM, 他就可以利用文章中所提到的例子: int 0×10(Windows在開機過程中會透過Ke386CallBios()呼叫int x010), 作他想作的任何事了.

可惜不論哪種攻擊方式, 最終都是要對OS kernel動手腳, 利用各種偵測工具(如: Archon Scanner), 一定可以找到有問題的地方, 如果最後的箭頭指向PCI ROM, 我們可以透過上文所述, 將存在PCI Device和memory中的ROM給dump出來, 需要dump兩邊的rom, 是因為PCI Spec規範中允許實際上所需要配置的記憶體不一定要等於原本rom的大小, 藉以節省保貴的記憶體(別忘了PCI ROM只能被配置到幾個64KB的segment裡而已), 然後向PCI Device的製造商索取正常版本的rom進行比對, 藉以得知是否為被修改的版本. 假如發現有不一樣的地方, 接下來可以朝幾個方向繼續分析是否為有問題的ROM, 我們可以檢查一下它是否修改了不必要的IVT, 像PXE ROM就不太可能hook int 0×10, 或是有保護模式相關的程式碼, 因為一般的ROM應該都是在real mode下執行, 所以應該不會切到protected mode, 如果有相關的程式碼那就非常可疑, 還有rom裡面是否有可疑的字串, 或是位在Windows Kernel位址空間裡的32-bit address, 另外ROM裡面也不太可能出現編碼過的code, 如果rom裡的code很難被disassemble, 或是充滿了一堆obfuscated code, 那也是很有問題.

除了軟體的方式, 最近興起的新技術TPM也能克制這種攻擊手法

打造自己的BIOS

(轉貼於"小華的部落格http://biosengineer.blogspot.com/")

第一集:

存放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。

BIOS開發

(轉貼於"小華的部落格http://biosengineer.blogspot.com/")

這篇文章主要是概述 BIOS 開發環境下的一些基礎知識,有助於了解如何自己去撰寫一個屬於你自己的 BIOS。

大家都知道Legacy BIOS是使用Assembly 所撰寫,目前的UEFI則是使用C語言,但是不論是哪一種BIOS,其開發環境下的基礎知識都還是相同。

ㄧ般BIOS工程師開始學習BIOS Vendor所提供的BIOS Code時,最主要會學習下列幾個項目:

1.Build process : BIOS ROM是如何產生,這部份要去了解的是整個流程為何?
例如: (ㄧ堆Source code) --> 經過哪些Build process --> (產生BIOS.ROM)

2.Directory : BIOS Code的目錄架構為何? 哪些是屬於Framework/Kernel/Oem ?

3.Build Config : BIOS 相關參數的設定,每家Vendor設定方式都不同!

4.Build Tools : BIOS 建立時使用了哪些工具,ㄧ般都是MASM+VisualStudio+DDK+Bios Vendor自己開發的一些Tools。

5.Build your BIOS ROM : 如何建立你的第一個BIOS ROM,ㄧ般都是使用nmake/直接在IDE(整合開發環境下)下設定好,就可以直接去Buildㄧ個完整的BIOS ROM。

有了上述的整理分類,其實不難發現,實際上我們撰寫的BIOS code只是一個BIOS Vendor做出來的環境下(或稱為框架下)去"填寫"一些屬於我們的程式碼,就像是C語言的開發環境下你只需要知道在main(){.....} 的括號內去撰寫程式碼就好了,後面的事情BIOS Vendor都幫你做好了。

所以OEM/ODM端的BIOS能夠處理的東西都是比較偏向客戶端的需求而去撰寫一些程式碼,我們稱這些程式碼為"Features"。而這些部份就像你買Asus /Acer/...etc 不同家的電腦,裡面所能提供的功能會不同。

雖然好像看起來只是"填入"ㄧ些程式碼,但是這部分又與整個硬體運作以及BIOS Vendor所提供的程式碼的"穩定度"有很大的關係,所以如果只是單純修改這些程式碼約1年可以上手,但是如果要能處理bug,那麼可能就需要多年的經 驗累積了。因此在這種OEM/ODM BIOS與BIOS Vendor分工合作的情況之下,OEM/ODM端的BIOS有自己負責解決問題的地方,而BIOS Vendor也有自己負責要處理的地方,大家相互合作。

說了這麼多,對於BIOS開發環境應該有所了解,但是最近案子開始在忙了,所以會寫Blog時間會比較少了,等過陣子等案子不忙的時候,我再告訴大家如何如果要實做一個類似BIOS vendor開發環境,你需要哪些工具,還有怎樣子做。

EFI(Extensible Firmware Interface)之2

Extensible Firmware Interface ,EFI 簡介 by Harrison
(轉貼於"小華的部落格http://biosengineer.blogspot.com/")

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 licenseEclipse 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, FreeBSDHP-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(Extensible Firmware Interface)之1

EFI為Extensible Firmware Interface的簡稱。
中文叫做可延伸式韌體界面...
這裡有詳細的討論文章可以參考
http://taiwan.cnet.com/enterprise/technology/0,2000062852,20098242,00.htm

Intel 搞的EFI叫Tiano,EFI只是一個SPEC名稱,
Tiano才是Intel搞出來bios source code的名稱。
EFI就是要各硬體廠商自己寫BIOS,就是所謂的
EFI driver,然後BIOS vendor只要整合combine
,甚至end user可以不改source code自己load driver
unload driver,很方便,可是對傳統的bios vendor就不妙了,
他們的角色變的可有可無啦。

现在TIANO已经Open Source了.
你可以在
http:\\www.tianocore.org
上获得它的source code.

最近又出現一種新發展標準, 叫uEFI (Unified Extensible Firmware Interface), :002: 據了解...它是建構在EFI 1.10 規格所發展出來的新標準。
目前力拱uEFI的大廠, 包括
Phoenix Technologies (http://www.phoenix.com/en/Home/default.htm)
Intel (http://www.intel.com/)
Microsoft (http://www.microsoft.com/)
AMD (http://www.amd.com/us-en/)
American Megatrends Inc. (http://www.ami.com/)
Dell (http://www.dell.com/)
Hewlett Packard (http://www.hp.com/)
IBM (http://www.ibm.com/us/)
Insyde (http://www.insydesw.com.tw/en/index.asp)
看來它將會取代EFI, 成為業界發展的主流啦:

詳細內容可以至http://www.uefi.org/index.php?pg=2獲得!!