此处的insmod函数是驱动加载wifi_load_driver之后会被调用的函数:关于wifi_load_driver的源码分析可见之前的博客:android移植wifi驱动流程porting
文件位置:rk3399-android-10/frameworks/opt/net/wifi/libwifi_hal/wifi_hal_common.cpp
static int insmod(const char *filename, const char *args) {
int ret;
int fd;
fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
printf("insmod filename = %s\n",filename);
if (fd < 0) {
PLOG(ERROR) << "Failed to open " << filename;
return -1;
}
ret = syscall(__NR_finit_module, fd, args, 0);
close(fd);
if (ret < 0) {
PLOG(ERROR) << "finit_module return: " << ret;
}
return ret;
}
其中,他调用到的函数有:
关于syscall:rk3399-android-10/kernel/arch/arm/kernel/entry-common.S
.macro syscall, nr, func
.ifgt __sys_nr - \nr
.error "Duplicated/unorded system call entry"
.endif
.rept \nr - __sys_nr
.long sys_ni_syscall
.endr
.long \func
.equ __sys_nr, \nr + 1
这部分看了很久也查了很多资料,但是依然无法理解macro宏定义和被调用函数之间的具体联系。希望有清楚的能指导下。。。
关于__NR_finit_module:rk3399-android-10/kernel/include/uapi/asm-generic/unistd.h
#define __NR_finit_module 273//系统调用号
__SYSCALL(__NR_finit_module, sys_finit_module)
目前只知道,insmod能通过上述的定义,通过这句代码syscall(__NR_finit_module, fd, args, 0);
,利用系统调用号(中断号)来调用sys_finit_module,finit_module的系统调用号是__NR_finit_module。
sys_finit_module的定义:rk3399-android-10/kernel/include/linux/syscalls.h
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
注:asmlinkage表示函数读取的参数来于栈,而非寄存器。
在rk3399-android-10/kernel/kernel/module.c
中,有以下定义:
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
{
struct load_info info = {
};
loff_t size;
void *hdr;
int err;
err = may_init_module();
if (err)
return err;
pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);
if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
|MODULE_INIT_IGNORE_VERMAGIC))
return -EINVAL;
err = kernel_read_file_from_fd(fd, &hdr, &size, INT_MAX, READING_MODULE);
//定义于rk3399-android-10/kernel/fs/exec.c里,函数作用是在保证安全的前提下,打开fd指向的文件并读取内容
if (err)
return err;
info.hdr = hdr;
info.len = size;
return load_module(&info, uargs, flags);
}
首先,由上述综合来看,可知该函数定义式为:SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
。这一行的意思与asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
的那行定义基本相同。详细的中间的宏定义的转换过程感兴趣的可见文章的”宏定义的等价“章节。
接着来看上方sys_finit_module调用的下一级函数。
文件位置:rk3399-android-10/kernel/kernel/module.c
static int may_init_module(void)
{
if (!capable(CAP_SYS_MODULE) || modules_disabled)//capable检查是否有权对指定的资源进行操作,无权限就返回0
//CAP_SYS_MODULE代表着加载或移除系统模块的操作,定义于rk3399-android-10/kernel/include/uapi/linux/capability.h
return -EPERM;
return 0;
}
//load_module就是最终实际执行加载模块的函数,本文略过
static int load_module(struct load_info *info, const char __user *uargs,
int flags)
{
struct module *mod;
long err = 0;
char *after_dashes
err = elf_header_check(info);
.....
return do_init_module(mod);
...
}
以下是关于宏定义最终等价的过程:
再来看syscalls.h文件。rk3399-android-10/kernel/include/linux/syscalls.h
#ifndef SYSCALL_DEFINE0
#define SYSCALL_DEFINE0(sname) \
SYSCALL_METADATA(_##sname, 0); \
asmlinkage long sys_##sname(void); \
ALLOW_ERROR_INJECTION(sys_##sname, ERRNO); \
asmlinkage long sys_##sname(void)
#endif /* SYSCALL_DEFINE0 */
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
由上方,可知,SYSCALL_DEFINE3 ==》 SYSCALL_DEFINEx(3, _finit_module, VA_ARGS)
其中__VA_ARGS__对应的是SYSCALL_DEFINE3 中的后面的所有参数集,
即 int, fd, const char __user *, uargs, int, flags
还是在rk3399-android-10/kernel/include/linux/syscalls.h
中,有以下定义:
#define SYSCALL_DEFINEx(x, sname, ...) \
SYSCALL_METADATA(sname, x, __VA_ARGS__) \
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
由上,知道SYSCALL_DEFINEx ==》 __SYSCALL_DEFINEx(3, _finit_module, VA_ARGS)
继续分析,还是在rk3399-android-10/kernel/include/linux/syscalls.h
#ifndef __SYSCALL_DEFINEx
#define __SYSCALL_DEFINEx(x, name, ...) \
__diag_push(); \
__diag_ignore(GCC, 8, "-Wattribute-alias", \
"Type aliasing is used to sanitize syscall arguments");\
asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \
__attribute__((alias(__stringify(__se_sys##name)))); \
c \
static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
{ \
long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\
__MAP(x,__SC_TEST,__VA_ARGS__); \
__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \
return ret; \
} \
__diag_pop(); \
static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
#endif /* __SYSCALL_DEFINEx */
由上,知__SYSCALL_DEFINEx(3, _finit_module, __VA_ARGS__)
等价于:
asmlinkage long sys_finit_module(__MAP(3,__SC_DECL, __VA_ARGS__)) \
__attribute__((alias(__stringify(__se_sys_finit_module)))); \
ALLOW_ERROR_INJECTION(sys_finit_module, ERRNO); \
static inline long __do_sys_finit_module(__MAP(3,__SC_DECL,__VA_ARGS__));\
asmlinkage long __se_sys_finit_module(__MAP(3,__SC_LONG,__VA_ARGS__));\
asmlinkage long __se_sys_finit_module(__MAP(3,__SC_LONG,__VA_ARGS__)) \
{
\
long ret = __do_sys_finit_module(__MAP(3,__SC_CAST,__VA_ARGS__));\
__MAP(3,__SC_TEST,__VA_ARGS__); \
__PROTECT(3, ret,__MAP(3,__SC_ARGS,__VA_ARGS__)); \
return ret; \
}\
static inline long __do_sys_finit_module(__MAP(3,__SC_DECL, __VA_ARGS__))
经过上述各类宏转换:
asmlinkage long sys_finit_module(int fd, const char __user * uargs, int flags) \
__attribute__((alias(__stringify(__se_sys_finit_module)))); \
ALLOW_ERROR_INJECTION(sys_finit_module, ERRNO); \
static inline long __do_sys_finit_module(int fd, const char __user * uargs, int flags);\
asmlinkage long __se_sys_finit_module(long fd, long uargs, long flags);\
asmlinkage long __se_sys_finit_module(long fd, long uargs, long flags) \
{
\
long ret = __do_sys_finit_module( (int) fd, (const char __user *) uargs, (int) flags);\
BUILD_BUG_ON_ZERO(sizeof(int) > sizeof(long)); \
BUILD_BUG_ON_ZERO(sizeof(char*) > sizeof(long)); \
__PROTECT(2, ret, fd, uargs , flags); \
return ret; \
}\
static inline long __do_sys_finit_module(int fd, const char __user * uargs, int flags)
实际上SYSCALL_DEFINE3(finit_module,int, fd, 。。。)
,最终等价于asmlinkage long sys_finit_module(int fd, 。。。)
在学习本部分代码的时候,借鉴了网上的一些博客,但不知道为什么大家写的insmod调用的函数都是__NR_init_module,也就是sys_init_module,应该是版本差异吧。
为了对比,也将它的代码贴上来。
定义位置:rk3399-android-10/kernel/include/linux/syscalls.h
asmlinkage long sys_init_module(void __user *umod, unsigned long len,
const char __user *uargs);
文件位置:rk3399-android-10/kernel/kernel/module.c
SYSCALL_DEFINE3(init_module, void __user *, umod,
unsigned long, len, const char __user *, uargs)
{
int err;
struct load_info info = {
};
err = may_init_module();
if (err)
return err;
printk("init_module: umod=%p, len=%lu, uargs=%p\n",umod,len,uargs);
pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
umod, len, uargs);
err = copy_module_from_user(umod, len, &info);
if (err)
return err;
return load_module(&info, uargs, 0);
}
经对比会发现,二者区别在于:
init_module 通过传统的 copy_from_user 来拷贝 ko 代码,finit_module 则通过文件描述符fd来调用 vfs 底层的读函数来读取 ko 代码到内核中。
总结:在学习过程中,发现其实还有一个insmod函数,位于external/kmod/tools/modprobe.c
,估计是工具modprobe所用到的insmod函数。不在此贴代码了。
modprobe和insmod的区别: