2.linux內核模塊

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/songze_lee/article/details/72797930

2.1 驅動模塊框架

Linux內核的整體架構非常龐大,其包含組件也非常多,怎樣把需要的部分包含在內核中?

一種方法是把所需要的功能編譯到linux內核中,這會導致兩個文件,一是生成的內核會很大,二是如果我們要在現有的內核中新增或刪除功能,將不得不重新編譯內核。

Linux提供了這樣一種機制,稱爲模塊(Moudle)。可使編譯出的內核本身並不包含所有的功能,而在這些被使用的時候,其對應的代碼可被動態的加載到內核。

模塊的特點

    模塊本身不被編譯到內核映像,從而控制了內核的大小。

    模塊一旦被加載,它就和內核中的其他部分完全一樣。

2.1.1對驅動模塊進行操作的shell命令

insmod demo.ko  插入驅動模塊

lsmod           查看插入正在運行驅動模塊

rmmod demo      移除驅動模塊  

modinfo demo.ko 查看驅動模塊信息

dmesg           查看內核緩存信息

dmesg -c        清除內核緩存信息

有依賴關係的

modprobe (智能安裝) xx(不加.ko)

modprobe -r 移除(注意:移除需要依賴的模塊,同時會移除被依賴的模塊)

2.1.2一個最簡單的linux內核模塊代碼如下:

A.hello world驅動模塊 demo.c

#include <linux/init.h>
#include <linux/module.h>

static int __init demo_init(void)
{
	printk("hello,word! driver module is inserted!\n");

	return 0;
}
module_init(demo_init);/*指定驅動模塊入口點*/


static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);/*指定驅動模塊出口*/

MODULE_LICENSE("GPL");/*公共許可聲明*/
MODULE_AUTHOR("Songze Lee");/*作者*/
MODULE_VERSION("Verson 1.0");/*版本號*/
MODULE_DESCRIPTION("It is a simple demo for driver module");/*描述*/

內核模塊中用於輸出的函數的內核空間的printk(),用法和printf基本相似,但可以定義輸出級別。

Makefile編寫如下:

obj-m	:= demo.o

OUR_KERNEL := /ARM/linux-3.5-songze/

all:
	make -C $(OUR_KERNEL) M=$(shell pwd) modules
#	進入到變量目錄(內核源碼目錄)下編譯  M 編譯pwd路徑下的模塊
clean:
	make -C $(OUR_KERNEL) M=`pwd` clean

調試結果如下:

[projct /]# insmod demo.ko

[ 1670.390000]hello,word! driver module is inserted!

  [projct /]#rmmod demo

  [ 1681.215000]goodbye, word! driver is removed!

  rmmod: module'demo' not found

B.驅動模塊調用子函數編寫

demo.c

/**
 * 驅動模塊調用子函數
 * 注意Makefile的編寫
 */

#include <linux/init.h>
#include <linux/module.h>

extern void call_func0(void);

static int __init demo_init(void)
{
	call_func0();
	printk("hello,word! driver module is inserted!\n");

	return 0;
}
module_init(demo_init);/*指定驅動模塊入口點*/


static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);/*指定驅動模塊出口*/

MODULE_LICENSE("GPL");/*公共許可聲明*/
MODULE_AUTHOR("Songze Lee");/*作者*/
MODULE_VERSION("Verson 1.0");/*版本號*/
MODULE_DESCRIPTION("It is a simple demo for driver module");/*描述*/
fun0.c

#include <linux/init.h>
#include <linux/module.h>

extern void call_func1(void);

void call_func0(void)
{
	call_func1();
}

fun1.c

#include <linux/init.h>
#include <linux/module.h>

void call_func1(void)
{	
	printk("you are a good boy.\n");
}

Makefile(重點注意)

obj-m	:= team_hehe.o
team_hehe-objs	:= demo.o fun0.o fun1.o

OUR_KERNEL := /ARM/linux-3.5-songze/

all:
	make -C $(OUR_KERNEL) M=$(shell pwd) modules
clean:
	make -C $(OUR_KERNEL) M=`pwd` clean

調試結果如下:

   [projct /]# insmod team_hehe.ko

    [ 1920.880000]you are a good boy.

    [ 1920.880000]hello,word! driver module is inserted!

    [projct /]#rmmod team_hehe

    [ 1932.020000]goodbye, word! driver is removed!

    rmmod: module'team_hehe' not found

2.1.3導出符號

    Linux的“/proc/kallsyms”文件對應着內核符號表,它記錄了符號以及符號所在的內存地址。

    模塊可以使用如下宏導出符號到內核符號表中:

    EXPORT_SYMBOL(符號表);

    EXPORT_SYMBOL_GPL(符號表);

    導出的符號(變量或函數)可以被其他模塊使用,只需要使用前聲明一下即可。EXPORT_SYMBOL_GPL()只適用於包含GPL許可權的模塊。

    示例代碼如下:

demo1.c

#include <linux/init.h>
#include <linux/module.h>

extern int sure;
extern void pri_value(int);
extern void call_func0(void);

static int __init demo_init(void)
{
	sure = 3856;
	pri_value(sure);

	printk("hello,word! driver module is inserted!\n");

	return 0;
}
module_init(demo_init);

static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Songze Lee");
MODULE_VERSION("verson 1.0");
MODULE_DESCRIPTION("It is a simple demo for driver module");

demo2.c

#include <linux/init.h>
#include <linux/module.h>

static int sure = 9527;

/*符號導出 static定義的變量或函數其他模塊可以調用*/
EXPORT_SYMBOL_GPL(sure);

static void pri_value(int val)
{
	printk("In %s: sure = %d\n", __FILE__, sure);
}
EXPORT_SYMBOL_GPL(pri_value);

static int __init demo_init(void)
{
	pri_value(sure);

	printk("hello,word! driver module is inserted!\n");

	return 0;
}
module_init(demo_init);


static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Songze Lee");
MODULE_VERSION("verson 1.0");
MODULE_DESCRIPTION("It is a simple demo for driver module");

調試結果如下:

[projct /]# insmod demo02.ko

[ 2484.680000] In/ARM/linux-3.5-songze/drivers/songze_drivers/module/

demo05/demo02.c: sure = 9527

[ 2484.680000] hello,word! driver module is inserted!

[projct /]# insmod msb.ko

[ 2491.690000] In /ARM/linux-3.5-songze/drivers/songze_drivers/module/

demo05/demo02.c: sure = 3856

[ 2491.690000] hello,word! driver module is inserted!

[projct /]# rmmod demo02

rmmod: remove 'demo02': Resource temporarily unavailabl兩者有依賴關係

[projct /]# rmmod msb

[ 2531.345000] goodbye, word! driver is removed!

rmmod: module 'msb' not found

[projct /]# rmmod demo02

[ 2542.910000] goodbye, word! driver is removed!

rmmod: module 'demo02' not found

2.1.4模塊參數

    在用戶態下編程可以通過main()來傳遞命令行參數,而編寫一個內核模塊則可通過module_param()來傳遞命令行參數。

module_param宏是Linux 2.6內核中新增的,該宏被定義在include/linux/

moduleparam.h文件中,具體定義如下:

    #define module_param(name, type, perm)              

       module_param_named(name, name, type,perm)

由此可知module_param的實現是通過module_param_named(name, name, type,perm)的。

module_param(name,type, perm)

name:參數名 type:參數類型perm:參數讀寫權限

    參數類型可以是byte、short、ushort、int、uint、long、ulong、charp(字符指針)、bool或invbool(布爾的反),在模塊被編譯時會將module_param中聲明的類型與變量定義的類型進行比較、判斷是否一致。

    module_param_array(name,type,num,perm)

name:數組名 type:數組類型num:數組長 perm:參數讀寫權限

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 修改, 你的模塊看到的參數值也改變了, 但是你的模塊沒有任何其他的通知. 你應當不要使模塊參數可寫, 除非你準備好檢測這個改變並且因而作出反應.

示例A:module_param(name, type, perm)

/**
 *module_param(name, type, perm) 內核模塊傳參
 *向當前模塊傳參
 */

#include <linux/init.h>
#include <linux/module.h>

static int x_rel = 480, y_rel = 272;

module_param(x_rel, int, 0);
module_param(y_rel, int, 0);

static char *info = "mdg: lol?";

static int num=10;
module_param(num,int,S_IRUGO);
module_param(info, charp, 0);

static int __init demo_init(void)
{
	printk("hello,word! driver module is inserted!\n");

	printk("x: %d, y: %d\n %s\n", x_rel, y_rel, info);
	printk("num=%d\n",num);
	return 0;
}
module_init(demo_init);

static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Songze Lee");
MODULE_VERSION("version 1.0");
MODULE_DESCRIPTION("It is a simple demo for driver module");

調試結果:

[projct /]# insmod demo.ko num=110 x_rel=123 y_rel=345info="hello world"

[ 4140.560000] hello,word! driver module is inserted!

[ 4140.560000] x: 123, y: 345

[ 4140.560000] hello world

[ 4140.560000] num=110

[projct /]# cat /sys/module/demo/parameters/num

110

[projct /]# ls -l /sys/module/demo/parameters/num

-r--r--r--    10        0             4096 Jan  1 14:06 /sys/module/demo/parameters/num

可發現num爲只讀文件

示例B:module_param_array(name,type,num,perm)

#include <linux/init.h>
#include <linux/module.h>

#define CNT 16
static int num = CNT;
static int array[CNT] = {1,2,3,4,5,6,7};
module_param_array(array, int, &num, 0);

static int __init demo_init(void)
{
	int i;
	printk("Insert module ok!\n");
	for(i = 0; i < num; i++){
		printk("array[%d] = %d\n", i, array[i]);
	}
	return 0;
}
module_init(demo_init);

static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 

module_exit(demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("millet9527");
MODULE_VERSION("uplooking plus 7");
MODULE_DESCRIPTION("It is a simple demo for driver module");

調試結果:

[projct /]# insmod demo.koarray=11,22,33,44,55,66,77,88,99

[ 4965.605000] Insert module ok!

[ 4965.605000] array[0] = 11

[ 4965.605000] array[1] = 22

[ 4965.605000] array[2] = 33

[ 4965.605000] array[3] = 44

[ 4965.605000] array[4] = 55

[ 4965.605000] array[5] = 66

[ 4965.605000] array[6] = 77

[ 4965.605000] array[7] = 88

[ 4965.605000] array[8] = 99


獲取源碼: git clone https://www.github.com/lisongze2016/Tiny4412_kernel.git


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