驱动初始化最原始的做法:开发者试图添加一个驱动初始化程序时,在内核启动 init 程序的某个地方直接添加调用自己驱动程序的 xxx_init() 接口函数,在内核启动时就自然会启动这个驱动程序,类似: void kernel_init() { a_init(); b_init(); ... m_init(); } 但是,这种做法在RTOS系统中或许可以,对于 Linux ...
一个用于卸载模块. linux代码中使用SYSCALL_DEFINEx这个宏定义一个系统调用的入口, 其中x代表系统调用的参数个数, 看一下内核代码就可以找到和模块的加载以及卸载相关的syscall函数, 使用正则表达式或者其他工具能很快在内核代码中找到这三个系统调用的定义.
加载内核模块有两个Linux 系统调用- init_module 和 finit_module。通过利用 init_module,我绕过了基于文件系统的 SELinux 规则,该规则阻止我通过传统方式(例如 insmod)加载内核模块。然后,我从 kernel-space 禁用了 SELinux。 为了避免透露目标实现的不必要细节,在下面的描述中,文件名和 SELinux 上下文等信息已被...
3.2. init_module的执行时机 命令行下使用insmod或modprobe安装模块,最终系统调用为init_module或finit_module。 可以使用strace insmod test.ko查看使用的具体的系统调用。 系统调用init_module和finit_module用来从用户态加载ko文件,man 2 init_module可以看到两者的介绍。init_module接收一个ELF文件的路径,而finit_modu...
关于系统调用,文件(include/linux/syscalls.h)中,有 #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) 从而形成 sys_init_module 函数。 SYSCALL_DEFINE3实现是在Linux内核源代码(kernel/module.c)下面,代码梳理调用如下: ...
void (*cleanup)(void); /*模块的清除函数指针 */ const struct exception_table_entry *ex_table_start; const struct exception_table_entry *ex_table_end; #ifdef __alpha__ unsigned long gp; #endif }; 除了next和refs外,所有的指针被期望指在模块体内, 该系统调用只对超级用户开放. ...
module_init -> init_module (alias(#initfn) 将函数变成init_module的别名。插入模块是寻找该函数。insmod后通过解析该模块,调用系统调用接口。 finit_module最终调用该init_module函数。 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
模块的初始化函数指针 */ void (*cleanup)(void); /*模块的清除函数指针 */ const struct exception_table_entry *ex_table_start; const struct exception_table_entry *ex_table_end; #ifdef __alpha__ unsigned long gp; #endif }; 除了next和refs外,所有的指针被期望指在模块体内, 该系统调用只对...
因此,该系统调用对应内核层的sys_init_module函数。 回到Linux内核源代码(kernel/module.c),代码梳理: SYSCALL_DEFINE3(init_module, ...) | -->load_module | -->do_init_module(mod) | -->do_one_initcall(mod->init); 1. 2. 3. 4.
}; 除了next和refs外,所有的指针被期望指在模块体内, 该系统调用只对超级用户开放. 返回值 成功时返回0,错误时返回 -1,errno被相应设置. 错误 EPERM 用户不是超级用户. ENOENT name指定的模块不存在. EINVAL EBUSY 模块的初始化函数失败. EFAULT name或image越出了程序可访问的地址空间. ...