欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Android10 insmod源码分析

程序员文章站 2022-06-24 09:49:27
rk3399-android-10/frameworks/opt/net/wifi/libwifi_hal/wifi_hal_common.cppstatic 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\...


本文代码来源于rk3399-android10。

insmod函数

此处的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表示函数读取的参数来于栈,而非寄存器。

sys_finit_module

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, 。。。)

关于__NR_init_module和sys_init_module

在学习本部分代码的时候,借鉴了网上的一些博客,但不知道为什么大家写的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的区别:

  1. modprobe可以解决load module时的依赖关系
  2. modprobe默认会去/lib/modules/当前kernel/下面查找module,而insmod只在给它的参数中去找module

本文地址:https://blog.csdn.net/krokodil98/article/details/112252034