内核模块开发 初步

LINUX内核模块基础

什么是内核模块:
Linux内核的整体结构非常庞大,其包含的组件也非常多,如何使用这些组件呢,有一种方法是:把所有的组件都编译进内核文件,即:zImage或bzImage,但这样会导致一个问题:占用内存过多。
应当采用一种机制能让内核文件本身并不包含某组件,而是在该组件需要被使用的时候,动态地添加到正在运行的内核中。

内核模块具有如下特点:
• 模块本身并不被编译进内核文件(zImage或者bzImage)。
• 可以根据需求,在内核运行期间动态的安装或卸载。

安装与卸载内核模块:
安装 insmod
例:insmod /home/dnw_usb.ko

卸载 rmmod
例:rmmod dnw_usb

查看 lsmod
例:lsmod

内核模块设计

内核模块C程序代码举例:

//Linux内核模块的三要素:头文件、加载函数、卸载函数
#include <linux/init.h>
#include <linux/module.h>

//加载和卸载函数都要加上static静态函数
//在内核中打印不能使用 printf ,要使用 printk 函数
static int hello_init()
{
    printk(KERN_WARNING"Hello world!\n");//没有逗号,KERN_WARNING 是优先级
    return 0;   
}

static void hello_exit()
{
    printk(KERN_WARNING"hello exit!\n");    
}

module_init(hello_init); //加载函数,insmod命令之后自动开始执行括号内的函数
module_exit(hello_exit); //卸载函数,rmmod命令之后自动开始执行括号内的函数

makefile文件编写:

obj-m := helloworld.o
#helloworld.o是最终生成的内核模块的名字,上面是单个文件的写法
#多个文件的写法:
#obj-m := hello.o
#hello-objs := file1.o file2.o file3.o

KDIR := /home/ARM_Linux/system2/season4/First/part3/linux-ok6410 
#开发板上运行的内核代码的路径,编译内核需要依赖于内核路径,注意斜线方向

all:
    make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
    # -C 表示进入后面的路径中,因此还需要加上内核模块代码的路径
    # pwd 是内核模块代码的路径
clean:
    rm -f *.o *.ko *.order *.symvers *.bak *.mod.c

对代码进行编译,可以得到 .ko 文件,将 .ko 文件拷贝到嵌入式系统的根文件系统中。

在嵌入式系统上,用insmod命令加载模块和用rmmod命令写在模块,都可以看到程序的运行效果。

内核模块可选信息

该部分是模块中可选的信息,可有也可以没有。

模块申明:
加入下面的宏,声明相应的信息:

1、MODULE_LICENSE(“遵守的协议”);
申明该模块遵守的许可证协议,如:GPL、GPL v2等

2、MODULE_AUTHOR(“作者”);
申明模块的作者

3、MODULE_DESCRIPTION(“模块的功能描述”);
申明模块的功能

4、MODULE_VERSION(“V1.0”);
申明模块的版本

模块参数:
在应用程序中:

int main(int argc, char** argv)

argc表示命令行输入的参数个数,argv中保存输入的参数。

内核模块中可以通过命令行输入参数,例如:

insmod xx.ko 某个变量=某个值(该变量必须在程序中用宏指定)

但是,必须先通过宏module_param指定保存模块参数的变量。模块参数用于在加载模块时传递参数给模块。

module_param(name, type, perm);

name:变量的名称
type:变量类型,bool:布尔型,int:整型,charp:字符串型。
perm:是访问权限。 S_ IRUGO:读权限,S_IWUSR:写权限。

例程,传入两个参数:

int a = 3;
char *st;
module_param(a,int, S_IRUGO|S_IWUSR);
module_param(st,charp, S_IRUGO|S_IWUSR);


insmod xx.ko a=xx st=xx

符号导出:
一个模块的数据给其他模块使用必须要进行符号导出。

内核符号的导出使用宏

EXPORT_SYMBOL(符号名);
EXPORT_SYMBOL_GPL(符号名);
//符号名可以是变量,可以是函数名
//调用该符号的文件要使用extern声明该符号
//同时还要注意不同内核的安装顺序

说明:
其中EXPORT_ SYMBOL_GPL只能用于包含GPL许可证的模块。

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