|
第14章 內核空間與用戶空間數據交互實驗
在“第12章 字符設備驅動框架實驗”中,已經對file_operations結構體的進行了填充,該結構體的每一個成員都對應著一個系統調用,例如read、write等,在對應的實驗中,只是對調用函數進行了標志打印,并沒有真正實現設備的讀寫功能,而在本章節將對內核空間與用戶空間的數據交換功能進行實現。
14.1 內核空間與用戶空間
Linux系統將可訪問的內存空間分為了兩個部分,一部分是內核空間,一部分是用戶空間。操作系統和驅動程序運行在內核空間(內核態),應用程序運行在用戶空間(用戶態)。
那么為什么要區分用戶空間和內核空間呢?
(1)內核空間中的代碼控制了硬件資源,用戶空間中的代碼只能通過內核暴露的系統調用接口來使用系統中的硬件資源,這樣的設計可以保證操作系統自身的安全性和穩定性。
(2)從另一方面來說,內核空間的代碼更偏向于系統管理,而用戶空間中的代碼更偏重業務邏輯實現,倆者的分工不同。
硬件資源管理都是在內核空間完成的,應用程序無法直接對硬件進行操作,只能通過調用相應的內核接口來完成相應的操作。比如應用程序要對磁盤上的一個文件進行讀取,應用程序可以向內核發起一個“系統調用”申請——我要讀取磁盤上的文件。這個過程其實是通過一個特殊的指令讓進程從用戶態進入到了內核態。在內核空間中,CPU可以執行任何命令,包括從磁盤上讀取數據,具體過程是先把數據讀取到內核空間中,然后再把數據拷貝到用戶空間并從內核態切換到用戶態。此時應用程序已經從系統調用中返回并拿到了想要的數據,可以繼續往下執行了。
進程只有從用戶空間切換到內核空間才可以使用系統的硬件資源,切換的方式有三種:系統調用,軟中斷,硬中斷,如下圖(圖 14-1)所示:
14.2 用戶空間和內核空間數據交換
內核空間和用戶空間的內存是不能互相訪問的。但是很多應用程序都需要和內核進行數據的交換,例如應用程序使用read函數從驅動中讀取數據,使用write函數向驅動中寫數據,上述功能就需要使用copy_from_user和copy_to_user倆個函數來完成。copy_from_user函數是將用戶空間的數據拷貝到內核空間。copy_to_user函數是將內核空間的數據拷貝到用戶空間。
這倆個函數定義在了kernel/include/linux/uaccess.h文件下,如下所示:
copy_to_user
函數原型:
unsigned long copy_to_user_inatomic(void __user *to, const void
*from, unsigned long n);
函數作用:
把內核空間的數據復制到用戶空間。
參數含義:
*to是用戶空間的指針
*from是內核空間的指針
n是從內核空間向用戶空間拷貝的字節數
copy_from_user
函數原型:
unsigned long copy_from_user(void *to, const void __user *from,
unsigned long n)
函數作用:
把用戶空間的數據復制到內核空間。
參數含義:
*to是內核空間的指針
*from是用戶空間的指針
n是從用戶空間向內核空間拷貝的字節數
14.3 實驗程序編寫
14.3.1 驅動程序編寫
本驅動程序對應的網盤路徑為:iTOP-RK3568開發板【底板V1.7版本】\03_【iTOP-RK3568開發板】指南教程\02_Linux驅動配套資料\04_Linux驅動例程\09\module。
在該實驗中將實現內核空間和用戶空間進行數據交換的功能。以12章編寫的字符設備驅動框架實驗為基礎編寫驅動程序,程序使用copy_to_user函數和copy_from_user函數來實現內核空間和用戶空間互傳數據的功能,編寫完成的file.c代碼如下所示:
以上代碼在cdev_test_read函數中使用copy_to_user函數將內核數據拷貝到用戶空間,在cdev_test_write函數中使用copy_from_user函數將用戶空間數據拷貝到內核空間。
14.3.2 編寫測試 APP
本應用程序對應的網盤路徑為:iTOP-RK3568開發板【底板V1.7版本】\03_【iTOP-RK3568開發板】指南教程\02_Linux驅動配套資料\04_Linux驅動例程\09\app。
編寫測試APP其實是在編寫Linux應用,編譯完成的應用程序app.c代碼如下所示:
14.4 運行測試
14.4.1 編譯驅動程序
在上一小節中的file.c代碼同一目錄下創建 Makefile 文件,Makefile 文件內容如下 所示:
對于Makefile的內容注釋已在上圖添加,保存退出之后,來到存放file.c和Makefile文件目錄下,如下圖(圖14-2)所示:
然后使用命令“make”進行驅動的編譯,編譯完成如下圖(圖14-3)所示:
編譯完生成 file.ko目標文件,如下圖(圖 14-4)所示:
至此我們的驅動模塊就編譯成功了,下面進行應用程序編譯.
下面進行驅動程序的測試。
輸入以下命令運行應用程序,如下圖(圖 14-7)所示
由上圖可知,打印“This is cdev_test_open”信息說明成功打開了字符設備驅動。
打印“ This is cdev_test_read”和“buf1 is This is cdev_test_read!”說明應用程序成功讀取到內核的數據。
打印“This is cdev_test_write”和“kbuf is nihao”說明應用程序向內核寫數據成功。
最后打印“This is cdev_test_release”說明卸載字符設備。
更多內容可以了解迅為RK3568開發板