• 从linux内核说起~模块篇(四)


    这一节主要内容讲解linux内核的模块机制。主要参考经典书籍《linux device drivers》。

    ①    大多数小规模及中规模的应用程序从头到尾执行单个任务,而模块却只是预先注册自己一边服务于将来的某个请求,然后他的初始化函数就立即结束了。

    模块仅仅被链接到内核,因此它能调用的函数仅仅是由内核导出的那些函数,而不存在任何可链接的函数库。所以源文件不能包含常用的头文件。内核模块只能使用作为内核一部分的函数。大多数相关的头文件保存在内核源码树的(/home/sml/linux2.6.37.4/)头文件声明里,include/linux和include/asm目录中。

    ②    最简单的模块构造(helloworld)

    1.     在虚拟机上面创建hello.c和Makefile。

    2.     Hello.c源代码如下:

    #include <linux/module.h>

    #include <linux/init.h>

    #include <linux/sched.h>

    #include <linux/kernel.h>

    MODULE_LICENSE("GPL");

     

    static int hello_init(void)

    {

           printk(KERN_EMERG "hello world!\n");

           return 0 ;

    }

     

    static void hello_exit(void)

    {

           printk(KERN_EMERG "crule world!\n");

    }

    module_init(hello_init);

    module_exit(hello_exit);

    3. makefile文件内容

    obj-m := hello.o

    4. 虚拟机上必须要有内核源码树,我的在/home/sml/linux2.6.37.4,因为我们构造的模块最终要运行的linux2.6.37.4内核上面,所以要在内核源码树下面编译模块。执行make -C/home/sml/linux2.6.37.4 M=$PWD modules.

    root@sml-VirtualBox:/home/sml/nfs_server#make -C /home/sml/linux-2.6.37.4 M=$PWD modules

    make:进入目录'/home/sml/linux-2.6.37.4'

      CC[M]  /home/sml/nfs_server/hello.o

      Buildingmodules, stage 2.

      MODPOST 1modules

      CC      /home/sml/nfs_server/hello.mod.o

      LD[M]  /home/sml/nfs_server/hello.ko

    make:离开目录“/home/sml/linux-2.6.37.4”

    执行完命令,生成hello.ko模块。

    5. make-C /home/sml/linux2.6.37.4 M=$PWD modules解析。

    前面讲到,模块依赖于内核导出的一些符号,主要的头文件声明在include/linux和include/asm目录下。所以编译模块肯定要依赖于内核源码树。-C 表示make切换到指定目录。M是makefile中的一个变量,指定为当前目录,也就是hello.c 的所在目录。Modules指向obj-m变量中设定的模块,就是hello模块。因为在hello.c的Makefile中没有指定内核源码树的目录,所以-C来告诉make内核源码树的路径。(这个地方理解的不是很透彻,但是我们要明白:内核模块的编译是依赖于内核源码树的。)。

    6. 模块的装载和卸载

    装载命令:insmod;卸载命令:rmmod;查看模块命令:lsmod;查看模块信息:modinfo;

    我们把上面的编译的模块放在根文件系统上面,然后执行装载命令,即可看到我们要打印的信息。如何放在开发板的根文件系统上,请参见:NFS实现开发板和虚拟机之间的文件共享。Make工具的使用方法请参见:MAKE工具介绍

    ③    内核符号表(模块层叠技术)

    Insmod使用公共内核符号表来解析模块中未定义的符号。公共内核符号表中包含了所有的全局内核项(变量和函数)的地址,这是实现模块化驱动程序的必须的。当模块被装入内核后,它所导出的任何符号都会成为内核符号表的一部分。新模块可以使用有我们自己的模块导出的符号。这样我们可以在其他模块上层叠新的模块(模块层叠技术)。符号导出实现模块之间的资源共享。驱动程序的模块层叠可以理解为抽象层为硬件驱动层提供符号,抽象层和硬件驱动层就相当于两个(或多个)模块。我们可以将模块划分为多个层,缩短开发时间。

    符号导出方法:

                           EXPORT_SYMBOL(name);

                           EXPORT_SYMBOL_GPL(name);

    ④    初始化和关闭

    module_init(hello_init);

    module_exit(hello_exit);

    初始化和关闭是强制性的,是模块被insmod和rmmod时执行的。

    ⑤    模块的参数

    内核允许驱动程序指定参数,而这些参数可以在装载驱动程序模块时改变。驱动程序参数包括设备编号,以及一些其他的控制驱动程序操作方式的参数。如:

    insmod hellop howmany=10 whom=”sml”

    在模块中,参数的申请方法,包含头文件

    #include <moduleparam.h>

    格式为:

    Module_param(name,type,s perm);

    如:

    Module_param(howmany,int,S_IRUGO);

    S_IRUGO表示任何人可读取参数,但是不能更改;

    S_IRUGO|S_IWUSR表示允许root用户修改该参数。大多数情况下,我们不应该让模块参数可写。

  • 相关阅读:
    详细描述一下 Elasticsearch 索引文档的过程 ?
    elasticsearch 索引数据多了怎么办,如何调优,部署 ?
    elasticsearch 了解多少,说说你们公司 es 的集群架构,索 引数据大小,分片有多少,以及一些调优手段 ?
    Dubbo 和 Dubbox 之间的区别?
    Dubbo 支持服务降级吗?
    Pipeline 有什么好处,为什么要用 pipeline?
    为什么redis 需要把所有数据放到内存中?
    你对线程优先级的理解是什么?
    在 java 中 wait 和 sleep 方法的不同?
    一个线程运行时发生异常会怎样?
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3100591.html
Copyright © 2020-2023  润新知