内核模块hello_module介绍

Linux内核结构:
  • Device Drivers 设备驱动

    • Linux 内核中大量代码在设备驱动程序部分,用于控制特定的硬件设备
    • Linux 驱动一般分为网络设备, 块设备, 字符设备, 杂项设备
  • 网络协议栈

    • 内核网络协议栈为Linux提供了丰富的网络协议实现


1. 准备工作
  1. Debian: 编译内核模块的准备

    1
    sudo apt-get install module-assistant  #获取模块助手
  2. Fedora: kernel-dedel 包包含了编译Fedora内核模块的所有必要文档和工具

    1
    sudo yum install kernel-devel
  3. 内核源码下载:

    http://kernel.org

    将内核放置到非超级用户目录下: 尽量少用sudo 等提权命令

    1. cd linux-<version>
      make menuconfig 生成 .config 规则文件
      make menuconfig

    2. make help 帮助文档

      • Configuration targets:

        ​ menuconfig - Update current config utilising a menu based program
        ​ oldconfig - Update current config utilising a provided .config as base

      • Other generic targets:

        ​ all - Build all targets marked with [*]
        ​ vmlinux - Build the bare kernel
        ​ modules - Build all modules

      • Kernel packaging:

        ​ rpm-pkg - Build both source and binary RPM kernel packages
        ​ binrpm-pkg - Build only the binary kernel RPM package
        ​ deb-pkg - Build both source and binary deb kernel packages
        ​ bindeb-pkg - Build only the binary kernel deb package
        ​ tar-pkg - Build the kernel as an uncompressed tarball
        ​ targz-pkg - Build the kernel as a gzip compressed tarball
        ​ tarbz2-pkg - Build the kernel as a bzip2 compressed tarball
        ​ tarxz-pkg - Build the kernel as a xz compressed tarball

      • Linux kernel internal documentation in different formats (DocBook):

        ​ htmldocs - HTML
        ​ pdfdocs - PDF
        ​ psdocs - Postscript
        ​ xmldocs - XML DocBook
        ​ mandocs - man pages
        ​ installmandocs - install man pages generated by mandocs to INSTALL_MAN_PATH

        ​ (default: ./usr)

        ​ cleandocs - clean all generated DocBook files

    3. sudo tar -C / -xvf linux-<version>.tar 安装内核 / make modules_install / make install

  4. 内核配置:

    • 使用menuconfig #make menuconfig 生成.config配置文件


2. 驱动模块编程:

​ printk相当于printf的孪生姐妹,她们一个运行在用户态,另一个则在内核态被人们所熟知。但是根据不同的操作系统也会有不一样的效果,例如编写一个hello word 内核模块,使用这个函数不一定会将内容显示到终端上,但是一定在内核缓冲区里,可以使用dmesg.查看效果。

hello内核模块功能:

​ printk 在内核中打印信息

​ 输出到内核的消息缓存kernel Message buffer 并拷贝到 /var/log/message中

/var/log/syslog
syslog

/var/log/kern.log
kern.log

  • hello_module 模块下载

  • 编写Hello Module必要头文件:

    <linux/module.h>

    1
    2
    MODELE_LICENSE(_license) 遵循开放协议 GPL
    MODULE_AUTHOR(_author) 代码作者

    <linux/init.h> 包含初始化宏定义的头文件。

    1
    2
    module_init(x)  
    module_exit(x)
  • 模块编写:

    • hello_printk.c:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      #include <linux/init.h>   // 模块加载;
      #include <linux/module.h> // GPL协议

      MODULE_LICENSE("Dual BSD/GPL");
      //可无;
      MODULE_AUTHOR("Rocky_Ansi");

      // __init关键字告诉内核这个代码只会被运行一次,而且是在内核装载的时候。
      static int __init hello_init(void)
      {  
      printk(KERN_WARNING "Welcome hello-module init\n");      
      return 0;
      }

      // __exit关键字告诉内核这段代码只在内核模块被卸载的时候运行一次.
      static void __exit hello_exit(void)
      {      
      printk(KERN_WARNING "Byebye hello-module exit\n");
      }
      module_init(hello_init);
      module_exit(hello_exit);

    • Makefile:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      #!/bin/bash

      #obj-m指出将要编译成的内核模块列表。.o格式文件会自动地有相应的.c文件生成
      #y build directly into the kernel
      #n leave entirely out of the kernel
      #m Build as a module, to be loaded if needed.
      #? print a bried descriptive message and repeat the prompt.
      obj-m += hello.o

      #CFLAGS += /home/Postgres/ubuntu-src/iTop4412_Kernel_3.0/include

      #KDIR表示是内核源代码的位置。 链接到包含着正在使用内核对应源代码的目录树位置。
      KDIR := /home/Postgres/ubuntu-src/iTop4412_Kernel_3.0

      #PWD指示了当前工作目录并且是我们自己内核模块的源代码位置
      PWD ?= $(shell pwd)

      #M= 指定hello.c Makefile所在目录
      all:
      make -C $(KDIR) $(CFLAGS) M=$(PWD) modules

      .PHONY:
      clean:
      rm -rf *.o
      • 编译流程:
        编译流程

        • 第一条红线: 进入Linux源码中,调用版本信息 以及 一些头文件。
          整个Linux的源码文件
        • 第二条橙线: 搜索完Linux源码树的信息之后,Makefile继续运行,调用编译.KO 文件的源码文件。
          hello_module.c 文件。


3. 生成ko模块

make #发现缺失 <bound.h> 等头文件
解决:

1
2
cd kernel-&lt;version&gt;
sudo make oldconfig && sudo make prepare // 产生缺失的必须模块文件


4. 挂载, 移除, 查看ko模块信息;
1
2
3
4
insmod 加载模块
dmesg |grep hello -- 可以查看模块输出到内核信息;
lsmod 查看模块
rmmod 卸载模块命令


printk函数 - IBM

陈皓 - 内核模块

欣赏此文? 求鼓励,求支持!