zoukankan      html  css  js  c++  java
  • (四) linux内核模块编程

      Linux 就是通常所说的单内核(monolithic kernel),即操作系统的大部分功能都被称为内核,并在特权模式下运行。通过 Linux 内核模块(LKM)可以在运行时动态地更改 Linux。Linux可加载内核模块(从内核的 1.2 版本开始引入)是 Linux 内核的最重要创新之一。它们提供了可伸缩的、动态的内核。探索隐藏在可加载模块后面的原理,并学习这些独立的对象如何动态地转换成 Linux 内核的一部分。

     (1) linux 内核模块的创建

      LKM 包含 entry 和 exit 函数。当向内核插入模块时,调用 entry 函数,从内核删除模块时则调用 exit 函数。因为 entry 和 exit 函数是用户定义的,所以存在 module_initmodule_exit 宏,用于定义这些函数属于哪种函数。LKM 还包含一组必要的宏和一组可选的宏,用于定义模块的许可证、模块的作者、模块的描述等等,见下例。

    #include <linux/module.h>     
    #include <linux/kernel.h>       
    #include <linux/init.h>         
    
    
    static int __init hello_3_init(void)
    {
            printk(KERN_ALERT "Hello, world n");
            return 0;
    }
    
    static void __exit hello_3_exit(void)
    {
            printk(KERN_ALERT "Goodbye, world 
    " );
    }
    
    MODULE_LICENSE("GPL");
    module_init(hello_3_init);
    module_exit(hello_3_exit);

    (2)构建linux 内核模块

      编译模块的make file 必须是Makefile,不能是makefile,并且要生成模块必须先编译通过。 内核模块的makefile如下

      ifneq ($(KERNELRELEASE),)
    
      obj-m := mytest.o
    
      mytest-objs := file1.o
    
      else
      
      KVER ?= $(shell uname -r)


      KDIR :
    = /lib/modules/$(shell uname -r)/build   PWD := $(shell pwd)   default:   $(MAKE) -C $(KDIR) M=$(PWD) modules

      clean:

      
      rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions   endif

      1> KERNELRELEASE是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时,KERNELRELEASE没有被定义。所以执行else之后内容。

      2> 当执行make 时候 执行默认目标defalult。

        $(KDIR) 指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD)   指示路径;表明然后返回到当前目录继续读入、执行当前的Makefile。

        $(KVER)  要生成的模块内核版本 当前系统版本

      3> 当从内核源码目录返回时,KERNELRELEASE已被被定义,kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。

        mytest-objs := file1.o  表示mytest.o 由file1.o 连接生成

        obj-m := mytest.o 表示编译连接后将生成mytest.o模块 mytest.ko。

    (3) 编译  安装 卸载

     1> 编译 执行make 生成mytest.ko内核模块

     2> 安装内核模块 sudo insmod mytest.ko  

     3> 查看内核模块输出 dmesg -

     4> 卸载内核模块 sudo rmmod mytest.ko  

     注意:Linux命令dmesg用来显示开机信息,kernel会将开机信息存储在ring buffer中。您若是开机时来不及查看信息,可利用dmesg来查看。开机信息亦保存在/var/log目录中,名称为dmesg的文件里。

    (4)内核模块的启动参数

      像我们普通的应用程序一样,有main函数启动可以有参数,内核模块启动时候也可以使用参数。这点很重要,如在视频压缩中通过最优参数达到不同压缩效率。先看一个例子 我们在解释其中的代码。

    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/kernel.h>
    
    #define MAX_ARRAY 66
    static int int_var = 0;
    
    static char *str_var = "default";
    static int int_array[6];
    int narr;
    
    module_param(int_var, int, 0644);
    MODULE_PARM_DESC(int_var, "A integer variable");
    
    module_param(str_var,charp,0644);
    MODULE_PARM_DESC(str_var, "A string variable");
    
    module_param_array(int_array, int, &narr, 0644);
    MODULE_PARM_DESC(int_array, "A integer array");
    
    static int __init hello_init(void)
    {
         int i;
         printk(KERN_ALERT "Hello, my LKM.
    ");
         printk(KERN_ALERT "int_var %d.
    ", int_var);
         printk(KERN_ALERT "str_var %s.
    ", str_var);
         for(i = 0; i < narr; i ++)
         {
            printk("int_array[%d] = %d
    ", i, int_array[i]);
         }
         return     0;
    }
    static void __exit hello_exit(void)
    {
        printk(KERN_ALERT "Bye, my LKM.
    ");
    }
    module_init(hello_init);
    module_exit(hello_exit);
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("This module is a example.");

     方式一:在内核模块里,参数的用法如同全局变量。

        module_param(name, type, perm);

        name  用户看到的参数名,又是模块内接受参数的变量

        type  表示参数的数据类型,下列之一:byte, short, ushort, int, uint, long, ulong, charp, bool, invbool

        perm 指定了在sysfs中相应文件的访问权限

      eg:

          static unsigned int int_var = 0;

        module_param(int_var, uint, S_IRUGO);

    方式二:模块源文件内部的变量名与外部的参数名有不同的名

        module_param_named(name, variable, type, perm);

        name 外部可见的参数名

        variable 源文件内部的全局变量名

    方式三:字符串

        static char *name;

        module_param(name, charp, 0); 

      或者

        static char species[BUF_LEN];

         module_param_string(name, string, len, perm);

    方式四:数组  

        static int finsh[MAX_FISH];

        static int nr_fish;

        module_param_array(fish, int, &nr_fish, 0444); //最终传递数组元素个数存在nr_fish中

    编译生成内核模块

    装载内核模块 sudo insmod parm.ko int_var=100 str_var=hello int_array=100,200

     

      

  • 相关阅读:
    ajax封装
    完美运动框架
    表单上传input=file
    面向对象入门
    浅谈javaScript内存
    关于使用iframe的父子页面进行简单的相互传值
    浅谈原生JavaScript的动画和特效
    rem 原理与简介
    移动 web 适配
    jsonp 简单封装
  • 原文地址:https://www.cnblogs.com/wolfrickwang/p/3261950.html
Copyright © 2011-2022 走看看