今天從網上看了個視頻教程,關於內核模塊開發的。網絡上有許多這樣的文章,應該比我這個詳細。
寫這篇博客的目的是做一下筆記,便於自己查閱。
首先給出內核模塊源代碼,當然是最最簡單的helloworld。
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
//GPL 開源協議
static int hello_init(void)
{
printk(KERN_ALERT "hello module!\n"); //內核打印信息函數,相當於應用層的printf();
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "bye module!\n");
}
module_init(hello_init); //必須使用的,模塊加載函數。向內核註冊
module_exit(hello_exit); //必須使用的,模塊卸載函數註冊
需要的Makefile
ifneq ($(KERNELRELEASE),) //判斷KERNELRELEASE不能與NULLobj-m:=hello.o //目標模塊的名稱
else
#generate the path
CURRENT_PATH:=$(shell pwd) //獲得當前目錄的名稱並賦值給CURRENT_PATH變量
#the absolute path // 是用絕對路徑
LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build //內核模塊所依賴的內核編譯路徑,shell uname -r獲得當前內核版本號
#complie object
default:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules //make -C 表示到$(LINUX_KERNEL_PATH)使用它的makefile編譯。
//M=$(CURRENT_PATH)表示你的內核源代碼的位置
// modules :編譯成爲模塊
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
endif
編譯一次內核模塊需要兩次執行上述makefile,第一次執行的時候KERNELRELEASE是沒有值得,第二次執行時KERNELRELEASE是有值得。需要
注意此處
如果多個C文件進行的編譯一個內核模塊。Makefile則需要寫爲如下格式
ifneq ($(KERNELRELEASE),) //判斷KERNELRELEASE不能與NULL
obj-m:=hello.o //目標模塊的名稱
hello.o-objs :=file1.o file2.o file3.o ... //(可以最近多個) ------>如果一個源文件可以用這個方式生產與文件名不同的內核模
else
#generate the path
CURRENT_PATH:=$(shell pwd) //獲得當前目錄的名稱並賦值給CURRENT_PATH變量
#the absolute path // 是用絕對路徑
LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build //內核模塊所依賴的內核編譯路徑,shell uname -r獲得當前內核版本號
#complie object
default:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules //make -C 表示到$(LINUX_KERNEL_PATH)使用它的makefile編譯。
//M=$(CURRENT_PATH)表示你的內核源代碼的位置
// modules :編譯成爲模塊
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
endif
編譯得到hello.ko,然後insmod hello.ko加載模塊,rmmod hello卸載模塊。
查看內核模塊lsmod。
modprobe hello:也是加載一個模塊,但是不同於insmod的是,它會在/lib/modules/$<$version>/modules.dep查看要加載的模塊,看它
是否依賴於其他的模塊,如果有modprobe會先找到那些被依賴模塊並先安裝它們。
--------------------------------華麗的分割線---------------------------------------
內核參數:
1.定義模塊參數的方法:
module_param(name, type, perm);
其中,name:表示參數的名字;
type:表示參數的類型;
perm:表示參數的訪問權限;
static int num=10;
module_param(num,int,S_IRUGO);
static int hello_init(void)
{
printk("Hello module init./n");
printk("num=%d/n",num);
return 0;
}
static void hello_exit(void)
{
printk("Goodbye module exit./n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("a simple module");
MODULE_ALIAS("hello");
shell $ insmod hello.ko num=100 即可改變num的值。
-------------------------------------------華麗分割線-----------------------------------
內核模塊符號導出
EXPORT_SYMBOL(函數名/變量名)
即當一個內核模塊調用另外一個內核模塊的函數或者變量時,需要再被調用的內核模塊中將變量或者函數使用EXPROT_SYMBOL 將對應函數或者變量導出,才能
正常使用。關於這部分內容網絡上有許多博文,具體使用時請參考其他博文吧。
----------------------------華麗分割線----------------------------------------------
內核打印&級別。
/proc/sys/kernel/printk中定義着其他控制檯和其他log文件的打印級別。
其他的就不再贅述了,網上有很多博文了。
-----------------------------------華麗結束線-----------------------------------