小華的部落格: 2007/7/1 - 2007/7/8

搜尋此網誌

星期五, 7月 06, 2007

System Shutdown

有些人對作業系統關機很有興趣,我這邊就大概描述一下BIOS在關機的動作中做了什麼事情,以及如何利用軟體工具去撰寫一段關機的程式碼。

一般在NoteBook上面控制電源的部分都是EC BIOS所控制,而有時候我們會透過Send EC Cmd方式給EC BIOS來達到關機的目的(Power Off)。

像是某些BIOS中會使用到關機的地方就是在Setup Menu-->Exit-->Shutdown 選項,而這個地方的BIOS code 就可以利用EC Cmd或是PM Register來達到關機的目的。

另外在進入作業系統後我們也可以透過上面的方式來強制關閉系統,所使用的方式就是利用PM Control Register。

所以BIOS扮演的角色就是去設定PM Register IO Address Range & ACPI Table ,這樣說或許很多人搞不懂,簡單說就是BIOS提供一些資訊給OS,提供的方式是透過ACPI Table(放在記憶體中),OS自己會去記憶體中找到ACPI Table,然後得到BIOS所提供的資訊,其中這些資訊就包含PM Register的IO Address。

底下提供一個範例程式來做系統關機的動作,如果你是在DOS下可直接用Debug.com 執行
如果是在 Windows下請自行撰寫Ring 0 程式去對IO Access 或利用相關工具:

mov ax,3c00h <--請參考ICH 手冊上面的說明
mov dx,0404h <--PM Register I/O Address. (PMBase+04h)
out dx,ax

上面有提到PM Register IO Address 資訊是由BIOS所提供,因此不同的BIOS廠商所設定 PM Register 的IO Address range也會不同,所以如果想要強制關機就必須先找到這個位址,這樣才能對PM Register做Soft off (S5 satte)的動作。 一般比較常見的就是Port 0404h,所以如果你不知道BIOS工程師設定在哪個位址,那麼你可以利用ACPI Table查詢或是請教你們的BIOS工程師。

另外如果你自己在Windows下寫了一個Ring 0 層級的程式去做S5 state(Soft Off),你會發現系統會直接關機,也就是OS不會去通知Driver工作站要關機,而是直接(立即)由硬體那邊關閉系統。

Reference
ACPI Spec 3.0
ICH8 Spec

星期一, 7月 02, 2007

逆向工程-基礎知識

MASM 運算式 C++ 運算式
========================================
BYTE PTR [bx] *(unsigned char) ebx

WORD PTR [bp] *(unsigned short *) ebp

DWORD PTR [bp] *(unsigned long *) ebp

OFFSET Var &Var


;----------------------------
; 呼叫協定 test1(par1,par2,par3)
;----------------------------
__cdecl PASCAL __stdcall
push par3; push par1 push par3
push par2; push par2 push par2
push par1; push par3 push par1
call test1 call test1 call test1;//函數內回復堆疊
add esp,0ch //回復堆疊

由上面範例可以得知,_cdecl 與_stdcall的參數都是由右邊開始堆到堆疊去,也就是說par1會在堆疊頂端。
依照__stdcall 範例:
push par2
push par1
call test2;
{
push ebp //保留原來的ebp
mov ebp,esp //ebp指向目前的堆疊頂端
mov eax, [ebp+0c] //參數par2
mov ebx, [ebp+08] //參數par1
sub esp,8 //如果程式內有變數,則保留變數大小,例如int i,j
...
add esp,8 //釋放變數佔用的堆疊
pop ebp //復原ebp
ret 8 //相當於ret : add esp,8
}
;----------------------------------------------------
;堆疊示意圖 (堆疊位址是由高往下,也就是堆疊頂端位址是低位址)
;----------------------------------------------------
... <-- ESP 會一直指向堆疊的最頂端
程式內的變數j <-- EBP-8h
程式內的變數i <-- EBP-4h
保留的EBP <-- EBP + 0 (進入副程式後會mov ebp,esp)
返回位址(Offset) <-- EBP + 4h
Par1 <-- EBP + 8h
Par2 <-- EBP + 0Ch (由左至右堆入堆疊,所以第一個被堆進去)
...

C語言複習~~~指標與函數

年紀大,東西都忘東忘西的,今天複習C Primer Plus 4/e,把一些東西記錄下來。

高度技巧的宣告
* 表示一個指標
() 表示一個函數
[] 表示一個陣列
※()與[]有相同的優先順序,他們的結合姓是由左到右 →

int a[8][8]; //int陣列的陣列
int **ptr; //指向int 指標的指標
int *risks[10]; //指向int 型態的10個指標陣列
int (*risks)[10]; //指向10個int 陣列的指標
int *oof[3][4]; //指向int型態的3x4指標陣列
int (*uuf)[3][4]; //指向3x4 int 陣列的指標
int (*uof[3])[4]; //指向4個元素的int 陣列的3個元素的指標陣列

char *fump(); //回傳指向字元的指標的函數
char (*fump)(); //指向會回傳字元型態的函數的指標
char (*fump[3])(); //3個指向會回傳字元型態的函數的指標陣列

typedef int arr5[5];
typedef arr5 *P_arr5;
typedef p_arr5 arrp10[10];
arr5 togs; //togs是有5個int元素的陣列
p_arr5 P2; //p2是指向有5個int陣列的指標
arrp10 ap; //ap是10個指向5個int陣列的指標陣列

函數宣告與指標

void ToUpper(char *); //將字串轉大寫

其中ToUpper()函數型態是void,參數是char *,如果宣告為這個函數宣告一個 pf指標,就會像下面一樣:

void (*pf)(char*); //指向函數的指標,例如: pf=ToUpper,但是不能寫成pf=ToUpper();

其中括號內的(*pf)會被括號結合,所以閱讀時他會是一個指標,所以他是一個指向函數的指標,如果省略就會不同意義:

void *pf(char *) ; //pf 是回傳指標的函數

※一般如果沒有註明時,定義的名稱本身就是位址起始,例如:
int a[10];
int *p;
p=a; 或是 p=&a[0];

void ToUpper(char *);
void (*pf)(char*);
pf=ToUpper;


應用範例:
void ToUpper(char *);
void (*pf)(char*);
void Show(void (*ff)(char*), char *str);
pf=ToUpper;

Show(ToUpper, mis); //Show函數使用ToUpper函數: ff=ToUpper
Show(pf, mis); //Show函數使用ToUpper函數: ff=pf

void Show(void (*ff)(char*), char *str)
{
(*ff)(str); //呼叫ToUpper函數,參數=str
puts(str); //顯示字串
}

C語言與組合語言對應
;-------------------------------------------
; VOID Funcation_A(VOID);
;-------------------------------------------
Funcation_A PROC PUBLIC
push eax
....
pop eax
ret
Funcation_A ENDP

;------------------------------------------------------------------------------
; VOID Funcation_B (IN UINT32 RegisterInEax, OUT OEM_REGISTER *Reg);
;
;typedef struct {
; UINT32 RegEax;
; UINT32 RegEbx;
; UINT32 RegEcx;
; UINT32 RegEdx;
;}OEM_REGISTER;
;------------------------------------------------------------------------------
Funcation_B PROC PUBLIC RegisterInEax:UINT32, Reg:PTR EFI_CPUID_REGISTER
pushad
...
mov edi, DWORD PTR Reg
...
mov DWORD PTR [edi].RegEax, eax ; Reg->RegEax
...
popad
ret
Funcation_B ENDP


;------------------------------------------------------------------------------
; UINT32 OemIoPortRead32 (IN UINT64 Address); //回傳值放EAX
;------------------------------------------------------------------------------
OemIoPortRead32 PROC PUBLIC Address:UINT64
push edx
mov edx, DWORD PTR Address
in eax, dx
pop edx
ret
OemIoPortRead32 ENDP