Linux内核模块

1 内核模块

  Linux内核的整体结构非常庞大,其包含的组件也非常多,如果把所有的组件都编译进内核文件,即:zImage或bzImage,但这样会导致一个问题:占用内存过多。

  所以就需要动态的添加某些组件,这些组件就是内核模块。特点:模块本身并不被编译到内核文件(zImage或bzImage);可以根据需求,在内核运行期间动态的安装或卸载。

    安装:insmod

      insmod /home/dongry/dnw_usb.ko

    卸载:rmmod

    rmmod dnw_usb

    查看:lsmod

    lsmod

2 内核模块的设计与编写

/*************************************************
*file_name:helloworld.c
*************************************************/
#include <linux/init.h>
#include <linux/module.h>

static int hello_init(void)
{
        printk(KERN_WARING"hello world\n");
        return 0;
}

static void hello_exit(void)
{
        printk(KERN_INFO"goodbye world\n");
}

module_init(hello_init);
module_exit(hello_init);

  printk的用法https://blog.csdn.net/eydwyz/article/details/53044863

  必要的头文件:<linux/init.h> <linux/module.h>

  module_init()内核模块的入口 即加载函数

  module_exit()内核模块的出口 即卸载函数

  当insmod安装helloworld.ko的时候module_init(hello_init)就会被调用

  当rmmod卸载helloworld.ko的时候module_exit(hello_exit)就会被调用

2.1 内核模块必要元素框图

  内核中打印用printk,应用程序用printf

/***********************************
*filename:Makefile
************************************/
obj-m := helloworld.o

KDIR := /home/dongry/mini2440/mini2440      /*开发板内核代码路径*/

all:
    make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
    
clean:
    rm -f *.o *.ko *.order *.symvers
/***********************************
*filename:Makefile
*function:can in x86 kernel run
************************************/
obj-m := helloworld.o

KDIR := /home/dongry/x86/linux-4.19.30      /*开发板内核代码路径*/

all:
    make -C $(KDIR) M=$(PWD) modules
    
clean:
    rm -f *.o *.ko *.order *.symvers

  make含有helloworld.c和Makefile的文件得到helloworld.ko文件;如果是经过编译的x86内核后可以直接在Terminal窗口运行insmod、lsmod、rmmod;如果是经过编译的arm内核需在secure crt上链接开发板才能运行。

3 模块声明

a)MODULE_LICENSE("遵守的协议"):声明该模块遵守的许可证协议,如"GPL"、"GPL v2"

b)MODULE_AUTHOR("作者"):声明模块的作者

c)MODULE_VERSION("版本"):声明模块的版本信息

d)MODULE_DESCRIPTION("模块功能描述"):声明模块的功能

/*************************************************
*file_name:helloworld.c
*************************************************/
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");  //模块声明

static int hello_init(void)
{
        printk(KERN_WARING"hello world\n");
        return 0;
}

static void hello_exit(void)
{
        printk(KERN_INFO"goodbye world\n");
}

module_init(hello_init);
module_exit(hello_init);

4 模块参数

  我们可以在加载内核模块的时候向其传递参数,以让同一代码达到不同的效果。通过宏module_param指定保存模块参数的变量。模块参数用于在加载模块时传递参数给模块。

  格式:module_param(name,type,perm)

  a)name变量的名称

  b)type变量的类型,数据类型内核支持模块参数类型有:bool、invbool(bool的发转,true变为false,false变为true)、charp(char类型指针值)、int、long、short、uint、ulong、ushort、

  c)perm访问权限,常见的访问许可值通常为S_IRUGO(读权限)和S_IWUSR(写权限)。通常情况下将他们按位或

  同时我们也可以用下面的宏声明数组:

    Module_param_array(name,type,num,perm) 

/*************************************************
*file_name:helloworld.c
*************************************************/
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");  //模块声明

int a=3;         
charp *p;

module_param(a,int,S_IRUGO | S_IWUSR);     //加载一个整型参数
module_param(P,charp,S_IRUGO | S_IWUSR);  //加载一个字符型参数

static int hello_init(void)
{
        printk(KERN_WARING"hello world\n");
        printk("a=%d\n",a);        
        printf("p is %s\n",p);
        return 0;
}

static void hello_exit(void)
{
        printk(KERN_INFO"goodbye world\n");
}

module_init(hello_init);
module_exit(hello_init);
/*结果显示*/

/*********************************************************/
#insmod helloworld.ko a=10 p=abcd
hello,world! 
a=10
p is abcd

5 模块符号导出

  当一个模块要使用另一个模块的函数(变量)的时候,要使用EXPORT_SYMBOL(符号名)或者EXPORT_SYMBOL_GPL(符号名)来申明。

  注:EXPORT_SYMBOL_GPL()只适用于遵循GPL协议的模块

/**********************************************
*filename:add.c
*********************************************/
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

int add(int a,int b)
{
        return a+b;
}

static int add_init(void)
{
       return 0;
}

static void add_exit(void)
{
}

EXPORT_SYMBOL(add); //可以将add导出给其他函数 module_init(add_init); module_exit(add_exit);
/*************************************************
*file_name:helloworld.c
*function:calling add.c
*************************************************/
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");  //模块声明

extern add(int a,int b);

int a=3;         
charp *p;

module_param(a,int,S_IRUGO | S_IWUSR);     //加载一个整型参数
module_param(P,charp,S_IRUGO | S_IWUSR);  //加载一个字符型参数

static int hello_init(void)
{
        printk(KERN_WARING"hello world\n");
        printk("a=%d\n",a);        
        printf("p is %s\n",p);
        return 0;
}

static void hello_exit(void)
{
        add(1,4);
        printk(KERN_INFO"goodbye world\n");
}

module_init(hello_init);
module_exit(hello_init);
/***********************************
*filename:Makefile
************************************/
obj-m := helloworld.o add.o

KDIR := /home/dongry/mini2440/mini2440      /*开发板内核代码路径*/

all:
    make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
    
clean:
    rm -f *.o *.ko *.order *.symvers

/*结果显示*/

/*********************************************************/
/***************先加载add.ko,后加载helloworld.ko***************/
#insmod add.ko
#insmod helloworld.ko a=10 p=abcd
hello,world! 
a=10
p is abcd

 

posted @ 2019-03-27 14:47  dongry  阅读(642)  评论(0编辑  收藏  举报