驱动模块(2)——模块信息与调试

摘要:
进入每个模块目录,这里有个“parameters”目录,列出了这个模块所有的参数。上面示例是要找出sd8xxx模块的参数。#cat/sys/module/sd8xxx/parameters/mfg_mode查看参数mfg_mode的值。七个等级的initcall都被存放在initcall_levels这个数组中了,在do_initcalls()中一次性全部调用完。

一、查看内核模块信息

相关命令:modprobe、insmod、rmmod、modinfo、lsmod

1.查看内核所有内置模块
# cat /lib/modules/$(uname -r)/modules.builtin

kernel/arch/arm64/crypto/sha1-ce.ko
kernel/arch/arm64/crypto/sha2-ce.ko
kernel/arch/arm64/crypto/ghash-ce.ko
kernel/arch/arm64/crypto/aes-ce-cipher.ko
......

2.查看有哪些内置模块
# grep "=y" /boot/config-$(uname -r) | more

3.查看内核模块参数和值
# ls /sys/module/sd8xxx/parameters
在/sys/module目录下,可以找到内核模块(包含内置和可加载的)命名的子目录。进入每个模块目录,这里有个“parameters”目录,列出了这个模块所有的参数。
上面示例是要找出sd8xxx模块的参数。
# cat /sys/module/sd8xxx/parameters/mfg_mode 查看参数mfg_mode的值。

4.显示模块参数信息
# modinfo -p sd8xxx 只显示参数

5.显示模块全部信息
# modinfo sd8xxx

filename:       /lib/modules/4.14.35/extra/sd8xxx.ko 模块存放的位置
license:        GPL
version:        C546 模块版本
author:         Marvell International Ltd.
description:    M-WLAN Driver
srcversion:     5F78B0AEFAD2117163CB186
alias:          sdio:c*v02DFd9135*depends:        cfg80211,mlan 模块依赖
name:           sd8xxx
vermagic:       4.14.35SMP preempt mod_unload aarch64  匹配内核版本信息
parm:           cfg80211_drcs:1: Enable DRCS support; 0: Disable DRCS support (int)
parm:           reg_alpha2:Regulatory alpha2 (charp) 模块参数
...

二、模块声明信息

MODULE_LICENSE ("GPL"); 许可证申明(最好有)
MODULE_DESCRIPTION("Hello world Module"); 模块描述(可选)
MODULE_VERSION("V1.0");模块版本(可选)
MODULE_ALIAS("a simple module");模块别名(可选)
Module_param(name,type,perm)Name是模块参数的名称,type是这个参数的类型,Perm是模块参数的访问权限
type常见值: Bool,int,charp:字符串型
perm常见值:S_IRUGO:任何用户都对/sys/module中出现的该参数具有读权限, S_IWUSR:允许root用户修改/sys/module中出现的该参数

EXPORT_SYMBOL(符号名)
EXPORT_SYMBOL_GPL(符号名)导出只能用于包含GPL许可证的模块
/proc/kallsyms记录了内核中所有导出的符号的名字与地址(记录输出到系统当中可以给其他模块使用的函数的名字)

三、内核模块的动态加载

request_module("sound-slot-%i", unit>>4);表示让linux系统的用户空间调用/sbin/modprobe函数加载名为sound-slot-0.ko模块

TODO:https://blog.csdn.net/liukun321/article/details/7057442

四、模块加载次序

1. 相关宏定义

//include/linux/init.h
#define pure_initcall(fn)            __define_initcall(fn, 0)
#define core_initcall(fn)            __define_initcall(fn, 1)
#define core_initcall_sync(fn)        __define_initcall(fn, 1s)
#define postcore_initcall(fn)        __define_initcall(fn, 2)
#define postcore_initcall_sync(fn)    __define_initcall(fn, 2s)
#define arch_initcall(fn)            __define_initcall(fn, 3)    /*gpio注册*/
#define arch_initcall_sync(fn)        __define_initcall(fn, 3s)
#define subsys_initcall(fn)            __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)    __define_initcall(fn, 4s)
#define fs_initcall(fn)                __define_initcall(fn, 5)
#define fs_initcall_sync(fn)        __define_initcall(fn, 5s)
#define rootfs_initcall(fn)            __define_initcall(fn, rootfs)
#define device_initcall(fn)            __define_initcall(fn, 6)     /*module_init()*/
#define device_initcall_sync(fn)    __define_initcall(fn, 6s)
#define late_initcall(fn)            __define_initcall(fn, 7)
#define late_initcall_sync(fn)        __define_initcall(fn, 7s)

#define __initcall(fn) device_initcall(fn)

#define __exitcall(fn)     static exitcall_t __exitcall_##fn __exit_call = fn /*exit call是没有等级的*/

#define console_initcall(fn)    ___define_initcall(fn,, .con_initcall)
#define security_initcall(fn)    ___define_initcall(fn,, .security_initcall)


//include/linux/module.h
#define module_init(x)    __initcall(x);
#define module_exit(x)    __exitcall(x);

2.do_initcall_level() 函数只在 do_initcalls() 中被调用一次,也就是说这七个等级的 initcall 没有任何一个等级做了特殊处理,同等对待,只是调用的先后次序不同而已。七个等级的 initcall 都被存放在 initcall_levels 这个数组中了,在 do_initcalls() 中一次性全部调用完。

static initcall_t *initcall_levels[] __initdata = { //init/main.c
__initcall0_start,
    __initcall1_start,
    __initcall2_start,
    __initcall3_start,
    __initcall4_start,
    __initcall5_start,
    __initcall6_start,
    __initcall7_start,
    __initcall_end,
};

static void __init do_initcall_level(intlevel)
{
    initcall_t *fn;

    strcpy(initcall_command_line, saved_command_line);

    /*先解析命令行参数后再执行*/parse_args(initcall_level_names[level],
           initcall_command_line, __start___param,
           __stop___param -__start___param,
           level, level,
           NULL, &repair_env_string);

    for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
        do_one_initcall(*fn);
}

static void __init do_initcalls(void)
{
    intlevel;
    /*这决定了pure/arch/late_initcall()等的先后顺序,越小越先被调用*/
    for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
        do_initcall_level(level);
}

3. 一个.c文件中可以有多个module_init()和多个module_exit()。

4.module_init 的 initcall level 为6,设备树的解析在init call 3 时段。

免责声明:文章转载自《驱动模块(2)——模块信息与调试》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇2019春第九周作业Android应用程序签名详解 简介下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

.Net程序员学用Oracle系列(9):系统函数(上)

1、字符函数 1.1、字符函数简介 1.2、语法说明及案例 2、数字函数 2.1、数字函数简介 2.2、语法说明及案例 3、日期函数 3.1、日期函数简介 3.2、语法说明及案例 3.3、日期函数补充 4、总结 Oracle 中系统函数特别多,有好几百个,其中大部分函数对开发者而言,似乎永远都用不到,本文将要介绍 Ora...

JSP页面之${fn:}内置函数

函数列表: 函数名 函数说明 使用举例 fn:contains 判断字符串是否包含另外一个字符串 <c:if test="${fn:contains(name, searchString)}"> fn:containsIgnoreCase 判断字符串是否包含另外一个字符串(大小写无关) <c:if test="${fn:con...

mac os hot key

了解常见 Mac OS X 快捷键。快捷键是通过按下键盘上的组合键来调用 Mac OS X 功能的一种方式。 要使用快捷键或组合键,您可以同时按修饰键和字符键。例如,同时按下 Command 键(标有符号的按键)和“c”键会将当前选中的任何内容(文本、图形等等)拷贝至夹纸板。这也称作 Command-C 组合键(或快捷键)。 许多组合键中都包含修饰键...

Rust 智能指针(一)

Rust 智能指针(一) 1.Box<T> Box<T>是指向堆中的指针。 fn main() { let box = Box::new(3); println!("{}", box); } 在出了指针的作用域之后,指针和它指向的对象都将被释放。 在本例中,box将在main函数之后被释放。 由于Box<T&...

linux kernel的cmdline參数解析原理分析

利用工作之便,今天研究了kernel下cmdline參数解析过程。记录在此。与大家共享。转载请注明出处。谢谢。 Kernel 版本:3.4.55 Kernel启动时会解析cmdline,然后依据这些參数如console root来进行配置执行。 Cmdline是由bootloader传给kernel。如uboot。将须要传给kernel的參数做成一个...

js 提示窗

/** * @Co.,Ltd. 千寻前端 * @authors 小石头(1348571886@qq.com) * @date 2014-12-22 * @version 4.0 */ var jAlert=(function(){ this.myalertin=function(text,color...