一個簡單的內核模塊實現

一個簡單的內核模塊實現

前言

這幾天因爲某些原因,需要學習下Linux內核模塊相關的知識,今天剛剛好學習完模塊的簡單實現,故將其整理出來,以供日後複習之用

一個簡單的內核模塊

模塊化的意義

在目前,內核的設計中,有兩種不同的趨勢,一種是單內核,另外一種是微內核,簡單而言
- 單內核就是一個很大的進程,在運行的時候,是一個單獨的二進制映像,模塊之間的通信是通過函數調用來實現
- 微內核則不同,各個模塊之間都作爲單獨的進程運行,模塊之間的通信是通過消息傳遞進行通信

關於這兩者的優勢,各有各的說法,本人研究也不深,無法做過多的點評,這裏我們只需要知道,Linux是單內核結構,但同時也支持一個模塊化的內核。

所謂的模塊化,就是各個部分以模塊的形式進行組織,可以根據需要對指定的模塊進行編譯,然後安裝到內核中即可,這種實現方式的優勢在於,不需要預先把一大堆的功能都編譯進內核,尤其是各種驅動,衆所周知,不同型號的硬件,對應的驅動不同,而如果爲了顧全所有的硬件,而把所有的驅動都編譯進內核,內核的體積會變得非常龐大,而且,當這些驅動需要進行更新的時候,必須要對內核重新進行編譯。

有了模塊化之後,可以根據需要將對應的模塊編譯進內核,並且可以動態的進行加載和卸載,這樣子,對應的模塊的維護以及系統的使用就簡單以及方便很多了

模塊的簡單實現

這裏我們來學習一個簡單模塊的實現

// hello_module.c

// 必備頭函數
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

// 該模塊的LICENSE
MODULE_LICENSE("GPL");
// 該模塊的作者
MODULE_AUTHOR("huanfeng.xu");
// 該模塊的說明
MODULE_DESCRIPTION("hello module");

// 初始化入口
// 模塊安裝時執行
// 這裏的__init 同樣是宏定義,主要的目的在於
// 高速內核,加載該模塊之後,可以回收init.text的區間
static int __init init_hello_module(void){
    printk("KERN_INFO init the module. \n");
    return 0;
}

// 模塊卸載時執行
// 同上
static void __exit exit_hello_module(void){
    // 輸出信息,類似於printf()
    // printk適用於內核模塊
    printk("KERN_INFO exit the module. \n");
}

// 模塊初始化宏,用於加載該模塊
module_init(init_hello_module);
// 模塊卸載宏,用於卸載該模塊
module_exit(exit_hello_module);

需要注意的是,在普通的c開發中,每個程序都有一個main函數,作爲入口,而在內核中,則是module_init()來負責

編寫對應的Makefile


# Makefile

# 內核源代碼所在位置
KERNEL_DIR = /lib/modules/`uname -r`/build

obj-m += hello_module.o

all:
    make -C $(KERNEL_DIR) M=$(PWD) modules

clean:
    rm *.o *.mod.c *.ko *.order *.symvers

模塊的編譯有兩種形式,一種是編譯成模塊,即上面的obj-m,另一中是直接編譯到內核文件中,則上面的obj-m需要更改爲obj-y

需要注意的是,由於我們是在內核源代碼之外編譯該模塊,所以在編譯的時候,需要暫時將編譯目錄切換到內核源代碼中,即上面的-C $(KERNEL_DIR),在Makefile中,可以聲明變量,即上面的KERNEL_DIR = /lib/modules/uname -r/build,使用時,直接$(KERNEL_DIR)即可,這裏的$(PWD)是內核自帶變量,所以無需聲明,可以直接使用

編寫完之後,直接執行make即可,可以看到目錄下生成一個.ko文件,這就行對應的模塊了

模塊的安裝

由於該模塊比較簡單,也沒有依賴於其他模塊,所以安裝的時候可以直接使用insmod hello_module.ko即可,安裝完成之後,可以使用dmesg查看是否有對應的內容輸出,如果操作沒有問題,則會看到這樣的日誌KERN_INFO init the module.

查看模塊是否已經安裝 lsmod | grep hello_module

查看模塊信息 modinfo hello_module

卸載模塊 rmmod hello_module,卸載之後同樣可以使用dmesg看到
KERN_INFO exit the module.

帶參數的模塊

有時候我們需要在模塊安裝的時候,傳遞一些信息給模塊,可以使用如下方式


// 需要加上該頭文件
#include <linux/moduleparam.h>

module_param(name, type, perm);
// name爲安裝以及使用時的參數名字,type爲類型,pram爲對應的sysfs的權限

module_param_string(name, string, len, perm);
// name爲外部名字,string爲內部名字

module_param_array(name, type, nump, perm)
// nump用於存放數組項數

使用的方式爲,在安裝模塊的指定對應的參數及其值即可,如insmod hello_module size=100

導出符號表

由於模塊之間是相通的,所以模塊中定義的符號需要導出之後才能被其他模塊使用

導出方式只需要在使用MODULE_EXPORT(VAR_NAME)或者MODULE_EXPORT_GPL(VAR_NAME)即可,VAR_NAME可以爲變量,也可以爲函數

其他模塊只需要使用extern [TYPE] VAR_NAME,即可在本模塊中使用其他模塊導出的變量或者函數了,需要注意的是,如果依賴其他模塊的導出符號,則在安裝該模塊的時候,對應的依賴模塊必須已經安裝好,否則會出現找不到對應符號的情況

總結

本小節主要簡單學習了模塊的寫法,模塊的編譯,傳遞參數以及導出符號,後面還會學習其他相關的內容,加油…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章