linux内核可加载模块编程简单入门

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux内核可加载模块编程简单入门相关的知识,希望对你有一定的参考价值。

1.linux源代码结构 fs:file system文件系统,usr/src/linux:linux内核头文件,mm:内存管理代码

 

 

 2.下载linux内核代码  可自己选择版本,这里是比较老的版本适合小白入手(eg:我用的是0.1x,点击直接下载即可)  http://oldlinux.org/Linux.old/kernel/

 3.Linux系统的整体结构

 

 

 

 

 4.可加载的内核模块,就是linux使用C语言写的,由于C语言是模块化编程的,添加模块很麻烦,所以为了给Linux添加模块,于是诞生了LKM,就是可以使使用户随时添加内核模块到内核,也可以随时卸下,不和内核建立捆绑,我们今天编写的内核程序就是基于这个原理的.

 

 

 5.内核模块的编写,简单例子,只使用一个内核函数printk();printk在内核源码中用来记录日志信息的函数,只能在内核源码范围内使用。用法和printf非常相似

创建k.c文件命令:sudo vim k.c   (sudo是切换到root用户,如果你已经是root了,就不用sudo了),另外请注意,内核模块只能root运行,普通用户无法让内核模块运行,

所以,得切换到root模式,su -  root,但是在root下操作要小心啊!!!

 

//k.c
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
//module.h包含了对模块的版本控制
//kernel.h包含了常用的内核函数
//init.h包含了宏__init和__exit
/*
 * 模块的初始化函数 lkp_init()
 * __init是用于初始化的修饰符
 */
static int __init lkp_init(void)
{
  //<1>是输出的级别,表示立即在终端输出
  printk("<1>hello,Kernal!...\\n!");
  return 0;
}
/*
 * 模块的退出和清理函数 lkp_exit()
 */
static void __exit lkp_exit(void)
{
  printk("<1>Goodbye,world!...\\n");
}

module_init(lkp_init);
module_exit(lkp_exit);
/*
 * 模块的许可证声明GPL
 */
MODULE_LICENSE("GPL");

 

 补充知识点:

printk相比printf来说还多了个:日志级别的设置,用来控制printk打印的这条信息是否在终端上显示的,日志级别的数值小于控制台级别时,printk要打印的信息才会在控制台打印出来,否则不会显示在控制台!内核中有个8个级别.

#define    KERN_EMERG    "<0>"    /* system is unusable            */
#define    KERN_ALERT    "<1>"    /* action must be taken immediately    */
#define    KERN_CRIT    "<2>"    /* critical conditions            */
#define    KERN_ERR    "<3>"    /* error conditions            */
#define    KERN_WARNING    "<4>"    /* warning conditions            */
#define    KERN_NOTICE    "<5>"    /* normal but significant condition    */
#define    KERN_INFO    "<6>"    /* informational            */
#define    KERN_DEBUG    "<7>"    /* debug-level messages            */

 6.Makefile文件编写,Makefile文件和k.c文件放在同一个目录下  创建Makefile文件命令:sudo vim Makefile

 引入原因之1:使用GCC的命令进行程序编译时,当程序是单个文件时编译是比较方便的,但当工程中的文件数目增多,甚至非常庞大,并且目录结构关系复杂时,便需要通过makefile来进行程序的编译

obj-m :=k.o                         #产生k模块的目标文件,这里的k必须和c语言的文件名对应,后缀不同,这里使用了一点shell脚本的知识,读者请百度自行参考
CURRENT_PATH := $(shell pwd)       #模块当前所在的当前路径
LINUX_KERNEL := $(shell uname -r)  #linux内核源代码的当前版本,uame -r 查看内核的linux命令
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
                                   #linux内核源代码的绝对路径
all:
        make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #编译模块,Makefile文件中若一行是命令,必须以tab键开头
clean:
        make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean   #清理模块

补充知识:
obj-m := *.o
obj-y := *.o
上面两者的区别在于,前者才会生成ko文件,后者只是代码编译进内核,并不生成ko文件。

7.编译,使用make命令

8.查看运行结果及常用命令    注意:在强调一下,root模式下才能运行

insmod 模块名    #将模块插入内核中,eg:insmod k.ko,把k.ko模块插入内核
rmmod  模块名    #将模块从内核中删去 eg:rmmod k.ko,将k.ko模块移出内核  o=哦,不是0
dmesg            #查看模块信息的命令,在make之后,使用就能看到信息
lsmod            #查看内核模块,可搭配grep使用,eg:lsmod | grep k 查找内核中的k模块

 程序运行结果:

 9.附加知识

以上是关于linux内核可加载模块编程简单入门的主要内容,如果未能解决你的问题,请参考以下文章

linux安装内核模块问题

Linux入门之CentOS7内核编译三部曲

[driver]简单地hello驱动加载

inux内核模块编程入门

Linux入门之CentOS7内核编译三部曲

如何创建为Android可加载内核模块