小華的部落格: 2007

搜尋此網誌

星期一, 12月 24, 2007

VC++ 與Windows Registry 註冊表

昨天因為工作需要寫了一個小工具去修正註冊表內的鍵值,所以自己留下一些筆記在部落格。

註冊表的存取方式由微軟文件上說明得知,需要做3種步驟:
1. 得到Handle
2. 存取你要的鍵值
3.關閉Handle

而步驟1中,最主要是透過RegCreateKey與RegOepnKey來得到Handle,而這兩種方式的不同點在於RegCreateKey會去搜尋子鍵是否存在,如果不存在時會建立一個新的子鍵,而另一個API則是找不到就找不到。

步驟2中,我們如果要去設定鍵值ㄧ般都會使用RegSetValueEx() 其中它裡面的參數有分成不同型態的鍵值,像是REG_DWORD、REG_SZ...etc,使用時需要步驟1 所得到的Handle。

步驟3中則是去關閉你開啟的Handle,因此這3個步驟必須合在一起做。

底下是我把這3個步驟整理成副程式,使用時直接呼叫就可以了:
1.SetRegValueBy_REG_DWORD();
2.SetRegValueBy_REG_SZ();
3. SetRegValueBy_REG_MULTI_SZ();

void SetRegValueBy_REG_DWORD(LPCSTR szKeyPath,LPCSTR szKeyName,DWORD *dwData)
{
HKEY hk;
if (RegCreateKey(HKEY_LOCAL_MACHINE,szKeyPath, &hk))
OutputDebugString("error!");

if (RegSetValueEx(hk,
szKeyName,
0,
REG_DWORD,
(LPBYTE) dwData,
sizeof(DWORD)))
OutputDebugString("error!");

RegCloseKey(hk);
}

void SetRegValueBy_REG_SZ(LPCSTR szKeyPath,LPCSTR szKeyName,LPCSTR keyValue)
{
HKEY hk;
if (RegCreateKey(HKEY_LOCAL_MACHINE,szKeyPath, &hk))
OutputDebugString("error!");

if (RegSetValueEx(hk,
szKeyName,
0,
REG_SZ,
(BYTE*)(LPCSTR) keyValue,
strlen(keyValue)))
OutputDebugString("error!");

RegCloseKey(hk);
}

void SetRegValueBy_REG_MULTI_SZ(LPCSTR szKeyPath,LPCSTR szKeyName,LPCSTR keyValue)
{
HKEY hk;
if (RegCreateKey(HKEY_LOCAL_MACHINE,szKeyPath, &hk))
OutputDebugString("error!");

if (RegSetValueEx(hk,
szKeyName,

0,
REG_MULTI_SZ,
(BYTE*)(LPCSTR) keyValue,
strlen(keyValue)))
OutputDebugString("error!");

RegCloseKey(hk);
}


由副程式內可以得知,我是存取主鍵"HKEY_LOCAL_MACHINE"內的子鍵,所以如果要存取不同的主鍵時,要修改副程式內的主鍵。

底下是呼叫時的範例:

BOOL MyPatch()
{
LPCSTR szKeyPath1="SOFTWARE\\Microsoft\\WindowsNT\\MyTest";
LPCSTR szKeyName1="Label";
DWORD dwData=11;

SetRegValueBy_REG_DWORD(szKeyPath1,szKeyName1,&dwData);

return 0;
}

我Win32 的程式不好,雖然上面的程式碼可以用,但是如果有發現錯誤的地方,還是請大家幫忙指正並且告訴我~~~感恩喔!

星期四, 12月 20, 2007

A20 開關 v.s 回繞

很多剛入行的朋友問我A20開關的知識,我這邊就整理一下相關資訊,讓大家查閱的時候可以有個參考。

首先先說明相關的CPU的工作模式:在目前x86下面工作模式與A20有關的就是保護模式跟真實模式。

真實模式下,它允許定址到1MB記憶體,所以超過1MB的位址(FFFFFh)要繞回去00000h,這就是所謂的回繞

保護模式下則分不同時間點來談,在80286 時,位址線增加到24 pin,所以可以定址到16M,而為了向下相容,所以設計了一個開關A20 Switch來控制A20~A23,當A20=0時,強制把位址線歸零,當A20=1時,可進位

後來因為這個開關要Reset才能回復狀態,因此出現一個新的問題就是進入保護模式後,要重新開機才能回到真實模式。

於是有人就想說找一個設備,然後控制這個設備就可以做A20的開與關,因此找上了8042 KBC,所以以後開關A20 Switch時,只要去設定8042就可以了,因此解決了每次回真實模式都要重新開機的問題。

後來80386 之後,CPU的設計可以直接從保護模式切換回去真實模式,但是為了向下相容,所以還是一值保留這個設計。

慢慢的這個留下來的設計又出現新的問題,x86設計師可能想說每次都透過8042去開關速度有點慢,因此後來又提出了Fast A20 的設計,簡單說就是透過Port 92h 直接設定A20 switch開關。

至於這個被保留下來的設計,還有沒有當初的功能我也沒去測試,不過已經變成一種習慣,就是進入保護模式要去開關A20 switch。

以上大致上就是x86對於 A20的歷史,有興趣的人可以多去找找ㄧ些資料來看,或是做做小實驗,看看A20 switch不開的時候,會發生什麼事情 ^^.

星期三, 12月 19, 2007

純手工打造你自己的x86 BIOS(4)

上ㄧ篇文章我已經針對我的實驗做了敘述,這裡我就針對實際上我的程式碼撰寫的內容做一個介紹。

在程式碼的撰寫中,其實我只有使用了簡單的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 Boot Specification

最近有些朋友問我有關BEV以及BCV的相關資訊,這邊轉貼一篇之前收集的文章中的部分內容,希望對大家有幫助。

原文章出處:http://tw.myblog.yahoo.com/jw!T20aSgeaCQdebnoX0CAb9Xk-/article?mid=17

~以下是轉貼內容~
BIOS Boot Specification
完整的文件可以參考
http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf
以下為一些重點整理
BBS (BIOS Boot Specification) 是用來規範 BIOS 如何選擇啟動裝置。它包含了
1. 辨識系統中的 IPL (Initial Program Load) 裝置
2. 根據使用者的選擇,尋訪每個裝置並檢視它是否能夠啟動系統

IPL
IPL 指的是可以啟動載入並執行作業系統的裝置。他包含了像是 Floppy, Hard drives, CD-ROM, PCMCIA conrtollers/cards, PnP Cards, Legacy cards 甚至像是 Network, Serial port, Parallel port 等等可開機的實體或虛擬裝置。
所有的 IPL 可以被歸類成下列三種
1. BAID
2. PnP Card (可再細分為 BCV 和 BEV 兩種裝置)
3. Legacy IPL Device

BAID (BIOS Aware IPL Device):
此類 IPL 需要 BIOS 的程式碼支援,來提供它啟動系統的能力。通常啟動的程式碼內建於 INT 19h (BIOS Bootstrap loader) 的服務之中。常見的裝置如下:
First floppy drive, First ATA Hard drive, PCI ATA card drive, ATAPI CD-ROM drive, PCMCIA controller bootable card, Ethernet controller code embedded in BIOS
PnP Cards:

此類 IPL 裝置,必須附加 option ROM 於 C0000h-EFFFFh (2K boundary)。而且在 Option ROM 中必須有 PnP Option ROM Header (Table 2)。另外,開機相關資訊會被記錄在 PnP Expansion Header (Table 3),在此表格中,包含了 BCV 或 BEV 的指標。

BCV (Boot Connection Vector):
BCV 是一個指標,指向 Option ROM 中的某一段程式碼。這段程式碼負責執行裝置的初始化、偵測硬體 (例如是否有 SCSI 裝置連接到系統) 或者在必要時 Hook INT 13h 的服務 (Disk I/O)。常見的有:
PnP SCSI card drive, NoN-PnP card PnP Expansion Header
BEV (Bootstrap Entry Vector):
BEV 是一個指標,指向 Option ROM 中負責載入作業系統的一段程式碼,並在必要時 Hook INT 18h 或 INT 19h 的服務。通常於網路卡裝置的 Network Remote Boot 時使用。常見的有:
PnP Token Ring card, PnP Ethernet card, NoN-PnP card PnP Expansion Header

Legacy IPL Devices:
此類裝置為標準的 ISA Card,其包含了一個 Option ROM 於 C0000h-EFFFFh (2K boundary)。此類型的裝置於 Option ROM 並沒有 PnP Expansion Header 的相關資訊。在它的 Option ROM 被 BIOS 找到時,會先執行一段初始化的程式。這段程式執行期間,會根據需要來 Hook INT 19h, INT 18h 以及 INT 13h。

IPL Table
每個 BAID 以及 BEV 裝置必須在 IPL Table 中有一個相對應的欄位
範例
0: Floppy A:
1: Hard Drive C:
2: CD-ROM
3: BEV #1
4: BEV #2

IPL Priority
IPL Priority 決定 IPL 開機的順序。它存在於非揮發性記憶體中,並且可以讓使用者修改。在 INT 19h (載入作業系統) 呼叫中,它必須能夠被取用,並且根據表格中的順序來進行開機的程序。

BCV Priority
在 BIOS INT 13h (Disk I/O) 的服務之中,磁碟機代號 00-7Fh 為 Floppy Disk, 而 80-FFh 為 Fixed Disk。而這些代號和實體磁碟的對應必須在 BIOS 中完成。另外值得注意的一點就是,由於只有第一台 Floppy 和第一台 Fixed Disk 可以用來啟動 (代號 00h 以及 80h),所以根據不同的啟動設定,也必須將 INT 13h Hook 的順序作調整才能夠順利開機。
舉例來說,如果 ATA 硬碟占用掉 80h,而 SCSI 只能占用 81h 之後的磁碟機代號的話,那麼 SCSI 硬碟就不能作為開機的硬碟了。
範例
BCV Table
0: ATA Drives
1: Legacy Cards
2: BCV #1
3: BCV #2
BCV Priority
0: 2 (BCV #1)
1: 0 (ATA Drives)
2: 1 (Legacy Cards)
3: 3 (BCV #2)

INT 13h 支援的裝置有下列幾種
1. ATA Drive
2. PnP Cards with BCVs
3. Legacy Cards with Option ROMs
4. Hard Drive BAID

關於 INT 13h 的幾個重點
1. 當 INT 13h 被 Hook 時,舊的 INT 13h Vector 必須被保存
2. 已經安裝的硬碟數目必須被保存在 BDA 0040:0075
3. 第一個安裝的硬碟會得到 80h 的代號,這也代表著它是開機硬碟
4. 一旦安裝到 INT 13h 之後,就不能被解除安裝

INT 19h
在這個服務呼叫時,所有的 IPL 已經被辨識,並且 INT 13h 的裝置也都已安裝完成。在呼叫之後,它會根據 IPL Priority 中的裝置,呼叫其 Boot handler。第一個呼叫成功的裝置會負責載入作業系統。如果全部的裝置都已呼叫過後還沒有成功載入作業系統,它會顯示一個錯誤訊息,並且等待重新開始。

INT 18h
原本的 INT 18h 的動作是將控制權交給 BIOS,顯示一個錯誤訊息並且等待使用者按下按鍵後進行下一個動作。而在 BBS 中重新定義 INT 18h 的功能為錯誤回復的中斷向量。這裡要注意的是 INT 18h 並不會返回至呼叫它的程序,並且在一開始就將堆疊重新設定。

Boot Menu (Optional)
在 POST 期間,部份 BIOS 充許使用者使用一個特定的 Hot Key 來呼叫 Boot Menu,並用它來改變 INT 19h 所使用的啟動裝置。這裡要注意的是,這個動作並不會改變 IPL Priority 的內容,它只是單純地選擇啟動的裝置。

一些相關的表格
Table 1 - IPL Table and BCV Table Entry Data Structure
Name Offset Size Description
deviceType 00h WORD See definitions below
statusFlags 02h WORD See bit definitions below
bootHandler 04h FAR PTR Far pointer to address of boot handler
descString 08h FAR PTR Far pointer to ASCIIZ description string
expansion 0Ch DWORD Reserved for future expansion

deviceType:
00h = Reserved
01h = Floppy
02h = Hard disk
03h = CD-ROM
04h = PCMCIA
05h = USB device
06h = Embedded network
07h..7Fh = Reserved
80h = BEV device
81h..FEh = Reserved
FFh = Unknown

Table 2 - PnP Option ROM Header
Offset Size Value Description
00h BYTE 55h Signature byte 1
01h BYTE AAh Signature byte 2
02h BYTE Varies Option ROM length in 512-byte blocks
03h DWORD Varies Initialization entry point
07h 17BYTES Varies Reserved.
18h WORD Varies Offset to PCI data structure
1Ah WORD Varies Offset to expansion header structure

Table 3 - PnP Expansion Header
0ffset Size Value Description
00h BYTE '$' Signature byte 1
01h BYTE 'P' Signature byte 2
02h BYTE 'n' Signature byte 3
03h BYTE 'P' Signature byte 4
04h BYTE 01h Structure revision
05h BYTE Varies Length (in 16 byte increments)
06h WORD Varies Offset of next header (0000h if none).
08h BYTE 00h Reserved
09h BYTE Varies Checksum
0Ah DWORD Varies Device identifier
0Eh WORD Varies Pointer to manufacturer string (Optional)
10h WORD Varies Pointer to product name string (Optional)
12h 3BYTES Varies Device type code
15h BYTE Varies Device indicators
16h WORD Varies Boot Connection Vector (BCV), 0000h if none
18h WORD Varies Disconnect Vector (DV), 0000h if none
1Ah WORD Varies Bootstrap Entry Vector (BEV), 0000h if none
1Ch WORD 0000h Reserved
1Eh WORD Varies Static resource information vector, 0000h if none

Table 4 - PCI Data Structure
00h BYTE 'P' Signature byte 1
01h BYTE 'C' Signature byte 2
02h BYTE 'I' Signature byte 3
03h BYTE 'R' Signature byte 4
04h WORD Varies Vendor Identification
06h WORD Varies Device Identification
08h WORD Varies Pointer to Vital Product Data
0Ah WORD Varies PCI Data Structure Length
0Ch BYTE Varies PCI Data Structure Revision
0Dh 3BYTES Varies Class Code
10h WORD Varies Image Length
12h WORD Varies Revision Level of Code/Data
14h BYTE Varies Code type
15h BYTE Varies Indicator
16h WORD Reserved

Flat Memory Mode

最近在逛ㄧ些網站看到下面這篇文章,在講所謂的Flat Memory Mode,由於資料說明的很詳細,所以就收集文章在自己部落格中,有興趣的朋友可以去原作者部落格看這篇的完整文章,以下是轉貼部份內容。

原文章出處:http://w3tony.blogspot.com/2006/04/flat-real-mode_114619442075796383.html

~以下是轉貼內容~
Flat real mode 或者是 unreal Mode,名詞很多,不過主要的用處都一樣,在 Real Mode 存取超過 1MB 以上的記憶體空間,下面就來介紹怎麼進入 Flat Real Mode。

要能夠使用 32bit 的 segment,首先需要進入保護模式,最簡單的方法是:

cli
mov eax,cr0
or al,1
mov cr0,eax
sti

cli 的目的是將中斷遮蔽,避免臨時的中斷服務打斷我們的工作,透過設定 CR0 的 PE bit 就可以進入 Protected Mode,接下來我們需要 descriptor table 才能夠將 segment limit 從 64K 換成 4G,

DataSel = 8
GDT dw 4 dup(0) ; NULL descriptor
dw 0ffffh,0ffh,9200h,8fh ;Data segment descriptor
GDT_ptr label fword
dw offset GDTptr-1-offset GDT
dd offset GDT

DataSel 指 Data segment entry 的 selector,設定為 8 表示我們的 entry 是在 NULL Descriptor 的下一個位置,GDT_ptr 用來存放 GDT Table 的長度以及 GDT Table 的 Linear Address,再來我們要將 GDT Table 載入到 gdt 暫存器,方法如下

mov ax,cs
mov ds,ax
movzx eax,ax
shl eax,4
add dword ptr ds:GDT_ptr+2,eax ;將 GDT 的 Linear Address 存入 GDT_ptr
lgdt fword ptr ds:GDT_ptr ;載入 GDT table

cli
mov eax,cr0
or al,1
mov cr0,eax
sti

然後需要一個 jump 的動作,目的是清除 instruction queue 的 real mode instruction:

mov ax,cs
mov ds,ax
movzx eax,ax
shl eax,4
add dword ptr ds:GDT_ptr+2,eax ;將 GDT 的 Linear Address 存入 GDT_ptr
lgdt fword ptr ds:GDT_ptr ;載入 GDT table
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
jmp short pmode ; Clear the execution pipe
pmode:
mov ax,DataSel ; 進入保護模式
mov ds,ax ; 設定 selector limits 為 4 GB
mov es,ax
mov fs,ax
mov gs,ax

現在我們已經進入 Protected Mode,不過這樣只是單純的保護模式,還不是 Flat Real Mode,所以我們還需要一個步驟,返回 Real Mode,方法如下:

mov ax,cs
mov ds,ax
movzx eax,ax
shl eax,4
add dword ptr ds:GDT_ptr+2,eax ;將 GDT 的 Linear Address 存入 GDT_ptr
lgdt fword ptr ds:GDT_ptr ;載入 GDT table
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
jmp short pmode ; Clear the execution pipe
pmode:
mov ax,DataSel ; 進入保護模式
mov ds,ax ; 設定 selector limits 為 4 GB
mov es,ax
mov fs,ax
mov gs,ax
jmp short Real_mode
Real_mode:
clc;我們已經返回 real mode了並且將 carry flag 清除,通常這代表正確執行

sti ;解除中斷遮蔽
ret

進行到這,我們已經將 fs 與 gs 設定成 4G 範圍的 segment,試試看使用
mov eax, 6400000H
mov edi, eax
mov eax, dword ptr gs:[edi]

能不能讀取到 100MB 的記憶體內容,是不是很有趣?Flat real mode 的應用很多,不過有個很大的缺點,執行的 code 還是只能放在 1MB 的範圍,只有 data 才能存取 4GB 的空間。往後我還會繼續介紹怎麼返回真實模式,有許多注意事項是常常被人乎略的,尤其是當我們需要重複進入跟退出保護模式時,很容易破壞暫存器的設定,例如 SS:SP 就是最常忘記的地方,下次有機會再繼續討論這個部份。

延伸閱讀:
Flat real mode
http://www.df.lth.se/~john_e/gems/gem0022.html
Flat real mode interface http://www.programmersheaven.com/zone5/cat19/1365.htm

星期四, 12月 06, 2007

BootBlock 程式碼流程

有關於P Code的BootBlock 相關流程在下面有詳細的解釋,如果你在追蹤程式碼的時候有問題,可以參考下面流程。

搜尋討論區's Keyword: "關於boot block... "

~轉載自程式設計俱樂部討論區~
1. Power on
2. BB's entry point
3. check shadow enable or NOT
if Enabled then jump far to F000:E05B
else jump far to BB tasktable ( <- step 4 )
4. many tasks within BB phase
...
check if BIOS checksum fails or specific device attached ?

if Y then jump to BB flashtable and execute crisis
else jump to POST entry point ( < step 5 )

5. many tasks within POST phase
...
...
shadow BIOS and enable shadow (address F000:FFF0 is set EA 5B E0 00 F0)
...
...
Boot to OS or DOS

如同前人所言,只是檢查是否 shadow有開或關. 因為:cold reset及 s/w reset都會進來這裡 !

Case 1:
s/w reset 只對CPU reset,chipset setting仍保留,如此將導致: shadow still enabled when s/w reset !!! 也導致 s/w reset後 CPU是到 DRAM裡抓指令執行,所以在那邊放了 EA 5B E0 00 F0 (最後將跳到 POST entry point)

Case 2:
cold reset 連同 CPU/chipset/others 都 reset,因此 shadow is disabled.故 reset 後CPU是去 ROM抓指令. 在該處也有 jump instruction(只是它會讓 CPU跳到BB去執行...非 POST entry point)

Notes:
1. "why shadow enabled or NOT" 會影響 "去哪裡抓指令",請查閱本網站的文章.
2. shadow control 會 embedded 在 chipset內.故 chipset 被 reset 會讓 shadow 是 disabled

* trace 過程中倒是發現:不管 BB entry point 或是 POST entry point,1st instruction都是 cli ( machine code: FA ) ^_^

星期三, 11月 28, 2007

純手工打造你自己的x86 BIOS(3)

在前面兩篇文章中的描述中其實大家就應該可以知道我的實驗環境由幾個部份所組成,所以我這邊假設 "如果我是ㄧ個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。

星期二, 11月 27, 2007

純手工打造你自己的x86 BIOS(2)

電腦發展至今已經經過了很長的時間,許多遇到的問題也都被ㄧ些前輩解決了,因此目前學校或是市面上的書籍幾乎都是講解如何在一個"現成且成熟"的平台上發展。

例如很多書會教你寫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),所以很多地方沒考慮進去,希望各位有其他意見請告訴我,謝謝!

~未完待續~

星期日, 11月 18, 2007

純手工打造你自己的x86 BIOS(1)

存放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或是組合語言語法就可以了,所以算是基本入門,重點還是在我ㄧ直強調的地方 "懂架構才是重點,程式語言只是工具而已"...。

~未完待續~

星期四, 11月 15, 2007

EFI Framework 概述

如果有下載Intel EFI Spec的人就知道每次提到EFI的時候就會有一個很大的綠色的H,這個就是EFI 的framework。

什麼是Framework呢? 這邊就簡單說一下整個EFI framework架構。

我個人猜想,當初Intel 開發EFI其實只是為了要擴充BIOS的功能,因為在Legacy BIOS的年代,很多的東西都沒有模組化,因此當硬體或是Platform有比較大的變動的時候,對於整個BIOS開發的時間就會延長,那種感覺就好像是你每次都要對一個新的硬體重新寫一次你的BIOS程式碼,很沒有效率。

另外在Legacy BIOS年代,所有的BIOS程式碼的開發幾乎都是不同的BIOS vendor與Chipset 廠商ㄧ同合作,因此不同家的BIOS Vendor對於相同Chipset 廠商所寫出來的程式碼的穩定度就會不同,這對於 Intel 來說就等於要多花好幾倍的時間去跟不同BIOS Vendor 來討論以及處理問題。

因此,假如Intel 能夠把底層的BIOS程式碼變成模組化容易抽換,那麼BIOS在開發的過程中就會快速以及方便許多,而這種概念就像是Windows裡面的HAL 層的概念,簡單說在Windows系統中實際存取硬體是透過ㄧ個叫做HAL介面的處理,所以當Windows想要在不同的硬體上執行的時候,他只要把HAL的介面換成新的硬體的處理方式就可以了,而在Windows可以不用再重新改寫,例如你把Windows拿到Apple上面去執行,對於微軟的工程師來說,只要把HAL從新改寫就可以了。

而EFI的Framework 就像是HAL,Intel 本身提供了一些Protocol以及一些Lib來存取他們的硬體,而這一層就叫做Framework。對於Intel來說,不管你是哪一家的BIOS Vendor就不會再出現A廠商存取Intel Chipset有問題而B廠商不會,因為最底層都是Intel 自己負責。

而建構在Framework 上的一些功能就是各家BIOS Vendor自己去負責,感覺就像我之前說的,Inetl 留下一些地方給BIOS Vendor填寫他們的程式碼,然後BIOS Vendor在留下一些地方給OEM/ODM BIOS填寫ㄧ些程式碼,彼此關係就是一層一層環環相扣。

這邊還要提到EFI Framework 除了前面說的那些之外,他還提供了一些Boot Flow的控制,這就像是說從Power On--->POST--->Boot to OS的一些流程的控制也是由這個Framework 提供,感覺就像是你寫了一個main{},而裡面的FunA()/FunB()/FunC() 的先後順序的執行你也都寫好了,之後FunA() 內要填什麼樣的子程式碼就屬於BIOS Vendor跟OEM/ODM BIOS自己決定了。
//--------------------------------------------------
// EFI Framework 的概念與C語言對應的示意圖
//--------------------------------------------------
#include <--Intel提供的函數
main() <--Intel 提供的Boot Flow
{
Dispatch FunA(); <--SEC
Dispatch FunB(); <--PEI
Dispatch FunC(); <--DXE
Dispatch FunD(); <--BDS
...
}

EFI Framework還有另一個優點就是移植性高,例如Intel 可以把整個EFI Framework概念移到嵌入式系統上去實做BIOS,這樣子他們能夠開發的市場就會越來越大。

前面提到這些都是Intel提供的EFI Framework,那麼AMD/其他廠商怎麼辦? 對,我也在想這個問題,由上面的說法可以看出Intel 的野心,他想把原本BIOS Vendor做的事情自己拿來做,為了不讓人家知道太多Chipset內的秘密,他自己寫Chipset的函數並做成Framework給BIOS vendor使用,所以我個人在思考幾個問題:

a) 假設不同 BIOS Vendor 都使用相同的函數的情況下,彼此的優缺點是不是只剩下誰提供的OEM/ODM Features比較多 ?

b) 假設不同 BIOS Vendor 都使用相同的Framework下,當底層換成AMD或是其他廠商後,彼此的優缺點是不是只剩下誰對不同廠商的支援度比較高,市場佔有率就比較高?

c)假設OEM/ODM BIOS 都使用相同的Framework後,開發時間縮短相對的被取代的性質是否也相對提高?

d) Others..

以上大致上就是個人對於EFI Framework 的一些理解跟想法,如有誤請先進不吝指正,謝謝!

星期三, 11月 14, 2007

BIOS 開發環境

這篇文章主要是概述 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開發環境,你需要哪些工具,還有怎樣子做。

星期一, 11月 12, 2007

Debug.com 查看記憶體資料的方式

ㄧ般我們都知道Debug.com 可以寫一些組合語言程式、除錯以及查看一些資料,但是要如何用呢?

這邊就簡單描述幾個基本的Debug 用法,用來查看一些BIOS留在記憶體中的一些資訊。

ㄧ開始我先介紹一下指令的用法以及我們要搜尋的內容是哪些:
1) 在執行Debug.com 後會出現"-" 的提示訊息,意思是說"換你了"
所以我們可以在提示訊息後面開始鍵入我們要的指令來達到一些目的
例如:
指令 S :搜尋記憶體內的內容,語法是 S <起始位址> <範圍> <搜尋的內容>
-S E000:0 ffff '1234' <--搜尋E0000h~Effffh 內的記憶體,找'1234' 指令D : 傾印記憶體內容,語法 D <起始位址> <結束位址,可略>
-D E000:0 <--查看E0000h內的記憶體內容 -D E000:0 100 <--查看E0000h~E0100h的記憶體內容 2)而這篇文章的範例中我們要找的是DMI Table 跟ACPI Table 的Entrypoint a.在搜尋DMI Table時我們要先找到SMBIOS的關鍵字 '_SM_' 所在位置,然後在經由這個位址找到實際DMI Table擺放的位址。 b.在搜尋ACPI Table的Entrypoint時,只要在E0000h~FFFFFh中搜尋關鍵字就可以找到了。 上面所提到的關鍵字都是標準的SMBIOS/ACPI Spec中所提到的,所以BIOS會依照這些Spec去建立一些資訊,並把他們擺放在1MB以下的記憶體中,也因此我們可以利用這些關鍵字去找到BIOS到底在這些Structure中填入了什麼樣的資料。 以下就是實際範例: 1.首先先點選"開始"-->"執行" 並且鍵入"cmd" 後按下"確定"按鍵:


2.依照下圖鍵入相關指令你就可以查看DMI Table Info:

上圖可以看出在記憶體F000:6D20 的地方有關鍵字'_SM_',然後使用D 指令去看這個記憶體的內容,再依照Spec中提到的偏移位址找到DMI Table擺放位址

接著ㄧ樣使用D指令去看DMI Table的內容,其中00 代表Type 0,18代表Type 0的長度...etc,其他就對照著Spec看就可以了。


3.依照下圖鍵入相關指令你就可以查看ACPI Table 的 EntryPoint:
上圖可以看到搜尋E0000h~Effffh找不到關鍵字'RSD PTR',所以接著搜尋F0000h~FFFFFh。

在找到關鍵字的位址後,ㄧ樣使用D指令去查看記憶體內的內容,在畫面右邊你可以看到"RSD PTR",他對應的記憶體內容就是 52 53 44 20 50 54 52,其他的部份你就可以查看ACPI Spec然後看其他欄位到底代表什麼意思。

[結論]

這篇文章最主要目的是簡介Debug.com 如何去查看BIOS所留下來的內容,有助於了解BIOS撰寫時你寫了什麼樣的程式碼,留下了什麼資料在哪一塊記憶體中。

※上面所提到的記憶體位址會依照不同BIOS而有所不同,所以你在你的電腦內看到的記憶體位址也會與本文中的範例不同。

星期三, 11月 07, 2007

ACPI Spec Overview

這篇文章最主要是說明一些ACPI Spec中基本架構的概念與一些基本的省電作法。

在系統中,硬體在正常情況下就會指示出電源系統進入Sleep時可以支援的省電層級,ㄧ個具有ACPI 功能的OS 是可以透過下列幾個項目來決定系統電源最低能夠支援的省電層級:

1. ACPI’s DSDT
2. ACPI’s SSDT
3. ACPI’s PSDT

一般來說OS與BIOS會依照ACPI規範去實做這部份的省電層級Sx。


ACPI Overview
ACPI 規範在OSPM中是一個主要的技術,ACPI主要有3個Runtime 元件:
1.ACPI Tables
在ACPI Tables中最主要是描述一個Platform上面的硬體介面資訊,這些描述包含了一些固定的暫存器位址,或是說明一些Register Blocks,另外ACPI Tables 中還包含了一些OS可以執行的AML code ,OS會透過自己的AML Interpreter 來執行這些AML code。

2.ACPI Registers
在ACPI Registers中是實體的硬體介面,這些暫存器就是被描述在ACPI Tables中的那ㄧ些。

3.ACPI BIOS
在ACPI BIOS中,他是一個符合ACPI規範下的BIOS,典型情況下,他會做系統開機的動作以及實做Sleep 介面的支援(BIOS支援S3/S4/…)

OSPM 最小需求
OSPM的最小需求為:
1.Power Management Timer 用來提供時間的計數,用來檢查系統是否在閒置。
2.一個Power 或是Sleep Button
3.一個real time clock alarm ,用來從Sleep state產生硬體Wakeup event
4.實做一個支援到某個Sleep State層級的OS系統
5.可以經由SCI 發出中斷事件
6.有GPE 硬體暫存器來產生一些通用硬體事件
7.ACPI BIOS有提供ACPI Tables
8.有一個”User-accessible fail-safe”機制,讓系統Reset 或是Shutdown
9.所有的Root PCI Bridge都要有 _PRT Method 來設定PCI interrupt pin to interrupt vector

Power States
在OSPM架構下,作業系統可以直接的對所有系統和設備做Power States 轉換,不過這部份就與使用者如何判定,以及應用程式如何控制,或是OS如何將設備轉換進入低電源狀態或是離開有關,另外還有設備如果沒在使用的情況下就把電源關閉…等的情況。一般來說,OS都是參考應用程式的設定或是使用者的設定來當作進入省電模式的依據,OS使用ACPI去控制硬體的電源狀態(Power-states)。

Global Power States
從使用者可見的環境下,系統電源狀態分成G0/G1/G2和G3 ,而這些狀態切換參考是依據:
a) 應用程式還在執行嗎 ?
b) 外部事件與應用程式回應的時間長短多長? 過長可能就沒在用了
c) 電源消耗量為何?
d)OS 重新開機後要求要回到工作狀態G0 ?
e) 是否安全的拆卸系統 ?
f) 電源狀態是否經由電氣的改變可以進入或是離開電源狀態? (是否硬體支援切換?)

而個別的States如下所示:
G0—Working
G1—Sleeping
G2 (or S5)--Soft Off
G3--Mechanical Off


Working & Sleeping States
在一般環境下,系統介於Working & Sleeping States的切換較多(G0<-->G1 互換),其中當系統在Sleep States(G1)時又要分成兩部分來談,分別是
a) Device 支援的電源省電層級(Dx-States)
b) Processor 支援的省電層級 (Cx-States)

因為不同的情況下,可能要省電的是設備、處理器或是兩個設備都要,所以底下分別談論他們的省電狀態。

Device Power States
i) D0--Fully-On : 設備可以完全回應,正常工作
ii) D1 : 依照不同Device class有不同規範,一般都是會節省一些電源
iii) D2: 依不同Device class有不同規範,但並非大多數設備都有支援,而這階段除了節省電源外,通常會關閉一些設備上的功能來達到更省電的情況。
iv) D3—Off : 把電源從設備移除,完全關閉設備電源,一般重新啟動設備通常會需要比較長的時間。
不同的設備通常會有不同的電源省電狀態,通常這些電源狀態的切換都可以經由他們的驅動程式或是軟體來切換,一般都是經由設備驅動程式送Command 到設備來切換他們的模式。

Processor Power States
處理器的電源狀態(Power States),Cx States 是指處理器的電源耗損以及Thermal 管理,而這些都是在G0 States 內所定義的:
a)C0 Processor Power State : 處理器正常處理Instructions。
b)C1 Processor Power State: 處理器有比較低的Latency,此時的硬體Latency 只保留足夠OS在不考慮Latency 情況下可以正常執行軟體,而當處理器進入這個”non-executing”狀態時,只有他自己知道,而沒有軟體會顯示這個狀態。
c)C2 Processor Power State: 處理器最差的Latency會定義在FADT Table,OS自己會決定何時要用C2來取代C1 以達到更省電的狀態,而當處理器進入這個”non-executing”狀態時,只有他自己知道,而沒有軟體會顯示這個狀態。
d)C3 Processor Power State : C3 狀態中的最差的Latency 也是定義在FADT Table,OS自己會去切換狀態,當處理器在C3狀態時,原本處理器負責的Cache狀態會忽略任何的探測(Cache snoop),所以OS要自己負責。

ASL Code Overview
Device Power Management Objects
1) 前面說過,每個Device支援的省電狀態不同,所以必須告訴OS在Sx與Dx的對應關係,而這部份是透過"_SxD"來決定。

2) 而設備的電源管理是透過"_PRx" 對應”_PSx”來決定,另外”_PRW”則不對應”_PSx”,而”_PRW”是一個控制物件,控制設備是否Enable/Disable從Sx Wakeup功能

附錄APPENDIX
Device Power Management Child Objects & Object Description

_IRC Object that signifies the device has a significant inrush
current draw.
_PRW Object that evaluates to the device's power requirements in order
to wake the system from a system sleeping state.
_PR0 Object that evaluates to the device's power requirements in
the D0 device state (device fully on).
_PR1 Object that evaluates to the device's power requirements in
the D1 device state. The only devices that supply this
level are those which can achieve the defined D1 device
state according to the related device class.
_PR2 Object that evaluates to the device's power requirements in
the D2 device state. The only devices that supply this
level are those which can achieve the defined D2 device state
according to the related device class.
_PSC Object that evaluates to the device's current power state.
_PSW Control method that enables or disables the device's
WAKE function.
_PS0 Control method that puts the device in the D0 device state
(device fully on).
_PS1 Control method that puts the device in the D1 device state.
_PS2 Control method that puts the device in the D2 device state.
_PS3 Control method that puts the device in the D3 device state
(device off).
_S0D Highest D-State supported by the device in the S0 state
_S1D Highest D-State supported by the device in the S1 state
_S2D Highest D-State supported by the device in the S2 state
_S3D Highest D-State supported by the device in the S3 state
_S4D Highest D-State supported by the device in the S4 state
_S5D Highest D-State supported by the device in the S5 state

上述都只是些基本概念,也是我自己的心得筆記,希望能夠給大家多一點ACPI認識,如資料有誤也請各位先進不吝指教,謝謝!

Reference
Acpi Spec3.0b

星期一, 11月 05, 2007

通過遊戲策劃階段防治遊戲外挂

~轉貼~
通過遊戲策劃階段防治遊戲外挂

網路遊戲外挂的名字一提起來是讓很多網路遊戲從業者和玩家都很憤怒的一件事,正是這些網路遊戲外挂讓我們遊戲從業者天天背著眾多玩家的責罵不說,更不可原諒的是我們辛苦的勞動成果遭受到了摧殘,並且還要和因為網路遊戲外挂而帶來的諸多遊戲問題,而經常的加班加點的工作,讓我們失去了更多開創新產品和後續作品的時機,還要耗費大量的人力物力與那些遊戲外挂進行週旋。更有因為網路遊戲外挂使網路遊戲公司所運營的遊戲最終關閉,最嚴重的就是網路遊戲運營公司也隨之關門。由此可見網路遊戲外挂它所影響的已經不僅僅是一款遊戲的平衡性問題,它已經開始影響了我們遊戲從業者的工作和生存的問題了。在網路上經常可以看到眾多遊戲行業的策劃人士在大談如何設計遊戲的內容可玩性,遊戲系統的設定等遊戲自身的一些問題。而對於網路遊戲存在的外挂問題卻一直沒有過多的討論,看到的文章大多只是在那裏大罵遊戲外挂以及譴責那些遊戲外挂的製作人或製作公司。那麼在我們一心的專研遊戲的可玩性,玩家的市場資訊以及遊戲的贏利模式時,是否也可深思一下在遊戲設計之初就開始思考遊戲外挂的防治方式了?

  讓我們先來看看現在眾多的網路遊戲運營商們是如何作的呢?現在的網路遊戲剛剛開始運營就都在官方的主頁上寫著請大家自覺遵守遊戲規則,杜絕使用遊戲外挂,以及對使用遊戲外挂者相對嚴重的處罰條例的一些文章,一方面拿起法律的武器對公司的權力進行保護,等遊戲外挂出現以後,進行相對應的遊戲程式修補對遊戲版本進行升級。可以說現在的網路遊戲運營商所用方式大多是被動的防禦,或者是從道德上來進行一種對遊戲外挂反擊的宣傳,但效如何呢?在此不作評價,到各個網路遊戲的論壇裏看看就知道結果了。當遊戲外挂真的出現了,如果在外挂進入到遊戲當中剛開始時就作一些應對措施進行補救效果可能會好些,但是隨著大量的玩家都開始使用外挂時,遊戲公司就會面對這樣一個嚴重的問題,對使用外挂的玩家帳號到底是封還是不封,封遊戲外挂對使用外挂的玩家嚴懲的話可能會讓遊戲失去大量的玩家,不封遊戲外挂那麼公司從遊戲中所得到利潤會大大的降低。甚至有時在遊戲中會有數種外挂同時對遊戲進行侵擾。當然遊戲運營公司對外挂的態度還會有其他因素在此就不作過多的討論。我們也知道在後期對遊戲外挂進行管理時的成本是相當高的,

  今天我打算從五個方面探討一下對網路遊戲外挂的一些思考,希望能夠對各位讀者有一個拋磚引玉的效果,讓我們的遊戲事業可以作的更好,走的更快。以下所列出來的條目,只是一些相對重要的因素,並沒有列的太全,因為不同的遊戲類型所出現的外挂也是多種多樣的,在歷此如有紕漏請見諒。

  網路遊戲外挂對遊戲影響

  對這第一個標題可能會引來一些人的不屑,外挂對遊戲的影響都已經在市場上體現出來了,用你在這裡總結嗎?其實不然,我在這裡不僅僅是要說出外挂在遊戲的表現形式,更想和大家深度的討論一下這將會對我們所產生的一系列的影響以及如何潛移默化的讓玩家對遊戲態度發生的轉變。

遊戲外挂會縮短網路遊戲的壽命使利潤降低並加大遊戲後續開發的困難

  加快玩家的遊戲速度,加快玩家的遊戲效率是遊戲外挂的重要功能之一,這一點最大的危害就在於,我們準備運營一年的遊戲計劃,因為外挂的因素,可能遊戲在半年或七、八個月內就讓玩家從頭玩到尾了,遊戲讓玩家沒有的新鮮感,遊戲內的機制或物品也會因為某種變態外挂的出現,而變得沒有用處或作用大大降低,玩家開始大量流失。如果裝備多,屬性複雜的遊戲可能會好過一些,因為玩家就算是將遊戲通關了,也會為了找齊一套上好的適合自己的裝備而繼續在遊戲中。可是如果我們要作的是一個系列的遊戲呢?我們設計了一個很大的故事背景,分為若干個章來進行分期新版本的發佈,這時遊戲的每一時期的市場佔有時間就變得相當的重要,因為我們要利用每一時期的市場佔有時間,來開發新的遊戲續篇,如果遊戲壽命時長減低,那麼對遊戲的研發和市場運作是相當有壓力的,使得遊戲公司處於非常被動的狀態。我們都知道由於市場上的同類型的網路遊戲相當多,導致中國的玩家耐心越來越差,一旦因為我們的研發速度沒有跟上玩家市場的需求,就會因此失去成批的玩家,雖然在遊戲更新後會有老玩家回來繼續進行,但是他們回來大多只是為了再看看遊戲,真正再次投入的少之又少,因為他們的人物可能以經被那些沒有離開遊戲的玩家人物遠遠的拋在了後面,可能原本高高在上的人物已成為往昔的回憶。更重要的是遊戲的壽命縮短也讓遊戲運營公司所代理的遊戲成本,從另一個角度上來說大大增加了,因為不可能在短時期內攢回買遊戲時所代價,這就是為什麼現在很多遊戲運營公司再壓縮遊戲的公測時間,通常在很短的時間內就開始投入了大量的遊戲收費項目,這與擔心外挂出現會讓遊戲的價值打折不無關係。

  遊戲外挂讓玩家產生不平等,進而引起玩家對遊戲及遊戲運營公司的憤恨離開遊戲

  從這個小標題就可以得出這樣的結論,使用外挂的玩家會讓沒有使用外挂的玩家產生心理的一種失衡,道理很簡單花同樣的時間和金錢,卻沒有產生相同的效果,當然這種效果在初期大多數玩家會把這種結果歸結到自己運氣不好,或者自己的打怪地點等沒有選好的個人原因。但是隨著玩家間互相PK或者玩家親眼看到和自己等級裝備相差無幾的玩家,卻在外挂的幫助下,人物有著相當大的能力提升,這時玩家就會產生心理的不平,就會出現二種情況一是離開這款遊戲,二是這個玩家也加入到使用外挂的行列當中,如果這些玩家剛使用外挂,就趕上游戲運營公司開始封外挂,尤其是他們被封而其他他們所認識的外挂玩家卻沒有任何事情,那麼這些玩家對遊戲運營公司的心理承受底線已經無法再退讓了,便也開始選擇了離開遊戲,但是玩家在這時很少會遷怒于那些玩家和遊戲外挂的製造者,而是責罵遊戲運營公司的不負責,在玩家看來這完全是由於遊戲本身存在著不足以及遊戲公司對外挂的管治不嚴而產生的結果。

  遊戲的金融系統混亂讓遊戲運營公司利潤減少

  在說這個標題之前,讓我們先來簡單的了解網路遊戲當前的生存方式。網路遊戲一方面要給玩家很高的自由度讓玩家可以在遊戲中展示自己的個性,而另一方面又要讓遊戲可以具有一定的故事背景,所以導致了遊戲雖然有劇情但是遊戲的結構和遊戲緊湊程度相對的鬆散,正是為了應對這種可能讓玩家過度自由的局面,所以眾多的網路遊戲將遊戲的核心服務方面指向了玩家的人物職業和裝備道具,可以說玩家的去留和目前眾多的網路遊戲公司中這二個服務內容起著重要的關係。這種生存方式雖然會被更新的遊戲理念所改變,可是在國內這種遊戲生存方式的轉變的時機還沒有成熟。

  言規正傳,目前大多數的遊戲外挂存在的另一個重要的功能就是縮短玩家得到某些裝備物品所需要的時間,原本需要玩家投入大量的時間和精力去得到的裝備道具,由於外挂的出現讓玩家在遊戲當中可以越來越快的得到他們想要的東西,使得物裝備道具等相關的物品大大的貶值,甚至於某些遊戲內的物品,由於外挂的原因已經成為可有可無的擺設了,將玩家對遊戲中追求的目標在數量上大大的減少,從另一個角度上來說由於外挂的出現,使得遊戲運營公司花錢購買的遊戲當中,包含了大量的無用物品,相對的造成成本的提高,而且這也是針對了當前眾多遊戲運營公司的命脈所在,一旦金融系統發生的混亂,那這款遊戲的壽命基本上也就走到了盡頭。

讓遊戲商提供的收費服務大打折扣降代遊戲運營公司的收益

  這是綜合了上面的三點而產生的一個系列反應,目前很多遊戲公司運營遊戲基本上是採用了免費玩遊戲的模式,然後在裝備道具和一些特殊的地圖或關卡上對玩家進行收費,當前市場上各款遊戲除了畫面上的差異外又有著更多的雷同性,這一點在MMORPG中相當的明顯,由於市場壓力巨大為了能夠讓自己的遊戲可以吸引到更多的玩家,所以在遊戲內部增設大量的關卡和任務為玩家可以在遊戲的不同階段都會有一定的目標性,並且很多遊戲公司還會在各種節日上還會搞一些送裝備和增加經驗值的系列任務活動,而這些遊戲服務的內容,都是建立在玩家間以及玩家和遊戲間是處於公平狀態的標準上,也就是如果遊戲中有上面三條中的一條,那麼搞這些收費服務都是相當有風險的,比如有的關卡當玩家完成後,會給玩家一些經驗或裝備道具上的獎勵,然而外挂會讓玩家可以輕易得到比這個任務關卡更好的道具,這樣在遊戲當中的一些遊戲關卡的設計變的沒有用處,無疑加大了遊戲的運營成本。當遊戲運營商組織一些活動時,如果玩家和玩家之間已經因為外挂的原因產生了不平衡,如果這時遊戲公司搞送裝備和增加經驗值的活動,無疑更加大了使用外挂和不使用外挂玩家間的距離,讓強者更強,有了更多的經驗和裝備,對遊戲吸引新玩家也是很大的障礙。而且外挂的產生會讓那些收費的服務項目的含金量大大降低,因為玩家在這個進期會有二種可能性,一種是玩家可能會通過外挂對自身的人物能力進行提升,另外會出現大量的僅次於收費服務的免費服務來降低玩家對收費服務內容的需求。

  人們為什麼使用外挂

  這是我們要探討的第二個話題,我們一方面對遊戲的外挂的危害有了一些了解,另一方面也要開始了解外挂當中到底是什麼吸引著玩家,為什麼玩家會對遊戲外挂產生了如此大的需求?這些在我們分析網路遊戲外挂時已經作了一些描述,可是往往就是一些簡單的話題要是深入的和遊戲其他因素聯繫起來後,就越能了解他們的存在基礎是什麼。在這一部分我們主要是對玩家使用網路遊戲外挂的遊戲心理進行一下探討。

  可以降低自己玩遊戲的難度,讓自己可以更快的得到高等級和好裝備

  這是眾多玩家在使用遊戲外挂時的第一種心理需求,因為網路遊戲與單機遊戲不同,遊戲的內容和機制不過是一個載體,它最終的目標除了可以讓玩家在遊戲當中得到娛樂性之外,更重要的是玩家和玩家之間的一種競爭,是比拼某個玩家或一個玩家團隊對遊戲各項內容的了解程度,以及對遊戲組織思維方式和操作上的熟練度,以及玩家間的合作熟練程度。這樣為了能夠讓自己比其他玩家可以更勝一籌,但自身因素所限的玩家,便想到通過遊戲外挂來將自己所面對遊戲變得相對簡單一些,這樣老玩家就可以更加快速的拉大和其他玩家的差距,進而可以在遊戲的某服某線達到可以號令或權威的地位,新玩家可以通過這種方式快速的拉近並趕超那些比自己更早進入遊戲的玩家的距離,以便可以讓自己獲得更多的遊戲樂趣。組成這種心理的表現形式主要體現在如下三個方面:

  第一,現在有很多網路遊戲為了能夠滿足遊戲內容的需要,會設置大量的操作鍵,雖然設了快捷鍵,但是還會有很多讓玩家感到難以在快節奏的遊戲過程當中很好的操作玩家所控人物,玩家為了能夠更加方便快捷的對人物進行操控,會使用遊戲外挂來降低遊戲上的難度;

  第二,為了能夠讓玩家分散或者能夠更好的體現遊戲關卡的內含,往往會將地圖作的大一些,這樣就造成了玩家在遊戲過程當中,往返跑動的時間過長,所以玩家為了可以更加快速和準確的到達目的地而使用遊戲外挂;

  第三,遊戲當中的怪物會在其死亡後給玩家提供一些物品,如果此時玩家正忙於打下一個怪物或者是忙著其他的事情,沒有去拾取那些物品,有時可能就會造成一些好裝備打出來卻沒有拾到而造成遺憾,為了減少這類事情的發生,所以有很多玩家會使用遊戲外挂以達到自動拾取的效果。

希望從遊戲中得到現實中的利益

  隨著網路遊戲的市場競爭越來越激烈,而且在國內遊戲行業十分盛行跟隨風氣,所以很多遊戲都有著很多的雷同部分,為了可以讓遊戲在同類遊戲當中獲得更大的市場,讓更多的遊戲玩家可以進入到自己運營的遊戲當中,很多遊戲運營公司從2001年左右的時間開始或明或暗的向玩家表明,在自己運營的遊戲當中不僅可以進行遊戲娛樂,還可以在遊戲當中獲得真實貨幣的收益,隨著這種運營方式不斷的獲得成功,讓更多的遊戲運營公司加入到此類行銷當中,依靠玩遊戲攢錢的風氣日益形成,國內也隨之成立了各種各樣的專門依靠在遊戲當中打裝備獲利的公司。然而這種行銷方式是一把雙刃劍,一方面為遊戲吸引了大量的人氣,而另一方面也為遊戲吸引來了以在遊戲當中攢錢為進入網路遊戲目標的玩家,而以攢錢為目標的玩家是會對網路遊戲造成損害最大的一類玩家群體,他們的目標很明確,就是要通過滿足玩家對遊戲中的一些物品產生的需求,進而產出大量的遊戲物品對玩家進行售賣,從中獲得一定的利益。正是有著利益的驅動這類玩家對遊戲外挂的需求是相當大的,為了可以得到更大的利益他們不僅是遊戲外挂的使用者,更有可能他們為了滿足可以更好的從遊戲當中獲得利益進而成為遊戲外挂的製作者。所以如何平衡這二方面的力量,是遊戲開發及遊戲運營公司需要共同面對的一個問題。

  滿足自己的內心需求

  了解我們的受眾群體才有可能讓我們更好的為之進行服務,才有可能讓我們從中得到更大的收益,遊戲的內容,體系,畫面,風格無論作的有多麼的好,最終還是要由玩家市場的接受程度來進行評測的,而且我們對玩家心理需求了解的越多,就越能夠更好滿足玩家的需求,進而降低玩家群體對遊戲外挂的需求。所以這一點我們就用一定的篇幅對玩家的遊戲心理進行一次探尋。

  玩家需要遊戲帶來成就感

  網路遊戲對於玩家最大的吸引力之一就是遊戲可以讓玩家在遊戲當中找到自我的尊嚴,這是由於社會現狀所制,目前有著相當一部分的年輕人在短時期內無法找到自己滿意的工作,年輕人都有著好勝的心理,在這段沒有一個空間可以讓其展示才華的時候,他們迫切的需要能有一件事物可以讓他們將自己的能力對其他人進行展示,網路遊戲目前就是在扮演著這個角色,他可以讓玩家通過在遊戲當中擊敗一個又一個困難,逐漸形成一種成功上的滿足感。並且隨著挑戰不斷的成功,成就感就會在玩家心裏不斷的得到滿足,另外玩家還可以對其他玩家進行權威性的幫助和指導,這樣玩家在遊戲中就會得到一種自我的滿足。

  如果遊戲提供了更強大的挑戰,玩家就可以在和他人進行交流或炫耀自己在遊戲過程中有多麼的強悍,解決各類難題時有多麼的了解。隨著遊戲時間的加長,儘管玩家所玩的遊戲每次都有所不同,但他們可以集中精神參與到遊戲當中。這是書刊、電影等其他單向欣賞式的娛樂形式是不同的。他可以讓玩家進入到遊戲所構建的世界當中,遊戲促使玩家主動思考解決問的不同方案,設法理解遊戲的邏輯性和遊戲的機制。

  玩家需要遊戲具有實用性

  遊戲的好壞更在於玩家是否可以從遊戲當中學到一些實用的東西,這可能讓人感到迷惑,遊戲本身就是讓玩家進行身心放鬆的,如果還加入一定的學習因素在裏面,是不是會讓玩家感到遊戲很枯燥呢?其實遊戲中的一些知識使玩家在不知不覺中就得到了一些經驗,比如玩家可以從遊戲中吸取到一些社交方面的經驗教訓,並應用於生活的其他方面,而他們自己卻沒有感到這一點。比如他們可以在高強度對戰的遊戲的戰鬥中學到在短時間內如何擊倒對手,如何讓自己能夠更安全一些。或許通過遊戲中角色的扮演來學習如何判斷是與非,如何更好的表達出個人的感情進而加強玩家在現實社會當中的人際交往能力。許多玩家希望能夠從遊戲中得到多種多樣的挑戰,並且通過挑戰所帶來的成就感來充實自己。

  玩家需要與其他人進行溝通

  遊戲尤其是網路類遊戲,就是一個小型的社會團體,所以很多玩家希望能夠在這裡結交到一些志同道合的朋友,並且將友情從網上發展到網下,玩家就需要溝通需要交流,因為只有這樣玩家才夠把自己驕傲的或失敗的事情與其他人進行交流,說自己驕傲的事可以讓其他玩家高看一眼,讓別人以敬佩的眼光看著,可能玩家在現實生活是無法得到這種感受的。訴說自己或聆聽別人的失敗,可以放鬆和總結一些不利的地方達到進步的效果。比如在休閒棋牌類遊戲中玩家可能通過互相交流得到更好的提高棋牌技藝,在MMORPG類的網路遊戲中玩家可以互相討論各個職業人物如何發展。所以網路遊戲的根源及其吸引力的重要部分是它的社會性。

  對大多數人來說,他們玩遊戲的根本原因是與朋友或家人進行交流。這裡,不僅僅指的是電腦遊戲,而是多種形式的遊戲形式包括打麻將,玩撲克,跳繩,打口袋等現實中的活動項目。人們玩這些遊戲就是因為他們喜歡和他人一起進行遊戲,雖然不少人喜歡玩一些單人的遊戲,但是更多的時候他們會在遊戲之外與他人進行溝通,對自己的能力進行一下展示。而且隨著遊戲的類型不斷的豐富越來越多的人傾向於多人遊戲。這是因為人們喜歡集體遊戲一起遊戲樂的感覺。

但是如何在電腦遊戲上實現交流呢?在當前大多數多人在線的遊戲當中,有相當一部分是從單機版遊戲中轉型過來的,這樣玩家在遊戲當中不僅僅會受到像單機遊戲中的挑戰(當然目前網路遊戲的挑戰性與單機遊戲還是無法比擬),也會受到真人玩家的挑戰,不僅增加了遊戲的可玩性和多變性,也在玩家交流這方面大大的提高。使玩家再也不會因為一個人玩遊戲而感到孤寂。

  例如目前許多新型的休閒類網路對抗多人遊戲是由以往的單機遊戲改成,比如泡泡堂,夢幻泡泡島等網路對抗遊戲是由《炸彈人》上轉型而來,《夢幻蛇》是由手機上的《貪吃蛇》演化而來,《天之炮炮》是由《坦克大戰》演化而來,等等很多以往知名的遊戲都是這樣出來的。這些多人遊戲和單人遊戲當中有著幾乎相同的規則和機制但即便是玩“由單人轉成多人”的遊戲,這些遊戲所以又重新讓玩家愛不釋手,是因為它們具有了網路功能,還具有了交流的功能。玩家是希望能在玩遊戲的過程中與其他人進行交流,任何與朋友們在一間屋子內一起通過局域網玩過這類遊戲的人都可以證實這一點。局域網遊戲的環境中有著玩家互相協作的叫喊,也有誇耀他們最近的“戰果”,或是告知他已經死亡的資訊。但是在Internet上這種高強度的對戰類遊戲,交流就變的相對困難了許多,人們無法通過話語進行資訊上的傳達只能通過電腦進行交流。由於這些遊戲強度高、動作快,玩家如果想有更長久的遊戲時間或更好的遊戲結果,就很少有空閒的時間將資訊發給目標玩家。在這一點上我們就可以效倣《CS》這款遊戲,它的經典之處在於玩家在體驗激烈精彩的倣真遊戲外,還可以達到快捷的交流方式,試想一下如果在《CS》當中如果沒有地圖區域的明確劃分(如DUST2中A區和B區),沒有快捷語命令(如X鍵快捷語等),我們在CS當中的樂趣必然會大打折扣。由此我們可以得出這樣的一個結論:“在高強度的對戰類遊戲中,如果我們能夠讓玩家依然能夠保持彼此之間發出準確度較高的消息時,是會深受玩家歡迎的。另一類多人遊戲可以說在時間的節奏上是相對較慢的。

  玩家需要一個安靜的地方

  在上一節我剛剛談到了玩家需要交流的機會,現在又談玩家需要一個安靜的地方,好像這兩點讓您感到了矛盾。當然這兩種需求心理是不會同時發生的。有些玩家在努力的找尋著與朋友們交流和共同遊戲玩耍的機會,而另外還有一部分人卻想在遊戲世界中找到一個安靜所在。他們可能沒有朋友在線上,也可能是交流的過於疲乏想休息一下,或者只想看著同在這個遊戲世界中的人,就好像在看一個個紛亂的、短小的電影一樣。這是一種造物主置身於塵世之外的一種欣賞。

  那麼有人會說,如果想找一個安靜那為什麼不下線呢?自己找一個不受人打擾的地方不是比在遊戲中更好,遊戲中有時還會有人打擾到。這樣想就不對了,因為玩家只是想一個安靜的地方,但是他還是需要一定的交流,與環境的交流,對某些事物的欣賞等,安靜並不代表著玩家就是什麼事情也不作,就好像我們有時喜歡一個人獨自的看看電影,或聽些自己喜歡的音樂,可能他想看看自己的成績,或欣賞一下別人的東東,玩家可以隨意開始和停止,電腦遊戲可以模倣出人類行為中有趣的部分,而不包含讓人煩惱的行為。這就需要遊戲設計者對此類玩家的心理消費需求進行某些方面的遊戲設定。就好像在WOW中有一種外挂讓玩家可以登高到遊戲中不到達的地方一樣。

  玩家需要另一種生活的體驗

  在現實生活中,人們有很多事沒有辦法去作,比如以不同的身份在人世間生活,回到古代去體驗當皇帝或俠客的感受。再比如我們要想體驗一些活動如開車,開飛機,在戰場上開著坦克等,要想在現實的生活中把這現全部實現,我們就要學習很多知識,甚至有的由於我們自身的原因無法辦到,但是隨著遊戲的技術不斷提高,我們玩家現在可以在電腦中去體驗,並且不用害怕會遇到各種災難比如死亡,受傷等。在遊戲中就算有事件發生,比如飛機墜毀,撞車,中槍等,我們也是站在欣賞的角度,對於我們自身並不會造成傷害。

  另外人們還需要對內心的一些好奇、或鬱悶的心裏,進行一下探索和釋放。使人們可以在遊戲中體驗一下在現實生活中不可接受的極端體驗。比如有的玩家想感受一下當規劃者(模擬城市)、當英雄(反恐精英)、當一個搞惡作劇的人(整蠱專家),有的在現實生活中去作,不僅會對他人造成傷害,而且也會讓玩家受到法律上的懲罰。所以玩家就可以在遊戲中去體驗,不僅達到了體驗的目的,還不會對其他人造成傷害。

雖然很多人批評電腦遊戲的種種不好,說什麼荒了正業,讓很多人迷茫了現實。但是如果把這類在遊戲中迷癡的人群和全體玩家相比較,這個比例是非常之小。很多人都想要進入一個比現實社會更為精彩的世界,在那裏他們可以進行一種情感上的宣泄,其實小說,電影,戲劇也是這樣的傾向,也是希望讓人們得到一種精神上的滿足一樣,但是對這些事物的批評與對電腦遊戲批評來說,程度就不相同了,當然就網路遊戲而言這也是人們對新事物認知的一個過程,只不過在文明的社會當中,人們不再需要向前人那樣用生命和鮮血來證明新事物的優與劣。

  玩家需要與其他人進行競爭

  在網路電腦遊戲當中玩家最大的樂趣就是可以和其他玩家同場競技,這是以往單機版遊戲所無法替代。為什麼玩家喜歡與其他玩家進行同場競技?因為以往單機版遊戲當中,儘管遊戲中的電子角色有了高強度的AI(人工智慧),但是AI再強畢竟也是一個固定的遊戲程式,在遊戲當中如果出現了一些情況,遊戲中的電子角色就未必會有相應的變化。在有些遊戲當中,為了能夠降低人工智慧的不足,所以增加了一些超出正常思維範圍的智慧程式。

  在CS這款遊戲當中,如遊戲中的機器人為了不讓玩家因為過於困難而對遊戲產生厭惡感,所以遊戲中的機器人的槍法,對於事件的處理能力相對差一點比如躲藏、拆彈等事件。又為了不讓玩家將這些機器人又列入到無趣,低智商的程度,所以讓機器人具有透視的功能,當玩家還沒有看到機器人時,機器人就已經發現了玩家,並且進入到了相應的戰鬥狀態。以此達到AI上的平衡。

  由此可見,如果安排了人與人之間的競技,我們只需為玩家提供了相同的遊戲環境,就會讓玩家將集中力放在如何打敗對方身上,如果對手過強,玩家就會認為是自己對遊戲了解的不夠,或認為技術上不如對方強;如果對方不強,玩家會認為在這個遊戲當中已經可以成為一個高手了。所以增強遊戲中玩家間競技的互動性,我們就會讓玩家把更多的想法放在如何更好的利用現有的機制,降低玩家對遊戲的要求。而且玩家如果打敗了一個真人的挑戰,會比打敗十個電子角色更有成就感。

  玩家需要提高操作能力

  隨著玩家對遊戲的機制及遊戲世界的認同,玩家就開始通過提高操作技能來進一步的融入到遊戲當中,只有更好的操作能力,才能讓玩家在遊戲當中做出心有所想的動作,作到手眼合一。所以設計出玩家能夠快速接受的操作方式,玩家通過用多種方式的按鍵組合來達到不同的人物動作效果。如果我們的操控鍵設定的不是大眾所熟悉的方式就會讓玩家摸不到頭序,那麼就不會讓玩家感受操作遊戲的樂趣。遊戲的操控方式在玩家對遊戲的認知上是有很大的作用,尤其是在初級階段玩家如果沒有辦法很快的熟練的操控遊戲的話,那麼這個玩家就會對這個遊戲產品產生反感情緒。

  玩家對遊戲的期望

  一旦玩家對某一類型遊戲產生了遊戲的需求,他就會對遊戲的一些機制和遊戲的內容帶有一定的期望值。玩家除了在這些遊戲的介面、遊戲的動畫等基本的要求外,玩家還會有一定的期望,如果這些期望沒有滿足,玩家就會感到失望,並且會離開這個遊戲,轉而去找其他遊戲,這就是表明為什同樣的一款遊戲,有的遊戲平臺上的遊戲就人滿為患,有的遊戲平臺上的人卻門可羅雀。這樣我們在設計遊戲時就要使遊戲滿足玩家的期望。那麼玩家對遊戲會有什麼樣的期望呢?

  玩家期望在遊戲中得到公平的

  當玩家進入到遊戲當中後,玩家首先會考慮到的一點就是新來的玩家是不是可以在遊戲中得到相對公平的待遇,在遊戲當中是不是會遇到一些無法正常遊戲的困難,這一點在網路遊戲中更為突出。比如下面的一些問題就是玩家在進入到一個新的遊戲當中所要想到的問題:1、 是不是會受到高級玩家的歧視,這一點在對抗類休閒遊戲中最容易看到,一些老玩家很不願意與新玩家進行同場競技。原因主要是可能會因為新玩家對遊戲機制的不熟悉而不能更的進行遊戲,最突出的是組隊戰,同隊的每一個隊員都對勝負起著重要的因素。

  2、 是不是會受到高級玩家的騷擾,有些高級的老玩家可能在遊戲的某一個階段中,無法在遊戲的本身找到他所想要的刺激,所以他們就會以一些等級較低的玩家為攻擊目標,使得新玩家無法正常遊戲。

  3、 收費和免費玩家間的不公平對待,這是在2005年新出來的一種遊戲收費方式,一些玩家在交費後可以進行很多新的刺激性的遊戲場景,有的休閒遊戲平臺還會給收費玩家一些特權,要麼是系統無故將玩家踢出遊戲。要麼是收費玩家可以隨意的將免費玩家踢出遊戲室。雖然在遊戲公司來看這可能是一個好的刺激玩家消費方式,可是代價卻是以傷害一片更大的免費市場,對於公司的長遠發展來看有百害而無一利。至少我看到的很多玩家在看到這樣的遊戲機制後就會感到遊戲公司唯利視圖,有錢也不會在這樣的公司消費。

當然遊戲公司也在努力的將玩家的遊戲環境處於一種相對公平的狀態下,讓玩家在遊戲中可以盡享遊戲所帶來的樂趣。目前維護玩家間公平的事主要有以下幾點:

  1、 打擊外挂程式。這一點相信很多人都不陌生,外挂程式的誕生就是為了打破遊戲的公平性,遊戲公司對其可以說是恨之入骨。很多玩家是看遊戲公司的態度而決定是否用外挂,有的單純以娛樂一下的玩家可能就會對那些不作為的公司不滿而離開。

  2、 分級制頻道設定。不同等級的玩家分別在與之相對應的等級頻道中進行遊戲,這樣玩家就可以和與自己同級的玩家進行遊戲競技,更好的避免了新玩家因為不熟悉遊戲規則和玩法而頻頻受挫。

  3、 根據網速上的控制來達到玩家遊戲競技上的平等。這一點在對抗型或競技性很強的遊戲中是相當重要的,遊戲的系統會在開始前對本遊戲室內的玩家進行一次判斷,如果有的玩家的網速較之其他玩家的網速過於高或過於低的,就會本著遊戲的公平性,將這個玩家自動踢出遊戲之外,以確保遊戲的正常運行。

  玩家期望在遊戲中有意外的事情

  玩家在遊戲當中讓他感到快樂的不僅僅是一個遊戲中的正常機制,玩家在遊戲中更期望在遊戲中有一些讓他們意想不到的事情發生,這些事件包括:遊戲的暗機制設定(大多數人稱之為BUG);一些讓玩家在正常遊戲時,用同樣的操作卻可以得到比其他遊戲中更有趣的動作;在一些本不可能的操作裏,卻可以躲避或擊中對方;在遊戲當中玩家可以找到某個地方躲藏使遊戲中的敵對方攻擊不到。

  遊戲的暗機制設定:比如說在《CS》1.5版當中,競技場遊戲模式當中,如果玩家的子彈在不滿的情況下,可以跳起對墻扔槍,讓槍在空中反彈回到玩家手中,就可以得到一個滿匣的子彈,這些都是一些遊戲的暗機制,只有當玩家在不經意間才會感到這類事件的發生,進而達到一種意外收穫的快感。

  在一些現實中本不可能的操作裏,卻可以躲避或擊中對方,比如說我們在《CS》1.5版當中,很多玩家都喜歡用狙擊槍進行“甩槍”(就是可以在遊戲中進行滑鼠快速橫甩,可以虛擬的飛出一行隱形的子彈達到殺死對方的目的)。玩家得到了這個不是人人都能掌握的技法後,就會在遊戲中大展英姿。

  在遊戲當中玩家可以找到某個地方躲藏使遊戲中的敵對方攻擊不到:在MMORPG類遊戲當中,我們經常會遇到這樣的事情,當我們走到某一個戰鬥場景後,只要我們移到一個指定的位置,在這個戰鬥場地裏的怪物就不會攻擊到我們所控制的角色,這些都是由設計者在有意的給玩家提供一些“BUG”,讓玩家感到意外的同時,又感覺自己好像佔到了天大的便宜。

  玩家期望得到適時的指導

  網路遊戲不同於單機遊戲,單機遊戲要是沒有打好可以回到存盤點重新來進行戰鬥,而網路遊戲則不會有這樣的好處,再者網路遊戲結構相對鬆散就是為了讓玩家可以在遊戲中塑造出一個個性的自我,而玩家這種發展方向是否正確?好的遊戲應告訴玩家他們可以做什麼。玩家希望創造自己的成功故事,希望遊戲能夠告他們如何去作,玩家也希望找到遊戲中取勝的方法和自己獨特的東西。玩家有其自己要完成的遊戲的設想,玩家有時是不會根據我們設定的故事結局,來規定自己的遊戲結果形式,這一點在MMORPG類遊戲中是最明顯的,有的玩家是想打敗遊戲中所有的BOSS,有的玩家是想玩一玩所有的地圖,有的玩家只是想集齊一套他們想要的一套裝備。而且許多玩家玩遊戲的目的是遠離現實生活的,他們渴望幻想和解脫,因此不願意在電腦上重復過多的現實生活。

  玩家想要知道自己的目標,並且希望得到如何達到目標的指導。當只有目標而不知道如何實現的時候,玩家就會到處亂撞,嘗試自己能想像到的操作方法,當所有的嘗試都失敗的時候,他們就會感到沮喪。比如我們製作了一個任務,沒有提示玩家要去哪個地圖去打哪一個怪物,這時玩家就會產生迷茫,感覺這是一個不可能完成的任務。當然有的遊戲就是沒有一個明確的目標,比如《模擬城市》實際上游戲的創造者Will Wright 稱它為“軟體玩具”而不是遊戲。《模擬城市》像玩具一樣,玩家可以對它作任何想做的事情,不必清楚地知道成功或失敗。玩家可以建造自己想要的城市環境,由於遊戲遵照了人們現實生活當中的認知規律性,於是玩家會本能地利用現實中的認知方式來建造城市,玩家也會根據現實中成功與失敗的準則,來自我評定。儘管遊戲沒有遊戲內的目標,但遊戲的本質和現實中的背景鼓勵玩家去實現他們的目標。玩具從最初變成了遊戲,這也讓玩家繼續玩下去。

  玩家期望得到“失敗”

  玩家得到一款遊戲後,他們就會在玩遊戲之前,先設想這個遊戲會有如何如何的難度,要如何去作,然後才開始遊戲。可是如果這個玩家在第一次就可以“打通關”,那就會失去遊戲的樂趣。如果遊戲如此沒有挑戰性,以至於玩家第一次嘗試的時候就通過了——它就不是什麼好遊戲。玩家所以玩遊戲,是因為他們需要挑戰。挑佔必然意味著玩家不能輕易得勝,在獲得最終成功之前,必須做出很多嘗試才能克服困難。太容易取得的勝利是沒有價值的,就好像讓國家足球隊與小學校足球隊比賽勝利後的感覺一樣。但是在真三國無雙當中,雖然各大名將打擊對方的小兵時是那麼的容易,玩家沒有什麼勝利的感覺,但是遊戲中敵對的兵力、兵種多的像潮涌一般的向玩家襲來,就會讓玩家感到一種勇貫三軍的一種威猛。

玩家在遊戲中我們要給玩家創造出有一種會輸的不確定思想存在,但是不是輸給遊戲本身的特性,玩家如果在其失敗後,能夠了解到或學習到其在失敗前本當作的事情,那麼他就會從自身上找原因,想想自己為什麼失敗,如何不失敗。如果玩家認為遊戲是通過一些小手段戰勝了玩家,那麼這個玩家就會遷怒于遊戲,而不是責怪自己,進而對遊戲失去了興趣。比如在一個沒有任何特徵的地面上,玩家走著走著突然受到一些意外事件死亡,而在這關遊戲開始之前沒有作任何解釋和說明的話,那就是遊戲設計者的失敗之處,讓玩家感到被遊戲玩弄了。

  讓玩家在遊戲開始的時候嘗到一點甜頭,這會讓玩家很快的沉浸在遊戲之中,在開始覺得遊戲並不是很難,玩家遊戲在這一時期時,我們讓玩家產生一種優越感,隨後困難必須逐漸升級,讓玩家失敗。這時,玩家已經沉浸于遊戲之中,有興趣的利用自己的所掌握的遊戲技巧去探索遊戲,並想要玩下去直到克服和解決他的困難。如果玩家在遊戲中過早地被打敗,他就會認為遊戲太難了,或者不知道如果繼續玩下去會得到什麼獎勵。允許玩家在最初的時候多些勝利,讓玩家知道是可以成功的,進而有克服困難的勇氣和動力。

  玩家期望的遊戲是可以玩的而不是觀賞

  在一個時期裏,遊戲裏面對片頭動畫和遊戲中的情感動畫都用了很大的手筆,還有一些電影演員也開始在片頭動畫中扮演主角。使得遊戲變的越來越缺乏交互性,事實上,也越來越不像遊戲。而預算卻在不斷上漲。然而讓人想不到的是,玩家一點也不買帳,大多數玩家會不耐煩的跳過這樣沒有幫助意義的動畫。於是製作公司倒閉,業界裏的人都在想為什麼玩家不會接受這樣的遊戲方式呢?玩家卻知道為什麼不要,遊戲的設計師也了解問題出在哪,那就是玩家對於遊戲的觀點是,他們要控制遊戲要去玩遊戲,而不是像看電影或書刊一樣被動的去欣賞。

  其實在遊戲前作片頭動畫和在遊戲中作一些情感渲染功能的動畫,對於向玩家交待遊戲的故事,或者向玩家說明在下一段遊戲中必要的一些資訊,以及對某一個時段的遊戲作一個總結式的動畫渲染讓玩家有一個階段性的勝利感和成就感。這樣的動畫是非常有用的工具。但是這樣的動畫應當明確的表達出所要的含義並且也要將時間盡可能的減短,當然要達到敘述遊戲和說明遊戲下一關的進程特點和總結本關故事情節所需要的內容。超過一分鐘的片頭動畫,尤其是那些並非提供後續情節基本資訊的動畫是要避免的。片頭動畫的方式倒無所謂,可以是滾動文字的,或者是真人出演的電影畫面,賽璐珞動畫(Cell Animation),或者是遊戲引擎直接生成的動畫畫面,反正只要使遊戲中斷的時間不要過多、過長就可以了。如果這其中包括了玩家的參與,如玩家部署下一關的部隊位置,那麼這就不是一個嚴格意義上的動畫,它是可以根據實際上的需求由時間或者是事件來進行控制。並且如果片頭動畫包含了遊戲過程中關鍵性的資訊時,設計者應當讓玩家不能跳過這樣的關鍵動畫,並且可以在遊戲中隨時調用這段動畫。

  片頭動畫的品質也不是重要的。有些遊戲的動畫的演技可能不敢讓人恭維的,這些常是遊戲開發的小組的成員表演的,也有的遊戲有著專業電影的品質和內容的片頭動畫,甚至更好。便是最後,只要遊戲本身的內容有著吸引人的地方,玩家就會希望儘快開始遊戲而跳過各個動畫。

  總之人們玩遊戲是因為他們希望得到不同於電影、書刊、電視劇的感受。我們不要為了豐富遊戲的可視效果而忽略了遊戲的本身職責。玩家需要遊戲,所以遊戲設計者就應該給他們一個遊戲。

  玩家期望遊戲中充滿各種功能任務的冒險

  玩家在遊戲中首先要明確一個主要的任務目標,然而玩家在完成這個最終的目標之前要完成一些小一些的輔助性的目標。這些輔助的目標我們通常是以任務的形式出現在玩家面前。任務分為多種形式,下面讓我們一起來看看主要的幾個類型。

  有的是讓玩家在遊戲中有一定的目標性的任務,讓玩家不會脫離我們的主要故事情節,玩家可以沿著這樣的路徑一步步地走下去,從一個次要的目標走到下一個次要的目標,這是獲得正確方法的必要手段。如果這種方法沒有提供正確的反饋,並且達到目標的道路漫長而艱辛,玩家可能會以為他們的方法不正確。當遊戲沒有積極地提示他堅持這個方法的時候,玩家就有可能嘗試其他方法。當他不能解決遇到的障礙的時候,他會因失望而離開遊戲,並告訴他的朋友玩此款遊戲是多麼痛苦。

  有的是讓玩家更全面的了解或改變遊戲中所控角色,這樣的角色渲染式的任務,主要是讓玩家對遊戲有更深入的認知,讓玩家對於所操控的人物有更大的好感,以便達到某種程度上的共鳴。所以我們所要作的角色渲染式的任務就不要單純的以純武力,純才智的方式來作,而是作一個近於完人的人物形象,這樣才能更廣泛的滿足玩家的心裏需求。

  有的是讓玩家得到某一種道具的任務,只有這樣才會讓遊戲具有一定的多變性和讓玩家更好進入到遊戲當中。通常這樣的任務分為不可選擇和可選擇兩種,如果遊戲裏面過某一關卡或要打倒目標敵人所必須的一件兵器或其他道具的話,玩家就是只有通過並得到了這個道具,才可以進行下一步的操作。對於像血瓶,魔法瓶等類型的道具,玩家並不一定要全部得到它們,我們就可以讓玩家僅僅知道它們存在就可以,而不會對玩家有更多的條件約束,讓玩家必須得到它們。

玩家期望得到方便快捷的溝通的表現形式

  我們在前面已經提到,玩家需要與他人進行溝通。在那裏我們提到我們如何在互聯網當中進行交流,如何滿足玩家聊天的需求,但是僅僅是滿足這麼簡單嗎?不是,我們還要滿足玩家更多的聊天要求,玩家在遊戲中不僅期望達到交流的目的,還希望能夠讓玩家找到比文字更加多的感性資訊,來豐富玩家之間的交流。提供一些動作或表情符號表達,就可以讓玩家之間可以用多種方便快捷且直接的方式交流,會更大的滿足玩家的需求。

  人物的動作式聊天方式:當玩家在遊戲裏聊天時,如果聊天的內容當中包含了一些特殊字符,遊戲中的人物就會作出一些相應的動作。比如在《奇跡》當中,當玩家說的話語中帶有“天”“強”“再見”“謝謝”等中文或英文時,人物就會作出相應的動作。

  表情符號:這一點相信很多人都不會陌生,當我們在聊QQ時就會有很多表情符號,讓玩家可以通過一個符號,就可以表達出來一串文字的含義。

  功能性短語:最早使用這個方式的是“網易聊天室”,目前這種聊天方式在很多遊戲中常可以見到,玩家先指定一個玩家的名稱,然後再點選想要的短語,這樣就會產生???對XXX作出了某一個動作,???代表的是玩家自己,這樣玩家只需要點選兩次就可以達到一次長語句的交流的目的。

  玩家期望能融合到遊戲中

  當玩家進入到遊戲中,處於某一通關過程中,玩家了解遊戲的控制規則,因此變得興奮,扮演起了幻想中的角色,玩家不會輕易走出這种經歷——當然,遊戲不要因自己的內部原因當機(運行不了)。這樣玩家就不會考慮太多的遊戲介面。如果用戶介面設計的不是很清晰,不適合遊戲世界的藝術,就會顯得很不和諧,並破壞玩家的專注性。如果遊戲中的人物沒有任何必要變化就可以上天入海,而且沒有必要的人物說明解釋,那麼就違背了人的正常思維方式,玩家將會認為這是一個缺點,並提醒自己只是在玩遊戲。這樣玩家就很難再次集中到遊戲之中。要記得玩家玩遊戲的目的就是要融合到遊戲的世界當中。如果遊戲經常提醒玩家這只是遊戲時,玩家就很難繼續他的幻想。

  玩家不期望無意義的重復

  當玩家已經完成了遊戲中的目標,通常不希望在本次遊戲當中多次重復。如果設計者設計了特別具有挑戰性的難題,就算玩家解決了它,並感覺很難完成,也不應該在遊戲中重復上述過程。除非解決難題有很多樂趣,或者在每次解決了難題以後玩家都可以得到不同的遊戲結果或獎勵,否則同樣痛苦的難題不應再以類似或稍加改動的形式出現。

  當然許多遊戲的原則就是讓玩家可以不斷的重復自己,或者至少以稍有不同的方式重復自己人的動作。儘管出現在不同遊戲中的挑戰是遊戲的獨特性所在,玩家在遊戲當中不想重復現實中的自己,也不想玩一款重復的遊戲,探索是遊戲這種娛樂的關鍵部分。在探索的過程中,在很多情況下玩家所面對的挑戰是沒有太大變化的。探索了一次遊戲世界之後,隨後的探索就沒有那麼多樂趣了。

  遊戲中存活的原因是玩家不期望重復自己。一旦能夠完成非常勇敢的任務,應該能夠退到玩家玩過之後的地方,當人物死掉的進候,玩家就能夠保存那個位置。如果遊戲給玩家出了一個大難題,經過多次嘗試後,玩家解決了,玩家應該有機會去保存遊戲的進程,允許玩家保存遊戲可幫助玩家避免重復。比如在《奇跡世界》中,玩家可以在很多較大的遊戲關卡當中找到傳送點。主要原因就是在《奇跡世界》這款遊戲中,玩家大多是採用組隊跨級打怪的,有時面對的關卡玩家想一個人走到某一個位置已是很難,所以這樣的一個存取方式可以很大程度上讓玩家有機會保存現有的遊戲進度,而不用反復的去走那些道路。

我們如何對待遊戲外挂,如何防治遊戲外挂

  在前面我們探討遊戲外挂給遊戲帶來的危害和玩家為什麼要去使用遊戲外挂,以及玩家對遊戲的心理需求。現在我們開始討論如何面對及引導遊戲外挂,以往遊戲公司對外挂的打擊方式,除了從道義上進行譴責外,就是加大對使用外挂的玩家的懲罰機制,並且通過程式等技術手段對遊戲進行升級,對系統存在的BUG進行封堵,然而這些我們完全可以從容的在遊戲設計階段就開始對這些不利的因素進行防治,這樣提前的作好應戰的準備,改變以往遊戲公司總是被動的受到遊戲外挂的騷擾,在遊戲外挂已經產生威脅後才會有相應的措施的情況,必免產生一些不必要的不良後果。在此提出幾個思路希望能讓同行得到一些靈感和啟發,讓我們可以更好的防治遊戲外挂的出現,即使防治不了也盡可能將外挂對遊戲的損害降到最低,因為封停玩家賬號無論是對遊戲公司還是玩家個人都不是一件好事情。

  一、從遊戲策劃設計時就開始考慮一些問題:

  1、找出我們設計遊戲的重點是哪些:主要是指我們所製作的網路遊戲到底哪些是我們的核心內容,並且這部分內容是那種一旦受到外挂的騷擾的話,就會讓整個網路遊戲都會受到毀滅性的打擊,把遊戲的這部分內容總結好後,我們在策劃這部分內容時就要進行大量的換位思考,如果我是一個玩家,如果我是一個遊戲外挂的設計者會如何對這部分內容進行改動,在玩遊戲時會因為這些設置,而產生哪些類型的心理需求,而後把這些想法融入到我們的策劃案當中,並且找出相應的對策,對這部分核心內容進行一些輔助性的設計,通過重重的條件設置產生大量的障礙讓外挂的製造者感到無從下手。

  例如在角色扮演類網路遊戲當中,玩家打怪升級目前依然是遊戲中很重要的部分,我們如何防治定點或挂機刷怪遊戲外挂呢?我從眾多網路遊戲中總結了幾種方法:

  A、通過大量的任務來化解單一的打怪方式:這種方式降低怪物自身的經驗數值,讓玩家獲得經驗的主要方式以作任務為主,玩家通過領取任務來打怪時,玩家不僅可以得到怪物本身的物品和經驗值,還可以讓玩家在完成任務後獲得額外的獎勵。並且在玩家完成一系統的任務後還可以得到更多的獎勵。而那些單純打怪的玩家只能得到很少的經驗,並且不會得到任務物品。

  為了避免玩家領到任務後用挂機外挂,我們可以這樣設定任務,這個任務只能在一定的級別內才可以進行領取,並且可以讓玩家反復領取的任務中,我們進行可以交任務的次數的設定,超過交任務的次數後,玩家就不能再對這個任務進行領取。每一種怪物只掉落一種任務物品,這樣玩家盲目的挂機也就沒有太大的作用了。

  B、遊戲中的怪物不再以單一的個體出現在玩家面前:怪物以種類組合形態出現有遠攻、近攻,這些怪物我們設定不同的追擊範圍和攻擊範圍,並且怪物在和玩家進行一種時間的戰鬥後就會引著玩家往怪物群體跑,玩家必須自己去慢慢的引怪等技巧與怪物進行戰鬥,否則玩家會讓怪物群給消滅。這樣玩家用外挂基本上也不會起到太大的作用。

  C、通過高經驗的引導讓玩家對跨級打怪產生興趣:在遊戲中極力推薦玩家組隊去跨級打怪,各玩家間需要用不同的技能配合與怪物進行戰鬥,並且我們還要設定好殺怪的速度以及所得的經驗,讓玩家認為這樣的打怪雖然具有一定的難度,但遠比自己打那些等級的怪物經驗得到的快且多,這樣外挂對玩家的影響會大大的降低。

  2、對重點的物品設置相應的應急預案:這類重點的物品就是那些在某些階段會對玩家產生強烈吸引力的遊戲道具,暫時按玩家的話來說就是“極品”,這類物品包括人物的裝備,兵器,首飾等,這些都是目前網路遊戲的命脈所在,而這也是那些靠遊戲攢錢的公司的目標,雖然一些網路遊戲在這類“極品”的物品上在每區每服以至於每線進行了數量上的限定,可是這種作法過於的死板,讓那些後進入遊戲的玩家會有很大的失落感,因為他們無論如何也不可能追上那些已經在遊戲中玩了很久的老玩家,而老玩家為了達到控制新玩家的目的,也會大量的掌握這些極品的所有權,所以不要在數量上進行設定約束,那麼我們要怎樣來應對“極品”物品會大量產出的這個必然會產生的情景呢?這時我們就需要在這些“極品”的物品之上再設定一個隱含的對應物品,這類物品在遊戲當中是無法得到的,一旦遊戲中的此類“極品”物品出現了大量產出的情況,我們就將提前設定好的隱含的對應物品的預案啟動,根據當前的遊戲情況進行一定比例的消化或者讓其開始在遊戲中的怪物身上掉落削弱“極品”物品對遊戲的影響力,給玩家創建一個新的追求目標。這樣即不會傷到玩家玩遊戲的熱情,從另一方面也減小了遊戲外挂對遊戲產生的損害。

3、提前設置好相對應的遊戲活動:這點主要面對的是由於遊戲外挂的出現,讓我們原本設計的一些遊戲物品變成了沒有用處的東西,這類物品不會對遊戲起到像“極品”物品那樣的影響力,但是這些輔助性的物品可能是為了體現遊戲中某些特點的道具,玩家可以對他們不加理會,可是作為靠遊戲生存的遊戲公司卻不能不去理會這種情況,我們要讓我們遊戲中的任何一個部分,任何一個道具,都能夠對遊戲中的玩家產生一定的吸引力,讓其在遊戲中都是一種具有價值的東西。這就需要我們在遊戲策劃之初就對這類物品進行一個輔助性的活動設定,一旦出現由於外挂的出現導致此類物品無用的情況,我們就可以通過相關的任務活動讓玩家對其進行收集,然後給予玩家一定的經驗或者其他類型的獎勵,將那些因為遊戲外挂而變得沒有用處的物品,再次變成有作用的產品。

  4、對人物的暗屬設定:這主要是應對在遊戲當中那些提供加速移動、攻擊加強等對人物自身屬性產生改變的外挂而設定的,一般我們在遊戲設定時就可以很輕易的得到玩家從某點到達地圖上的某一點所需要用的時間最快有多少,玩家如果對怪物進行攻擊時不同的等級的人物對同一個怪物的攻擊速度的最快時間是多少,有了這些數據我們就可以通過這些遊戲人物的暗屬性進行設定,這些人物的暗屬性在平時不會對遊戲人物的屬性進行限定的,一旦玩家因為使用遊戲外挂加強移動速度和攻擊速度或攻擊力時超過了人物暗屬性的設定,遊戲的暗屬性懲罰機制便會啟動,在一個時間段內讓玩家對下一個怪物在攻擊時的攻擊力為零或將玩家所控的人物移動速度變為零,這樣即不會讓玩家有反感情緒,同時也會讓玩家對遊戲外挂產生厭惡。

  5、前四點主要是針對遊戲策劃之初時如何對遊戲外挂進行設定性的反擊對抗方式,這第四點主要說的就是如何順應遊戲外挂,可能是出於對外挂的處理習慣,很多公司對那些只要是對遊戲本身的規則和人物屬性產生影響的遊戲外挂都會加以應對,然而這樣作並不一定會得到好的結果,對待外挂我們也要能夠區分的來對待,有的遊戲外挂不僅不會對遊戲產生不好影響,反之如果我們利用好的話還會為遊戲增光加色。為了能夠更好的說明這一點,在此舉一個XX賽車的例子和大家共同的探討,目前在市場上有一款XX賽車的競速類遊戲很受玩家的喜愛,由於遊戲有了大量的玩家市場遊戲外挂便開始進入到這款遊戲當中,這個外挂有加速、無視道具攻擊等功能,其中以對玩家所控車輛進行加速效果為這些外挂的主要內容,現在我們開始思考這樣一個問題這款XX賽車地圖以及道具對於玩家來說已經不具有新鮮感,這款遊戲對玩家最大的吸引力就是讓玩家在不同的比賽道路上利用比賽用車的速度和轉彎的技巧二者之間的一種配合,隨著比賽車輛的速度提升也加大了玩家對車輛的控制難度,還加大了玩家在使用攻擊性道具時的準確性,那麼這款遊戲中以加速功能為主的遊戲外挂不正好為遊戲本身的難度提升進行了服務了嗎?說到這裡會有人說要是這樣的話那麼玩家對遊戲中各種需要花錢夠買的車輛需求不就減低了嗎?我認為對這種以加速為主的遊戲外挂的利用是不會讓玩家對車輛的需求減低的,因為不同級別的車輛它們的最高時速上限是不同的,就算是加速外挂也不會提供某款車輛額外的馬力,另外玩家對不同車輛的追求是為了滿足其個性化的需要,對這種個性化需要影響最大的是車型外表而不是車輛的時速,所以我個人認為此類加速外挂完全沒有必要將其封掉,而是要將其成為每一個玩家的遊戲工具,這樣一方面我們讓所有的玩家都具有了加速的功能,將比賽又拉回到公平的狀態,另外遊戲外挂的開發也會自然罷手,因為官方的介入必然導致無利可圖。

我們的反思

  現在我們探討了遊戲外挂的危害,人們為什麼要使用遊戲外挂以及防治遊戲外挂的幾個思路,我們就又要考慮這樣一個問題:為什麼會出現外挂橫行這樣的情況?我初步的總結出來了以下幾點,和大家一起思考:

  一、遊戲內的物品的品種過於單一化

  二、遊戲宣傳時對玩家市場的引導過於簡單化

  三、對遊戲外挂的功能內容預計的不足,導致系統設定的不足

  四、遊戲模式過於簡單,在此我想多說幾句,現在很多遊戲策劃在想著用什麼樣的工具可以更加的先進,最新的遊戲形式是什麼樣的?新的遊戲產品裏麵包含了哪些以往遊戲所沒有設定,在網上進行著強烈的爭論,誠然這是作為一個遊戲策劃所必須的,我們要不時的補充自己的學識,可是我們是否要想一想遊戲策劃最終的工作目標不是學到了什麼,而是要知道我們如何把我們已經具有的知識如何的使用到遊戲當中,就像當初任天堂紅白機上的一款有名的遊戲《魂鬥羅》,通過橫卷軸和縱卷軸兩種視角表達方式,就很好的設定出來了遊戲空間和遊戲難度和不同的遊戲方式,讓很多玩家樂此不疲的一遍又一遍的玩著,現在我們有的國內公司採用了很新的遊戲引擎和先進技術,用了很多中華文化背景,卻沒有在市場上得到很好的效益。我想如何更好的用我們已有的知識來策劃出順應玩家遊戲心理,才是當前至關重要的。

  當前遊戲外挂的表現形式

  最後給大家列出一些在網路遊戲外挂當中使用相當高的幾個主要功能,以供大家一起分析研究,由於外挂的內容多種多樣,而且不同的遊戲類型所具有的外挂功能也大不相同,在此僅以目前佔市場比重相對較大的MMORPG類遊戲外挂功能作出列舉:

  一、加快玩家的移動速度和瞬間移動的功能;

  二、加快玩家的打怪速度,加大玩家可以打怪的距離

  三、降低玩家的操控難度:自動按鍵,自動補藥,自動瞄準,自動射擊,自動撿取物品,吸引怪物功能,固定怪物功能,自動使用技能為隊友加血等;

  四、對遊戲場景物體進行修改:透視,玩家可以到達遊戲不讓到達的地方等;

  五、自動練級外挂:它主要包括自動打怪,自動選怪,自動選擇性拾取物品,自動將物品存在倉庫,自動進行購買商品。


Reference
http://211.147.225.34/gate/big5/game.chinaitlab.com/machinate/721168_10.html

星期日, 11月 04, 2007

ACPI v.s ASL Code

ㄧ般OEM/ODM BIOS工程師接觸到BIOS中比較特殊的部份是屬於ACPI的ASL Code,因為這部份的程式碼主要的功能就是提供OS去做一些服務以及提供一些資訊給OS使用,因此本篇文章重點放在事件的觸發(event)的概念與ASL Code架構。

先說明一下何謂硬體事件: 在系統中,常常有一些硬體會產生一些事件,例如使用者按下Power Button,而這個動作需不需要讓OS知道 ? 答案是肯定的;當OS知道後,最常出現的畫面就是會跳出一個視窗,然後讓你選擇”重新開機” 、 “登出” 或是 “關閉電腦”,另外像是你的NoteBook 插上船塢(Docking) 時,也是要通知OS 目前系統插在船塢上,這樣子才能更新狀態或是做其他需要服務的事情。而這些動作就是硬體所產生的事件,【而事件產生後需要通知OS】,通知的方式也分成不同類型,最常見的方式就是SCI。

假設產生的硬體事件是透過SCI 來告知OS有事件產生,而OS的驅動程式會去辨別是屬於哪一種硬體事件(系統中可以產生事件的硬體有很多類型),然後針對不同的事件去執行不同的ASL Code。

一般透過SCI 來通知OS的硬體事件都會有一個事件編號,假設有一個硬體事件產生,而他的事件編號是Number 20(編號是BIOS端自己定義的,所以家OEM/ODM製造出來的電腦中所代表的意思也不同),一般我們稱為此事件為Q event 編號20,寫作Q20; 當OS 知道是Q20 event後,就會執行對應的ASL Code,例如:

Method(_Q20){ <--ACPI Spec定義Q Method 可以從00~FFh,其意義由製造商自己定義
…..
}

範例中 方法“Method()” 這個語法類似C語言的副程式寫法,他代表著當編號20 的硬體事件產生後,OS會去執行這個Method內所撰寫的程式碼,至於撰寫什麼功能就要參考這家BIOS規範書中的說明,一般比較常見的就是Fn+Key 的硬體事件產生後,透過ASL Code通知Application去改變音量大小。

所以對於ASL Code來說,並沒有所謂的類似C語言的主程式進入點,因為他是一個屬於event-based 的程式架構。

Main() <--C語言程式的進入點
{

FunA(...);
}

………………………………
Method(_Q20) <--ASL Code沒有進入點
{

}
Method(_Q8A)
{

}

Method(OEMM,2) //自己定義且帶有引數的方法
{
Store(Arg0,Local0);
...
}

結論:
整篇文章的重點在於說明 ASL Code是事件驅動類型,沒有所謂的程式進入點,因此你要多了解不同的硬體事件是透過什麼方式告知OS(SCI/GPE…etc),然後OS會幫你執行哪些ASL code。 至於ASL Code語法說明則參考ACPI Spec 中有更詳細的說明。

BIOS's 神秘面紗





對於一般使用者來說,BIOS的存在與否有可能連系統從買進、使用、壞損後都還不知道有他的存在,但是對於進階的使用者來(DIY 玩家),BIOS 的校調確可以增加對於系統的操控以及效能的調整。如圖所示,這是一般BIOS設定畫面,依照這家BIOS廠商的不同,所提供的設定畫面與功能也有所不同。

因此一般多數人的印象還是停留在對於BIOS 要如何設定與校調,因此對於一般想進入這個行業的新手們的入門資料也是非常的少。

目前市面上的書籍中對於BIOS比較有深入探討的是 旗標出版社 "BIOS Inside,BIOS研發技術剖析",ㄧ共是兩版本,但書籍中比較著墨在 AMI BIOS 的程式碼撰寫方式以及工具的使用,對於系統平台部分著墨較少,但是卻也涵蓋了大部分的資訊,所以比較像AMI BIOS 新進員工訓練手冊。因此,對於想進入這個行業的人,我建議可以參考這本書中的指引,對於了解BIOS 工作性質會有許多的幫助。

至於有些人認為要不要 "很懂" 組合語言? 這部分我個人覺得不是那麼重要,因為了解系統架構會比你撰寫程式碼來的重要,畢竟程式語言只是一個工具,你只要懂工具的用法就可以了,懂得系統架構的人才能對於這些語言有更深入的體會,就像是有些人會寫組合語言,但是連邏輯位址/線性位址/實體位址都搞不清楚,還會把虛擬位址搞在ㄧ起。而實際上真正懂組合語言的人真的不多,像是我本身對於組合語言就還是懵懵懂懂的,這是因為我對於硬體架構還不是那麼了解,所以對於組合語言的精神我還無法掌握,但是對於工具的應用(用組合語言撰寫程式或是修改BIOS程式碼)卻也還可以符合工作上的需求。

我對於ㄧ般有興趣的人的建議是多去看一下IA32硬體架構的書籍(PC 硬體介面研究),多了解組合語言用法,其他的就是多撰寫ㄧ些與BIOS/系統有關的程式,像是如何存取CMOS,如何呼叫BIOS提供的中斷,如何呼叫OS提供的中斷,如何存取硬碟資訊,如何列舉PCI設備...等,進階的部份就是如何切換CPU工作模式,中斷的管理...等,進階的部分一般Windows 程式書籍中會有提到。希望藉由這些資訊能夠幫助大家更了解如果要踏入 BIOS 行業你需要哪些知識。

OEM/ODM BIOS工程師的行情價: 嗯看公司...目前3x000NT(大學畢,不含公司分紅)...
如果換算其他公司算法(沒股票的那種),約5x000~6x000NT*14 個月

星期四, 11月 01, 2007

可以反組譯的 Debug 工具簡介~~~

ㄧ般Debug BIOS程式碼的時候會透過幾個反組譯工具或是Debug Tools來輔助,這邊大概就簡略說明一下我比較習慣的工具(可以反組譯程式碼及修改的工具):

1. BIOS Vendor 提供的Debug Tools
ㄧ般OEM/ODM BIOS工程師比較主要的Debug Tools,他的連線介面方式像目前最火紅的 USB2.0 cable 連線方式或是以前的1394 cable...etc.ㄧ般這種工具需要搭配BIOS Vendor的BIOS 程式碼來達成,也就是你會去使用某個"switch"來開關BIOS Code, 簡單的說就是當Switch = ON時,BIOS 的Build Tools在Compiler 你的BIOS Code時,會把Debug Tools需要用到的BIOS 程式碼拉進來一起Compiler,於是會影響到你的BIOS ROM Size的問題,因此ㄧ般我們會把ㄧ些不必要的程式碼先註解掉,以免當Debug code拉進來一起Compiler的時候造成BIOS Size爆掉(不夠用),至於"Switch"的設定則依照不同BIOS廠商就會有不同的開關方式,而建立的BIOS ROM 就是一個 Debug version,接著需要將這個BIOS燒入到主機板內,然後透過BIOS Vendor提供的Debug 軟體來做除錯的動作。

而這種架構下的Debug 方式稱為 Client(要被除錯的那塊主機板或系統) 與 Server(安裝了Debug 軟體的系統,一般就是你的工作機) 的關係,其原理簡單說就是 Client 會透過連線(USB/1394) 把ㄧ些資訊傳給Server上面的Debug 軟體,接著你就可以去做一些除錯的動作。

各家BIOS廠商的除錯工具都不同,但是方式大同小異,因此工具的學習只是基本的知識,重點還是在你對於整個系統架構的了解程度才能夠有效的針對問題解決。

2. Windows 附帶的Debug.com 以及Debug32.com
ㄧ般用來查看一些BIOS code留在系統記憶體的ㄧ些資訊(E0000~FFFFFh),這些資訊就像是DMI/PnP BIOS Struct / PCI IRQ Routing Table ...etc 或是查看一些OpROM 甚至是手動載入某個OpROM 到記憶體中並追蹤他或是修改ROM的時候可以用,其應用就看個人經驗而有不同的發揮,不過一般修改ROM還會搭配HEX Editor 直接修改機器碼就可了。

3. IDA Pro + Softice + Win32DASM + OllyDbg
這幾個工具都是針對Windows的一些問題去追蹤或是反組譯某些bin file或是破解程式時在使用,其應用範圍也是看個人經驗而有所不同,這邊只是簡單說明我個人習慣的一些工具。

4. Other
除了上面說的這些工具之外當然還會透過一些應用程式來幫忙,像是RU.EXE/SE.EXE/ACPIView.exe...etc,因為這些工具不能反組譯程式碼,所以我就不多加討論。

在這篇文章中,最主要是能將 BIOS 工作性質做一些基本說明,對於有心進入這個行業的朋友們了解,一個BIOS工程師基本上會做哪些事情以及你需要了解哪些工具,而上述的工具都是我個人習慣使用的工具,當然其他人也可能會跟我不一樣,因此希望能藉由這篇文章讓有興趣的朋友能有個方向。

星期三, 10月 31, 2007

SlickEdit® 2007's Tags






對於SlickEdit® 2007 如何建立一個專案檔我這邊就不說明了,這邊只強調如何建立Tags (標籤)。在ㄧ般我建立一個Workspace後,我會在裡面建立專案(Project)接著選取你的資料匣;而這個資料匣就是你的Source code的目錄,例如P 廠商Assembly的Corebase目錄或是I 廠商UEFI的Codebase目錄。

建立的時候因為你的目錄內可能會有很多種不同的檔案類型(*.asm ; *.c ;*.inc ...) 所以你在Add Tree的時候必須把你的檔案類型都加進去,不然預設值只會找C++的檔案格式的檔案,所以建立Tags的時候會找不到你要的檔案內的定義。如同上圖中所示,你把你要的通通都加進去。

在點選【OK】後,你會看到下圖所示的畫面,他會開始去建立Tags ....














對於建立好的專案檔中,你看到的畫面ㄧ般都是分類成Source file / Header files...等(下圖左邊),如果你想要用目錄型態顯示,就使用下面我說的方式,在專案瀏覽的地方按滑鼠右鍵,會跳出ㄧ個選單(下圖右邊),然後選擇Directory View 來顯示就可以了:







最後,你開啟你要編輯的檔案,把滑鼠移動到關鍵字中,接著按滑鼠右鍵,在跳出來的選單中選擇Go to definition 或是Go to Reference ,這樣子就可以做到很便捷的Trace Code 的方式。

不過,我忘記預設的SlickEdit中到底有沒有這兩個選項,因為如同我之前文章說的,這個工具功能強大不過要自己手動增加功能,因此我在下面的圖中有說明如何去設定他,在下圖中你可以選擇Edit Menu,然後你會看到ㄧ個設定畫面; 接著設定一些你要的功能,至於哪些指令可以做哪些功能就請你自己參考他的Help 文件檔的說明,因為我也是從那邊看,然後去設定這些功能的。

附帶一提,這個工具還可以自己擴充 "巨集Macro",我記得這個工具的目錄內有一個資料匣,裡面放了很多巨集,你可以修改它來擴充你的編輯器功能,像是點Tab 兩下就關閉你開啟的檔案...etc,利用Google應該也可以找到ㄧ些範例。


星期日, 10月 28, 2007

ACPI Table 基本知識

ACPI Table基本知識(BIOS觀點):

1.包在BIOS ROM中 的 ASL Code 就是ACPI Table,而ACPI Table有分成不同類型的Table(RSDT/FADT/DSDT...etc.)。

2.像是我們比較常使用的DSDT Table就是放了一些event code,簡單說就是當某個H/W event 發生後,系統OS會去依照描述在這個DSDT Table中的ASL Code去執行,而這些Acpi Table包在BIOS ROM中的形式是AML Code (類似機器碼)。

3.BIOS在開機過程中會把包在BIOS ROM中的Acpi Table 載入到RAM 中,然後留下一些資訊給OS來找到他們,最簡單的例子就是RSDP Table會放在1M以下的某個位址(一般都是在E0000h~FFFFFh),然後OS就可以透過搜尋"Signature"(某個標記字)的方式來找到其他的Acpi Table entry point。

[勘誤] 應該是RSDP Structure 不是 RSDP Table ,打錯了 >.< ,感謝糾正! 這個Struct內的RSD PTR欄位會指向RSDT Table ,而如何找這個Struct的方式就是在1M以下的地方找"RSD PTR",有興趣的自己用Debug.com 找看看吧 ^^。 4. OS 需要有一個 AML 翻譯器去翻譯這些AML Code,然後執行他們。 5. 每個Platform 的Host Controller 的暫存器位址會不同,所以BIOS需要透過ACPI Table來告知OS這些暫存器的位址,這樣子做的好處是OS不需要知道你是在什麼Platform,因為他只單純看BIOS所提供的H/W 資訊。 6. ACPI Table還可以用來當作OS 啟動金鑰,例如SLIC Table就是一個例子,OS透過檢查包在BIOS ROM中的ACPI Table的內容來決定是不是一個台OEM 電腦。 其他詳細介紹請參閱ACPI Spec 3.0b 以及微軟網站介紹,下圖為參考微軟文件說明:

SCI v.s SMI 基本概念

這邊大概描述一下這兩種東西的不同處(BIOS 觀點):

SMM is entered via the SMI (system management interrupt).
SMI - System Managment interrupt
SCI - System Control interrupt

由上面字義的解釋可以得知幾件事情:
1. SMI pin 觸發後會使CPU 進入SMM Mode,而BIOS會把某些程式碼放在SMM 所在位置(SMRAM)
所以簡單說就是SMI pin 觸發後,CPU會去執行BIOS中的某個程式碼,至於是哪段程式碼,就要看BIOS註冊了哪個Functon。

SMI pin--> CPU SMM Mode --> BIOS routine

2. SCI pin 觸發後是系統OS 接手後面的事情。 所以SCI觸發後,CPU會去執行某個放在中斷描述表中的程式(IDT),一般都是指向某個驅動程式(ACPI.sys )。
所以簡單說就是當SCI pin 觸發後,ACPI driver會通知相關的驅動程式(ACPI EC Driver),然後跟EC BIOS取得一個代碼,而這個代碼就是ASL Code中的Qxx Number ,接著OS 會去執行某一段ASL Code ,一般都是Method(Qxx)。至於Method(Qxx) 內要做什麼事情就要看一些BIOS Features Spec的定義。

SCI pin --> OS Acpi Driver --> ASL Code (Q event) --> ? (看BIOS Spec需求)

結論:
IA32架構中,EC Chipset會連接 2 pins(SCI/SMI)到I/O Control Host ,接著當EC 去拉這兩根pin的電位的時候(Low/High active) 南橋會告知CPU 處理後續動作(進入SMM Mode執行某段BIOS Code或是執行OS內的ACPI Driver),接著後續的動作就如同你們在BIOS 程式碼中看到的部份。

至於詳細設定資料請參考ACPI Spec、ICH Spec與IA32 Spec SMM Mode章節所描述,這部份是屬於經驗累積,江湖一點訣點破就不值錢 ^^b。

另外,為何要用SCI/SMI 則是在IA32 系統發展史中有說明,如果有興趣的人可以從APM/ACPI 歷史開始看。

星期三, 10月 24, 2007

SlickEdit & Beyond Compare 小技巧

今天在Debug BIOS code 過程中發現軟體工具的一些小技巧:

SlickEdit : 可以直些按下Ctrl + D 去開啟"某路徑的檔案"
例如:

某個xxx.dsc 檔案內容中有一行內容為
Chipset\Ich9\Ich9Init.inf
如果你想要開啟這個inf的時候,只要把游標移動到這一行,然後按下Ctrl+D ,那麼你就可以在SlickEdit中看到它開啟了Chipset\Ich9\Ich9Init.inf 這個檔案來讓你編輯。

Beyond Compare : 可以使用外部檢視工具來編輯
一般使用Beyond Compare比對兩個不同目錄內的檔案後,你可以直接點選檔案,然後Beyond Compare會使用自帶的檔案編輯器來比較檔案內容,並且顯示不同的地方,但是當你要修改內容的時候,你只能在視窗最下面"一行一行"修改,沒辦法一次修改兩行以上。

所以我們改使用另一個比較工具(Araxis Merge v6.5)來當作檔案編輯器:
1.Beyond Compare中點選 工具選項-->偏好設定-->外部檢視工具選項 然後點選"新增"
2.接著依照下面設定:

說明: AraxisMerge 快速鍵: Ctrl+A
命令列參數(你安裝的路徑): C:\Program files\....\AraxisMerge.exe %f %f
(%f %f 代表比較兩個檔案)

設定好之後,下次要開啟編輯器來比較內容的時候就按下Ctrl+A 你就可以改用Araxis Merge來編輯。

有人可能會問說,Araxis Merge 跟Beyond Compare都是一樣的東西,可以比較目錄或是檔案,幹麻要在Beyond內改用Araxis Merge所提供的檔案編輯器,直接使用Araxis Merge 來比較就好了 ?

這是因為Beyond Compare的比較畫面的視窗比較好看很清晰明瞭,但是編輯器很討厭,只能一行一行編輯,而Araxis Merge則是比較的畫面很難看,但是編輯器很好用,可以一次編輯很多行,所以我只好混搭,這樣子比較好用。

星期二, 10月 23, 2007

POST Card & Port 80h

[前言 -什麼是Debug Card]
對於BIOS 工程師來說,常常會因為我們在移植程式碼到不同平台的時候,因為忽略了一些細節而讓BIOS程式碼無法工作,最常見的就是當機。

由於BIOS是屬於一個Loader(引導程式,或是初始化程式),可能當機的地方在VGA還沒辦法顯示的地方,所以錯誤訊息可能沒辦法顯示在螢幕上,因此透過其他的方式來讓我們知道BIOS 程式碼已經執行到了哪個階段,這樣子有助於我們去Debug 。

另外對於ㄧ台已經出貨給使用者的電腦,也可以透過這個方式來維修。而對於BIOS工程師來說I/O Port 80h 是一個很實用的Debug Port,而這個I/O Address已經成為一個標準,所以我們可以透過寫入代碼到Port 80h的方式,將代碼送到ㄧ張有七段顯示器的卡片來顯示,而顯示的那張卡片就稱為Debug Card或是Post Card,而顯示在卡上面的代碼就稱為POST Code(0x00~0xFF),當然也會因為不同BIOS廠商所以代碼也會有所不同。

[IA32 架構下的Port 80h]
Port 80h 與Debug Card 的路徑是如何被初始化的呢? 這部份是討論你寫入Port 80h 的資料是如何經過硬體電路然後解碼到Debug Card?

ㄧ般而言,目前IA32架構下的電腦中POST Card可以連接到PCI/LPC...etc 不同型態的bus,在IA32架構底下I/O Control Host 會負責將寫入到Port 80h的資料往PCI/LPC Bus送,然後我們就可以顯示在七段顯示器上面。

所以,由上述可以得知:
1.BIOS端需要去組態(設定) I/O Control Host ,然後選擇Port 80h資料要送到哪邊(PCI/LPC)。
2.HW需要設計一塊POST Card來負責將I/O Control Host 送過來的資料解碼(decode)成七段顯示器能夠顯示的訊號。

所以看起來很簡單吧,其實實做的時候只要拿著ICH Spec然後ㄧ步一步下去設定就可以了。

可能會有人想問,BIOS不是自己會去初始化這部分嗎,那幹麻還要自己做?
如果你想問這個問題的話,又剛好你是一個BIOS工程師時,你可以自己實驗一樣東西,就是在FFFF_FFF0的指令跳躍之後,你寫一段下面的Code 來做一個簡單的測試,這段code最主要是在POST Card上面ㄧ直顯示99h:

FirstPostCode:
mov al,099h
mov dx,80h
out dx,al
jmp FirstPostCode

由於BIOS一開始執行的地方你就輸出資料到Port 80h,此時系統上面的POST Card 不會顯示99h,這是因為你沒有初始化I/O Control Host 所以會造成系統當機,這也就是這篇文章的重點 "如何自己動手做"。

因為BIOS 能開始讓你寫入資料到Port 80h的地方可能不是一開始的BIOS entry point ,所以如果你想要在更早的地方去輸出ㄧ個代碼到Port 80h時,你就必須這樣子做。

由於我沒觸過PCI介面的POST Card,所以沒研究要如何針對這種類型的POST card初始化,但是對於LPC bus的方式則是去組態LPC中的暫存器以及RCRB中的設定就可以了讓寫入Port 80h的資料正確的送到LPC Bus,相關詳細資訊可參考I/O Control Host Spec中的說明。

[註]
P廠商的BIOS 在Post 階段一開始的時候就會去初始化Port 80h的相關設定,而I廠商的BIOS 則會到PEI 的某個點才會去做這部份的動作。

但是不管是哪一家的BIOS,如果你想更早一點就丟Port 80h,你就必須這樣子做,當然也有例外,例如硬體電路預設就已經是對的路徑的時候(例如預設PCI Bus,而你也用PCI Debug Card),這篇文章就沒有用了...呵呵 ^^


圖 Mini PCI Debug Card

星期二, 10月 16, 2007

[我所知道的BIOS]->[Remaining POST Tasks] 11

除了之前所提的 tasks外,還有下列 main tasks是 BIOS POST會執行的:

[USB init]
=> initialize USB的部份.這方面的code幾乎是 kernel code,再加上少許的 chipset code(因為,chipset's USB controller是哪一種需要 customize, Ex. OHCI or UHCI...etc).

主要在 implement USB spec的部份(USB 1.1/2.0 and USB legacy). (天書也...沒看過...)

[KB init]
=> init KBC的部份

[HDD init]
=> 這是 locate IPL(Initial Program Load)的code.因為最終系統需要 load OS,而OS是存在 storage device中,因此需要讓storage....動起來 !

主要的工作有:
- 設定 chipset端的 storage controller(PATA or SATA)'s settings
- identify HDD
- config HDD by set-feature(<-設定 device端的 settings)

這樣一來,controller端與 device端有了 "相同的認知" 後,就可以 access HDD了 !

[ACPI]
=> 主要是將所有的 ACPI tables建至 memory中;讓ACPI OS可以 parse & config.

[Boot-to-OS]
=> 最後 BIOS's 工作是: invoke int19h(for Boot-strap) !此中斷服務程式會嘗試去找 boot device,並從中(storage)將 boot-loader 載入至 memory中;然後跳到 boot loader處,開始執行載入OS的工作 !


* 一但進入OS後,與BIOS會有關的....幾乎只剩 ACPI 了 !

BIOS不是雞肋 ^_^

[我所知道的BIOS]->[VGA init] 10

一般而言,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" 也未必完全相同 !!!

星期三, 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 說明。