linux 内核模块 教程,Linux内核动态模块开发入门

写在前面

这篇文章旨在介绍Linux内核动态模块开发时的基本结构,以及如何编译开发的模块。

Linux内核模块开发

我们知道Linux的内核是可以定制的,在编译之前我们可以通过make menuconfig对我们的内核进行配置。其中,在配置的过程中,有些模块我们可以选择直接编入内核,或者编成模块动态使用,或者不编译。

6c3ecb2876c7a6e27a263e9e52f327a3.png

如上图所示,当我们选择编译成模块的话,在menuconfig中的配置就可以选择为M,直接编入内核的话就可以选择*,不编译就选空。

所以,当我们开发的内容的内容相对于原本的内核比较独立的时候,我们就可以使用模块开发,并且可以选择性的配置。

模块开发的结构

从结构上来说,Linux内核一个模块的规范还是比较简单的:初始化处理和结束处理。我们可以看一段最为简单的模块代码。

/*===========================================================================

FILE:

printk_test.c

DESCRIPTION:

moddule printk test

==========================================================================*/

//---------------------------------------------------------------------------

// Include Files

//---------------------------------------------------------------------------

#include

#include

#include

static void __init TestInit( void )

{

printk(KERN_INFO "This is test start.\n" );

}

static void __exit TestExit( void )

{

printk(KERN_INFO "Test over.\n" );

}

module_init( TestInit );

module_exit( TestExit );

在上面的一段代码中,只要掌握里面四个地方,就能做简单的内核模块的开发了。

__init和module_init(…)

当一个模块加载的时候(insmod),最先执行的就是使用__init声明的这个函数。当然我在上面作为示例,只做了一些打印信息的操作。在实际开发中,通常在这个函数里面,我们可以做一些初始化的操作,比如参数检查、线程创建等等。初始化完成后,就可以执行我们所需要的具体操作了(执行线程主任务等)。

另外,我们还需要告诉内核,加载这个模块的时候从这个__init函数里面开始执行。告诉内核的方法就是module_init(…)这个函数,使用方法很简单,仿照上面的那段代码就可以。

__exit和module_exit(…)

相对应的,我们在卸载一个模块的时候(rmmod),启动的就是用__exit声明的函数。同样的,在这个函数里面我们就可以做一些结束处理,比如内存释放,文件关闭,线程关闭等等。

当然,我们还是需要告诉内核,在卸载模块的时候调用这个结束函数——module_exit(…)。

内核模块编译

准备工作

Linux的内核是开源的,所以我们可以从官网上下载它的源码包。当然,从它的官网下载可能会比较慢,这里推荐一个下载较快的上海交通大学的ftp服务器,根据需要选择内核的版本进行下载。

内核下载地址

我们把内核源码包拷贝到虚拟机,解压。(我在这里下载了一个3.10版本的内核)

$ tar -zxvf linux-3.10.tar.gz   

解压完成后,我们就要把我们的这个测试模块加进内核的工程编译了。

Linux内核的工程结构是比较复杂的,我们如果加一个对原本没什么影响的模块,那么就不需要修改原本的内核代码,只需要在工程中加入我们的模块就可以,在这里需要修改两个内容:Kconfig和Makefile。

Kconfig

这个文件的功能就是我们在最开始提到的配置文件了,我们通过修改和添加Kconfig文件,来使得我们能在make menuconfig时,对我们新加的文件进行配置。

以这次的示例,我们加一个打印模块的测试。

首先,在源码工程中的**/linux-3.10/driver/** 下面建立一个我们的文件夹目录printktest,把我们的代码printk_test.c拷贝到这个路径下。

然后,我们在这个路径下面添加Kconfig文件:

config PRINTK_TEST

tristate "PRINT INFOMATION"

---help---

JUST TEST

在这个Kconfig文件中,第一行是对我们这个模块的命名,编译的时候,它会告诉编译器是否要编译这个模块,所以它同样会在之后的Makefile中体现。第二行有一个关键字tristate,这个单词是告诉make menuconfig它可以选择静态编译到内核里,或者动态编译为ko文件,再或者选择不编译。help后的文件就是对模块的解释说明了。

—————————————————————————————————

写好了这个Kconfig文件,我们需要告诉原本的工程,把这个新加的模块包含进去。这个时候需要修改原本的Kconfig文件,把我们自己写的Kconfig文件包含进工程。是哪个文件呢,通常就是上级目录的Kconfig文件。在本例中,我们的模块路径在/driver/printktest里面,所以打开/driver/路径下面的Kconfig文件,添加一行。

source "drivers/printktest/Kconfig"

现在,我们可以再源码的根目录执行make menuconfig,看看它能否找到我们所添加的这一模块。

b88c7ce0d3c6c1e52ff9651cace15b09.png

我们可以很容易在Device Drivers下面找到我们添加的PRINT INFORMATION TEST,按下M将其配置成动态模块编译,保存退出。这个时候在内核源码的根目录下面会生成一个隐藏文件**.config**,我们在终端下使用vim编辑器可以看到,这个隐藏文件里面,可以找到我们刚刚所作的操作——有一个变量CONFIG_PRINTK_TEST,这个变量被设置成了M。这个变量就是我们Kconfig文件中声明的模块名,Linux对配置文件的命名规则就是再加一个CONFIG。而这个变量就会在接下来写Makefile中用到。

Makefile

Makefile这个东西,想必大家都很熟悉它的作用了。上面是让我们的模块在make menuconfig的时候可配置,但到了真正的编译还是靠Makefile起的作用,所以我们也需要添加和修改Makefile。

与Kconfig文件类似,首先还是要在我们模块的路径下加一个Makefile文件,因为本例比较简单就一个c文件,所以Makefile也比较简单,就一行:

obj-$(CONFIG_PRINTK_TEST) += printk_test.o

这个时候我们可以看到,在Makefile里面有一个很眼熟的东西,就是CONFIG_PRINTK_TEST。这个就是我们通过make menuconfig后生成.config文件里面的那个变量,我们选择静态编译、动态编译或者不编译,就是通过这个变量来实现的。

—————————————————————————————————

同样的,我们还需要在上一级目录/driver的Makefile里面加一句话,把包含我们新加的路径:

obj-$(CONFIG_PRINTK_TEST) += /printktest

编译

当我们开发给不同的平台时,会用到交叉编译工具。对于交叉编译的情况,首先要安装配置交叉工具链,然后再对内核进行make menuconfig配置,配置结束后,再编译。对于交叉编译工具的配置这里暂时不做详解了。编译方法同我们编译其他工程一样,make或者make后跟你所需要的参数。

使用

编译完成后,我们可以在我们新建的路径下找到后缀名为ko的驱动文件,当然这个驱动文件在交叉编译的build机上是无法运行的,需要在host上,也就是开发板上挂载。

挂载时,到ko文件所在的路径运行:

$ insmod printk_test.ko

我们也可以查看当前已经挂载的驱动:

$ lsmod

卸载驱动时,不管在什么路径下,运行:

$ rmmod printk_test.ko

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值