内核模块编写

本文档的Copyleft归rosetta所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性。
参考资料:《Linux设备驱动程序 第三版》
来源:http://blog.csdn.net/rosetta/article/details/7563601

  以前也曾经想过往Linux内核编程方向长展,但总归是没有入门的机会,看过《Linux设备驱动程序》(买来已经两年多了),但就像看天书似的。
现在往网络编程方面发展,涉及面还是挺广的,这也是一次偶然的机会,上头让我把Ipsec的算法模块整理下,虽然这工作做起来非常无聊,但还是让我发现了和设备驱动相关的东西,让我的精神为之一振,从而再次拿起《Linux设备驱动程序》来为我答疑。
最近还在看openswan klips的实现,涉及到网卡驱动程序编写,慢慢都给整理成笔记,今天先把这最基本的基础知识先帖上。

知识点:
1.    编译多个.c源文件的ko(单个文件编写网上有太多的教程,多个c源文件编译是这我这回遇到的)
2.    编写带参数的内核模块(这个顺便也给记下,虽然貌似没有用到)
3.    insmod,rmmod,mknod,modprobe,dmesg等命令使用(dmesg比较有用,有些人不知道用这个命令,就说要用串口显示信息,其实dmesg命令更方便,-c选项清空信息)
4.    无法插入内核的原因。(这个也是关键,很多时候操作起来比较简单,比如编译内核源码,但可能会碰到一系列错误,解决一堆错误最能提升一个人的能力)

一、编译多个.c文件的ko模块并插入内核
   //test_module.c
  #include <linux/init.h>
  #include <linux/module.h>
 
  #include "extern_app.h"
 
  static char *who = "linux ss";
  static int many = 1;
  module_param(many, int, S_IRUGO);
  module_param(who, charp, S_IRUGO);
 
  static int __init hello_init(void)
  {
      test();
      static int i = 0;
 
      for(i = 0; i < many; i++)
          printk(KERN_ALERT "Hello, %s!\n", who);
 
      return 0;
  }
 
  static void __exit hello_exit(void)
  {
      printk(KERN_ALERT "Goodbye\n");
  }
 
  module_init(hello_init);
  module_exit(hello_exit);
  MODULE_LICENSE("GPL");

  //extern_app.c
  #include <linux/init.h>
  #include <linux/module.h>
  int test(void)
  {
      printk("test here.\n");
 
      return 0;
  }

  //extern_app.h
  #ifndef __EXTERN_APP_H
  #define __EXTERN_APP_H
 
  extern int test(void);
 
  #endif

  //Makefile
  #ifneq ($(KERNELRELEASE),)
      obj-m := my_module.o
      my_module-objs := test_module.o extern_app.o
  #else
  KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  PWD := $(shell pwd)
 
  default:
      $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
 
  clean:
      rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
      rm -rf Module.* modules.*
 
  .PHONY: default clean
  #endif

  make,如果执行成功则生成my_module.ko
 
  //执行insmod 后并调用dmesg,正常情况如下显示:
  [root@localhost module_kernel]# insmod my_module.ko who=Coding many=5
  [root@localhost module_kernel]# dmesg
  test here.
  Hello, Coding!
  Hello, Coding!
  Hello, Coding!
  Hello, Coding!
  Hello, Coding!
  [root@localhost module_kernel]#

  //rmmod从内核移除模块
  [root@localhost module_kernel]# insmod my_module.ko
  insmod: error inserting 'my_module.ko': -1 File exists
  [root@localhost module_kernel]# rmmod  my_module

二、出错原因解决方法
  在插入模块时常遇到的错误:
  [root@panlimin module_study]# insmod my_module.ko
  insmod: error inserting 'my_module.ko': -1 Invalid module format
  dmesg查看内核报错消息:
  [root@panlimin module_study]# dmesg
  my_module: no symbol version for module_layout
  [root@panlimin module_study]#

  一般出这个错在make时会有类似这样的警告:
  WARNING: Symbol version dump /root/study/kernel/linux-2.6.34/Module.symvers
           is missing; modules will have no dependencies and modversions.

  这是应该Linux内核版本依赖出现了问题,这种情况一般出现在自行编译内核后没有链接到正确的内核源码目录树情况,或者
  内核目录树顶层的Module.symvers文件丢失。因为模块代码必须针对要链接的内核版本重新编译。
  如果没有此警告,但在insmod时还是报此错误,就需要查看Module.symvers文件是否正确,比如这个文件可能是0字节,
  Module.symvers在编译内核时会生成,如果发行版本在/lib/module/目录下对应的内核目录树中会有,此时只要确保该文件正确
  再重新make,insmod应该就没问题了。

  除了insmod可以将模块插入内核外,modprobe也可以,它们的区别在于后者会考虑要插入的模块是否引用了一些当前内核不存在的符号,
  如果有这类引用,modprobe会在查找相应模块并尝试插入到内核。所以有时使用insmod插入无效时还可以使用modprobe.

  如果由于模块依赖导致符号表出现问题,比如,~/.viminfo被破坏,甚至无法加载网络接口等,可以在/lib/module/对应的内核目录下
  执行depmod -a重新生成正确的符号表,执行过程需要点时间。


### 回答1: Linux内核模块编写是指在Linux操作系统中编写可动态加载和卸载的内核模块,以扩展操作系统的功能或添加新的设备驱动程序。内核模块编写需要掌握C语言编程技能和Linux内核的基本知识,包括内核数据结构、系统调用、进程管理、内存管理、设备驱动等。编写内核模块需要遵循一定的规范和流程,包括编写Makefile文件、定义模块参数、注册模块、实现模块功能、编写模块文档等。内核模块编写对于Linux系统的开发和维护非常重要,可以为系统添加新的功能和设备支持,提高系统的可靠性和性能。 ### 回答2: Linux内核模块是一段能够扩展或增强Linux内核功能的代码,它可以动态地加载或卸载到内核中运行。Linux内核模块编写需要遵循一定的规范和步骤,下面是详细介绍。 一、编写和编译内核模块 1、编写内核模块源代码,通常以.c或.cpp文件为扩展名。 2、生成一个Makefile文件,编写编译和链接内核模块所需的命令。 3、进入内核源代码目录,运行make命令编译内核模块,生成模块的.ko文件。 二、加载和卸载内核模块 1、运行insmod命令加载内核模块内核中,在加载模块时需要指定模块的路径和名称。 2、运行rmmod命令从内核中卸载内核模块,在卸载模块时需要指定模块的名称。 三、接口函数 内核模块需要实现init和exit函数,分别用于模块的初始化和卸载。例如: ``` static int __init my_module_init(void) { /* 模块初始化代码 */ return 0; } static void __exit my_module_exit(void) { /* 模块卸载代码 */ } module_init(my_module_init); module_exit(my_module_exit); ``` 四、模块参数 内核模块可以接受一些通过命令行传递的参数,在模块加载时指定。例如: ``` static char *my_string = "hello"; module_param(my_string, charp, 0); ``` 这段代码定义了一个名为my_string的字符串类型参数,初始值为"hello",模块加载时可以使用如下命令指定: ``` insmod my_module.ko my_string="world" ``` 五、调试技巧 1、使用pr_info、pr_err等宏函数输出调试信息。 2、使用printk_ratelimit限制调试信息的输出频率。 3、使用gdb对内核模块进行调试。 以上就是Linux内核模块编写的基本流程和注意事项,需要注意的是内核模块编写需要具备一定的Linux内核编程基础和相关知识。 ### 回答3: 在Linux操作系统中,内核模块是一个可以动态加载或卸载的程序。内核模块可以扩展操作系统的功能,例如添加新的设备驱动程序、实现新的系统调用、修改内核运行时行为等。而内核模块编写就是指为Linux内核添加新功能的过程。 内核模块编写可以分为以下几个步骤: 1. 准备开发环境:向Linux内核开发组申请开发账户,并下载内核源代码。编译好内核源代码,并安装相关的开发工具。 2. 编写代码:根据需求编写内核模块的源代码。在Linux内核编写模块需要使用C语言,并按照内核代码风格格式要求来编写编写的代码最终会成为一个称之为内核对象文件的二进制文件。 3. 编译内核模块:使用内核源代码目录下的Makefile文件来编译内核模块。Makefile文件主要是用来控制编译过程的,其中包含了编译规则、库文件、头文件、链接文件等重要的指令。使用“make”命令可以执行Makefile文件中的编译规则,生成一个后缀名为.ko的内核模块二进制文件。 4. 加载内核模块:使用insmod命令来加载内核模块。加载成功后,内核会告知用户已经成功注册了一个新的驱动程序。可以使用lsmod命令来查看当前系统中已经加载的内核模块。 5. 卸载内核模块:使用rmmod命令来卸载已加载的内核模块。卸载内核模块后,内核会告知用户已经成功注销了一个驱动程序。 总之,内核模块编写是操作系统内核开发的一部分,需要开发者具备扎实的C语言技能,并了解操作系统与内核模块相关的底层知识。内核模块编写能够使我们更加深入地了解Linux内核,并扩展操作系统的功能。在编写内核模块时要格外小心,因为内核模块代码是运行在内核空间中的,不当操作可能会导致系统崩溃,因此需要十分谨慎。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值