四。向内核添加内核模块

内核版本:3.4.24

大家发现什么错误一定要告诉我,大家共同学习了;


########## 内核模块 ###########

1.开发阶段,不能每改一次程序就重新编译一次内核,所以我们通过向内核添加模块的方式调试
    注:a.编译内核时,出现的警告也不能忽略,可能导致大错误
        b.向其添加模块的内核必须是正确编译通过的

2.向内核添加模块,必须:
    a.与内核版本有关;不能把写好的模块插入到其它版本的内核中
    b.与内核配置相关;不能把写好的模块插入到相同版本不同配置的内核中
        抢占式内核(2.6板之后的内核支持):
            默认不支持,可配置成支持抢占
            抢占式内核响应迅速,并且一个进程意外死在内核里不会影响整个内核
3.代码参考/nfsroot/code/01module
    vim Makefile    //创建 Makefile
-->    LINUX_PATH := /home/musesea/arm_class/smdk6410_lzy/src/linux3.4        //内核所在路径
    obj-m += module_test.o    //编译模块

    prefix      ?= /home/musesea/nfsroot
    
    //以下格式是固定的
    //涵义:告诉内核的Makefile,模块在这,内核的Makefile 来给你编译,并将生成的文件放在这个目录下
    all:
        make -C $(LINUX_PATH) M=`pwd` modules
        //-C:指定编译路径;
        //M=`pwd`:模块所在路径,pwd是命令,显示当前路径;
        //modules:内核对于编译模块实现的一个宏
        //注意,pwd 上的两个单引号是键盘 Tab 键上面的那个键
    clean:
        make -C $(LINUX_PATH) M=`pwd` modules clean
        //modules clean:内核对于删除模块实现的一个宏
    install:
        make -C $(LINUX_PATH) M=`pwd` modules_install INSTALL_MOD_PATH=$(prefix)
        //modules_install:内核对于安装模块实现的宏
        //INSTALL_MOD_PATH=$(prefix):将实现的模块安装到变量prefix 定义的路径下
<--        //INSTALL_MOD_PATH:内核实现的宏
    =======================================================================================
    = make 之后生成xxx.ko 文件就是模块
    = make install 后在本目录和创建的根文件系统目录/lib/modules/3.4.24/extra/都会有一个 .ko 文件
    = 开发板在成功挂载根文件系统后,执行 insmod xxx.ko 命令即可插入模块
    =     成功插入后,lsmod 查看插入的内核模块,会显示
    =    module_test1 585 0 - Live 0xbf018000 (O)
    =         模块名字    模块大小    没有依赖(有依赖会显示个数,紧接着显示被谁依赖) 模块状态 位置
    =======================================================================================

    vim module_test1.c        //编写练习程序
-->    //这两个头文件一上来写上就好,宏和函数经常会用到
    #include <linux/init.h>
    #include <linux/module.h>

    //实现来自modules_test2.c
    //使用之前必须声明,以后在写C程序的时候在使用的时侯最好也声明,这样在编译的时候会检测函数参数的正确性
    void my_printf(int num);

    //规则和添加驱动时一样
    static __init int module_test_init(void)
    {
        printk("hello world!\n");

        my_printf(100);

        return 0;
    }

    //类型是定死的,类型void,参数void;代码放在exit段,被保留到程序最后,最后执行,执行完释放
    static __exit void module_test_exit(void)
    {
        printk("Bye bye\n");
    }

    //在插入模块的时候只执行一次
    //insmod xxx.ko
    module_init(module_test_init);
    //在模块删除时执行
    //rmmod xxx.ko
    //rmmod xxx
    module_exit(module_test_exit);

    MODULE_LICENSE("GPL");        //开源规则;必须有这句,下面可有可无
    MODULE_AUTHOR("musesea");    //声明作者
    MODULE_VERSION("1.0");        //声明版本
    MODULE_DESCRIPTION("Class test for module");//声明描述

    vim module_test2.c        //被上面的函数依赖
-->    #include <linux/init.h>
    #include <linux/module.h>

    //普通的函数实现,相当于C语言中写函数,没有固定格式
    void my_printf(int num)
    {
        printk("nihao module %d\n", num);
    }
    //模块间标号共享
    EXPORT_SYMBOL(my_printf);

<--    MODULE_LICENSE("GPL");
    ===============================================================
    = C语言函数名默认是共享的
    = 汇编语言的标号默认是不共享的
    = 内核模块函数名默认是不共享的,只有EXPORT_SYMBOL(函数名),才能共享
    ===============================================================

######### PS #####################################
inclede/linux/    此目录下的代码一般是平台无关
include/asm/    此目录下的代码一般是平台相关

include/linux/stat.h    保存的是和权限相关的宏定义
include/linux/moduleparam.h
        module_param_named
        module_param
        module_param_string
        module_param_array
###################################################

    < 模块参数 >
    vim module_test3.c
-->    #include <linux/init.h>
    #include <linux/module.h>

    //insmod xxx.ko xxx(参数)
    //与此int main(int argc, char *argv[])比较

    //事先声明需传的参数
    static int age = 10;
    char * name = "zhangsan";
    char s[100];//必须事先分配空间
    int array[100];

    //module_param_named(a, age, int, S_IRUGO);
    //S_IRUGO 是文件的权限;宏定义的位置,include/linux/stat.h
    //module_param_named(n, name, charp, S_IRUGO);

    //默认名字和变量相同
    module_param(age, int, S_IRUGO)
    //等价于module_param_named(age, age, int, S_IRUGO);
    module_param(name, charp, S_IRUGO)    //charp 指针类型
    //等价于module_param_named(name, name, charp, S_IRUGO);

    module_param_string(s, s, 100, S_IRUGO);
    //100传入字符串最大长度字节,可以小于100,规定大小为了防止越界

    //内核会自动把传入的元素个数放入num
    int num;
    module_param_array(array, int, &num, S_IRUGO);

    static __init int module_test_init(void)
    {
       printk("hello world!\n");
        printk("age = %d\n", age);
        printk("name = %s\n", name);
        printk("string = %s\n", s);

        while(num--)
            printk("array[%d] = %d\n", num, array[num]);

        return 0;
    }

    static __exit void module_test_exit(void)
    {
        printk("Bye bye\n");
    }

    module_init(module_test_init);

    module_exit(module_test_exit);

    MODULE_LICENSE("GPL");//开源规则

你可能感兴趣的:(规则,开源,内核,内核模块,模块参数)