当前位置: 首页 > news >正文

驱动:驱动相关概念,内核模块编程,内核消息打印printk函数的使用

一、驱动相关概念

1.操作系统的功能

                向下管理硬件,向上提供接口

                操作系统向上提供的接口类型:

                内存管理:内存申请(malloc) 内存释放(free)等

                文件管理: 通过文件系统格式对文件ext2、ext3、 ext4格式进行管理

                进程管理: 进程的创建/调度/消亡

                网络管理: 通过网络栈协议,完成数据的收发

                 设备管理: 字符设备、块设备、网卡设备

 2.驱动的概念

                  2.1.定义

                       驱动是能够让硬件实现某个特定功能的软件代码,根据驱动代码是否使用了系统内核提供的接口,将驱动分为裸机驱动和系统驱动

                  2.2.裸机驱动和系统驱动

                         裸机驱动:不基于操作系统提供的接口完成驱动的编写,这种驱动比较简单,由开发者独立即可编写完成,但是实现的功能比较单一

                        系统驱动(操作系统设备驱动):编写驱动时调用系统内核提供的接口,驱动程序会被加载到内核空间。系统驱动开发者无法独立完成,需要操作系统内核的辅助,但是基于系统驱动完成的硬件控制工作会更加完善和复杂。

3.系统驱动(操作系统设备驱动)在操作系统中的层次

        设备驱动会被加载到系统内核空间,设备驱动主要完成对硬件功能的实现,相当于拓展了系统内核设备管理的功能

4.设备驱动的类型

       设备驱动的类型时根据设备类型的不同进行划分的,一般将设备分为字符设备、块设备、和网卡设备 三类:

                字符设备:以字节流的形式进行顺序访问的设备叫做字符设备。 90%的设备为字符设备,鼠标、键盘、摄像头...

                块设备:以块为单位进行随机访问的设备叫做块设备。块设备一般是一些磁盘设备

                网卡设备:用于进行网络数据传输的设备。网卡设备没有网卡设备文件,想要读取网卡设备的数据,需要基于socket套接字实现

二、内核模块编程

1.内核模块编程的意义

           驱动属于内核的一部分,驱动资源要加载到内核中,所以要按照内核模块的编程去编写框架

 2.内核模块的三要素

           入口:主要进行资源的申请工作,安装内核模块时执行

           出口:主要进行资源的释放工作,卸载内核模块时执行

           许可证:声明当前内核模块遵循GPL协议

 3.内核模块编写实例及代码解释

#inckude <linux/init.h>
#include <linux/module.h>//入口函数:安装内核模块时执行
static int __init mycdev_init(void)
{//static: 修饰当前函数只可在本文件使用//int:函数返回值类型,如果函数规定了返回值但是没有加返回值,编译会报错//mycdev_init:函数名,可以自己命名//void:表示函数无参数,void不可以省略//__init:告诉编译器当前函数保存在.init.text段  #define __init    sectoin(".init.text")//linux内核中有自己的链接脚本文件 vmlinux.lds,这个链接脚本文件规定了不同的内容存放在内存中的哪个位置return 0;
}//出口函数:卸载内核模块时执行
static void __exit mycdev_exit(void)
{//__exit:告诉编译器当前函数保存在.exit.text段  #define __exit    section(".exit.text")
}//声明入口函数
module_init(mycdev_init);
//声明出口函数
module_exit(mycdev_exit);
//声明当前内核模块遵循GPL协议
MODULE_LICENSE("GPL");

4.内核模块的编译

        编译内核镜像:make uImage

        编译设备树:make dtbs

        模块化编译:make modules

        内核模块编译有两种方式:内部编译和外部编译

        4.1内部编译

                内部编译又称为静态编译,需要依赖于内核的源码树:

                        ① 编写内核模块

                        ② 将内核模块文件移动到内核指定路径下

                        ③ 在内核指定路径下的Makefile文件中添加编译文件

                        ④ 修改Kconfig文件,添加当前内核模块文件的菜单选项(选配项)

                        ⑤  在源码顶层目录下make menuconfig将当前文件的选配项选配为M,保存退出,此时.config被修改

                        ⑥ make modules  进行模块化编译

         4.2.外部编译

                外部编译又称为动态编译,可以在内核路径外单独编译当前模块文件,外部编译需要我们自己手写Makefile

        通用版本的Makefile

modname ?= demo  #内核模块名称,询问赋值,若无对应的外部变量,则为demo,有则为外部变量
arch ?= arm  #架构,询问赋值,若无对应的外部变量,则为arm,有则为外部变量
ifed ($(arch),arm)    #通过命令行是否有对应的外部变量来判断采用什么架构进行编译#KERNRLDIR保存开发板内核源码路径KERNRLDIR := /home/ubuntu/linux.5.10.61/
else#KERNRLDIR保存ubuntu内核源码路径KERNRIDIR :=/lib/kernel/$(shell uname -r)/bulid   #uname -r命令是查找当前操作系统使用的内核版本
endif#PWD保存当前内核模块的路径
PWD := $(shell pwd)all:#make modules是模块化编译的命令#-C $(KERNELDIR) 表示执行make前到$(KERNELDIR)所保存路径下,读取该目录下的Makefile文件执行make编译#M=$(PWD) 指定模块化编译的路径,进行模块化编译的路径是PWD保存的路径make -C $(KERNELDIR) M=$(PWD) modules
clean:#编译删除make -C $(KERNELDIR) m=$(PWD) clean#将obj-m保存的文件单独链接生成内核模块
obj-m := $(modname).o    #此处写.o不写.c,虽然当前目录下没有.o文件,但是Makefile有自动推导功            能,会自动寻找对应.c

5.内核模板操作相关命令

        安装内核模块命令 insmod *.ko

        卸载内核模块命令 rmmod *.ko (后缀名.ko可省略)

        查看内核已经安装的内核模块 lsmod

        查看某个内核模块的信息 modinfo *.ko

三、内核消息打印函数printk函数的使用

1.printk函数的使用格式

        printk("格式控制符",输出列表)

                这种格式消息按照默认输出级别进行输出

        或

        printk(消息级别 "格式控制符",输出列表)

2.printk函数消息队列打印级别

        prink函数打印的内容属于内核消息。内核消息根据消息的轻重缓急给他们设置不同的消息级别。终端也会存在一个默认的消息级别,只有消息级别高于终端默认消息级别,消息才可以在终端进行输出,消息级别共分为0-7总共8级,数字越小代表消息级别越高,一般常用3-7级 

#define KERN_EMERG         KERN_SOH "0"         /* system is unusable */

#define KERN_ALERT         KERN_SOH "1"         /* action must be taken immediately */

#define KERN_CRIT         KERN_SOH "2"         /* critical conditions */

#define KERN_ERR         KERN_SOH "3"         /* error conditions */

#define KERN_WARNING         KERN_SOH "4"         /* warning conditions */

#define KERN_NOTICE         KERN_SOH "5"         /* normal but significant condition */

#define KERN_INFO         KERN_SOH "6"         /* informational */

#define KERN_DEBUG         KERN_SOH "7"         /* debug-level messages */

 3.查看消息默认级别

        消息默认级别保存在/proc/sys/kernel/printk文件

        查看cat /proc/sys/kernel/printk

        4        4        1        7

        4        终端默认消息级别

        4        printk默认的消息级别

        1        终端支持的消息最高级别

        7        终端支持的消息最低级别

代码示例

#include <linux/init.h>
#include <linux/module.h>// 入口函数,安装内核模块时执行
static int __init mycdev_init(void)
{// static 修饰当前函数只能在本文件使用// int 函数的返回值类型,如果函数规定返回值但是没有加返回值,编译会报错// mycdev_init函数名,可以自己起名字// void表示函数无参数,当没有参数时void一定要加,不然报错//__init的作用是用来告诉编译器当前代码保存在.init.text段中// #define __init       __section(".init.text")// linux内核也会有自己的链接脚本  vmlinux.lds,这个链接脚本里规定了不同的内容在// 内存中的什么位置printk(KERN_ERR "hello world\n");int a=10;printk(KERN_ERR "%d\n",a);return 0;
}
// 出口函数,卸载内核模块时执行
static void __exit mycdev_exit(void)
{// #define __exit       __section(".exit.text")//__exit指定出口函数保存在.exit.text段中
}
// 用于声明入口函数
module_init(mycdev_init);
// 用于声明出口函数
module_exit(mycdev_exit);
// 声明当前内核模块遵循GPL协议
MODULE_LICENSE("GPL");

 5.如何修改消息默认级别

        ubuntu:

                先切换到管理员:sudo su

                再输入以下内容:echo 4 3 1 7 >  /proc/sys/kernel/printk

                注:这种修改方式ubuntn重启后,级别恢复默认设置的4 4 1 7

        开发板上linux

                进入根文件系统下的etc下的init.d文件夹:cd ~/nfs/rootfs/etc/init.d

                打开rcS脚本文件:vi   rcS

                在rcS中最后一行添加:echo 4 3 1 7 > /proc/sys/kernel/printk

6.ubuntu虚拟终端的使用

        切换到虚拟终端:ctrl+alt+[f2-f6](fn)

        退出虚拟终端:ctrl+alt+f1(fn)

7.dmesg命令的使用

        dmesg:查看内核打印消息

        dmesg -c:先将保存的内核消息打印在终端再清除

        dmesg -C:直接清除

相关文章:

驱动:驱动相关概念,内核模块编程,内核消息打印printk函数的使用

一、驱动相关概念 1.操作系统的功能 向下管理硬件&#xff0c;向上提供接口 操作系统向上提供的接口类型&#xff1a; 内存管理&#xff1a;内存申请&#xff08;malloc&#xff09; 内存释放&#xff08;free&#xff09;等 文件管理&#xff1a; 通过文件系统格式对文件ext2…...

【Qt控件之QListWidget】介绍及使用,利用QListWidget、QToolButton、和布局控件实现抽屉式组合控件

概述 QListWidget类提供了基于项目的列表小部件。 QListWidget是一个方便的类&#xff0c;类似于QListView提供的列表视图&#xff0c;但使用经典的基于项目的接口来添加和删除项目。QListWidget使用内部模型来管理列表中的每个QListWidgetItem。 对于更灵活的列表视图小部件…...

【Java基础面试二十四】、String类有哪些方法?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;String类有哪些方法&…...

[DRAFT] LLVM ThinLTO原理分析

我们在《论文阅读&#xff1a;ThinLTO: Scalable and Incremental LTO》中介绍了ThinLTO论文的主要思想&#xff0c;这里我们介绍下LLVM ThinLTO是如何实现的。本文主要分为如下几个部分&#xff1a; LLVM ThinLTO Object 含有哪些内容&#xff1f;LLVM ThinLTO 是如何做优化的…...

使用Gitlab构建简单流水线CI/CD

什么是Gitlab Gitlab实质上是一套DevOps工具 目前看起来&#xff0c;Gitlab属于是内嵌了一套CI/CD的框架&#xff0c;并且可以提供软件开发中的版本管理、项目管理等等其他功能。 这里需要辨别一下Gitlab和Github Gitee的区别。 GIthub大家都很熟悉了&#xff0c;一般大家都会…...

【AIGC核心技术剖析】用于高效 3D 内容创建生成(从单视图图像生成高质量的纹理网格)

3D 内容创建的最新进展主要利用通过分数蒸馏抽样 &#xff08;SDS&#xff09; 生成的基于优化的 3D 生成。尽管已经显示出有希望的结果&#xff0c;但这些方法通常存在每个样本优化缓慢的问题&#xff0c;限制了它们的实际应用。在本文中&#xff0c;我们提出了DreamGaussian&…...

nginx平滑升级添加echo模块、localtion配置、rewrite配置

nginx平滑升级添加echo模块、location配置、rewrite配置 文章目录 nginx平滑升级添加echo模块、location配置、rewrite配置1.环境说明&#xff1a;2.nginx平滑升级原理&#xff1a;3.平滑升级nginx&#xff0c;并添加echo模块3.1.查看当前nginx版本以及老版本编译参数信息3.2.下…...

系统架构师备考倒计时19天(每日知识点)

软件架构评估&#xff08;ATAM&#xff09; 在SAAM的基础上发展起来的&#xff0c;主要针对性能、实用性、安全性和可修改性&#xff0c;在系统开发之前&#xff0c;对这些质量属性进行评价和折中。ATAM方法的主要活动领域包括&#xff1a; 第一阶段 场景和需求收集 收集场景…...

谈谈 Redis 如何来实现分布式锁

谈谈 Redis 如何来实现分布式锁 基于 setnx 可以实现&#xff0c;但是不是可重入的。 基于 Hash 数据类型 Lua脚本 可以实现可重入的分布式锁。 获取锁的 Lua 脚本&#xff1a; 释放锁的 Lua 脚本&#xff1a; 但是还是存在分布式问题&#xff0c;比如说&#xff0c;一个客…...

.NET 6.0 Web API Hangfire

Hangfire 文档 Hangfire 中文文档 Hangfire GitHub使用示例源码 在线Cron表达式生成器 ● Hangfire允许您以非常简单但可靠的方式在请求管道之外启动方法调用。 这种 后台线程 中执行方法的行为称为 后台任务。 ● 它是由:客户端、作业存储、服务端 组成的。 ● Hangfire可以在…...

基于java的校园论坛系统,ssm+jsp,Mysql数据库,前台用户+后台管理,完美运行,有一万多字论文

目录 演示视频 基本介绍 论文目录 功能架构 系统截图 演示视频 基本介绍 基于java的校园论坛系统&#xff0c;Mysql数据库&#xff0c;系统整体采用ssmjsp设计&#xff0c;前台用户后台管理&#xff0c;完美运行&#xff0c;有一万多字论文。 用户功能&#xff1a; 1.系统…...

Django小白开发指南

文章目录 HTTP协议socket实现一个web服务器WSGI实现一个web服务器WSGI实现支持多URL的web服务器WSGI实现图片显示的web服务器MVC && MTV1.MVC2.MTV3.总结 一、创建Django项目1.创建项目2.创建app3.第一次django 请求 二、模板1.配置settings.py2.模板语法3.继承模板 三…...

保序回归与金融时序数据

保序回归在回归问题中的作用是通过拟合一个单调递增或递减的函数&#xff0c;来保持数据点的相对顺序特性。 一、保序回归的作用 主要用于以下情况&#xff1a; 1. 有序数据&#xff1a;当输入数据具有特定的顺序关系时&#xff0c;保序回归可以帮助保持这种顺序关系。例如&…...

基于单片机设计的家用自来水水质监测装置

一、前言 本文介绍基于单片机设计的家用自来水水质监测装置。利用STM32F103ZET6作为主控芯片&#xff0c;结合水质传感器和ADC模块&#xff0c;实现对自来水水质的检测和监测功能。通过0.96寸OLED显示屏&#xff0c;将采集到的水质数据以直观的方式展示给用户。 随着人们对健…...

ubuntu20.04运用startup application开机自启动python程序

运用startup application开机自启动python程序。在终端中输入gnome-session-properties,如果显示没有则先进行安装&#xff0c;sudo apt-get update 和sudo apt install StartupApplications(根据显示提示安装)。在显示程序中搜索startup&#xff0c;打开应用程序。 在程序目录…...

SpringBoot整合Caffeine实现缓存

Caffeine Caffeine是一种基于Java的高性能缓存库&#xff0c;它提供了可配置、快速、灵活的缓存实现。Caffeine具有以下特点&#xff1a; 高性能&#xff1a;Caffeine使用了一些优化技术&#xff0c;如基于链表的并发哈希表和无锁算法&#xff0c;以提供卓越的读写性能。容量…...

DVWA-弱会话IDS

弱会话IDS Session简介&#xff1a; 用户登录后&#xff0c;在服务器就会创建一个会话(session)&#xff0c;叫做会话控制&#xff0c;接着访问页面的时候就不用登录&#xff0c;只需要携带Session去访问即可。 sessionID作为特定用户访问站点所需要的唯一内容。如果能够计算…...

【C++中cin、cin.get()、cin.getline()、getline() 的区别】

文章目录 引入cin基本用法输入多个变量换行符存放在缓冲区中 cin.get()基本用法重载函数换行符残留在缓冲区中 cin.getline()基本使用重载函数换行符不会残留在缓冲区中 string 流中的 getline()总结用法总结几个输入实例输入格式输入格式输入格式输入格式 输出格式 写在最后 引…...

SSH连接华为交换机慢

ssh连接交换机慢是因为交换计算密钥算法阶段默认使用安全性更高的秘钥&#xff0c;由于性能问题导致连接比较慢&#xff0c;如一台华为S5735S-L24T4S-QA2的交换机默认使用如下秘钥&#xff0c;安全行由高到低。 ssh server key-exchange dh_group16_sha512 dh_group15_sha512 …...

Web攻防03_MySQL注入_数据请求

文章目录 PHP-MYSQL-数据请求类型1、数字型(无符号干扰)2、字符型&#xff08;有符号干扰&#xff09;3、搜索型&#xff08;有多符号干扰&#xff09;4、框架型&#xff08;有各种符号干扰&#xff09; PHP-MYSQL-数据请求方法数据请求方法GET&#xff1a;POST&#xff1a;Coo…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...