小華的部落格: 2007/10/7 - 2007/10/14

搜尋此網誌

星期三, 10月 10, 2007

SCI Check List

前陣子新板子的SCI不能work ,在Debug之餘,剛好做做筆記。

【檢查項目】

-------------------------------
1. Registers (先得到GPIO & PMBase,檢查SCI 是否繞到IRQ9,GPI是否組態成SCI)
-------------------------------
GPIOBASE—GPIO Base Address Register (LPC I/F —D31:F0)Offset Address: 48h–4Bh
PMBASE—ACPI Base Address Register (LPC I/F—D31:F0) Offset Address: 40h–43h

ACPI_CNTL—ACPI Control Register (LPC I/F — D31:F0) Offset Address: 44h
GPIO_ROUT—GPIO Routing Control Register(PM—D31:F0)Offset Address: B8h – BBh

-------------------------------
2. GPIOBase Registers (先確認是Native還是GPIO,然後設定成GPI還是GPO,需不需要Low active)
-------------------------------

GPIO_USE_SEL—GPIO Use Select Register [31:0]Offset Address: GPIOBASE + 00h
GP_IO_SEL—GPIO Input/Output Select Register [31:0] Offset Address: GPIOBASE +04h
GPI_INV—GPIO Signal Invert Register [31:0] Offset Address: GPIOBASE +2Ch

-------------------------------
3.PMBase Registers (SCI總開關有沒有開,OS有沒有設定Enable bit)
-------------------------------
PM1_CNT—Power Management 1 Control I/O Address: PMBASE + 04h
GPE0_EN—General Purpose Event 0 Enables Register I/O Address: PMBASE + 28h

-------------------------------
4.ASL Code (OS依照EC.ASL 內的_GPE來設定GPE0_EN bit)
-------------------------------

(a)EC.ASL 內的Name(_GPE,0xNN)
(b)GPE.ASL 內的Method(_Lxx) 先移除,避免不必要的誤會
(c)PCIIRQ.ASL 內的_PRS(_CRS不用改),把IRQ9 保留下來,以免跟別人共享造成SCI反應過慢
(d)_REG 或是_INI 內檢查一下是否有其他ASL Code會造成系統當機...etc因素存在
(e)檢查FACP Table中的SCI_INT欄位是否與ICH9 Registers內填的值一樣(IRQ9)
(f)檢查MADT Table中的Interrupt override field內的IRQ設定是否有對SCI_INT做覆蓋,且設定是否正確? (微軟Spec中提到APIC也使用SCI_INT,但是如果有MADT時,會以Interrupt override設定來覆蓋SCI_INT設定,一般都是設定成IRQ9,所以有沒有覆蓋都無所謂,但不一樣的時候會以MADT Table為主。)

-------------------------------
5. Debug
-------------------------------
a) 利用SE.EXE 工具在Windows下觀察GPE0_STS—General Purpose Event 0 Status Register
I/O Address: PMBASE + 20h 是否有變化,當有SCI event時,對應的bit=1,但是一般速度很快所以不易觀察有沒有SCI event,如果有看到變化則代表SCI 應該是正常的。

b) 利用EC BIOS提供的工具在Windows下讀取EC RAM/EC Cmd Data Port,一般EC 如果有進入ACPI Mode or 拉SCI pin之後,會把一些訊息留在EC RAM,例如某某bit=1=ACPI Mode Enable,或是EC Data Port有Qxx Number,而這些資訊可以問EC BIOS工程師,另外Qxx Number則可透過標準ACPI 66 cmd來得到。

-------------------------------
6.ACPI-defined port 66 commands
-------------------------------
0x80 Read EC (write 0x80 to port 66, write address byte to port 62, read data byte from port 62)
0x81 Write EC (write 0x81 to port 66, write address byte to port 62, write data byte to port 62)
0x82 Burst Enable (write 0x82 to port 66, read data byte from port 62 - the data byte is "burst ACK", value 0x90)
0x83 Burst Disable (write 0x83 to port 66, wait for port66.IBF=0)
0x84 Query EC (i.e. read SCI event queue) (write 0x84 to port 66, read data byte from port 62). When the data byte is 0, it means that the SCI event queue is empty.


如果EC有拉SCI pin,則利用自己撰寫的工具透過Port 66 cmd 0x84 讀取的時候,應該會讀取到0,因為如果SCI有發送且OS有收到,則OS會自己透過這個cmd把Qxx Number讀走,讀走後我們應該讀取不到值。

-------------------------------
6. 示波器(oscilloscope)
-------------------------------
在檢查所有暫存器設定與ASL Code設定後,在一切正常的情況下用SE.EXE 去觀察GPE0_STS 變化,但是一直沒有變化,所以懷疑OS沒收到SCI 或是EC 沒進入ACPI Mode,接著與EC BIOS溝通後,使用EC BIOS撰寫的wKX 工具去讀取EC RAM 的某個bit 來確定EC是否進入ACPI Mode,檢查後確認EC已經在ACPI Mode;

"wKx P80 Q43 J" <--送80 cmd到Port 66,讀取EC RAM Offset 43的位址的值,然後利用J參數顯示

接著利用wKx工具讀取Qxx Number "wKx P84",在EC 發送SCI訊號後(目前是利用LID變化或是AC/DC變化來使EC發出SCI訊號)讀取Qxx Number,結果發現還是可以讀取到Qxx Number,所以代表OS沒有收到SCI訊號。

在綜合上述實驗,決定請HW在EC 端與ICH9 端各拉一條線出來檢查訊號,因此利用示波器去觀察EC是否有拉SCI訊號,在觀察兩端訊號後發現,EC並沒有正確的把SCI訊號拉Low (Low Active),所以EC BIOS會檢查哪裡出現問題。

[我所知道的BIOS]->[PCI SCAN] 9

這次要提的是: PCI !

[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 << 31 ) // Type-1 PCI Configuration
+ (0x00 << 16 ) // Bus#0
+ (0x01 << 11 ) // Device#1
+ (0x00 << 8 ) // Function#0
+ 0x40 // Register#40
mov dx, 0xCF8 // Index Port 0xCF8 ~ 0xCFB
out dx, eax
mov dx, 0xCFC // Data Port 0xCFC ~ 0xCFF
in eax, dx // Get Data in EAX

如果是透過MMIO的方式則簡單多了:

mov esi, (MMIO_BASE) + (0x00 << 20) + (0x01 << 15) + (0x00 << 12) + 0x40
mov eax, [esi]

今天我們比較有興趣的是位在0×30~0×33的register, 在PCI Spec定義中, 這裡的值存放的就是expansion rom在physical memory中被decode到IO的位址, 比如說這個位址是0xFE000000, 如果你在0×30把bit0設為0×1(io->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]->[Shadowing] 8

[Why shadow BIOS ?]
在此之前所提的BIOS tasks,都是循著 CPU->NB->SB->SIO->ROM的路徑來達成的;意即: CPU是去BIOS ROM裡面抓code來執行 ! 明顯的一件事是: ROM access time > DRAM access time ! 且RAM access width is 32bits,而 ROM access width 通常為 16 bits. 因此,便有了所謂" BIOS Shadowing"的觀念產生 ! <- "performance consideration" !!!

[What is shadowing]
意即: 將部分BIOS CODE(in ROM)拷貝至DRAM中 ! (此後, CPU將從DRAM中抓code來執行...)這樣的動作便稱做 "Shadowing" ! 而該處的DRAM即稱為 shadow memory.

Shadowing 在BIOS 中是極為複雜的 kernel code part ! 想深入瞭解的人最好有 source code可 trace.

[When to shadow BIOS]
=> 當然是等記憶體穩定了,可以使用後,才做 ^_^

*因此,假如 DRAM sizing 有問題, BIOS shadowing必定有問題 !!!


以下是之前在其他文章中發表關於 shadow 的文章,再次節錄以供參考 !

[System Behavior before & after shadow]
說的更白話一點就是 : 當 Power On後, 跑完 system power-on sequence後, CPU會被 reset ( reset 指的是 CPU 的 內容會回到 "初始值" ); 而 CPU內部的 EIP (32-bit )的初值是 FFFFFFF0h, 所以, CPU的 第一個 code read 就是到 FFFFFFF0h fetch code...

這個 memory cycle 從 CPU發出, 先會經過 North bridge ; 此時, north bridge會說 "這不是我的"...然後,往 south bridge 丟 ; south bridge 會說, "這是我的",收下後丟給 ROM ! 所以, FFFFFFF0h 會被 ROM 接走 !!! ( 所以 前人才說 "硬體初始值要把0xFFFFFFF0 和 0x000FFFF0 要mapping到同一個地方", 這個地方就是.....ROM !!! )

之後, CPU所發的 cycle 都會照上述的方式一路抵達 ROM...由 CPU循著 fetch, decode, execute, store的順序作事情...

但到某一個階段前, BIOS的 code 會指示 " 要將 BIOS data 從 ROM 搬到 DRAM" ! 而在此階段之後, BIOS會設定 north bridge 暫存器, 告訴 north bridge "之後 CPU所發的 cycle 不可以不收而傳到 south bridge"....

自此之後, CPU 所發的 cycle 全部轉到 DRAM 中,由 CPU循著 fetch, decode, execute, store的順序作事情...

[Summary] 總而言之, BIOS 一開始是CPU讀取 ROM content來執行,之後是CPU 讀取 DRAM content 執行 ^_^

[補充][以提問的方式^_^]

[Q]: shadow memory到底是那一塊 ?
[A]: 以現在的電腦系統而言, shadow memory 是在UMA(upper memory area;傳統記憶體 640K以上至1M之間) "裡面"(part of it) ;在此UMA內可以分為 6 segments(64kB/each), total 384KB.

其中 C0000h~DFFFFh: for VGA BIOS and other devices' Option ROMs
E0000h~FFFFFh: BIOS ROM code

這兩個 blocks 本質是 memory;之後會被載以ROM content;因此,便稱為 shadow memory(好像: ROM在上面, memory在下面,是ROM的 "shadow"...)

[Q]: shadow memory 的內容 完全 "=" ROM content ?
[A]: of course NOT ! 除了 UMA不大以外,BIOS ROM因為必須support more and more functions/features,size已經越長越大;除此之外,BIOS ROM中也有部分module是經過壓縮的.(UMA不夠放...)

當BIOS shadow時,只會 copy necessary code(Ex. run-time要用的...etc)至 shadow memory ! 另外,已經執行過後的code也不會被載入. 因此,不是 1-1的copy...

[Q]: what Shadow enabled/disable mean in chipset ?
[A]: 前面提過, CPU要 fetch的code由 shadow memory 提供 or ROM提供,其根本關鍵在於 chipset's behavior ! 意即,NB必須做此決定 ! 所以,這機制一般是由NB來實現的.

NB內有所謂的 shadow registers. 當 shadow register enable時, memory cycle由 shadow memory 來回應;若 shadow disable,則由ROM回應.

意即:
000E0000h~000FFFFFh由 shadow memory replies if (shadow enabled)
000E0000h~000FFFFFh由 ROM chip replies if (shadow disabled)

若FFFE000h~FFFFFFFFh呢 ? 必定由ROM chip來回應(不然一開機怎麼辦?). 與 shadow disable/enable無關 !!!

*若使用 ru.exe 並檢視 memory space,可發現上述的情況.

[Q]: shadow有何好處 ?
[A]: 因為 slower ROM v.s faster RAM,所以放在RAM可以增加 system performance.

*各位可以發現,同樣的code放在 rom & dram中執行速度將大不相同 !

[Q]: shadow memory的 issue ?
[A]: 被 shadowed 的 memory area都會被設成 write-protected ! 因此,這塊area是不能 write 的.所以,若有程式會 "write"這塊,則會有問題 !!!

其實, BIOS shadow這段code大家不太會碰觸到...瞭解基本information即可.

有錯誤請指正 !!!

[附註]
[Q1] "BIOS的所有動作都必須先從ROM COPY至DRAM之後CPU才有辦法去執行"

Ans : 講簡單一點就是對CPU來說,他只負責提取指令,解碼指令,執行指令。至於是讀取到哪邊的指令他就不管了(IA32 架構)。例如CPU要讀取F0000h的指令來執行,那F0000h有可能是ROM也有能是DRAM。

[Q2] "那BIOS一開始的0E05BH是ROM的位置?還是DRAM的位置呢?"
==>0~4G 是指位址線的位址(因為Address bus = 32 bits=2^32),至於位址線上面是分配給DRAM還是ROM使用還是Others...就要看實際的硬體架構,例如IA32 架構就有其分配的方式。

==>所以某個位址線的位址可以被分配給ROM使用也可以分配給DRAM使用,還可以重疊一起使用,例如 F segment (000F_0000h)就是重疊使用,所謂的重疊就是就像是CPU 對F0000h存取的時候,他是存取到DRAM的資料還是ROM的資料 ? 答案就是看北橋....如果北橋在此時把這個位址是映對到ROM,那麼CPU讀取到的F0000h資料是ROM裡面的,如果北橋是映對到DRAM那麼CPU一樣是讀取F0000h但是會讀取到DRAM內的資料。

==> 所以0E05Bh 是位址線的位址。
==> 另外BIOS一開始的位址是在FFFF_FFF0 不是在0E05Bh...
==> BIOS的程式碼會去改變北橋設定,讓在不同階段的執行期間去存取到DRAM/ROM的資料,我們稱為shadow....例如從F0000h的 ROM讀資料,寫到F0000h 的DRAM中
==> 這邊說的都是IA32,其他架構要看Spec 說明。

星期一, 10月 08, 2007

[我所知道的BIOS]->[DRAM Sizing](2) 7

DRAM Sizing 的程序與chipset design息息相關,不同家chipset其DRAM sizing sequence亦不同.在此只列出 rough sequence以供參考. (真正的 detailed sequence仍須以各家的 code為準)

[假設]:
A. memory controller integrated into NB
=> NB PCI config space有一部份與DRAM相關
B. This chipset support 4 DRAM sockets(max.)
=> 存在 4 registers,分別代表此 4-socket DRAMs' information
=> 存在 4 bits ,分別控制 4-socket's CS(chip select;enable DRAM用的)

[程序]
1. Configure registers by DRAM frequency:
=> 許多DRAM相關的 registers(Ex. tRFC,tRP,tRCD,tWTR,CAS,...etc)都必須根據DRAM operating frequency來設定. (DRAM frequency 可由 CPU freq and CPU/DRAM ratio求得)

2. Execute Initial sequence for DDR(or DDR2)
=> DRAM spec都有列 initial sequence;既定的流程.

3. Set MAX-supported Size of this chipset for 4 sockets !
=> 因為"不知道"插進來的DRAM到底多大,所以假設: 每一個 socket上都有插DRAM,且size 是->此 chipset所 support的最大 size(Ex. 2G)

4. Do the followings for Socket 0/1/2/3 sequentially (<-此時,一次 "只 enable 1 socket"來做事)

1) check DRAM exist or NOT
=> 藉由簡單的 write-then-read pattern來判定 socket上是否有 installed DRAM

2) decide DRAM "TYPE" if DRAM exist
=> 假如DRAM有在socket上,則進一步去取得其 "TYPE" information
以DDR2 SDRAM為例,此步驟即:求取該記憶體的 (Bank,Row,Column,Side) information
Ex. 2x12x9's DRAM 且 double side ,則記憶體大小為 128MB

* 找DRAM information 有分 MA table & by SPD.

3) write this information to corresponding register

5. Configure registers by DRAM loading
=> 步驟4做完後,所有 installed DRAM已經找到. 此時,需要對一些與 "loading" 相關的DRAM registers做調整(因為: 不同數目的DRAM需要有不同的 driving strength !)

6. Remaining tasks:
=> disable one-page mode
enable dynamic reset
enable refresh cycle ( <- DRAM is ok to use ^_^ )

[注意事項]
1. 至此 Top memory( "可使用的記憶體上限" 已經...決定了 ^_^)
2. 在此 stage,並沒有對 DRAM 做嚴密的測試. 測試階段在後面的 tasks
3. 一般若 register config錯誤,或是 DRAM frequency不對(起因於clockgen config 錯誤),都會 hang在這個 stage ! 若系統僥倖 passed this stage並進到DOS,則可以再用 memory test utility來 verify DRAM is stable or NOT !!!

[補充]
在此stage(Sizing)完成之前, DRAM is not ready to use. 故撰寫此code時得全靠 CPU GPR(general purpose register)來傳遞參數 or return address ! 因此,得時時注意是否 register content 被改變 ( 因為 GPRs不多...)

但是,若是 activate CAR(Cache as Ram),則在此stage就可以使用 push/pop,所撰寫的code將較為模組化及彈性,也不必擔心 register content會被破壞了...
Ex. AMD Kx sizing code便是很早便使用 cache 來當作RAM,因此可以寫出 module code for sizing !!!

從前從前,Big-Endian與Little-Endian?

~轉載~

從前從前,記憶體是非常昂貴的. 資料寬度是8位元,一個記憶體位址存一個字,剛剛好.
但隨著科技進步,ALU已可做到16位元甚至32位元的運算,但記憶體實在太貴,所以只好想辦法偷機.
也就是用2個連續位址的記憶體來存16位元的資料.

問題來了,哪一個byte所存的是 b0~b7,哪個是 b8~b15呢?
所以: 低位元組放較低的位元資料,很合理阿
ex: 1234h byte0放34h,byte1放12h

或是: 低位元組放較高位數資料,也很好呀

ex: 1234h byte0放12h,byte1放34h

兩套標準就此產生.為什麼要有兩套標準?支持不同標準的廠商們異口同聲地說:
我設計處理器/電路比較好設計,不然你咬我阿.........

[我所知道的BIOS]->[DRAM Sizing] (1) 7

現在要提到的是BIOS POST中一個重要的 task : DRAM sizing !
它主要的工作是:讓我們所插的記憶體可以正常且穩定的運作 !

[Q] 為什麼穩定的記憶體這麼重要 ?
=> 因為,有太多東西需要存放其上了,例如: BIOS code(之後在 shadow部分會提到), 開機之後所需要的 device drivers and OS,etc...假如記憶體不穩,在存取 memory時無法得到需要的資料,或是根本連 read or write都不行,那麼便會發現: 不是 system hang(maybe randomly) during POST ,或是進OS後 blue screen...

所以,"BIOS DRAM sizing不好" 是系統不穩的原因之一. (地基都不穩了,怎能奢求其上的房子可以堅固 ^_^ )

在介紹 DRAM sizing之前,先稍微簡單說明 DRAM 的相關知識.(若有不足或錯誤之處,請不吝指正...)

1. DRAM chip 可看做是 square array;基本的單位 is cell. 每一個 cell 是由數個電晶體組成(depends on cell width;記得是: 1 bit 由一個電晶體組成,可以記錄 0 and 1的資訊; 1 cell 可能含 n bits;讀取DRAM cell屬於破壞性的讀取,因此讀取的同時常伴隨著 "refresh" <- 與 SRAM不同)

2. 要存取 DRAM chip 中的資料,必須提供 row and column address;這兩個 address是有先後順序的;意即: row address先送,然後再送 column address to chip.
(呼應前面所言: square array,類似 x,y 定址) 最後 指到的 data 將被放到 data bus上,CPU會讀走

*若有空可以上網查: 為什麼DRAM chip所需的 pins 是減半(half)的 ^_^

3. DRAM controller 現在一般都做在 chipset 中,Ex. NB內(AMD K8 CPU則是將 memory controller做在CPU內 ,for better performance);其工作便是 interfacing DRAM chip;充作其他 devices(Ex. CPU,DMA controller...etc) 與 DRAM chip 之間的橋樑 !

Ex. In BIOS ,寫下列的 code 欲 "read", "記憶體", "位置8處"的資料:
xor ax, ax
mov es, ax
mov edi, 00000008h
mov al, BYTE PTR es:[edi]

[00000008h] 是 programmer所"知"的 linear address,但DRAM chip 只認得 MA0~MAx,BA0~BA1..etc訊號,如何溝通 ? => 靠 DRAM controller 來轉換 !!!

4. DRAM access time => 從 DRAM chip 接到 address signals 直到 valid data 出現在 data bus上的時間(assume "read" memory),稱之;也是DRAM chip的特性之一.

5. 現今常見的 DRAM is DDR/DDR2 SDRAM. 所謂的 "S"DRAM 指的是 Synchronous DRAM,即 DRAM operation 都是參考一個 clock執行的;即與它同步(synchronous). DDR 指得是 Double Data Rate,亦即在 clock 的 rising and falling edge都可以傳資料. 而DDR2指的是: DDR的 "第二代" ! (別想成 DDR2 = DDR x 2 !!! 雖然剛好有些數值是兩倍的關係...)

Ex. DDR2 533(or called PC2 4200) =>
1. "2" means DDR2
2. 533 is transfer rate( 每一秒可做 533筆資料 transfer )
3. 4200 means: 533筆資料/s * 每筆 8 bytes( => 64 bit width) ~= 4200MB/s


下一章將介紹 DRAM sizing 的 flow/information !

[我知道的BIOS]->[系統資源] 6

在此,想先提一下所謂的系統資源(system resources). 在電腦的世界裡,所謂的系統資源約可分為四大類,亦即: DMA, Memory, IO, and Interrupts. (大家若是仔細檢視一下 [我的電腦]->[內容]->[硬體]->[裝置管理員]->[檢視]->[資源(依類型)],便可以發現我想表達的)

* DMA:
=> CPU可以說是系統的大腦;在沒有DMA時,CPU幾乎得參與所有的事情;但是有了DMA後,可以讓 DMA controller或是bus-mastering devices自己來執行data transfer from and to memory,CPU只在開始及結束時參與;如此CPU可以做其他事情. 典型的電腦系統有八個 DMA channels. 檢視 "資源(依類型)"中DMA的部分可以知道哪一個 channel被哪一個 device使用.

* Interrupt:
=> 周邊devices請求 cpu 服務的方式. 一般的電腦系統中有 16IRQs(IRQ0~15). 由兩個 cascade的8259所提供. 當有device透過 IRQx發 interrupt時, CPU會被告知;然後,CPU最後會得到對應於該IRQx的 service routine的 entry point,之後便跳到該處去執行ISR(interrupt service routine). 現在的電腦系統有發展出APIC mode(有別於原有的8259 mode),其目的在於提供更多的 interrupt inputs以及專有的interrupt機制.

在檢視 "資源(依類型)"中的interrupt可發現: IRQ 0/1/4/6/8/12/13/14/15其實是dedicated to specific devices使用的;而剩下的IRQs則是分給PCI devices共同/單獨使用. 若是APIC mode,則可以看到超過15的IRQ !

* Memory:
=>在此所謂的memory,並非指記憶體模組那種memory,而是: CPU memory addressing space ! 亦即,以32-bit CPU而言,可以定址到的 memory space is 2^32 = 4GB. 這麼大的空間就是一種資源 !因為,在此範圍內,CPU可以完全存取,而且,也是有限的 !那,要如何利用這麼大的資源呢 ? 方法就是所謂的 "Mapping(映射)".

舉FM為例,在收音機上一定有旋鈕可以調,亦即, FM的波段是有範圍的. 只有在此範圍,才能收到訊號(<-這也是資源). 然後,在此範圍內,要發射訊號的人,會先提出申請,看要使用那個頻率,經過認可後便可以使用該頻率波段了. 所以在此範圍內便可以聽到警廣,中廣,空中英語教室...等的廣播. (記住: "每個人" 都可以使用該資源中的"一部份",只要"被核准"...)

Memory space 也是一樣 ! 在廣大的 0~4G space中,也有很多人可以使用. Ex. 記憶體模組可以使用某一塊,BIOS ROM也可以使用某一塊, PCI devices也可以使用某一塊,APIC也可以使用某一塊,...etc. 常見的字眼 "Memory map" 就是闡述這樣的觀念 !

*I/O
=> 同理, IO 指的也是 CPU I/O addressing space. 也是一種資源. 現在 I/O addressing space 是 0000h~FFFFh,共64KB的範圍.

[Summary] 資源是有限的,要斟酌使用 ^_^

[補充memory部分]
假設系統插有1G記憶體,使用外部的顯示卡,且使用512KB BIOS ROM,則:

[Part1]
-memory space 0~(1G-1)被此1G記憶體所佔用;或說此1G記憶體被映射到memory space 0~(1G-1);只要CPU存取這個範圍,就會存取到此1G記憶體.

Ex. 在BIOS中寫:(前提: in big-real mode)
xor ax,ax
mov es,ax
mov esi, 00000000h
mov al, BYTE PTR es:[esi] ; access 此1G記憶體中 位置0處的資料 !

[Part2]
-memory space 1G~4G 則是由"其他人"所佔用,例如:(below are examples ONLY)
1.memory space 0xD4100000~D410FFFF是由 Ethernet card的 operational registers 所佔用
2.memory space 0xD4204000~D4204FFF是由 USB 1.1 host的 operational registers 所佔用
3.memory space 0xD4206000~D4206FFF是由 USB 2.0 host的 operational registers 所佔用
4.memory space 0xD4200000~D4203FFF是由 High Definition Audio的 Operational registers 所佔用
5.memory space 0xFEC00000~FECFFFFF是被 IO APIC 所佔用
6.memory space 0xFFF80000~FFFFFFFF是被 512KB BIOS ROM 所佔用
.....

只要CPU存取這範圍,則會access到 "對應" 的device registers.

Ex. 假設要access USB 1.1 HOST's operational register offset 0,則BIOS只要寫:
(前提: big-real mode)

xor ax,ax
mov es,ax
mov esi, 0D4204000h
add esi, 0 ; 0 means offset 0
mov al, DWORD PTR es:[esi] ; access


[Q] 那問題來了:CPU發了一個memory cycle,誰來決定/如何決定要給誰(記憶體 or USB 1.1 HOST OP registers)呢?

=>chipset一定知道系統插了1G記憶體,也會將此資訊,1G( = 40000000h ),記錄在內部register中.當cpu要存取記憶體而發 address: 00000000h 的cycle時,chipset會將 address與 1G比較;因為小於1G,則 "知道" 要發給記憶體 !

當cpu要存取USB OP而發 address: 0D4204000h 的cycle時,chipset會將 address與 1G比較;因為大於1G,則 "知道" 要發給PCI devices, Ex. USB host !

* 1G這個 information 的有一個名詞代表它: Top Memory ! 代表可用的記憶體的上限.

[結論]: 4G memory space 充斥著各式各樣的 "H/W registers"(假如把記憶體也視為 registers,ROM chip也視為registers.....)


Q:問個問題一下古時候, VGA 的memory 是被mapping 到0xA000 的一個64KB 的area,如果你的VGA card 有1MB 的memory 就無法全部mapping, 需要banking 的動作.在big-real mode 中, 如果還是1MB 的memory 會是多大 ,它會比mapping 從哪到哪?

A:就我所知,以前的VGA display會使用到 installed memory A0000h~BFFFFh間的範圍;這是屬於UMA(upper memory area)的一部份;其中A0000h~AFFFFh(64k) for VGA graphics mode memory;B0000h~B7FFFh for VGA mono text mode memory;B8000H~BFFFFh for VGA color text mode memory.

*上述的 三塊 memory 都是 video memory(or called frame buffer),用來儲存要顯示的image的記憶體

* 還記得組語練習中有 output color text to screen,其中所用到的 segment = B800h !!!
( for color text )

當program存取到這塊時,VGA card便會 read it and 負責將之顯示到 monitor !

現在的 VGA cards則是含有 built-in video memory;雖然不是使用系統記憶體,仍是被 mapped to A0000h~BFFFFh.(此時,很重要的一點是:系統記憶體的 A0000h~BFFFFh不再被VGA display用了....這點之後會提到,將被用來放 SMI code...)

你所說的1M memory,因為無法全部 mapped,所以有 bank switch來解決;那麼我的感覺是:還是一樣用 bank switch來解決 !!! 沒有變...

因為,我所知道的 memory map中在1M以下只有 A0000h~BFFFFh for Video card用的(你從 資源(依類型)中去看,也可以發現這範圍是給 display用的...) 而且,in big-real mode 也不會讓 1M memory可以完全 mapped,這是沒關係的 !

這個其實跟系統chipset無關, 跟VGA chip比較有關. 如果VGA chip不支援 linear frame buffer, 我想你只有用banking的方法做. 如果有支援, 正確方式是要透過VBIOS. VBE 2.0以後有定義linear frame buffer的地址位置.你可以呼叫 return VBE mode infomation 這個 function call 來取得位址.