一个Linux驱动工程师必知的内核模块知识

简介: 一个Linux驱动工程师必知的内核模块知识

最简单的驱动

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
static int __init my_init(void)
{
 printk("my_init\n");
    return 0;
}
static void __exit my_exit(void)
{
 printk("my_exit\n");
}
module_init(my_init);
module_exit(my_exit);

加载卸载模块命令

模块加载

insmod:加载指定目录下的一个.ko文件到内核。例如:

# insmod drv.ko

modprob:自动加载模块到内核,相对于insmod来讲更智能。在执行该命令前最好运行一次depmod命令来更新模块的依赖信息,使用modprobe不指定路径和后缀,例如:

# depmod
# modprobe drv

模块卸载

rmmod:卸载模块。例如:

# rmmod drv

模块信息

modinfo:查看模块的信息。例如:

# modinfo drv
filename: /lib/modules/3.13.0-32-generic/drv.ko
srcversion: 533BB7E5866E52F63B9ACCB
depends:
vermagic: 3.13.0-32-generic SMP mod_unload modversions 686

多个源文件编译生成一个内核模块

例如,将hello.c和world.c两个c文件编译生成一个叫hello_world.o的目标文件,则在Makefile中添加以下两句:

obj-m := hello_world.o
hello_world-objs = hello.c world.c

内核污染

insmod ko模块时,可能出现如下提示:

loading out-of-tree module taints kernel

几个可能原因:

  • 模块没有声明GPL协议
  • 当前linux内核版本和编译模块使用的内核版本不一致
  • 使用内核源代码未包含的树外模块

printk和printf

在内核中的打印函数是printkprintkprintf的行为非常相似,但是通常printk不支持浮点数,例如要打印一个浮点变量,在编译时通常会出现如下警告,并且模块也不会加载成功:

WARNING:"__extendsfdf2" [/home/ubuntu/driver/user.ko] undefined!
WARNING:"__truncdfsf2" [/home/ubuntu/driver/user.ko] undefined!
WARNING:"__divdf32" [/home/ubuntu/driver/user.ko] undefined!
WARNING:"__floatsidf" [/home/ubuntu/driver/user.ko] undefined!

内核模块参数

在加载一个.ko模块时,也可以像应用程序那样,通过命令行传入一些参数,这个过程发生在调用模块初始化函数之前。

内核支持的参数类型有:boolinvbool(反转值bool类型)、charp(字符串指针)、shortintlongushortuintulong。这些类型又可以复合成对应的数组类型。

具体用法,在驱动中定义三个变量baudrateportname

static int baudrate = 9600;
static int port[4] = {0,1,2,3};
static char *name = "user";
module_param(baudrate, int, S_IRUGO);
module_param_array(port, int, NULL, S_IRUGO);
module_param(name, charp, S_IRUGO);

使用module_parammodule_param_array宏声明这些变量为模块参数。说明:

module_param(name,type,perm)
module_param_array(name,type,nump,perm)

name:变量的名字

type:变量或数组元素的类型

nump:数组元素个数的指针,可选

perm:在sysfs文件系统中对应文件的权限属性。

权限的取值参考<linux/stat.h>头文件。

修改这三个变量的值,即加载模块时传参:

insmod user.ko baudrate=115200 port=1,2,3,4 name="virtual-serial"

C库

内核模块处于C函数库之下,自然就不能调用C库函数(内核源码会实现类似的函数).

而应用程序则可以随意调用C库函数。

end

猜你喜欢

不敲一行代码,实现Linux下的LED驱动!

Linux内核中常用的数据结构和算法

Linux内核中常用的C语言技巧

Linux内核基础篇——常用调试技巧汇总

Linux内核基础篇——动态输出调试

Linux内核基础篇——printk调试

Linux内核基础篇——initcall

相关文章
|
2天前
|
Ubuntu Linux Windows
如何在WSL中的ubuntu编译Linux内核并且安装使用ebpf?
请注意,在WSL1中可能会由于内核架构限制而无法成功进行以上过程,WSL2对于Linux内核的完整支持更为合适。此外,部分步骤可能因不同的Linux发行版或内核版本而异。
9 4
|
1天前
|
Linux 开发者
Linux的诞生:Linus Torvalds的“惊天一敲”与Linux内核的“首秀”
在科技界璀璨星辰中,Linus Torvalds以一次“惊天一敲”悄然点燃了革命之火——Linux就此诞生。1991年,不满现状的Linus决定创造更好的操作系统,这一敲不仅开启了个人传奇,更奏响了技术革新的序章。他将Linux内核低调发布网络,随即吸引了全球开发者的目光与贡献,使之迅速成长为开源世界的巨星。Linus的故事告诉我们:伟大创举常源于微小想法,也许下一个改变世界的“一敲”就出自你手。
14 1
|
16天前
|
Ubuntu Linux 开发工具
深入探索Linux内核模块编程
【8月更文挑战第4天】在这篇文章中,我们不仅将探讨Linux内核模块的基础知识,还将通过一个实际的例子来展示如何编写一个简单的内核模块。我们将从理论出发,逐步过渡到动手实践,最终实现一个可以在Linux系统上运行的模块。文章的目标是为读者提供足够的信息和知识,以便他们能够自己编写内核模块,从而对操作系统的内部工作原理有更深入的了解。
|
14天前
|
存储 Unix Linux
揭秘Linux硬件组成:从内核魔法到设备树桥梁,打造你的超级系统,让你的Linux之旅畅通无阻,震撼体验来袭!
【8月更文挑战第5天】Linux作为顶级开源操作系统,凭借其强大的功能和灵活的架构,在众多领域大放异彩。本文首先概述了Linux的四大核心组件:内核、Shell、文件系统及应用程序,并深入探讨了内核的功能模块,如存储、CPU及进程管理等。接着介绍了设备树(Device Tree),它是连接硬件与内核的桥梁,通过DTS/DTB文件描述硬件信息,实现了跨平台兼容。此外,还简要介绍了Linux如何通过本地总线高效管理硬件资源,并阐述了文件系统与磁盘管理机制。通过这些内容,读者可以全面了解Linux的硬件组成及其核心技术。
30 3
|
15天前
|
缓存 网络协议 Unix
Linux 内核参数
Linux 内核参数
17 1
|
3天前
|
Ubuntu Linux Shell
这7个重要的Linux命令,每一位Linux工程师都必须盘它!
这7个重要的Linux命令,每一位Linux工程师都必须盘它!
|
4天前
|
网络协议 算法 Unix
Linux源码学习笔记01-Linux内核源码结构
Linux源码学习笔记01-Linux内核源码结构
|
12天前
|
运维 网络协议 Linux
[linux]常见内核TCP参数描述与配置
[linux]常见内核TCP参数描述与配置
|
5天前
|
NoSQL 关系型数据库 MySQL
Linux学习记录---(1、基本命令)
该博客文章提供了Linux系统中基本命令的使用记录,包括文件和目录操作、Redis服务管理、MySQL数据库操作以及Tomcat服务器的启动和检查。
Linux学习记录---(1、基本命令)

热门文章

最新文章