OpenWrt自动编译加载ko

今天在调试ko的时候,发现没有在开机的时候进行自动加载,之前只知道在Makefile文件中增加一个配置就可以实现。

AUTOLOAD:=$(call AutoLoad,60,leds-gpio,1)
但是我这边也有注意到,一些ipt相关的ko makefile的写法是:
AUTOLOAD:=$(call AutoProbe,$(notdir $(NFT_BRIDGE-m)))

我这边做一下分析。

引用1:Linux新版OpenWrt自动编译加载ko

编译

在 include/kernel.mk中可以看到定义

version_filter=$(if $(findstring @,$(1)),$(shell $(SCRIPT_DIR)/package-metadata.pl version_filter $(KERNEL_PATCHVER) $(1)),$(1))

# 1: priority (optional)
# 2: module list
# 3: boot flag
define AutoLoad
  $(if $(1),$(1),0) $(if $(3),1,0) $(call version_filter,$(2))
endef

# 1: module list
# 2: boot flag
define AutoProbe
  $(call AutoLoad,,$(1),$(2))
endef

其实 AutoProbe 就是 AutoLoad, ( 1 ) , (1), (1),(2) 的封装。封装的时候省略了 priority。
自己也可以实现:

AUTOLOAD:=$(call AutoLoad,,leds-gpio,1)
# 或者
AUTOLOAD:=$(call AutoLoad,0,leds-gpio,1)

编译配置加载顺序

系统启动加载的时候分为两种方式:

  1. /sbin/init 中加载
    其实这块有点表述不清,应该说是在 /sbin/init 的时候加载的一些系统关键ko,此时没有执行 /etc/init.d/boot 中的操作(挂在文件系统等等)
    /sbin/init 阶段加载的模块列表是在 /etc/modules-boot.d/ 目录下
    实现的关键是 AutoLoad 的第三个参数(boot flag), 如果设置了这个值为1,则会在boot阶段加载
  2. 系统启动过程自动加载
    在/etc/init.d/boot 中的操作,此时系统文件系统等已经挂载完。
    加载的模块列表是在 /etc/modules.d/ 目录下

看一下编译时候是怎么根据配置生成的:

define Package/kmod-$(1)/install
    @for mod in $$(call version_filter,$$(FILES)); do \
        if grep -q "$$$$$$$${mod##$(LINUX_DIR)/}" "$(LINUX_DIR)/modules.builtin"; then \
                echo "NOTICE: module '$$$$$$$$mod' is built-in."; \
        elif [ -e $$$$$$$$mod ]; then \
                mkdir -p $$(1)/$(MODULES_SUBDIR) ; \
                $(CP) -L $$$$$$$$mod $$(1)/$(MODULES_SUBDIR)/ ; \
        else \
                echo "ERROR: module '$$$$$$$$mod' is missing." >&2; \
                exit 1; \
        fi; \
    done;
    $(call ModuleAutoLoad,$(1),$$(1),$(filter-out 0-,$(word 1,$(AUTOLOAD))-),$(filter-out 0,$(word 2,$(AUTOLOAD))),$(sort $(wordlist 3,99,$(AUTOLOAD))))
    $(call KernelPackage/$(1)/install,$$(1))
endef


# 1: name
# 2: install prefix
# 3: module priority prefix
# 4: required for boot
# 5: module list
define ModuleAutoLoad
  $(if $(5), \
    mkdir -p $(2)/etc/modules.d; \
    ($(foreach mod,$(5), \
      echo "$(mod)$(if $(MODPARAMS.$(mod)), $(MODPARAMS.$(mod)),$(if $(MODPARAMS), $(MODPARAMS)))"; )) > $(2)/etc/modules.d/$(3)$(1); \
    $(if $(4), \
      mkdir -p $(2)/etc/modules-boot.d; \
      ln -sf ../modules.d/$(3)$(1) $(2)/etc/modules-boot.d/;))
endef

加载ko

ko加载log信息:

root@MUXI:/# logread | grep kmodloader
Fri Jul 14 12:23:40 2023 user.info kernel: [    2.129349] kmodloader: loading kernel modules from /etc/modules-boot.d/*
Fri Jul 14 12:23:40 2023 user.info kernel: [    2.462703] kmodloader: done loading kernel modules from /etc/modules-boot.d/*
Fri Jul 14 12:23:40 2023 user.info kernel: [    6.045561] kmodloader: loading kernel modules from /etc/modules.d/*
Fri Jul 14 12:23:40 2023 user.info kernel: [   12.411877] kmodloader: done loading kernel modules from /etc/modules.d/*

/sbin/init 阶段ko加载

引用2: openwrt启动流程(一)

/sbin/init 的源码:
其中就包含了 /sbin/kmodloader /etc/modules-boot.d/

int
main(int argc, char **argv)
{
	pid_t pid;

	ulog_open(ULOG_KMSG, LOG_DAEMON, "init");
    // 挂载了 /proc 、/sys 、/dev 、/tmp …等目录,并设置 PATH 环境变量
	early();
    // 从cmd line中获取debug log等级
	cmdline();
    // 开启看门狗
	watchdog_init(1);

	pid = fork();
	if (!pid) {
        ///etc/modules-boot.d/ 目录下保存了需要开机自动加载的kernel模块信息。
		char *kmod[] = { "/sbin/kmodloader", "/etc/modules-boot.d/", NULL };

		if (debug < 3)
			patch_stdio("/dev/null");
        //加载kernel模块
		execvp(kmod[0], kmod);
		ERROR("Failed to start kmodloader: %m\n");
		exit(EXIT_FAILURE);
	}
	if (pid <= 0) {
		ERROR("Failed to start kmodloader instance: %m\n");
	} else {
		const struct timespec req = {0, 10 * 1000 * 1000};
		int i;

		for (i = 0; i < 1200; i++) {
			if (waitpid(pid, NULL, WNOHANG) > 0)
				break;
			nanosleep(&req, NULL);
			watchdog_ping();
		}
	}
	uloop_init();
    // 执行/sbin/procd -h /etc/hotplug-preinit.json, 然后是 /bin/sh /etc/preinit ,并在/etc/preinit 执行结束的回调函数中调用 /sbin/procd
	preinit();
	uloop_run();

	return 0;
}
系统启动阶段ko加载

在 /etc/init.d/boot 文件中

boot() {
        [ -f /proc/mounts ] || /sbin/mount_root
        [ -f /proc/jffs2_bbc ] && echo "S" > /proc/jffs2_bbc
        # ...

        # 这个步骤会安装  /etc/modules.d/ 目录下的ko文件
        /sbin/kmodloader
        # ...
        /bin/config_generate
        uci_apply_defaults
        # temporary hack until configd exists
        /sbin/reload_config
}
/sbin/kmodloader 源码

提供一下 /sbin/kmodloader 的源码,作为备注查看
ubox/kmodloader.c

static int main_loader(int argc, char **argv)
{
        char *dir = "/etc/modules.d/";
        //参数判断,由参数的话加载指定路径下的ko文件,没有参数的话,加载默认路径下的文件
        if (argc > 1)
                dir = argv[1];
        //...  省略部分代码
        scan_module_folders();
        scan_loaded_modules();

        ULOG_INFO("loading kernel modules from %s\n", path);
        // ...
        for (j = 0; j < gl.gl_pathc; j++) {
                FILE *fp = fopen(gl.gl_pathv[j], "r");

                while (getline(&mod, &mod_len, fp) > 0) {
                        //...
                        m = find_module(get_module_name(mod));
                        //...
                }
        }
        fail = load_modprobe(true);
        // ...
}

你可能感兴趣的:(Opwnert,openwrt)