內核空間與用戶空間的通信方式
下面總結了7種方式,主要對以前不是很熟悉的方式做了編程實現,以便加深印象。
1.使用API:這是最常使用的一種方式了
A.get_user(x,ptr):在內核中被調用,獲取用戶空間指定地址的數值並保存到內核變量x中。
B.put_user(x,ptr):在內核中被調用,將內核空間的變量x的數值保存到到用戶空間指定地址處。
C.Copy_from_user()/copy_to_user():主要應用於設備驅動讀寫函數中,通過系統調用觸發。
2.使用proc文件系統:和sysfs文件系統類似,也可以作為內核空間和用戶空間交互的手段。
/proc 文件系統是一種虛擬文件系統,通過他可以作為一種linux內核空間和用戶空間的。與普通文件不同,這里的虛擬文件的內容都是動態創建的。
使用/proc文件系統的方式很簡單。調用create_proc_entry,返回一個proc_dir_entry指針,然后去填充這個指針指向的結構就好了,我下面的這個測試用例只是填充了其中的read_proc屬性。
下面是一個簡單的測試用例,通過讀虛擬出的文件可以得到內核空間傳遞過來的“proc ! test by qiankun!”字符串。
3.使用sysfs文件系統+kobject:其實這個以前是編程實現過得,但是那天太緊張忘記了,T_T。每個在內核中注冊的kobject都對應着sysfs系統中的一個目錄。可以通過讀取根目錄下的sys目錄中的文件來獲得相應的信息。除了sysfs文件系統和proc文件系統之外,一些其他的虛擬文件系統也能同樣達到這個效果。
4.netlink:netlink socket提供了一組類似於BSD風格的API,用於用戶態和內核態的IPC。相比於其他的用戶態和內核態IPC機制,netlink有幾個好處:1.使用自定義一種協議完成數據交換,不需要添加一個文件等。2.可以支持多點傳送。3.支持內核先發起會話。4.異步通信,支持緩存機制。
對於用戶空間,使用netlink比較簡單,因為和使用socket非常的類似,下面說一下內核空間對netlink的使用,主要說一下最重要的create函數,函數原型如下:
extern struct sock *netlink_kernel_create(struct net *net,
int unit,unsigned int groups,
void (*input)(struct sk_buff *skb),
struct mutex *cb_mutex,
struct module *module);
第一個參數一般傳入&init_net。
第二個參數指的是netlink的類型,系統定義了16個,我們如果使用的話最好自己定義。這個需和用戶空間所使用的創建socket的第三個參數一致,才可以完成通信。
第四個參數指的是一個回調函數,當接受到一個消息的時候會調用這個函數。回調函數的參數為struct sk_buff類型的結構體。通過分析其結構成員可以得到傳遞過來的數據
第六個參數一般傳入的是THIS_MODULE。指當前模塊。
下面是對netlink的一個簡單測試,將字符串“netlink test by qiankun”通過netlink輸出到內核,內核再把字符串返回。Netlink類型使用的是22.
5.文件:應該說這是一種比較笨拙的做法,不過確實可以這樣用。當處於內核空間的時候,直接操作文件,將想要傳遞的信息寫入文件,然后用戶空間可以讀取這個文件便可以得到想要的數據了。下面是一個簡單的測試程序,在內核態中,程序會向“/home/melody/str_from_kernel”文件中寫入一條字符串,然后我們在用戶態讀取這個文件,就可以得到內核態傳輸過來的數據了。
6.使用mmap系統調用:可以將內核空間的地址映射到用戶空間。在以前做嵌入式的時候用到幾次。一方面可以在driver中修改Struct file_operations結構中的mmap函數指針來重新實現一個文件對應的映射操作。另一方面,也可以直接打開/dev/mem文件,把物理內存中的某一頁映射到進程空間中的地址上。
其實,除了重寫Struct file_operations中mmap函數,我們還可以重寫其他的方法如ioctl等,來達到驅動內核空間和用戶空間通信的方式。
7.信號:從內核空間向進程發送信號。這個倒是經常遇到,用戶程序出現重大錯誤,內核發送信號殺死相應進程。
附件列表