Linux核心模組程式設計

2021-08-22 18:48:14 字數 4464 閱讀 4223

linux核心模組程式設計的資料有些紛繁複雜,有的過於簡單,有的過於龐雜,我試圖用筆記的形式想讀者展示怎樣來程序linux模組程式設計,力圖做到簡明扼要,這篇文章也是作為本人備忘的資料,所以有些地方過於簡略是難免的。本來這篇文章的目的就是讓使用者知其然,至於所以然還是請參考相應的資料,其實最好的資料莫過於linux kernel source。

適用範圍:

首先這個module不同於microkernel的module,microkernel的module是乙個個的daemon程序,工作於使用者空間,linux的module只是乙個核心的目標**,核心通過執行執行時的連線,來把它整合到kernel中去,所以說linux的module機制並沒有改變linux核心為monolithic os本質,其module也是工作於核心模式,享有核心的所有特權。

至於為什麼要引入linux kernle module(一下簡稱lkm),我想至少有一下幾點:

lkm需要包含以下標頭檔案:

需要定義以下巨集:__kernel__, module

/*file:   hello.c*/

#ifndef __kernel__

#define __kernel__

#endif

#ifndef module

#define module

#endif

#include

#include

static int __init hello_init(void)

static void __exit hello_exit(void)

module_init(hello_init);

module_exit(hello_exit);

很簡答吧,不是嗎?這個lkm的功能其實也很簡單,就是當通過insmod載入它的時候,他列印hello, my lkm.通過rmmod解除安裝它的時候他列印bye, my lkm.乙個最基本的核心模組一般都包含有兩個函式,乙個是初始化函式(比如說這裡的hello_init),乙個是解除安裝函式(hello_exit), 當然也可以沒有任何函式,只是提供一些變數。但是初始化函式和解除安裝函式必須成對出現。並且init函式當操作成功時返回值大於等於零,當操作失敗時,返回非零。巨集module_init和module_exit用於註冊初始化函式和解除安裝函式。

乙個示例的makefile如下所示

obj-m:= hello.o 

kernelbuild:= /lib/modules/`uname -r`/build

default:

make -c $(kernelbuild) m=$(shell pwd) modules

clean:

rm -rf *.o .*.cmd *.ko *.mod.c .tmp_versions

如果這個目錄下面還有其它模組,只需要在hello.o後面新增就行了。

obj-m:= hello.o mod.o

在模組所在目錄執行make,等成功後就可以得到我們想要的模組(hello.ko)了。

如果乙個模組存在許多原始檔,比如:hello, 由hello1.c hello2.c共同連線而成,需要在makefile中加入如下行

hello-objs:= hello1.o hello2.o

linux為使用者提供了modutils,用來操縱模組。這個工具集主要包括:

insmod 安裝模組

rmmod 刪除模組

modprobe 比較高階的載入和刪除模組,可以解決模組之間的依賴性

lsmod 列出已經載入的模組和其資訊

modinfo 用於查詢模組的相關資訊,比如作者,版權...

試著用命令insmod hello.ko載入模組,rmmod刪除模組,看看有什麼事情發生了。你有可能看不見任何輸出,難道是有錯誤發生?no,執行命令tail /var/log/message呵呵,是不是看到了?

feb 19 00:07:35 gentux hello, my lkm.

feb 19 00:07:38 gentux bye, my lkm.

module_author("author");

module_description("the description");

module_license("gpl");

module_supported_device("dev"); // 裝置驅動程式所支援的裝置。

比較常用的free license有"gpl", "gpl v2", "gpl and additional rights", "dual bsd/gpl", "dual mpl/gpl"。

module_parm(var, type);

module_parm_desc(var, "the description of the var");

模組引數的型別(即module_parm中的type)有一下幾種:

這些引數最好有預設值,如果有些必要引數使用者沒有設定可以通過在module_init指定的init函式返回負值來拒絕模組的載入。 lkm還支援陣列型別的模組,如果在型別符號前加上數字n則表示最大程度為n的陣列,用「-」隔開的數字分別代表最小和最大的陣列長度。

示例:

module_parm(var, "4i"); // 最大長度為4的整形陣列

module_parm(var, "2-6i"); // 最小長度為2,最大長度為6的整形陣列

如何用insmod傳入引數,其實man一下就可以了,不過現在的man有些過於簡單,所以在此說明一下:

insmod variable=value[,value2...] ...

其中value可以用引號括起來,也可以不用。但是有一點「=」前後不能留有空格,並且value中也不能有空格。

和使用者空間的應用程式不同的是,引入乙個模組的目的常常是為了給核心提供一些routine,來完成特定的功能,很少有模組什麼符號都不匯出,為此linux為使用者提供了如下巨集:

export_symbol(var); // 輸出symbol var

export_symbol_gpl(var); // 輸出的symbol版權為gpl

有的時候兩個模組之間可能有依賴性,要載入的模組a,依賴於模組b,此時insmod是無能為力的,只能用modprobe來載入模組和其依賴的模組,否則只能手動乙個個載入。

modprobe通過讀取由depmod -a生成的/lib/modules/version/modules.dep來獲得其所依賴的模組列表(也有可能是乙個模組樹),然後呼叫insmod來乙個個按順序載入。

對於不需要export的全域性symbol最好用static進行修飾,限制其作用域為本檔案,以防汙染核心的命名空間。

對於由核心或其它模組export的一些symbol,最好用extern進行修飾,以示其不在本檔案。

在可能用到errno變數的場合,因為核心沒有export此symbol,只能有使用者自行定義,比如:int errno;

/*file:   hello.c*/

#ifndef __kernel__

#define __kernel__

#endif

#ifndef module

#define module

#endif

#include

#include

module_author("xiaosuo ");

module_license("gpl");

module_description("this module is a example.");

static int int_var = 0;

static const char *str_var = "default";

static int int_array[6];

module_parm(int_var, "i");

module_parm_desc(int_var, "a integer variable");

module_parm(str_var, "s");

module_parm_desc(str_var, "a string variable");

module_parm(int_array, "2-6i");

module_parm_desc(int_array, "a integer array");

static int __init hello_init(void)

return 0;

}static void __exit hello_exit(void)

module_init(hello_init);

module_exit(hello_exit);

the linux kernel module programming guide

linux 核心程式設計指南(第三版)

linux核心分析及程式設計

Linux核心模組程式設計

目標 熟悉linux模組相關函式等 模組載入,例 static int init initialization function void module init initialization function 這裡 init define init attribute section init.t...

linux 2 6 核心模組程式設計探索

乙個linux 核心模組程式設計的手記,未寫完不斷更新中 一 相關命令 0 檢視系統裝載了哪些 核心模組 lsmod modulename 1 載入核心模組 insmod modulename 2 解除安裝核心模組 rmmod modulename 3 建立裝置檔案 mknod filename d...

linux 2 6 核心模組程式設計探索

乙個linux 核心模組程式設計的手記,未寫完不斷更新中 一 相關命令 0 檢視系統裝載了哪些 核心模組 lsmod modulename 1 載入核心模組 insmod modulename 2 解除安裝核心模組 rmmod modulename 3 建立裝置檔案 mknod filename d...