在解決了在內核空間置入可運行代碼后,需要解決的是用戶空間和內核空間的交互。具體來說,需要達到以下三個功能:用戶空間的程序向內核空間下的程序控制,用戶空間到內核空間的數據傳遞,內核空間到用戶空間的數據傳遞。以下小節,都旨在利用系統提供給我們的各種接口,實現以上三個目標中的一個或幾個。
4.1 printk
printk是內核用來記錄系統運行日志的方法。對于用戶,可以通過dmesg命令查看近期的系統日志信息,或者直接訪問/var/log/kernel 查看內核輸出的所有歷史log。在kernel module中調用printk是最簡單的傳遞信息到用戶空間的方法。printk函數的使用方法和用戶態下的printf類似,區別是可以通過 KERN_INFO等宏輸出從0-7的指定級別的log信息。常見的使用方式如下:
char myname[] = "chinacodec\n";
printk(KERN_INFO "Hello, world %s!\n", myname);
4.2 偽字符設備
在linux中,用戶對設備的操作往往被抽象為對文件的操作。利用這一特性,可以通過注冊和實現偽字符設備到內核,來實現用戶進程和內核空間的交互。當在用戶空間執行對該偽設備的open/read/write /ioctl/mmap/release等操作時,這些被復用的系統調用就會使進程從用戶態進入到內核態,從而在內核中完成事先注冊的操作,當然可以包括對KAPI的調用等。
具體方法是,首先,在kernel module中通過register_chrdev注冊一種偽字符設備到內核,參數包括:設備的major號,需要和系統已有設備不沖突;設備的名稱name;文件操作函數集fops。register_chrdev的定義如下:
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
其中,結構file_operations中包含一系列的函數指針,對應每種系統調用(包含read/write/open等),使用中,可以用如下的方式賦值(而不必為每一個元素都賦值),那些未顯式賦值的元素被賦值為null。
static struct file_operations fops = { .read = device_read, .write = device_write, .ioctl = device_ioctl, .open = device_open, .release = device_release }; |
register_chrdev一般在kernel module中的init函數中執行,當insmod這個module時,設備就被注冊到內核中。然后,用戶就可以通過mknod命令可以創建對應的字符設備文件。然后通過open/write/read/ioctl/mmap/release等系統調用以訪問設備文件的方式,訪問該設備。每種調用都會執行到在注冊設備時注冊的對應的文件操作函數。此外,對應于register_chrdev,從內核卸載該偽設備驅動的函數為 unregister_chrdev。
以ioctl為例,當以上面的file_operations注冊了偽字符設備后,當用戶對偽設備文件執行ioctl后,調用會進入內核態,執行 device_ioctl函數。如果我們在自定義的device_ioctl函數中去調用KAPI,就實現了用戶進程對KAPI的訪問。
4.3 普通文件讀寫
內核態中,可以完成對用戶文件系統任意文件的訪問。因此,可以在內核態將要輸出的信息寫入文件,寫入后用戶態程序直接讀取文件就可以完成從內核空間向用戶空間的數據傳遞。但是在內核態下,對文件進行訪問的調用函數和用戶態下的系統調用有所區別。通常的使用方法是通過filp_open打開文件,然后利用獲得的文件指針得到文件操作函數,以讀取和寫入文件,基本代碼如下:
tmp _filp = filp_open(dst_file_name, O_RDWR | O_CREAT, 00); tmp _copied = dst_filp->f_op->write(tmp_filep, buffer, size, offset); tmp _len = dst_filp->f_op->read(tmp _filep, buffer, size, offset); |
因為是在內核中對文件操作,所以為了通過系統調用中對緩沖區內存地址參數的檢查,需要修改檢查允許范圍。方法是在read或write操作前通過set_fs擴大允許空間,操作后再通過setfs恢復到此前的允許范圍,具體方法是:
orig_fs = get_fs(); set_fs(KERNEL_DS); //write or read set_fs(orig_fs); |
4.4 Proc文件系統
proc文件系統,是當前內核或內核模塊,和用戶交互的主要方式,它通過將虛擬的文件系統掛載在/proc下,利用虛擬文件讀寫在用戶和內核態間傳遞信息。通過內核模塊,可以向/proc下注冊新的文件,指定用戶讀寫該文件時的回調函數;這樣,當用戶讀寫該文件時,工作在內核態的回調函數就可以執行信息交互的有關工作。
原文轉自:http://www.uml.org.cn/Test/201210242.asp