Linux内核模块原理

2021-10-01DEEPIN v20.24 5.10.6内核 蓝牙rtl8761B驱动程序安装 问题: 插入蓝牙适配器后 #lsusb #dmesg 查看问题如下: 0110] Bluetooth: hci0: RTL: examining hci_ver=0a hci_rev=000b lmp_ver=0a lmp_subver=8761 [ 2853.461063] Bluetooth: hci0: RTL: rom_version status=0 version=1 [ 2853.461067] Bluetooth: hci0: RTL: loading rtl_bt/rtl87 阅读详情
  • 什么是Linux内核模块

模块是向内核添加新功能的一种方法,当需要为内核编写设备驱动程序,扩展内核功能时,就可以通过编写内核模块扩展内核,模块可以动态的加载和移除,所以无须重新编译内核或者重启操作系统,现在5.X内核源码和之前研究的2.6.X关于内核模块的改动比较大,所以基于当前最新的5.X内核源码重新研究下内核模块的实现。

  • 模块的内核表示

Module结构的成员较多,这里我提取了部分重要的成员注释说明

 

struct module {
	enum module_state state; //模块的状态

	//链接到内核模块链表的元素
	struct list_head list;

	//模块名称
	char name[MODULE_NAME_LEN];

    //导出到内核的模块符号
    const struct kernel_symbol *syms;
	const s32 *crcs;
	unsigned int num_syms;

    //模块核心代码在地址空间的位置信息
    struct module_layout core_layout __module_layout_align;

    //模块初始化代码地址信息
	struct module_layout init_layout;
    
    //模块初始化函数
    int (*init)(void);


    //模块是否会污染内核
    unsigned long taints;

    //本模块被其它模块依赖的链表
	struct list_head source_list;
	
    //本模块依赖哪些其它模块
	struct list_head target_list;

	//模块销毁时调用的函数
	void (*exit)(void);

    //模块被引用的次数
	atomic_t refcnt;
}
  • 插入内核模块过程

内核执行流程:

  1. 用户空间insmod发起加载模块系统调用
  2. init_module函数,它复制模块二进制代码到内核地址空间,初始化load_info结构体(包含模块二进制内容)

  3. load_module 检查模块有效性(elf头部检查、签名检查),解决引用、修复重定位项等

  4. do_init_module 设置module状态等信息,并执行模块初始化函数,至此模块已加载完毕

init_module说明

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;

	
	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);
}

 

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 = module_sig_check(info, flags);
	if (err)
		goto free_copy;

	//检查ELF 头部和区段有效性
	err = elf_validity_check(info);
	if (err) {
		pr_err("Module has invalid ELF structures\n");
		goto free_copy;
	}

	 //设置模块结构各个区段在内核地址空间的位置
	err = setup_load_info(info, flags);
	if (err)
		goto free_copy;

	
	//检查模块是否在内核黑名单内,如果是则禁止加载
	if (blacklisted(info->name)) {
		err = -EPERM;
		pr_err("Module %s is blacklisted\n", info->name);
		goto free_copy;
	}

	//设置所有节区在内核临时内存地址空间的位置
	err = rewrite_section_headers(info, flags);
	if (err)
		goto free_copy;

	//检查模块版本
	if (!check_modstruct_version(info, info->mod)) {
		err = -ENOEXEC;
		goto free_copy;
	}

	//为内核模块分配内存
	mod = layout_and_allocate(info, flags);
	if (IS_ERR(mod)) {
		err = PTR_ERR(mod);
		goto free_copy;
	}

	audit_log_kern_module(mod->name);

	//判断模块是否已经加载,若没有则将模块添加到内核模块链表中
	err = add_unformed_module(mod);
	if (err)
		goto free_module;

#ifdef CONFIG_MODULE_SIG
	mod->sig_ok = info->sig_ok;
	if (!mod->sig_ok) {
		pr_notice_once("%s: module verification failed: signature "
			       "and/or required key missing - tainting "
			       "kernel\n", mod->name);
		add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK);
	}
#endif

	/* To avoid stressing percpu allocator, do this once we're unique. */
	err = percpu_modalloc(mod, info);
	if (err)
		goto unlink_mod;

	//初始化模块依赖引用链表并增加引用计数
	err = module_unload_init(mod);
	if (err)
		goto unlink_mod;

	init_param_lock(mod);

	/*
	 * Now we've got everything in the final locations, we can
	 * find optional sections.
	 */
	err = find_module_sections(mod, info);
	if (err)
		goto free_unload;

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

	/* Set up MODINFO_ATTR fields */
	setup_modinfo(mod, info);

	//修复模块未解决引用
	err = simplify_symbols(mod, info);
	if (err < 0)
		goto free_modinfo;

	//处理重定位
	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);

	//拷贝模块参数到module->args
	mod->args = strndup_user(uargs, ~0UL >> 1);
	if (IS_ERR(mod->args)) {
		err = PTR_ERR(mod->args);
		goto free_arch_cleanup;
	}

	dynamic_debug_setup(mod, info->debug, info->num_debug);

	/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
	ftrace_module_init(mod);

	//模块已准备完成,设置模块状态标识等
	err = complete_formation(mod, info);
	if (err)
		goto ddebug_cleanup;

	err = prepare_coming_module(mod);
	if (err)
		goto bug_cleanup;

	/* Module is ready to execute: parsing args may do that. */
	after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
				  -32768, 32767, mod,
				  unknown_module_param_cb);
	if (IS_ERR(after_dashes)) {
		err = PTR_ERR(after_dashes);
		goto coming_cleanup;
	} else if (after_dashes) {
		pr_warn("%s: parameters '%s' after `--' ignored\n",
		       mod->name, after_dashes);
	}

	//链接到/sysfs文件系统
	err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
	if (err < 0)
		goto coming_cleanup;

	if (is_livepatch_module(mod)) {
		err = copy_module_elf(mod, info);
		if (err < 0)
			goto sysfs_cleanup;
	}

	//释放加载模块过程中分配的临时内存
	free_copy(info);

	/* Done! */
	trace_module_load(mod);

	return do_init_module(mod);

do_init_module说明

static noinline int do_init_module(struct module *mod)
{
	int ret = 0;
	struct mod_initfree *freeinit;

	//为内核初始化代码分配内存
	freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL);
	if (!freeinit) {
		ret = -ENOMEM;
		goto fail;
	}
	freeinit->module_init = mod->init_layout.base;

	/*
	 * We want to find out whether @mod uses async during init.  Clear
	 * PF_USED_ASYNC.  async_schedule*() will set it.
	 */
	current->flags &= ~PF_USED_ASYNC;

	do_mod_ctors(mod);
	
	//启动模块,如果存在初始化函数则执行它
	if (mod->init != NULL)
		ret = do_one_initcall(mod->init);
	if (ret < 0) {
		goto fail_free_freeinit;
	}
	if (ret > 0) {
		pr_warn("%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();
	}

	//设置模块运行标识
	mod->state = MODULE_STATE_LIVE;
	blocking_notifier_call_chain(&module_notify_list,
				     MODULE_STATE_LIVE, mod);

 

至此模块已加载到Linux内核,以后再分享将如何使用内核提供的模块机制来编写自己的内核模块,内核模块编写这块资料还是比较多,而且内核关于这块的变动不大,各个内核版本几乎是兼容的。

 

 

 

 

 

 

 

Linux内核模块加载机制与实现原理 内核模块是Linux系统实现动态功能扩展的核心机制,通过模块化设计可以在运行时加载驱动程序或功能组件。其技术原理基于ELF文件格式解析和动态链接技术,内核通过sys_init_module系统调用入口处理模块加载请求。在工程实践中,模块加载涉及权限验证、内存管理、符号解析等关键技术环节,其中load_info和module结构体承载关键状态信息。该机制广泛应用于设备驱动开发、文件系统扩展等场景,特别是insmod工具链和module_param参数传递机制为驱动调试提供了重要支持。通过分析模块状态机(MOD 阅读详情

相关推荐

Linux内核模块Makefile编写指南:从Kbuild原理到实战配置

Makefile是Linux内核开发中的核心构建配置文件,它定义了模块的编译规则和依赖关系。其工作原理基于内核的Kbuild系统,通过声明式变量(如obj-m)告知构建系统如何将源代码编译为可加载的内核模块(.ko文件)。理解Makefile对于确保模块与内核版本兼容性、管理符号导出和优化编译过程至关重要。在嵌入式开发、设备驱动编写等应用场景中,掌握Makefile的编写能有效解决模块加载错误、符号未定义等常见问题。本文结合Kbuild系统原理和工程实践,深入解析了如何编写高效、健壮的内核模块Makefil

weixin_30268921的博客 441

insmod加载内核模块后报错,Invalid module format

错误通常意味着内核模块与当前运行的内核不兼容,但我是因为开了好几个终端,可能占用太多资源了,关掉几个就不报错了。

2302_76306559的博客 402

Linux内核模块签名机制:从原理到实践的安全验证指南

在Linux系统安全领域,内核模块的动态加载机制提供了强大的扩展能力,但也引入了潜在的安全风险。非对称加密技术中的数字签名机制为解决这一问题提供了基础方案,其核心原理是利用公钥和私钥对实现身份认证与完整性校验。该技术的核心价值在于构建可信的代码执行环境,通过密码学手段确保模块来源的真实性和内容的完整性,防止恶意代码潜入内核空间。在应用场景上,模块签名广泛应用于服务器安全加固、嵌入式设备防护以及遵循安全启动规范的现代计算平台。本文聚焦于Linux内核模块签名与验证机制,详细解析了其基于非对称加密的完整工作流程

weixin_29315569的博客 282

linux内核模块的实现机制,Linux 内核模块工作原理及内核模块编译案例

一、Linux内核模块基本原理Linux 内核模块(LKM)是一些在启动的操作系统内核需要时可以载入内核执行的代码块,不需要时由操作系统卸载。它们扩展了操作系统内核功能却不需要重新编译内核、启动系统。如果没有内核模块,就不得不反复编译生成操作系统的内核镜像来加入新功能,当附加的功能很多时,还会使内核变得臃肿。一个Linux 内核模块主要由以下几个部分组成:(1) 模块加载函数(必须):当通过ins...

weixin_36387104的博客 790

Linux内核模块安全卸载指南:从rmmod原理到生产环境实践

内核模块是Linux系统实现动态功能扩展的核心机制,它允许在不重启系统的前提下加载或卸载驱动程序与内核功能。其工作原理基于模块的初始化与退出函数,通过module_init和module_exit宏定义生命周期回调,确保资源的申请与释放。这项技术的核心价值在于提供了系统的灵活性与可维护性,使得硬件驱动调试、功能热插拔和内核裁剪成为可能,广泛应用于嵌入式开发、服务器运维和云计算等领域。在模块卸载环节,若操作不当极易引发系统不稳定,因此必须掌握安全卸载流程。本文聚焦于rmmod命令的深度解析,涵盖lsmod状态

weixin_31364787的博客 313

Linux内核模块卸载:rmmod命令原理、实战与安全规范

内核模块是Linux系统中动态扩展功能的核心机制,它允许在不重启内核的情况下加载驱动或功能。其生命周期管理遵循加载与卸载的对称性原则,卸载过程需要确保资源被正确释放,以避免内存泄漏或系统不稳定。这一机制对于系统调优、驱动开发和嵌入式场景具有重要技术价值。在实际应用中,模块卸载常面临依赖管理、引用计数和资源清理等挑战。本文聚焦于rmmod命令,深入解析其工作原理、常见错误排查方法,并分享安全卸载的最佳实践,帮助开发者掌握模块管理的核心技能,确保系统稳定运行。

weixin_28347369的博客 270

CTF-内核pwn入门1: linux内核模块基础原理

内核模块(*.ko文件)可以扩展内核的功能,允许内核在运行时动态加载或卸载代码。常见用途包括硬件驱动、文件系统支持、网络协议栈、安全性增强、性能监控等。insmod:手动加载模块,但不会处理依赖。modprobe:推荐的加载模块方式,支持自动处理依赖关系。lsmod:查看已加载的模块。rmmod:卸载模块。自动加载:通过配置文件实现。modinfo:查看模块详细信息。如果你需要加载一个模块,并且该模块有依赖关系,使用modprobe会更方便,因为它能自动加载依赖的模块。在最简单的形式下,

weixin_59166557的博客 1193

[无效的 ELF 头部]:解决 Linux 命令报错问题

这个错误提示意味着 Linux 系统找不到指定文件的 ELF 头部,因为文件可能已经损坏或者它的格式不符合 ELF 头部的标准。第一种方法是检查你所使用的工具链是否兼容当前的操作系统。如果你的代码是在另一台机器上编译完成的,并且你正尝试在不同的机器上运行它,那么请确保两台机器的系统版本和架构配置相同,否则就会出现 ELF 头部错误。如果你的代码需要其他的特殊库或者头文件,你可以通过安装相应的工具链来满足这些要求。以上是解决 ELF 头部错误的三种方法,希望对你在处理 Linux 命令时遇到的问题提供帮助。

. 9654

linux 内核模块原理,linux 了解内核模块的原理 《Rice linux 学习开发》

更多技术干货内容请稳步到“电子发烧友网”公众号,回复资料即可免费获取一份技术资料,在这里每天可以获取最专业、最前沿的电子技术。Linux内核是整体性结构,各个子系统紧密联系,上接用户控件,下接硬件,作为一个大程序在内核控件运行。如果将所有的设备驱动和内核功能都集成在内核中,则内核会不断的庞大,对我们的内核裁剪也会带来更大的挑战,为了解决这个问题,Linux内核引入内核模块机制,通过动态加载内核模块...

weixin_32309879的博客 258

Kernel: module: Invalid module format

这里是说文件的大小小于16个字节,或者对应文件的开始4个字节不是,“\177ELF”,就认为这个kernel module的文件有问题。根据文件的magic数,有对应的文件打开函数来处理。如果不是压缩过的kernel module,最后会用reg_ops,出现ENOEXEC的地方是,说这个size 小于EI_NIDENT 或者。最后通过mmap映射文件内容到内存。

mzhan017的博客 818

嵌入式linux内核模块编程底层原理详解

Linux 内核模块被精确地定义为能够动态 根据需要在 kernel 中加载和卸载。这些模块增强了内核 功能,而无需重新启动系统。一个值得注意的例子是 device driver 模块,便于内核与硬件组件交互 链接到系统。在没有模块的情况行的方法倾向于单体内核,需要将新功能直接集成到 kernel 镜像。这种方法会导致更大的 kernel 并且需要 kernel 当新功能出现时,重建和随后的系统重启 期望。

嵌入式技术开发 422

Linux内核模块全景与核心原理深度解析(含代码注释)

Linux内核模块结构清晰、分工明确。各模块通过抽象和接口协作,实现了高效、稳定、可扩展的操作系统。理解其模块划分、核心原理和关键代码实现,是深入Linux内核开发与调优的基础。如需对某个模块做更细致的行级源码讲解(如进程调度、内存管理、网络协议等),欢迎进一步提问!

IT技术学习与工作笔记分享 2263

大模型量化技术全解析:从INT8到GPTQ/AWQ,降低部署成本实战指南

模型量化是一种通过降低神经网络权重和激活值的数据精度(如从FP16降至INT8/INT4),从而大幅减少模型内存占用和计算开销的核心模型压缩技术。其原理基于线性变换,将高精度浮点数映射到低精度整数表示,在硬件层面能利用专用低精度计算单元实现显著加速。这项技术的核心价值在于解决了大模型(如千亿参数LLM)部署时面临的高昂显存成本和推理延迟问题,使其能在消费级GPU和边缘设备上高效运行。当前,后训练量化(PTQ)因其无需重新训练的特性成为主流,衍生出GPTQ、AWQ、SmoothQuant等多种方法,广泛应用于

weixin_33804582的博客 630

Linux内核模块参数机制底层原理与实现

本文深入剖析了Linux内核模块参数机制的实现原理。该系统基于sysfs虚拟文件系统,通过kobject机制将内核对象映射为用户空间可见的文件接口。核心数据结构包括kernel_param(参数描述符)和kernel_param_ops(参数操作函数集),它们共同实现了参数读写功能。模块参数通过/sys/module/模块名/parameters/目录下的文件进行访问,支持动态生成和权限控制。该机制为内核模块提供了灵活的参数配置能力,同时确保了用户空间与内核空间的安全交互。

图形/计算GPU的驱动与虚拟化技术分享园地 2198

量化交易新手必看:如何用vnpy+Tushare轻松获取A股历史数据(附完整代码)

本文为量化交易新手提供了使用vnpy和Tushare构建A股历史数据获取系统的完整指南。通过详细的代码示例,手把手教你搭建环境、封装数据获取引擎,并实现日线等数据的格式转换与本地存储,为策略回测与分析奠定坚实的数据基础。

weixin_29098117的博客 378

避坑指南:ROS2 Humble摄像头标定常见错误排查(从‘CALIBRATE’按钮不变绿到保存文件找不到)

本文详细解析了ROS2 Humble环境下摄像头标定的常见问题及解决方案,从CALIBRATE按钮不变绿到标定文件保存失败等疑难杂症。提供硬件准备、参数设置、实时诊断到结果验证的全流程指导,特别针对Ubuntu2204系统和usb_cam驱动的兼容性问题给出实用建议,帮助开发者高效完成内参标定。

weixin_29193359的博客 398

Linux内核模块编程——实现原理

Linux内核模块编程 http://www.hzlitai.com.cn/article/ARM9-article/system/1601.html

星愿心愿的专栏 1497

光模块组成

时钟恢复电路(Clock Data Recovery,简称CDR)是光模块中的关键组成部分,CDR的作用主要是从接收到的信号中提取出数据序列,并且恢复出与数据序列相对应的时钟时序信号,从而还原接收到的具体信息。因为光信号传输至一定距离的时候,通常是长距离传输,其波形会出现一定程度的失真,接收端接收到的信号是一个个长短不一的脉冲信号,这个时候在接收端,我们就无法得到我们需要的数据。所以,这个时候就需要有信号的再生,信号的再生功能为再放大、再整形和再定时,其中的再定时指的就是CDR时钟数据恢复。

han_better的博客 5721

Linux 内核模块开发终极指南:动态加载代码的实现原理与实战

Linux 内核模块开发是深入理解操作系统核心机制的关键一步。通过动态加载代码,开发者可以在不重启系统的情况下扩展内核功能,实现真正的热插拔体验。本文将为你揭开内核模块的神秘面纱,从基础概念到实战应用,带你全面掌握这一强大技术。🚀 ## 什么是 Linux 内核模块? Linux 内核模块是一种可以**动态加载到内核中**的代码片段,它们能够**扩展内核功能**而无需重新编译整个内核。模块可

gitblog_00026的博客 466

华为2288H-V5服务器做raid的详细步骤

操作步骤 服务器启动界面 按del键进入设置输入密码,2288H-v5默认密码是Admin@9000 移动光标选择device manager 驱动管理选择configurationutility 配置管理 选择main menu 主菜单 选择第一个 configuration management 配置管理 选择create virtual driver 创建虚拟驱动选择select RAID level 选择RAID等级选择level-5 选择select drivers 选择驱......

weixin_46041124的博客 1万+

别再死记硬背MAML原理了!用PyTorch手撸一个Omniglot小样本分类器(附完整代码)

本文详细介绍了如何使用PyTorch实现MAML(模型无关的元学习)算法,构建一个Omniglot小样本分类器。通过实战代码演示,帮助读者理解MAML的双层优化原理,并提供了完整的训练循环、网络架构设计及调试技巧,适合想要掌握元学习技术的开发者。

weixin_29191669的博客 131

linux设备驱动框架构建,Linux设备驱动程序原理及框架内核模块入门篇.ppt

Linux设备驱动程序原理及框架内核模块入门篇课程内容 内核模块 内核模块 课程内容 内核模块 内核模块 内核模块 内核模块 内核模块 课程内容 内核模块 内核模块 内核模块 内核模块 内核模块 内核模块 课程内容 内核模块 内核模块 内核模块 内核模块 内核模块 课程内容 内核模块 内核模块 内核模块 内核模块 内核模块 内核模块 内核模块 内核模块 内核模块 内核模块 内核模块 内核模块 内核...

weixin_35724224的博客 107

ARM CoreLink 系列 5.1.1 -- CI-700 System Address Map 】

所有的CHI 命令都包含一个 Source ID 和 Target ID, 其中 Source ID 可以来自于 RN Node, Target ID 可以来自于HN node或者其他 SN node. 其中 Target ID 是通过 SAM解析传入的地址得到的。对于 CI-700中的所有 RN Node 中的 SAM 多会进行配置,因为RN Node 访问的是整个地址空间,不同的地址空间会有不同的属性(I/O, DRAM),所以会对RN SAM 配置多个不同属性的区域。

CodingCos的博客 771

Linux内核模块开发核心原理与工程实践

内核模块是Linux实现动态功能扩展的基础机制,其本质是在不重启系统前提下安全注入可执行代码到内核空间。该机制依托模块生命周期管理、符号解析、内存隔离与权限控制等底层原理,具备高灵活性与低侵入性技术价值。广泛应用于设备驱动开发、嵌入式系统定制、IoT边缘网关及工业控制等对实时性与可维护性要求严苛的场景。本文围绕模块初始化与清理、`insmod`/`modprobe`加载逻辑、`printk`日志规范、模块参数传递及`kmalloc`等内核API边界展开,结合`vermagic`校验与内核污染(tainted

weixin_30481539的博客 136

基于非接触式微波雷达设计的跌倒检测预警系统【短信报警】

本项目选择基于非接触式微波雷达的跌倒检测预警装置作为技术核心,采用云帆瑞达的R60AFD1跌倒检测模组。这一模组能够根据人体的运动变化,如速度、距离和姿态等特征,判断是否发生跌倒,并可以持续监控老年人是否处于危险状态。此外,本项目还结合4G通信技术,通过Air724UG模块实现短信报警功能,一旦检测到跌倒事故,系统将自动通过4G网络向紧急联系人发送短信报警,及时通知亲属或医护人员进行救援。

1753

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

上一篇: X86架构保护模式研究
下一篇: Linux 字符设备驱动程序
IT回忆录
博客等级 码龄16年 42粉丝 100原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值