• 沒有找到結果。

3 The Comparison of Development Environment

3.2 Compiler Require Files

一般來說,要能在 Windows 平台成功編譯一個基本的驅動程式需要四類檔:

第一個是 makefile 檔

第二個是 Driver Source Code 第三個是 sources 文件 第四個檔是 RC 檔

RC 檔及 sources 檔是根據 Table 7 所示。

Windows

需求修改。Linux 平台只需 makefile 及 Driver Code 即可,如

Linux

Table 7: Compiler Required Files

兩邊的編譯檔都有使用Makefile,Makefile是用來指定要編譯的檔及要連結的函式 庫(Li

indows makefile in Linux

brary)。不過Windows不用修改Makefile,而是用sources檔來取代Makefile的功能。

Table 1是兩邊編譯程式的範例,作法十分類似,但本論文將不會探討兩個平台Makefile 的轉換。

source in W

TARGETNAME = TestDriver R

TARGETTYPE = DRIVE MSC_WARNING_LEVEL =/W3 C_DEFINES = $(C_DEFINES) /DMAXDEBUG /DDEBUG /DDBG=1 SOURCES = TestDriver.c

ED_ p.

PRECOMPIL INCLUDE=precom PRECOMPILED_PCH =precomp.pch PRECOMPILED_OBJ=precomp.obj

obj-m := TestDr

DIR := /lib/modules/$(shell unam K

-r)/buil

PWD := $(shell pwd) A_

EXTR CFLAGS := -I/u -I/usr/include/

efault:

d

SUBDIRS=$(PWD) modules Table 8: The Ex

.3 Building Environment

安裝Windows DDK(Device Driver Kit),用其編譯器 來編

tools Linux use gcc ample with Makefile

3

在Windows平台編譯Driver必須

譯Device Driver,而Linux則是使用一般的gcc(GNU Compiler Collection)來編譯程 式。其編譯指令如Table 9。

Windows use DDK Building

C:\WINDDK\3790\src\network\ndis\netvm EL__ -DMODULE all ini>build -cZ

#gcc -D__KERN

-I/usr/src/linux-2.6.10/include -c -O -W demodriver.c -o demodriver.ko

#./makefile

Table 9: Compile your Device Driver

Figure 10,Windows Device Driver的編譯與連結是由DDK Builder來控制,其編 譯器

有Checked與Free兩種版本[22]。Checked Build建立含有除錯資訊的驅動程式,您可

在開發時期使用。編譯程式最佳化在此狀況下是停用的狀態且程式中將會加入用於

Figure 10: Windows DDK has Checked and Free Build

3.4 anual Install、Located and Set Loading Sequence

Linux則是 Device Manager to install

The way to manual remove

Remove the device driver by Device Manager

# rmmod ./fdo.ko

Driver configuration odprobe)

file

%win%/inf /etc/modules.conf(#m

Driver location %win%/system32/drivers /lib/modules、/proc/modules、 /sys/modules

Driver file extension *.sys *.ko

Tab Management and Located vice Driver

若要指定Device Driver開機後的啟動順序,分別可在Windows的Registry及Linux Kern

ence in

le 10: of De

el的drivers目錄下,修改makefile,如Table 11及Figure 11。

Windows Set the LoadOrderGroup in INF File to set the boot sequ HKLM\CurrentControlSet\Control\ServiceGroupOrderKey Linux usr\src\linux-2.6.9\drivers\Makefile

Table 11: Driver Loading Sequence OS

Odds

Figure 11: Loading Sequence in Windows Driver

3.5 Debug Kernel Mode Driver

兩邊的平台也各提供了一些類似的方法讓我們在Kernel Mode有和善的除錯工具,

Table 12為兩個平台相關的函數及工具。

Windows Linux

Print message function KdPrint(); printk();

False then break expression

ASSERT(); BUG_ON();

WARN_ON();

Show the message DbgViewer Tool #dmesg

message can appear at console and /var/log/messages

Kernel mode debugging tools

WinDbg/KD/SoftICE/Dump Kernel Memory

gdb/Oops

Document DDK usr/src/linux/Documentation/

Odds

OS

Table 12: Debug Relative Function and Tool

在撰寫驅動程式的過程中有時會導致整個系統當機,在Windows平台會顯示藍色死

亡畫面("Blue Screen of Death" - BSOD),並秀出錯誤的位址及錯誤代碼(Bug Code)3,而 Linux也有類似的訊息來告知使用者系統已當機,如Figure 12。

Windows example blue screen

Linux will show panic or halt

Figure 12: OS Crash in Both Platforms

3 相關資料請查看 DDK 的 inc\w2k\bugcodes.h

從上面的種種對應及比較可以看出兩個平台在編輯及處理程式提供了許多功能相 近的工具,也因此我們可用這些工具觀察出兩個平台驅動程式與作業系統、硬體互動的 更多對應之處。

4 The Classify of Driver Function

4.1 The Skeleton of Program Function

要分析及轉換一個程式前,我們必須先了解一個程式的結構,以下面一個C語言所 寫的範例為例:

void main() {

printf(“ 5 + 5 = ", add(5,5));

}

int add(x,y) {

return sum(5,5);

}

程式由小到大的分別由三個步驟完成,如Table 13紅色箭頭所示:

Step 1:單一識別子( Single Identifier)組成一行函數原型(Function Prototype)。

Step 2:每個單行的函數原型再組成一個函數區塊(Function Block)。

Step 3:所有函數區塊的集合就形成了最後的程式區段(Program Section)。

Element Example

Single Identifier void、main、int、printf、sum 、return

Function Prototype

printf(“ 5 + 5 = ", add(5,5)); 、 sum(5,5);

Function Block

int add(x,y) {

return sum(5,5);

}

Program Section

void main() {

printf(“ 5 + 5 = ", add(5,5));

}

int add(x,y) {

return sum(5,5);

}

Table 13: Construct a Program Function

把要比對的識別子(Identifier)分成五種型態,存在資料庫並給予一個代號(flag)來區 別,如Table 14所示,藍色字體為Windows Identifier、紅色字體為Linux Identifier,分別 介紹如下:

No Flag Type Example

1 F Function ExFreePoolÆkfree

KeSetPriorityThreadÆset_user_nice 2 S Status STATUS_UNSUCCESSFULÆ-EFAULT

STATUS_DEVICE_BUSYÆ-EBUSY 3 P Function Parameter PagedPoolÆGFP_KERNEL

NonPagedPoolÆGFP_ATOMIC 4 T Data Type PUINTÆunsigned int *

KSPIN_LOCK Æspinlock_t LIST_ENTRYÆlist_head 5 D Driver Only DriverEntryÆfile_operations

DEVICE_EXTENSIONÆprivate_data

Table 14: The Category of Single Identifier

z 第一種F為函數,釋放記憶體的函數原型在Windows和Linux分別為:

VOID ExFreePool(IN PVOID P);

void kfree (void *ptr);

以及調整執行緒優先權的函數原型在Windows和Linux分別為:

KPRIORITY KeSetPriorityThread(IN PKTHREAD Thread, IN KPRIORITY Priority);

void set_user_nice ( task_t *p , long nice);

以及插入項目到串列尾部的函數原型在Windows和Linux分別為:

VOID InsertTailList(IN PLIST_ENTRY ListHead,IN PLIST_ENTRY Entry);

void list_add_tail(struct list_head *new, struct list_head *head);

z 第二種S為回傳的狀態值,失敗的回傳值在Windows和Linux分別為:

STATUS_UNSUCCESSFUL -EFAULT

以及裝置忙碌的回傳值在Windows和Linux分別為:

STATUS_DEVICE_BUSY -EBUSY

z 第三種P為函數的參數值,可移出分頁的參數在Windows和Linux分別為:

PagedPool GFP_KERNEL

以及不可移出分頁的參數在Windows和Linux分別為:

NonPagedPool GFP_ATOMIC

z 第四種T為資料型態,指向無正負符號的整數型態變數,在Windows和Linux 分別為:

PUINT unsigned int *

以及自旋鎖的資料型別在Windows和Linux分別為:

KSPIN_LOCK spinlock_t

以及雙向鏈結串列型態在Windows和Linux分別為:

LIST_ENTRY list_head

z 第五種D為驅動程式特有的識別子,驅動程式指定Entry Function在Windows和 Linux分別為:

DriverEntry file_operations

以及驅動程式內部資料在Windows和Linux分別為:

DEVICE_EXTENSION private_data

4.2 Classify the Map with Driver Function

收集常用的Function比對後,可以完全對應(Full Map)的Identifier有77個,部分對應 (Partial Map)的有33個,只有Windows才有的Function有73個,只有Linux才有的Function 有28個,如Table 15。

Symbol Map Count

0 Full Map 77

1 Partial Map 33

2 Only for Windows, will mark it 73 3 Only for Linux, no influence or added 28

Total 211 Table 15: The Statistic of Function Map

兩邊的程式都是使用C語言來撰寫,所以平時用到的函數,如sizeof()、sum()函數

Windows Linux

Function Prototype

VOID RtlCopyMemory(

IN VOID UNALIGNED *Destination, IN CONST VOID UNALIGNED *Source, IN SIZE_T Length

);

Unsigned long copy_from_user(

void *to,

Table 16: Full Map with Data Copy Function

z Partial Map:函數功能完全相同但參數部分相同,以I/O位址對映到記憶體的函 數為例,如Table 17,在Windows的函數名為MmMapIoSpace,在Linux函數名 為ioremap,均有指定記憶體位置及大小的參數,但Windows平台多了一個指 定CacheType的參數。

Windows Linux

Function Prototype PVOID MmMapIoSpace(IN

PHYSICAL_ADDRESS PhysicalAddress, IN ULONG NumberOfBytes,

IN MEMORY_CACHING_TYPE CacheType );

void *ioremap(

unsigned long phys_addr, unsigned long size );

Token with parameter

MmMapIoSpace ioremap

Table 17: Partial Map with I/O Map Function

另一個類似的例子是將某塊記憶體清空為零的函數,如Table 18,在Windows的函 數名為RtlZeroMemory對應到Linux的函數名為memset,均有指定記憶體位置及長度的參 數,但Linux平台的函數較有彈性,在第二個參數可設定將記憶體清成偏好的值。此部

分要轉換必須將各個Identifier轉成Lex/Yacc可辨識的Token,再重新排放。

Windows Linux

Function Prototype VOID RtlZeroMemory(

IN VOID UNALIGNED *Destination, IN SIZE_T Length

);

void *memset(

void *s,

int c, // can set to prefer value size_t n

);

Table 18: Partial Map with Memory Set Function

z 特殊情況一:Windows沒有但Linux才有的函數,像module_init及module_exit 這兩個函數是Linux Driver特有的函數,如Table 19。此部分轉換後由Driver Generator另行加入程式碼即可。

Map Type Include Windows Linux

2 F linux/init.h Windows not Exist but Linux Exist module_init(XXX_init);

2 F linux/init.h Windows not Exist but Linux Exist module_exit(XXX_exit);

Table 19: Linux Only Function

z 特殊情況二:Windows有但Linux沒有的函數,像IoCreateSymbolicLink及 IoDeleteSymbolicLink這兩個函數是Windows Driver特有的函數,如Table 20。

此部分轉換到Linux後必須將Windows程式註解掉。

Map Type Include Windows Linux

3 F IoCreateSymbolicLink Windows Exist but Linux not Exist 3 F IoDeleteSymbolicLink Windows Exist but Linux not Exist

Table 20: Windows Only Function

有了上面的分類基礎及處理方式才能著手建立轉換模式,在後面的章節我們會使用 Lex/Yacc[19][20]來做轉換,並將這些函數的對應建立在資料庫裏以便做前置處理。

5 The Comparison of Driver Function

有了函數分類的方法,便可著手收集Device Driver的相關函數,分類並記錄對應函 數的各種屬性(Map Type),以便轉換時能有足夠的訊息判斷及處理。在本章我們把 Windows Driver一般用途(General Purpose)的函數分成十五類並找出Linux對應的函數來 探討。最後的結果會存放在資料庫,並以欄位記錄對應函數的類別、是否完全對應、Linux 函數的標頭檔以及對應的函數名稱,如Figure 13。

Figure 13: Store the Function Map in Database

5.1 Entry Function Point in Driver

Windows 將Driver所需的Entry Function利用DriverObject的變數來傳遞而Linux則 是用file物件,如Table 21所示,Windows的Entry Function被註冊在

DriverObject->MajorFunction,而Linux則是註冊在file->file_operations。此外Windows將 Driver Internal Data記錄在DeviceObject->DeviceExtension而Linux則是記錄在

file->private_data。

Windows Linux

Entry Function DriverObject->MajorFunction file->file_operations

Driver Internal Data DeviceObject->DeviceExtension; file->private_data;

Parameter will passed in Entry Function

DeviceObject、IRP file、inode, etc.

Table 21: Driver Relative Mapping Data

Windows及Linux在Kernel Mode Driver都定義一組的基本的函數,當Driver初始化時 就會註冊並呼叫這些函數,如Figure 22,一般來說整個Driver在載入及卸載的過程中會 與OS有Load、Unload、Read、Write、I/O、電源、熱插拔的問題要處理。

Windows Linux

Entry Function

DriverEntry() file_operations

Init DriverObject->DriverExtension->AddDevice XXX_init module_init(XXX_init);

Unload DriverObject->DriverUnload XXX_exit module_init(XXX_exit);

IRP_MJ_CREATE open IRP_MJ_CLOSE release

IRP_MJ_READ read4

IRP_MJ_WRITE write

IRP_MJ_PNP Minor Functions:

IRP_MN_START_DEVICE IRP_MN_QUERY_STOP_DEVICE IRP_MN_STOP_DEVICE

IRP_MN_CANCEL_STOP_DEVICE IRP_MN_QUERY_REMOVE_DEVICE IRP_MN_REMOVE_DEVICE

IRP_MN_CANCEL_REMOVE_DEVICE IRP_MN_SURPRISE_REMOVAL IRP_MN_QUERY_CAPABILITIES IRP_MN_QUERY_PNP_DEVICE_STATE

4因 Windows Driver 的 I/O 為非同步 I/O(asynchronous I/O)所以在 linux 的 file_operations 應選用 aio_write/aio_read 來對應,並在標頭檔加入<linux/aio.h>。

IRP_MJ_POWER Minor Functions:

.shutdown //power off .suspend //low power .resume //full power in <linux/device.h>.

IRP_MJ_INTERNAL_DEVICE_CONTROL Windows Exist but Linux not Exist

IRP_MJ_CLEANUP Windows Exist but Linux not Exist

IRP_MJ_QUERY_INFORMATION Windows Exist but Linux not Exist IRP_MJ_SET_INFORMATION Windows Exist but Linux not Exist IRP_MJ_SYSTEM_CONTROL Windows Exist but Linux not Exist

Windows not Exist but Linux Exist mmap

Windows not Exist but Linux Exist check_flags Windows not Exist but Linux Exist llseek Windows not Exist but Linux Exist send_file

Table 22: The Entry Function between Windows and Linux

5.2 Hardware

Windows與Linux硬體操作的函數,如Table 23所示,大部分的函數參數相同且完全 對應(Map=0)。

Map Type Include Windows Linux

0 F asm/io.h WRITE_PORT_BUFFER_UCHAR outsb 0 F asm/io.h WRITE_PORT_BUFFER_ULONG outsl 0 F asm/io.h WRITE_PORT_BUFFER_USHORT outsw

1 F asm/io.h WRITE_PORT_UCHAR outb

1 F asm/io.h WRITE_PORT_ULONG outl

1 F asm/io.h WRITE_PORT_USHORT outw

0 F asm/io.h WRITE_REGISTER_BUFFER_UCHAR iowrite8_rep 0 F asm/io.h WRITE_REGISTER_BUFFER_ULONG iowrite32_rep 0 F asm/io.h WRITE_REGISTER_BUFFER_USHORT iowrite16_rep 0 F asm/io.h WRITE_REGISTER_UCHAR iowrite8 0 F asm/io.h WRITE_REGISTER_ULONG iowrite32 0 F asm/io.h WRITE_REGISTER_USHORT iowrite16 0 F asm/io.h READ_PORT_BUFFER_UCHAR insb 0 F asm/io.h READ_PORT_BUFFER_ULONG insl 0 F asm/io.h READ_PORT_BUFFER_USHORT insw

0 F asm/io.h READ_PORT_UCHAR inb

0 F asm/io.h READ_PORT_ULONG inl

0 F asm/io.h READ_PORT_USHORT inw

0 F asm/io.h READ_REGISTER_BUFFER_UCHAR ioread8_rep 0 F asm/io.h READ_REGISTER_BUFFER_ULONG ioread32_rep 0 F asm/io.h READ_REGISTER_BUFFER_USHORT ioread16_rep 0 F asm/io.h READ_REGISTER_UCHAR ioread8 0 F asm/io.h READ_REGISTER_ULONG ioread32 0 F asm/io.h READ_REGISTER_USHORT ioread16

Table 23: The Hardware Function between Windows and Linux

以Table 24所對應的函數為例,WRITE_PORT_BUFFER_UCHARÆ outsb傳入的參 數都是一樣。

Windows Linux

Function Prototype VOID WRITE_PORT_BUFFER_UCHAR(

IN PUCHAR Port,

unsigned long count);

Token without parameter

WRITE_PORT_BUFFER_UCHAR outsb

Table 24: The Map of Port I/O Function

5.3 Reply Status

Windows與Linux的回傳值狀態的對應,如Table 25所示。Windows的狀態值被定義 在DDK的ntstatus.h,此檔定義了500多個值;而Linux則被定義在errno-base.h,只有定義 34個值。因此無法對應的部分會先行轉成-EFALUT值,再由程式設計師自行判斷調整。

Map Type Include Windows Linux

0 S linux/errno-base.h STATUS_INSUFFICIENT_RESOURCES -ENOMEM 0 S linux/errno-base.h STATUS_INVALID_PARAMETER -EINVAL 0 S linux/errno-base.h STATUS_UNSUCCESSFUL -EFAULT 0 S linux/errno-base.h STATUS_DEVICE_BUSY -EBUSY 0 S linux/errno-base.h STATUS_UNEXPECTED_IO_ERROR -EIO

0 S STATUS_SUCCESS 0

Table 25: The Reply Status between Windows and Linux

5.4 Data Type

Windows與Linux一般資料型態的函數,兩邊函數原型(Function Prototype)幾乎完全 對應(Map=0),如Table 26所示。

Map Type Include Windows Linux

0 T linux/types.h PUINT u8 *

0 T linux/types.h PUSHORT u16 *

0 T linux/types.h PULONG u32 *

0 T linux/types.h PULONGLONG u64 *

0 T linux/types.h PVOID void *

0 T linux/types.h PUCHAR unsigned char *

0 T linux/types.h PUINT unsigned int *

0 T linux/types.h PUSHORT unsigned short *

0 T linux/types.h PULONG unsigned long *

0 T linux/types.h UCHAR unsigned char

0 T linux/types.h UCHAR_PTR unsigned char *

0 T linux/types.h UINT unsigned int

0 T linux/types.h UINT_PTR unsigned int *

0 T linux/types.h USHORT unsigned short

0 T linux/types.h USHORT_PTR unsigned short *

0 T linux/types.h ULONG unsigned long

0 T linux/types.h ULONG_PTR unsigned long *

Table 26: The Data Type between Windows and Linux

Table 26: The Data Type between Windows and Linux

相關文件