有了函數分類的方法,便可著手收集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
5.5 Create Device Object and Set Permission
如Table 27所示,Windows使用IoCreateDevice函數來建立DeviceObject(裝置物件),
並以DeviceCharacteristics參數設定存取權限;而Linux則是使用mknod來建立一個Device File,再使用chmod指令來設定權限,。兩者的差別在於Windows將權限寫在程式裏,而 Linux是利用指令去變更存取Device File的權限。
Windows Linux
Create device file:
mknod device_file_name type major minor
Change file permission:
chmod permissions device_file_name Format
NTSTATUS IoCreateDevice(
IN PDRIVER_OBJECT DriverObject, IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName OPTIONAL, IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics, IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject );
DeviceObject ->Flags |= DO_DIRECT_IO;
int register_chrdev(
unsigned int major, const char * name, struct file_operations *fops
);
Driver checks any ACLs for the file name
Windows DeviceCharacteristics parameters
Linux chmod permissions parameters
Administrator/Root FILE_DEVICE_SECURE_OPEN 700
Read only FILE_READ_ONLY_DEVICE 444
Table 27: Create Device Object and Set Driver Permission
Windows與Linux註冊及解註冊Device函數,如Table 28所示。Windows的
IoCreateDevice函數會根據產生的DeviceObject其Flags值(DeviceObject ->Flags)來決定對 應到Linux的是register_chrdev/unregister_chrdev或register_blkdev/unregister_blkdev函 數,也決定Linux用mknod命令來建立device file時要使用參數c(Character Device)或 b(Block Device)的type值(咖啡色字體)。
Map Type Include Windows DeviceObject->Flags Linux
1 F linux/fs.h DO_DIRECT_IO register_chrdev
1 F linux/fs.h IoCreateDevice
DO_BUFFER_IO register_blkdev
1 F linux/fs.h DO_DIRECT_IO unregister_chrdev
1 F linux/fs.h IoDeleteDevice
DO_BUFFER_IO unregister_blkdev
Table 28: Determine I/O Type between Windows and Linux
以Table 29的例子為例,產生的裝置物件(DeviceObject)是Windows的DriverObject 對應到Linux的fops參數(紫色字體);Windows產生裝置之相關函數為IoCreateDevice及 DeviceObject ->Flags |= DO_DIRECT_IO;對應到Linux則是register_chrdev及mknod的參 數(紅色字體);裝置名稱是Windows的DeviceName對應到Linux的name參數(深藍色字 體);裝置類別在Windows指定DeviceType為FILE_DEVICE_UNKNOWN對應到Linux為 Major5參數(咖啡色字體);權限設定是Windows的FILE_DEVICE_SECURE_OPEN對應到
5在 Linux 使用 cat /proc/devices 來查看可用的 Major/Minor 值
Linux的chmod 700的permisson參數(綠色字體)。
Windows Linux
# cat /proc/devices //check major
# mknod /dev/TestDevice c 253 0
# chmod 700 /dev/TestDevice Example char devicename=”TestDevice”
status = IoCreateDevice(
DriverObject,
DeviceObject ->Flags |= DO_DIRECT_IO;
char name="TestDevice";
int major=253;
int register_chrdev(
unsigned int major, const char * name, struct file_operations *fops
);
Table 29: Create Device Function between Windows and Linux
5.6 I/O Control
在32位元的平台上,Windows與Linux對於I/O Control函數6的對應也有類似的手 法,如Table 30。Windows的DeviceType對應到Linux的type參數(紫色字體),用來表示裝 置類別,Windows的DeviceType共有16 bits,而Linux的type共有8 bits,如:
Windows: #define FILE_DEVICE_PARALLEL_PORT 0x00000016 Linux: #define 'p' 80-9F
1 F asm/ioctl.h Windows not Exist but Linux Exist #define _IO(type,nr)
1 F asm/ioctl.h
1 F asm/ioctl.h #define IOCTL_Device_Function CTL_CODE(DeviceType,
#define IOCTL_Device_Function _IOW(type,nr,size)
6 請參照 Windows DDK 及 Linux Kernel 的 Documentation/ioctl-number.txt
FunctionCode, Method,
Table 30: The I/O Control between Windows and Linux
5.7 Memory Management
Windows與Linux記憶體管理的函數,如Table 31,兩邊函數原型(Function Prototype) 幾乎完全對應。
Map Type Include Windows Linux
1 F linux/slab.h ExAllocatePool kmalloc
0 F linux/slab.h ExFreePool kfree
1 F linux/slab.h RtlZeroMemory memset 0 F asm/uaccess.h RtlCopyMemory copy_from_user 0 F asm/uaccess.h RtlMoveMemory copy_from_user 0 F linux/slab.h MmFreePagesFromMdl free_page 1 F linux/vmalloc.h MmMapIoSpace ioremap 1 F linux/vmalloc.h MmUnmapIoSpace iounmap 2 F linux/mm.h Windows not Exist but Linux Exist do_mmap
0 P linux/gfp.h NonPagedPool GFP_ATOMIC
0 P linux/gfp.h PagedPool GFP_KERNEL
Table 31: The Memory Management Function between Windows and Linux
5.8 Interrupt
Windows與Linux註冊中斷的函數,如Table 32,Linux比Windows多出許多中斷函數 來處理中斷,這部分需要程式設計師自己參酌是否需要加到程式中。
Map Type Include Windows Linux
1 F linux/interrupt.h IoConnectInterrupt request_irq 1 F linux/interrupt.h IoDisconnectInterrupt free_irq 0 P asm/signal.h In Function IoConnectInterrupt()
ShareVector=FALSE
In Function request_irq() flags=SA_INTERRUPT 0 P asm/signal.h In Function IoConnectInterrupt()
ShareVector=TRUE
In Function request_irq() flags=SA_SHIRQ
2 F linux/interrupt.h Windows not Exist but Linux Exist void local_irq_save(unsigned long flags);
2 F linux/interrupt.h Windows not Exist but Linux Exist void local_irq_disable(void);
2 F linux/interrupt.h Windows not Exist but Linux Exist void local_irq_restore(unsigned long flags);
2 F linux/interrupt.h Windows not Exist but Linux Exist void local_irq_enable(void);
2 F linux/interrupt.h Windows not Exist but Linux Exist unsigned long probe_irq_on(void);
2 F linux/interrupt.h Windows not Exist but Linux Exist int probe_irq_off(unsigned long);
2 F linux/interrupt.h Windows not Exist but Linux Exist void enable_irq(int irq);
2 F linux/interrupt.h Windows not Exist but Linux Exist void disable_irq(int irq);
Table 32: The Interrupt Function between Windows and Linux
如Table 33所示,Windows的IoConnectInterrupt/IoDisconnectInterrupt函數對應到
Windows Linux
NTSTATUS IoConnectInterrupt(
OUT PKINTERRUPT *InterruptObject, IN PKSERVICE_ROUTINE ServiceRoutine, IN PVOID ServiceContext,
IN PKSPIN_LOCK SpinLock OPTIONAL, IN ULONG Vector,
IN KIRQL Irql,
IN KIRQL SynchronizeIrql,
IN KINTERRUPT_MODE InterruptMode, IN BOOLEAN ShareVector,
IN KAFFINITY ProcessorEnableMask, IN BOOLEAN FloatingSave);
int request_irq(
unsigned int irq, irqreturn_t (*handler)(), unsigned long flags, const char *dev_name,
void *dev_id);
Table 33: The Interrupt Function between Windows and Linux
5.9 Synchronization
Windows與Linux的同步函數,如Table 34。Linux比Windows多出許多同步函數來處 理同步,這部分需要程式設計師自己參酌是否需要加到程式中。以取得自旋鎖(SpinLock) 為例,Windows多了一個IRQ Level的參數要輸出,而Linux沒有這樣的機制,因此轉換 時可將這部分忽略不處理。
Windows: VOID KeAcquireSpinLock(IN PKSPIN_LOCK SpinLock, OUT PKIRQL
OldIrql);
Linux: void spin_lock(spinlock_t *lock);
Map Type Include Windows Linux
0 F asm/atomic.h InterlockedIncrement atomic_inc 0 F asm/atomic.h InterlockedDecrement atomic_dec
2 F asm/atomic.h Windows not Exist but Linux Exist void atomic_set(atomic_t *v, int i);
2 F asm/atomic.h Windows not Exist but Linux Exist int atomic_read(atomic_t *v);
2 F asm/atomic.h Windows not Exist but Linux Exist int atomic_add(int i, atomic_t *v);
2 F asm/atomic.h Windows not Exist but Linux Exist int atomic_sub(int i, atomic_t *v);
2 F asm/atomic.h Windows not Exist but Linux Exist int atomic_inc(atomic_t *v);
2 F asm/atomic.h Windows not Exist but Linux Exist int atomic_dec(atomic_t *v);
2 F asm/atomic.h Windows not Exist but Linux Exist int atomic_inc_and_test(atomic_t *v);
2 F asm/atomic.h Windows not Exist but Linux Exist int atomic_dec_and_test(atomic_t *v);
2 F asm/atomic.h Windows not Exist but Linux Exist int atomic_sub_and_test(int i, atomic_t *v);
2 F asm/bitops.h Windows not Exist but Linux Exist int set_bit(int nr, void *addr);
2 F asm/bitops.h Windows not Exist but Linux Exist int test_bit(int nr, void *addr);
2 F asm/bitops.h Windows not Exist but Linux Exist void clear_bit(int nr,void *addr);
2 F asm/bitops.h Windows not Exist but Linux Exist void change_bit(int bit, void *addr);
2 F asm/bitops.h Windows not Exist but Linux Exist int test_and_set_bit(int nr, void *addr);
2 F asm/bitops.h Windows not Exist but Linux Exist int test_and_clear_bit(nr,void *addr);
2 F asm/bitops.h Windows not Exist but Linux Exist int test_and_change_bit(int nr, void *addr);
0 T linux/types.h KSPIN_LOCK spinlock_t 0 T linux/types.h PKSPIN_LOCK spinlock_t *
3 F KeReadStateSemaphore Windows Exist but Linux not Exist
1 F KeReleaseSemaphore up
1 F KeInitializeSemaphore sema_init
1 F KeWaitForMultipleObjects down_interruptible 1 F KeWaitForSingleObject down_interruptible 0 F asm/spinlock.h KeInitializeSpinLock spin_lock_init 1 F asm/spinlock.h KeAcquireSpinLock spin_lock 1 F asm/spinlock.h KeReleaseSpinLock spin_unlock
2 F Windows not Exist but Linux Exist void spin_lock_irq(spinlock_t *lock);
2 F Windows not Exist but Linux Exist void spin_lock_bh(spinlock_t *lock);
2 F Windows not Exist but Linux Exist void spin_unlock_bh(spinlock_t *lock);
0 F KeAcquireSpinLockAtDpcLevel spin_lock 0 F KeReleaseSpinLockFromDpcLevel spin_unlock
2 F Windows not Exist but Linux Exist void init_rwsem(struct rw_semaphore *sem);
2 F Windows not Exist but Linux Exist void down_read(struct rw_semaphore *sem);
2 F Windows not Exist but Linux Exist void up_read(struct rw_semaphore *sem);
2 F Windows not Exist but Linux Exist void down_write(struct rw_semaphore *sem);
2 F Windows not Exist but Linux Exist void up_write(struct rw_semaphore *sem);
2 F Windows not Exist but Linux Exist void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
2 F Windows not Exist but Linux Exist void spin_ulock_irqrestore(spinlock_t *lock, unsigned long flags);
Table 34: The Synchronization Function between Windows and Linux
5.10 Double Linked List
Windows與Linux的雙向鏈結函數,如Table 35所示,兩邊函數原型(Function Prototype)幾乎完全對應。
Map Type Include Windows Linux
0 F linux/list.h InitializeListHead INIT_LIST_HEAD 0 F linux/list.h InsertHeadList list_add
0 F linux/list.h InsertTailList list_add_tail 0 F linux/list.h IsListEmpty list_empty 1 F linux/list.h RemoveHeadList list_move 1 F linux/list.h RemoveTailList list_move_tail 0 T linux/list.h PLIST_ENTRY list_head * 0 T linux/list.h LIST_ENTRY list_head
Table 35: The Double Linked List Function between Windows and Linux
5.11 Timer
Windows與Linux的計時器函數,如Table 36所示。Windows平台使用KeSetTimer函 數來指定時間及回呼函數(Call Back Function)而Linux則使用timer_list的結構來存放這些 對應參數。
Map Type Include Windows Linux
0 F linux/time.h KeInitializeTimer init_timer 0 F linux/time.h KeCancelTimer del_timer
2 F linux/time.h Windows not Exist but Linux Exist int mod_timer(struct timer_list *timer, unsigned long expires);
1 F linux/time.h
BOOLEAN KeSetTimer(
IN PKTIMER Timer,
IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL );
struct timer_list TIMER_INITIALIZER(
_function, _expires, _data);
_timer.expires _timer.function
Table 36: The Timer Function between Windows and Linux
5.12 Work Thread
Windows與Linux的工作項函數,如Table 37所示。
Map Type Include Windows Linux
1 F linux/interrupt.h IoAllocateWorkItem create_workqueue 0 F linux/workqueue.h IoFreeWorkItem destroy_workqueue 1 F linux/interrupt.h IoQueueWorkItem int queue_work
3 F linux/workqueue.h IoSizeOfWorkItem Windows Exist but Linux not Exist
Table 37: The Work Thread Function between Windows and Linux
5.13 Module Description and Function Export
Module是Linux獨有但Windows沒有的函數,如Table 38所示,此部分會在轉換時加 入,程式設計師可自行調整內容。
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);
2 P Windows not Exist but Linux Exist MODULE_AUTHOR("Undefined");
2 P Windows not Exist but Linux Exist MODULE_LICENSE("GPL");
2 P Windows not Exist but Linux Exist MODULE_DESCRIPTION("Undefined");
Table 38: The Module Description is Linux Only Function
Function Export也是Linux才有的函數,如Table 39,此部分視程式設計師需要增加。
Map Type Include Windows Linux
2 F Windows not Exist but Linux Exist EXPORT_SYMBOL(name);
2 F Windows not Exist but Linux Exist EXPORT_SYMBOL_GPL(name);
Table 39: The EXPORT_SYMBOL is Linux Only Function
5.14 IRP Relative Function
在Linux沒有Irp的封包也沒有IRQ Level,如Table 40,因此這部分可忽略不必移轉
到Linux。
Map Type Include Windows Linux
3 F IoFreeIrp Windows Exist but Linux not Exist
3 F IoGetCurrentIrpStackLocation Windows Exist but Linux not Exist 3 F IoGetNextIrpStackLocation Windows Exist but Linux not Exist 3 F IoInitializeIrp Windows Exist but Linux not Exist 3 F IoMakeAssociatedIrp Windows Exist but Linux not Exist
3 F IoMapTransfer Windows Exist but Linux not Exist
3 F IoMapTransfer Windows Exist but Linux not Exist