【学习记录】从0开始的Linux学习之旅——驱动模块编译与加载

一、概述

    Linux操作系统通常是基于Linux内核,并结合GNU项目中的工具和应用程序而成。Linux操作系统支持多用户、多任务和多线程,具有强大的网络功能和良好的兼容性。本文主要讲述如何编译及加载linux驱动模块。

二、概念及原理

    应用程序通过系统调用与内核进行交互,而驱动程序则提供了硬件设备的访问接口,内核本身则提供了系统调用、驱动框架等基础设施。
    驱动开发:Linux 驱动开发是指为 Linux 内核开发各种设备驱动程序,用于控制和管理硬件设备。驱动程序运行在内核空间,直接与硬件进行交互。Linux 内核提供了丰富的接口和框架,开发者可以编写各种类型的设备驱动,包括网络设备、存储设备、输入设备等。驱动程序通过内核提供的接口与用户空间的应用程序进行通信。
    应用开发:Linux 应用开发是指在 Linux 系统上开发各种类型的应用程序,包括命令行工具、图形界面应用、服务器端应用等。Linux 提供了丰富的开发环境和工具链,开发者可以使用各种编程语言和开发工具进行应用开发。应用程序运行在用户空间,通过系统调用与操作系统内核进行交互,执行各种任务和功能。
    内核开发:Linux 内核开发是指对 Linux 内核本身进行开发和维护。Linux 内核是操作系统的核心,负责管理系统资源、调度任务、提供系统调用等功能。内核开发包括对内核功能的添加和修改,修复内核漏洞,优化性能等工作。内核开发人员通常会编写和维护内核的各种子系统和模块,包括调度器、文件系统、网络协议栈等。
    模块加载与卸载:在 Linux 中,模块是指可以动态加载到内核中并扩展其功能的代码段。模块的加载意味着将模块的代码和数据加载到内核空间并使其在内核中运行,从而扩展内核的功能。模块的卸载则是将其从内核中移除,释放其占用的资源。模块的加载与卸载允许内核在运行时动态地添加或移除功能,这为系统提供了灵活性和可扩展性。

三、编译前准备

    在 Ubuntu 系统中进行 Linux 内核驱动模块的编译,需要做一些准备工作:

  1. 安装必要的软件包
    确保你的系统已经安装了必要的软件包,包括编译工具链、内核源码和头文件等。你可以使用以下命令来安装这些软件包:

    sudo apt update
    sudo apt install build-essential linux-headers-$(uname -r)
    
  2. 确认内核源码路径
    确保你知道系统中内核源码的路径,通常位于 /lib/modules/$(uname -r)/build。这个路径在编译驱动模块时可能会用到。

四、代码实现及编译

  • 驱动模块代码

    新建一个名为helloworld.c的文件,添加如下代码。

#include <linux/init.h>
#include <linux/module.h>

/* 定义模块的初始化函数 */
static int Helloworld_Init(void)
{
    printk("I'm Chewie, Helloworld init ok!\n");
    return 0;
}

/* 定义模块的退出函数 */
static void Helloworld_Exit(void)
{
    printk("Bye bye!\n");
}

/* 注册模块的初始化和退出函数,这个是给内核识别的 */
module_init(Helloworld_Init);
module_exit(Helloworld_Exit);

/* 声明该模块符合GPL协议 */
MODULE_LICENSE("GPL");
  • Makefile编写

    新建一个名为Makefile的文件(不需要后缀,必须是Makefile首字母大写,makefile识别不了,一开始不知道踩了个坑),这个 Makefile 文件主要是用于告诉 make 命令如何编译驱动程序模块,并提供了编译和清理的规则。在文件中添加如下内容。

obj-m := helloworld.o

KDIR := /lib/modules/$(shell uname -r)/build

all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	make -C $(KDIR) M=$(PWD) clean

    其中各部分的具体含义如下:

  1. obj-m := helloworld.o:

    • obj-m 是一个特殊的变量,用于指定要编译成模块的目标文件。
    • helloworld.o 是模块的目标文件名,这里是你要编译生成的驱动模块文件名。
  2. KDIR := /lib/modules/$(shell uname -r)/build:

    • KDIR 是一个变量,用于指定内核源码的路径。
    • /lib/modules/$(shell uname -r)/build 是一个动态获取当前系统内核版本并拼接出内核源码路径的命令。
  3. all::

    • all 是一个 Makefile 中的默认目标,表示默认情况下执行的规则。
  4. make -C $(KDIR) M=$(PWD) modules:

    • make -C $(KDIR) 是在内核源码路径下执行 make 命令,M=$(PWD) 表示当前目录是模块源码的路径。
    • modules 是指定了要编译生成模块对象文件的规则。
  5. clean::

    • clean 是一个用于清理的目标,用于清理编译产生的文件。
  6. make -C $(KDIR) M=$(PWD) clean:

    • make -C $(KDIR) 是在内核源码路径下执行 make 命令,M=$(PWD) 表示当前目录是模块源码的路径。
    • clean 是指定了要执行清理操作的规则。

    然后在当前helloworld.c目录下,打开终端,输入以下命令进行编译。

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

五、模块加载及卸载

    编译完模块后,需要把模块加载到内核才可正常使用。这里可以使用insmod指令加载驱动模块。注意需要加上sudo使用root权限。

sudo insmod helloworld.ko

    那如何知道模块是否加载成功呢?这里需要使用lsmod | grep helloworld检查模块加载情况。如果有如下显示则说明加载成功。
在这里插入图片描述

    卸载模块时,则需要使用rmmod进行卸载。同样需要加上sudo使用root权限。

sudo rmmod helloworld

    到这里可能有人要问了,模块初始化和退出函数里不是加了printk打印了一些信息吗,为什么终端里没有显示任何内容?是因为printk打印的信息是在内核空间中,而终端是属于用户空间的,所以不会显示内核的信息。如果想要显示这个打印内容,可以使用dmesg打印内核日志(同样的要加上sudo使用root权限),这样就能看到上面模块加载和卸载的信息及打印的相关信息。
在这里插入图片描述
    如果想要实时查看内核日志,可以通过以下命令实时打印内核日志。这里建议单独开一个终端实时查看。

sudo tail -f /var/log/kern.log

在这里插入图片描述

六、相关链接

【学习记录】从0开始的Linux学习之旅——编译linux内核

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/191548.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STK Components 二次开发-创建地面站

1.地面站只需要知道地面站的经纬高。 // Define the location of the facility using cartographic coordinates.var location new Cartographic(Trig.DegreesToRadians(-75.596766667), Trig.DegreesToRadians(40.0388333333), 0.0); 2.创建地面站 创建方式和卫星一样生成对…

【开源】基于Vue+SpringBoot的食品生产管理系统

项目编号&#xff1a; S 044 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S044&#xff0c;文末获取源码。} 项目编号&#xff1a;S044&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 加工厂管理模块2.2 客户管理模块2.3…

UE5人物残影学习(材质实现)

学习视频 UE4简单的材质球残影人教学&#xff0c;你学会了吗&#xff01;_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1rY411q7Yb/?spm_id_from333.788.top_right_bar_window_history.content.click 结果预览 1.创建残值&#xff0c;混合模式勾选半透明 “混合模…

Qt4利用MVC开发曲线数据编辑器

目录 1 需求 2 开发流程 1 搭建框架 2 构造函数 3 打开工程 4 实现应用程序参数加载 5 QCustomPlot和TableView的联动 6 数据的可视化修改 7 列表点击事件事先键盘控制 8 表格实现复制&#xff0c;粘贴&#xff0c;删除等一系列功能 9 曲线实现自适应范围和统一范围…

MyBatis插入操作返回主键报错问题记录

一开始用直接传参数的方法写的插入操作 StudentMapper.java接口 Integer insertStudent(Param("sname") String name,Param("sage") int age); 然后在网上搜了返回主键的方法 StudentMapper.xml: <insert id"insertStudent" useGenerat…

CAN通信协议

CAN 文章目录 CAN前言一、什么是CAN二、CAN的用途三、CAN协议简解1.can的通信过程1.1空闲状态1.2.起始状态1.3 仲裁机制1.4 位时序 前言 前面学了232、485、IIC、SPI等通信协议&#xff0c;还有一个强大的协议CAN&#xff0c;值得记录一下 一、什么是CAN CAN是Controller Ar…

爬取极简壁纸

js反编译的代码需要解密之类的&#xff0c;直接给我干蒙圈了&#xff0c;借助selenium可以直接获取到调式工具中的源码&#xff0c;可以获取渲染后的链接&#xff0c;然后将链接交给下载函数&#xff08;使用异步提高效率&#xff09;即可。 后续学习完js反编译的话&#xff0…

Unity-链接MySql8.0

链接MySql8.0 1.准备dll 一、找到l18N相关的dll 这里给出一个参考地址 D:\Unity\2020.3.48f1c1\Editor\Data\MonoBleedingEdge\lib\mono\unityjit在里面找到如下图的四个dll 二、下载数据库链接dll https://downloads.mysql.com/archives/c-net/在这里搜索历史版本(Archiv…

AIGC ChatGPT4总结Linux Shell命令集合

在Linux中,Shell命令的数量非常庞大,因为Linux提供了各种各样的命令来处理系统任务。这些命令包括GNU核心工具集、系统命令、shell内置命令以及通过安装获得的第三方应用程序命令。以下是一些常见的Linux命令分类及其示例,但请注意,这不是一个全面的列表,因为列出所有命令…

linux复习笔记05(小滴课堂)

hell脚本与crontab定时器的运用 查看状态&#xff1a; 关闭服务&#xff1a; 开启服务&#xff1a; 重启服务&#xff1a; crontab定时器的使用&#xff1a; 我们可以看到没有任何任务。 编辑&#xff1a; 我们可以看到这个任务了。 删除所有任务&#xff1a; 这代表着每分钟…

【NeRF】3、MobileR2L | 移动端实时的神经光场(CVPR2023)

论文&#xff1a;Real-Time Neural Light Field on Mobile Devices 代码&#xff1a;https://github.com/snap-research/MobileR2L 出处&#xff1a;CVPR2023 贡献&#xff1a; 设计了一套移动端实时的 R2L 网络结构 MobileR2L&#xff0c;在 iphone13 上渲染一张 1008x756…

PgSQL技术内幕-Analyze做的那些事-pg_stat_all_tables

PgSQL技术内幕-Analyze做的那些事-pg_stat_all_tables pg_stat_all_tables视图中记录有analyze信息&#xff0c;比如何时做的analyze、表元组个数&#xff08;活元组、死元组&#xff09;等。重启后发现该视图中表的统计信息重置不见了&#xff0c;发生了什么&#xff1f; 1、p…

Centos 7.9 Install Docker Insecure Registry

文章目录 1. 镜像存储规划2. 安装定制 docker3. 部署 registry4. 验证镜像仓库 1. 镜像存储规划 linux LVM /dev/sdb mount dir /data【linux LVM 磁盘挂载目录】 创建两个目录 一个 docker 数据存储目录 &#xff1a;/data/docker&#xff0c;默认一般为linux为 /var/lib/d…

AIGC ChatGPT 4 快速整理不规则数据

从业务系统中采集到的数据如下: 序号 省份 英文 2022年销售额 2021年销售额 增量 1 广东guangDOng129068.58 124319.67 4748.91 2 江苏 JiangSu 122825.6 116314.2 6511.4 3 山东ShAnDong 87385 83045.9 4339.1 4 浙江…

C语言:求Sn=a+aa+aaa+aaaa+……(n个a)之值,其中a表示一个数字,n表示a的位数,n由键盘录入。

分析&#xff1a; 在主函数 main 中&#xff0c;程序首先定义四个整型变量 a、n、i 和 sn&#xff0c;并初始化 a、n 和 i 的值&#xff0c;其中 sn 用于记录数列的和。然后使用 scanf 函数从标准输入中读取用户输入的两个整数 a 和 n。 接下来&#xff0c;程序通过 while …

1.5 C语言之字符输入输出

1.5 C语言之字符输入输出 一、概述二、字符计数三、行计数四、单词计数五、练习 一、概述 字符文本流&#xff0c;是由多行字符构成的字符序列&#xff0c;而每行字符都由0个或多个字符组成&#xff0c;行末是一个换行符。 标准库提供的输入输出模型&#xff0c;用于读取文本内…

树状数组 / pbds解法 E2. Array Optimization by Deque

Problem - 1579E2 - Codeforces Array Optimization by Deque - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 树状数组解法 将 a i a_i ai​插入到队头&#xff0c;贡献为&#xff1a;原队列中所有比 a i a_i ai​小的数的数量将 a i a_i ai​插入到队尾&#xff0c;贡献为&a…

JPA 自关联 设置单向多对一

Spring boot 3 JPA中&#xff0c;遇到一个需求&#xff0c;建一个数据字典表&#xff1a; Dictionary&#xff0c;存放两级数据&#xff0c;第一级为字典项目&#xff0c;第二级为项目内容&#xff0c;查询时要把parent_id对应父项的名称也一起查出来&#xff0c;返回前端。 …

python类和对象

1.使用对象组织数据 class Student:nameNone #记录名字 stu1Student() #创建对象 stu1.name"abc" #为对象属性赋值2.类的定义和使用 2.1成员方法的定义语法 传参的时候self是透明的&#xff0c;不用管 class Stu:nameNonedef sayHi(self):print(f"你好&#x…

Kotlin应用——使用kt进行web开发 使用h2database进行初始化数据库 mybatis-plus使用

Kotlin 是一门现代但已成熟的编程语言&#xff0c;旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作&#xff0c;并提供了多种方式在多个平台间复用代码&#xff0c;以实现高效编程。 kt入门的合集文章如下&#xff1a; Kotlin学习——kt入门合集博客 &…