Linux編寫核心模組及檔案讀寫
sysfs是什麼
sysfs是一個基於記憶體的檔案系統,它的作用是將核心資訊以檔案的方式提供給使用者程式使用。該檔案系統的目錄層次結構嚴格按照核心的資料結構組織。除了二進位制檔案外(只有特殊場合才使用),sysfs檔案內容均以ASCII格式儲存,且一個檔案只儲存一個數據,另外,一個檔案不可大於一個記憶體頁(通常為4096位元組)。
專案要求將char陣列儲存到屬性檔案,下面將介紹如何完成。Linux核心模組是什麼
核心模組是Linux核心向外部提供的一個插口,其全稱為動態可載入核心模組(LoadableKernel Module,LKM),我們簡稱為模組。Linux核心之所以提供模組機制,是因為它本身是一個單核心(monolithic kernel)。單核心的最大優點是效率高,因為所有的內容都整合在一起,但其缺點是可擴充套件性和可維護性相對較差,模組機制就是為了彌補這一缺陷。
模組是具有獨立功能的程式,它可以被單獨編譯,但不能獨立執行。它在執行時被連結到核心作為核心的一部分在核心空間執行,這與執行在使用者空間的程序是不同的。模組通常由一組函式和資料結構組成,用來實現一種檔案系統、一個驅動程式或其他核心上層的功能。
總之,模組是一個為核心(從某種意義上來說,核心也是一個模組)或其他核心模組提供使用功能的程式碼塊。
Linux核心模組編寫
首先得包含核心模組程式設計所需的標頭檔案,一般以下三種需要包含:
linux/module.h,該標頭檔案作用是動態的將模組載入到核心中
linux/kernel.h,該標頭檔案包含了常用的核心函式
linux/init.h,該標頭檔案包含了巨集_init和_exit,它們允許釋放核心佔用的記憶體
接下來就是模組載入函式和模組解除安裝函式。
載入函式需要新增_init標識,如
static int __init ***_init(void)
返回0表示載入成功,失敗則返回一些錯誤程式碼,參考<linux/errno.h>,在載入函式中一般用於初始化硬體,申請資源。
解除安裝函式需要新增_exit標識,如
static void __exit ***_exit(void)
一般在該函式完成以下幾件事情,
若模組載入函式中註冊了***,則在模組解除安裝函式中需登出;
若在模組載入函式中動態申請了記憶體,則在此亦需要釋放;
若在模組載入中申請了一些硬體資源(如:IRQ, DMA channel,I/O ,memory),則在此需釋放。
然後通過module_init(***_init)函式告訴核心編寫的模組從哪裡開始執行,引數就是註冊函式的函式名;通過module_exit(***_exit)函式告訴核心編寫的模組從哪裡推出,引數就是解除安裝函式的函式名。
gcc編譯的時候需要加上 modules 引數,表示編譯為核心模組,如下圖所示
下面介紹如何在初始化的時候從使用者空間讀檔案內容並寫入該核心模組的屬性檔案中。
核心模組讀寫檔案
首先簡單瞭解下linux檔案讀寫的工作流程
所以,在核心中開啟檔案,需要通過filp_open 函式,其引數與open函式一樣, 原形如下
strcut file* filp_open(const char* filename, int open_mode, intmode);
然後通過get_fs()取得當前的設定,並通過set_fs()改變kernel對記憶體地址檢查的處理方式,其原形如下:
void set_fs(mm_segment_t fs);
然後才能使用vfs_read 和vfs_write這兩個函式對檔案進行讀寫。原形如下
ssize_t vfs_read(struct file* filp, char __user* buffer, size_t len,loff_t* pos);
ssize_t vfs_write(struct file* filp, const char __user* buffer,size_t len, loff_t* pos);
最後通過filp_close關閉檔案。
具體實現過程如下:
核心模組建立屬性檔案
首先呼叫kobject_create_and_add函式,動態建立一個kobject結構並註冊到sysfs,函式原形如下
struct kobject *kobject_create_and_add(const char *name, structkobject *parent)
接下來屬性檔案通過函式sysfs_create_file建立。這個也同時建立了檔案與操作之間的聯絡和對應。函式原形如下
int sysfs_create_file(helloworld_kobj, &hello_value_attribute)
當完成前面呼叫後之後. 呼叫kobject_put,這樣kobject結構在不再使用時將會動態的釋放。函式原形如下
void kobject_put(struct kobject *kobj)
具體實現過程如下