sys_ini_module简要分析

1.sys_init_module系统调用代码分析

/* This is where the real work happens */
/*
宏展开结果
long sys_init_module(void __user * umod,
		unsigned long len, const char __user * uargs))
*/
SYSCALL_DEFINE3(init_module, void __user *, umod,
		unsigned long, len, const char __user *, uargs)
{
	struct module *mod;
	int ret = 0;

	/* Must have permission */
	// 确保有插入和删除模块不受限制的权力
	if (!capable(CAP_SYS_MODULE) || modules_disabled)
		return -EPERM;

	/* Do all the hard work */
	// 分配,加载模块,并创建相关的sysfs文件
	mod = load_module(umod, len, uargs);
	if (IS_ERR(mod))
		return PTR_ERR(mod);
	
	// 通知内核通知链module_notify_list上的监听者,模块状态变为MODULE_STATE_COMING
	blocking_notifier_call_chain(&module_notify_list,
			MODULE_STATE_COMING, mod);

	// core,init相关的region的只读和读写权限
	/* Set RO and NX regions for core */
	set_section_ro_nx(mod->module_core,
				mod->core_text_size,
				mod->core_ro_size,
				mod->core_size);

	/* Set RO and NX regions for init */
	set_section_ro_nx(mod->module_init,
				mod->init_text_size,
				mod->init_ro_size,
				mod->init_size);

	// 调用本模块的所有构造器
	do_mod_ctors(mod);
	
	/* Start the module */
	// 调用模块的init方法
	if (mod->init != NULL)
		ret = do_one_initcall(mod->init);

	
	if (ret < 0) {
		/* Init routine failed: abort.  Try to protect us from
                   buggy refcounters. */
		mod->state = MODULE_STATE_GOING;
		synchronize_sched();
		module_put(mod);
		blocking_notifier_call_chain(&module_notify_list,
					     MODULE_STATE_GOING, mod);
		free_module(mod);
		wake_up(&module_wq);
		return ret;
	}
	if (ret > 0) {
		printk(KERN_WARNING
"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
"%s: loading module anyway...\n",
		       __func__, mod->name, ret,
		       __func__);
		dump_stack();
	}

	/* Now it's a first class citizen!  Wake up anyone waiting for it. */
	mod->state = MODULE_STATE_LIVE;

	// 唤醒module_wq队列上等待本模块初始化的所有任务
	wake_up(&module_wq);

	// 通知内核通知链module_notify_list上的监听者,模块状态变为MODULE_STATE_LIVE
	blocking_notifier_call_chain(&module_notify_list,
				     MODULE_STATE_LIVE, mod);

	/* We need to finish all async code before the module init sequence is done */
	// 等待所有的异步函数调用完成
	async_synchronize_full();

	mutex_lock(&module_mutex);
	/* Drop initial reference. */
	module_put(mod);
	
	trim_init_extable(mod);
#ifdef CONFIG_KALLSYMS
	mod->num_symtab = mod->core_num_syms;
	mod->symtab = mod->core_symtab;
	mod->strtab = mod->core_strtab;
#endif
	// 取消init相关region的读写权限设置
	unset_module_init_ro_nx(mod);
	// 释放模块初始化区相关的内存
	module_free(mod, mod->module_init);
	mod->module_init = NULL;
	mod->init_size = 0;
	mod->init_ro_size = 0;
	mod->init_text_size = 0;
	mutex_unlock(&module_mutex);

	return 0;
}

2.load_module函数分析

/* Allocate and load the module: note that size of section 0 is always
   zero, and we rely on this for optional sections. */
static struct module *load_module(void __user *umod,
				  unsigned long len,
				  const char __user *uargs)
{
	struct load_info info = { NULL, };
	struct module *mod;
	long err;

	DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
	       umod, len, uargs); // %p打印指针的值,也就是地址

	/* Copy in the blobs from userspace, check they are vaguely sane. */
	// 为模块分配内核空间,并复制到该空间,Sets info->hdr and info->len
	err = copy_and_check(&info, umod, len, uargs);
	if (err)
		return ERR_PTR(err);

	/* Figure out module layout, and allocate all the memory. */
	// 布置模块,并分配相关的内存,把相关块复制到最终镜像中
	mod = layout_and_allocate(&info);
	if (IS_ERR(mod)) {
		err = PTR_ERR(mod);
		goto free_copy;
	}

	/* Now module is in final location, initialize linked lists, etc. */
	err = module_unload_init(mod);
	if (err)
		goto free_module;

	/* Now we've got everything in the final locations, we can
	 * find optional sections. */
	 // 寻找可选块,并设置mod中相关块的相关项
	find_module_sections(mod, &info);

	err = check_module_license_and_versions(mod);
	if (err)
		goto free_unload;

	/* Set up MODINFO_ATTR fields */
	// 设置模块属性
	setup_modinfo(mod, &info);

	/* Fix up syms, so that st_value is a pointer to location. */
	err = simplify_symbols(mod, &info);
	if (err < 0)
		goto free_modinfo;

	// 对info代表的模块做重定位操作
	err = apply_relocations(mod, &info);
	if (err < 0)
		goto free_modinfo;

	err = post_relocation(mod, &info);
	if (err < 0)
		goto free_modinfo;

	flush_module_icache(mod);

	/* Now copy in args */
	// 把参数从用户空间复制到内核空间
	mod->args = strndup_user(uargs, ~0UL >> 1);
	if (IS_ERR(mod->args)) {
		err = PTR_ERR(mod->args);
		goto free_arch_cleanup;
	}

	/* Mark state as coming so strong_try_module_get() ignores us. */
	mod->state = MODULE_STATE_COMING;

	/* Now sew it into the lists so we can get lockdep and oops
	 * info during argument parsing.  No one should access us, since
	 * strong_try_module_get() will fail.
	 * lockdep/oops can run asynchronous, so use the RCU list insertion
	 * function to insert in a way safe to concurrent readers.
	 * The mutex protects against concurrent writers.
	 */
	 // 确定没有已经加载的同名模块
	mutex_lock(&module_mutex);
	if (find_module(mod->name)) {
		err = -EEXIST;
		goto unlock;
	}

	/* This has to be done once we're sure module name is unique. */
	dynamic_debug_setup(info.debug, info.num_debug);

	/* Find duplicate symbols */
	// 确定没有重复的导出符号
	err = verify_export_symbols(mod);
	if (err < 0)
		goto ddebug;

	module_bug_finalize(info.hdr, info.sechdrs, mod);
	// 添加模块到全局模块链表中
	list_add_rcu(&mod->list, &modules);
	mutex_unlock(&module_mutex);

	/* Module is ready to execute: parsing args may do that. */
	err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
	if (err < 0)
		goto unlink;

	/* Link in to syfs. */
	// 在sysfs创建模块的文件支持
	err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp);
	if (err < 0)
		goto unlink;

	/* Get rid of temporary copy and strmap. */
	// 释放临时模块镜像和其他临时辅助内存
	kfree(info.strmap);
	free_copy(&info);

	/* Done! */
	trace_module_load(mod);
	return mod;

 unlink:
	mutex_lock(&module_mutex);
	/* Unlink carefully: kallsyms could be walking list. */
	list_del_rcu(&mod->list);
	module_bug_cleanup(mod);

 ddebug:
	dynamic_debug_remove(info.debug);
 unlock:
	mutex_unlock(&module_mutex);
	synchronize_sched();
	kfree(mod->args);
 free_arch_cleanup:
	module_arch_cleanup(mod);
 free_modinfo:
	free_modinfo(mod);
 free_unload:
	module_unload_free(mod);
 free_module:
	module_deallocate(mod, &info);
 free_copy:
	free_copy(&info);
	return ERR_PTR(err);
}

猜你喜欢

转载自blog.csdn.net/qq_36412526/article/details/89375037
今日推荐