linux編寫一個簡單的內核模塊

編寫一個簡單的內核模塊

(一)實驗目的

Linux 操作系統的內核是單一體系結構(monolithic kernel)的,也就是說,整個內核是一個單獨的非常大的程序。這樣,系統的速度和性能都很好,但是可擴展性和維護性就相對比較差。爲了彌補單一體系結構的這種缺陷,Linux操作系統使用了一種全新的機制-模塊機制,用戶可以根據需要,在不需要對內核重新編譯的情況下,模塊能動態地載入內核或從內核移出。
本實驗通過分析代碼,學習Linux 是如何實現模塊機制的;通過一個實例,掌握如何編寫模塊程序並進一步掌握內核模塊的機理。

(二)實驗內容

實驗內容一:

(1)編寫一個內核模塊helloworld.c當用insmod命令加載模塊後,會顯示HelloWorld !

#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jiang shuliang");
MODULE_DESCRIPTION("Hello World Module");
static int __init hello_init(void)
{
    printk(KERN_EMERG"Hello World!\n");
    return 0;
}

static void __exit hello_exit(void)
{
    printk("<6>hello exit\n");
    printk(KERN_EMERG"good bye!\n");
}

module_init(hello_init);
module_exit(hello_exit);

(2)編寫Makefile文件

ifneq ($(KERNELRELEASE),)		#注意ifneq後空格
obj-m := hello.o
else
KDIR := /lib/modules/$(shell uname -r)/build	#改地址
all:
	make -C $(KDIR) M=$(PWD) modules		#注意tab
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif

(3)執行make生成.ko文件
(4)加載模塊 insmod 文件名.ko
(5)lsmod | grep 文件名       查看加載的模塊
(6)dmesg
查看日誌文件中模塊輸出的內容
(7)rmmod 文件名.ko     移除模塊可以使用(5)查看是否移除成功

注意:
1.在makefile編寫要使用tab
2.注意ifneq後有空格
3. 內核中無法使用printf
4.注意makefile中obj-m後面.o文件名和.c一致 5.前面的if和後面的endif配對
6.__init __exit 後面的函數內參數要寫上void
7.KDIR指向內核位置/lib/modules/內核名稱/build是鏈接指向了/usr/src/內核名文件下
8.在ubuntu系統中設置了printk的級別也需要在dmesg中查看

實驗內容二:
編寫一個包含2.c文件的內核模塊程序,進行編譯,掌握多文件模塊編譯的方法及Makefile書寫規則!

  1. 編寫兩個.c文件

hello1.c

#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jiang shuliang");
MODULE_DESCRIPTION("Hello World Module");
static int __init hello_init(void)
{
    printk(KERN_EMERG"Hello World1!\n");
    return 0;
}

static void __exit hello_exit(void)
{
    printk("<6>hello exit1!\n");
    printk(KERN_EMERG"good bye!\n");
}

hello2.c

#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jiang shuliang");
MODULE_DESCRIPTION("Hello World Module");
static int __init hello_init(void)
{
    printk(KERN_EMERG"Hello World2!\n");
    return 0;
}

static void __exit hello_exit(void)
{
    printk("<6>hello exit2!\n");
    printk(KERN_EMERG"good bye!\n");
}
  1. 編寫Makefile
ifneq ($(KERNELRELEASE),)
obj-m := hello1.o hello2.o
else
KDIR := /lib/modules/$(shell uname -r)/build            #改地址
all:
        make -C $(KDIR) M=$(PWD) modules                                #注意tab
clean:
        rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif

3.生成兩個.ok文件同上個實驗加載模塊查看卸載即可

實驗內容三:

一. 原理
module_param
1.爲什麼引入
在用戶態下編程可以通過main()來傳遞命令行參數,而編寫一個內核模塊則可通過module_param()來傳遞命令行參數.
2. module_param宏是Linux 2.6內核中新增的,該宏被定義在include/linux/moduleparam.h文件中,具體定義如下:

/* Helper functions: type is byte, short, ushort, int, uint, long,
ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
param_set_XXX and param_check_XXX.

*/ #define module_param_named(name, value, type, perm)
param_check_##type(name, &(value));
module_param_call(name, param_set_##type, param_get_##type, &value, perm);
__MODULE_PARM_TYPE(name, #type)

#define module_param(name, type, perm)                
module_param_named(name, name, type, perm)

由此可知 module_param的實現是通過module_param_named(name, name, type, perm)的。
3.module_param使用了3個參數:變量名,它的類型,以及一個權限掩碼用來做一個輔助的sysfs入口。
這個宏定義應當放在任何函數之外,典型地是出現在源文件的前面。

eg: static char *whom=“world”
static int tige=1;
module_param(tiger,int,S_IRUGO);
module_param(whom,charp,S_IRUGO);

4.模塊參數支持許多類型:
bool
invbool
一個布爾型( true 或者 false)值(相關的變量應當是 int 類型). invbool 類型顛倒了值, 所以真值變成 false, 反之亦然.
charp :一個字符指針值. 內存爲用戶提供的字串分配, 指針因此設置.
int
long
short
uint
ulong
ushort
基本的變長整型值. 以 u 開頭的是無符號值.
5.數組參數, 用逗號間隔的列表提供的值, 模塊加載者也支持。

聲明一個數組參數, 使用:
module_param_array(name,type,num,perm);
這裏 name 是你的數組的名子(也是參數名),
type 是數組元素的類型,
num 是一個整型變量,
perm 是通常的權限值.
如果數組參數在加載時設置, num 被設置成提供的數的個數. 模塊加載者拒絕比數組能放下的多的值.

Tiger-John說明:

perm參數的作用是什麼?
最後的 module_param 字段是一個權限值,表示此參數在sysfs文件系統中所對應的文件節點的屬性。你應當使用 <linux/stat.h> 中定義的值. 這個值控制誰可以存取這些模塊參數在 sysfs 中的表示.當perm爲0時,表示此參數不存在 sysfs文件系統下對應的文件節點。 否則, 模塊被加載後,在/sys/module/ 目錄下將出現以此模塊名命名的目錄, 帶有給定的權限.。
權限在include/linux/stat.h中有定義
比如:

#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001

使用 S_IRUGO 參數可以被所有人讀取, 但是不能改變; S_IRUGO|S_IWUSR 允許 root 來改變參數. 注意, 如果一個參數被 sysfs 修改, 你的模塊看到的參數值也改變了, 但是你的模塊沒有任何其他的通知. 你應當不要使模塊參數可寫, 除非你準備好檢測這個改變並且因而作出反應.

二.實例:

說了這麼多,看一個程序體驗以下:
file name : module_param.c

#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
MODULE_LICENSE("GPL");
static char *who;
static int times;
module_param(who,charp,0644);
module_param(times,int,0644);
static int __init hello_init(void)
{
 int i;
 for(i = 1;i <= times;i++)
 printk("%d  %s!\n",i,who);
 return 0;
}
static void __exit hello_exit(void)
{
 printk("Goodbye,%s!\n",who);
}
module_init(hello_init);
module_exit(hello_exit); 

2.編寫Makefile文件

obj-m:=module_param.o
CURRENT_PATH:=$(shell pwd)
VERSION_NUM :=$(shell uname -r)
LINUX_PATH  :=/usr/src/linux-headers-$(VERSION_NUM)

all :   
        make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules   
clean :   
        make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean  

3.在終端輸入:make

4 .加載模塊: sudo insmod module_param.ko who=tiger times=4
5.dmesg :查看結果。

在寫完了.c文件和Makfile之後過程實例步驟:
a. 在終端輸入:make

think@Ubuntu:~/module_param$ make
make -C /usr/src/linux-headers-2.6.32-25-generic M=/home/think/module_param modules
make[1]: 正在進入目錄 `/usr/src/linux-headers-2.6.32-25-generic'
  Building modules, stage 2.
  MODPOST 1 modules
make[1]:正在離開目錄 `/usr/src/linux-headers-2.6.32-25-generic'
think@ubuntu:~/module_param$ 

b.在終端輸入:

sudo insmod module_param.ko who=tiger times=4 
think@ubuntu:~/module_param$ sudo insmod module_param.ko who=tiger times=4 

c 在終端輸入:dmesg

[ 4297.711137] 1 tiger!
[ 4297.711139] 2 tiger!
[ 4297.711140] 3 tiger!
[ 4297.711141] 4 tiger!

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