Linux系统调用过程详解:应用程序调用驱动过程

Linux下应用程序调用驱动程序过程:

(1)加载一个驱动模块(.ko),产生一个设备文件,有唯一对应的inode结构体

                a、每个设备文件都有一个对应的’inode‘结构体,包含了设备的主次设备号,是设备的唯一标识。

                b、驱动加载至内核,初始化时通常会调用’register_chrdev()‘或’register_blkdev()‘(字符设备和块设备),注册设备号和关联文件操作file_operation。

                c、有了设备号后,用class_create()和 device_create()创建设备文件 ,device_create()该函数需要一个有效设备号

                d、当设备文件创建后,文件系统会为其创建和初始化一个’inode‘结构体,包含文件类型、权限、所有者信息以及重要的设备号

(2)应用层调用open函数打开设备文件(该函数是在应用层中写好的),对于上层open调用到内核时,发生一次软中断,从用户空间进入到内核空间

(3)open会调用到sys_open(内核系统调用函数),sys_open根据文件的地址(文件的路径),找到设备文件对应的struct inode结构体描述的信息,得知要操作的设备类型(字符设备还是块设备),还会分配一个struct file结构体。

  • sys_open:

                内核级的系统调用函数,用于打开文件和设备。系统调用是用户空间和内核空间之间的接口,通过系统调用可从用户态切换至内核态。

  • sys_open函数的基本操作:

                a、解析用户提供的文件名,确定文件位置和权限(通常为文件的路径名,如/dev/设备名)

                b、检查文件访问权限

                c、分配并初始化一个文件描述符(对该文件操作的引用,非负的整数,是该文件表条目在文件表中的索引)

                d、将文件描述符返回给用户空间

  • struct file:
    • 内核中的重要结构体,表示一个已打开的文件(信息)。
    • 包含相关的文件状态信息,如当前偏移量、文件操作指针file_operation(包含对文件读写的操作函数指针)、'inode'结构体指针
    • 由sys_open创建,内核为打开的文件创建一个新的'struct file'实例

(4)根据struct inode结构体内记录的主次设备号,在驱动链表(管理所有设备驱动)里面,找到字符设备驱动。

        这一步也是后续为了给创建的file结构体内的f_ops成员,文件操作指针赋值

  • 驱动链表:
    • Linux内核中用于管理设备驱动的关键数据结构,是一个链表或哈希表结构,其中包含了所有注册的设备驱动。
    • 字符设备的驱动链表中,每个成员(设备)确实是通过 struct cdev 结构体来表示的。
    • 字符设备驱动通过调用 cdev_add() 函数将自己的 cdev 结构体添加到内核的设备表中(这通常是在调用 register_chrdev_region() 或 alloc_chrdev_region() 注册设备号之后进行的。

(5)每个字符设备都有一个struct cdev结构体。描述了字符设备的所有信息,其中最重要的一项是字符设备的操作函数接口

(6)找到struct cdev结构体后,linux内核就会将struct cdev结构体所在内存空间首地址记录在struct inode结构体i_cdev成员中,将struct cdev结构体中记录的函数操作接口地址记录在strct file结构体的f_ops成员中

(7)执行xxx_open驱动函数。

流程架构参考自:最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客

inode结构体组成

变量赋值的来源

这些变量的值大多是由文件系统、内核的设备管理子系统,或驱动自身在注册设备时设置的。

例如:

  • i_mode(文件模式):通常由驱动设置以标识设备文件的类型(字符设备或块设备)
  • i_rdev(实际设备ID):包含主设备号和次设备号(高12位和低20位),由register_chrdev()或register_blkdev()设置

文件系统中对于'inode'

在创建和管理'inode'结构体中起到核心作用,当一个文件系统被挂载时,它会初始化其管理的所有 inode,并负责管理它们的生命周期。文件系统会定义自己的'inode'操作方法('inode_operation'结构体,也是inode结构体的成员变量),包括:

        a、创建 (create):当新文件被创建时,文件系统会分配和初始化一个 inode 结构体。这包括设置文件类型、权限、所有者等。

        b、查找 (lookup):在访问文件时,文件系统需要通过路径查找相应的 inode。

        c、删除 (delete):当文件被删除时,文件系统负责清理 inode 结构体,并可能将其空间释放回 inode 缓存。

文件描述符:
用于访问文件和设备的一个抽象表示。文件描述符本质上是一个非负整数,当一个程序打开一个文件(包括设备文件)时,操作系统返回的文件描述符作为未来所有对该文件的操作的引用。

文件描述符的形式和功能

  • 形式:文件描述符是一个简单的整数值。在一个进程的上下文中,每打开一个文件或设备,内核就会分配最低未被使用的文件描述符。
  • 功能:文件描述符提供了一个通用的方法来引用所有类型的文件,无论它们是普通的磁盘文件、目录、链接还是设备(如键盘、硬盘、网络设备等)。

文件描述符的操作

当一个文件或设备被打开时,内核会创建一个文件表条目。文件描述符就是这个文件表条目在文件表中的索引。

文件表条目包括:文件位置、当前偏移量、访问权限、指向具体文件操作的指针等。

  • 基于文件描述符的标准操作:

                a、打开操作open(pathname, flags, ... ):打开一个已存在的文件或创建一个新文件,并返回一个文件描述符

                b、读操作 (read(fd, buffer, size)):从由 fd 指定的文件或设备中读取数据。

                c、写操作 (write(fd, buffer, size)):向由 fd 指定的文件或设备写入数据。

                d、输入输出控制操作 (ioctl(fd, command, ...)):对特定的设备执行控制和配置操作。

                e、文件控制操作(fcntl(fd, command, ...)):改变已打开的文件性质。

                f、关闭操作 (close(int fd)):关闭文件描述符。

file结构体组成

struct file主要成员解释

  • f_path:包含文件的路径和文件系统信息,struct path 结构体包括一个指向 dentry(目录项)和 vfsmount(文件系统挂载点)的指针。
  • f_inode:指向与文件关联的 inode 结构体的指针,它存储了文件的大部分元数据。
  • f_op:指向文件操作表的指针,这个表包含了各种文件操作相关的函数指针,如 readwriteopenrelease 等。
  • f_lock:自旋锁,用于保护文件相关的敏感操作。
  • f_count:原子类型,表示文件描述符的引用计数,用于文件描述符的复制和释放管理。
  • f_flags:打开文件时使用的标志,如 O_RDONLYO_NONBLOCK 等。
  • f_mode:文件模式,指定文件的访问模式,如只读、只写等。
  • f_pos:当前文件的偏移量,表示下一次读/写的起始位置。
  • f_owner:文件所有者的信息,常用于信号发送。
  • f_mapping:指向文件的地址空间结构,用于文件映射和内存管理。

驱动链表的设备匹配

当一个应用程序尝试通过系统调用(open())访问一个字符设备时,内核在驱动链表中找到相应的设备驱动的步骤:

1、设备号解析

应用程序请求打开一个设备文件(/dev/example)时,内核首先获取该设备文件的'inode'结构体,从中读取主次设备号

  • 主设备号:用于识别该设备的驱动程序
  • 次设备号:用于识别该驱动程序控制的特定设备实例(控制的是哪个设备)

2、驱动链表搜索

内核中维护了一个包含所有已注册字符设备的列表(register_chrdev()),每个注册设备通过一个'struct cdev'实例表示,并链接到全局链表中。内核遍历这个链表,比较每个'struct cdev'的设备号

  • 链表遍历:从链表头部开始,内核遍历每个'cdev'条目
  • 匹配主设备号:内核检测每个'cdev'的主设备号是否与请求的主设备号匹配

3、文件操作结构体关联

一旦找到匹配的'cdev'结构体,内核将使用该结构体中的'file_operations'指针。

  • 设备操作:应用程序通过系统调用请求的操作(如读取或写入数据)将由file_operations结构体中相应的函数处理。

4、f_op指针设置

内核在打开文件时会创建file struct结构体,但此时部分成员未设置,包括f_op指针(file_operation的指针)。一旦找到正确的驱动,f_op指针会被设置为指向该驱动的file_operations结构体。

后续的操作(如再次读写文件)都会通过这些函数处理(file_operation中的函数)。

Linux设备号:

Linux中每个设备都有一个设备号,由主设备号和次设备号组成。主设备号对应一个具体的驱动,次设备号表示使用这个驱动的各个设备。Linux中提供了一个名为dev_t的数据类型表示设备号,定义在include/linux/types.h中。

1、dev_t类型

  • _u32类型别名为_kernel_dev_t;
  • _kernel_dev_t别名为dev_t
  • 所以dev_t 是__u32 类型的(即unsigned int)

  • _u32:32位的无符号整形unsigned int。

该32位数据构成了主设备号和次设备号,高12位为主设备号,低20位为次设备号,所以系统中主设备号范围为0~4095。

2、设备操作函数:

  • MINORBITS:次设备号位数,20位。
  • MINORMASK:次设备号掩码
  • MAJOR(dev):从dev_t中获取主设备号,将dev_t右移20位
  • MINOR(dev):从dev_t中获取次设备号,取dev_t低20位的值
  • MKDEV(ma,mi):将给定的主设备号和次设备号的值组合成dev_t类型的设备号。(主设备号左移20位)

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Qt复习第二天

1、菜单栏工具栏状态栏 #include "mainwindow.h" #include "ui_mainwindow.h" #pragma execution_character_set("utf-8"); MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);//菜…

重生我是嵌入式大能之串口调试UART

什么是串口 串口是一种在数据通讯中广泛使用的通讯接口,通常我们叫做UART (通用异步收发传输器Universal Asynchronous Receiver/Transmitter),其具有数据传输速度稳定、可靠性高、适用范围广等优点。在嵌入式系统中,串口常用于与外部设备进…

【数据结构与算法】常见的排序算法

文章目录 排序的概念冒泡排序(Bubble Sort)插入排序(Insert Sort)选择排序(Select Sort)希尔排序(Shell Sort)写法一写法二 快速排序(Quick Sort)hoare版本&a…

从零开始搭建Ubuntu CTF-pwn环境

下面就将介绍如何从零搭建一个CTF-pwn环境(由于学习仍在进行,故一些环境如远程执行环境还没有搭建的经历,如今后需要搭建,会在最后进行补充) 可以在ubuntu官方网站上下载最新的长期支持版本:(我下载的是22.04版本) h…

AXI4写时序在AXI Block RAM (BRAM) IP核中的应用

在本文中将展示描述了AXI从设备(slave)AXI BRAM Controller IP核与Xilinx AXI Interconnect之间的写时序关系。 1 Single Write 图1是一个关于32位宽度的BRAM(Block RAM)的单次写入操作的例子。这个例子展示了如何向地址0x1000h…

如何查看centos7中Java在哪些路径下

在 CentOS 7 上,你可以通过几种方式查找安装的 Java 版本及其路径。以下是一些常用的方法: 1. 使用 alternatives 命令 CentOS 使用 alternatives 系统来管理同一命令的多个版本。你可以使用以下命令来查看系统上所有 Java 安装的配置: su…

【JVM】了解JVM规范中的虚拟机结构

目录 JVM规范的主要内容 1)字节码指令集(相当于中央处理器CPU) JVM指令分类 2)Class文件的格式 3)数据类型和值 4)运行时数据区 5)栈帧 6)特殊方法 7)类库 JVM规范的主要内容 1&#…

小程序如何确定会员身份并批量设置会员积分或余额

因为一些原因,商家需要从其它系统里面批量导入会员,确定会员身份,然后给他们设置对应的账户余额。下面,就具体介绍如何进行这种操作。 一、客户进入小程序并绑定手机号 进入小程序:客户打开小程序,系统会自…

在51单片机里面学习C语言

在开始前我有一些资料,是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!! 说出来你们可能都…

创新案例|搜索新王Perplexity如何构建生成式AI产品开发的新模式

Perplexity AI:生成式搜索的颠覆者 刚刚成立满两年,Perplexity AI已经变成了我日常频繁使用的工具,甚至取代了我对 Google搜索的依赖 —— 而我并非个案。该公司仅凭不到 50 名员工,已经吸引了数千万用户。他们目前的年收入超过 …

浅析扩散模型与图像生成【应用篇】(二十三)——Imagic

23. Imagic: Text-Based Real Image Editing with Diffusion Models 该文提出一种基于文本的真实图像编辑方法,能够根据纯文本提示,实现复杂的图像编辑任务,如改变一个或多个物体的位姿和组成,并且保持其他特征不变。相比于其他文…

YOLO系列笔记(十)—— 基础:卷积层及其计算公式

卷积层及其计算公式 前言定义与功能计算过程与输出尺寸没有填充的情况有填充的情况 网络结构中的表示分析一:数字的含义分析二:分支的含义 前言 卷积层是在深度学习领域中非常常见、基础且重要的一种神经网络层。许多初学者可能会对卷积层的功能、其计算…

JDK不同版本里中国夏令时时间

什么是夏令时? 夏令时,(Daylight Saving Time:DST),也叫夏时制,又称“日光节约时制”和“夏令时间”,是一种为节约能源而人为规定地方时间的制度,在这一制度实行期间所采…

部署xwiki服务需要配置 hibernate.cfg.xml如何配置?

1. 定位 hibernate.cfg.xml 文件 首先,确保您可以在 Tomcat 的 XWiki 部署目录中找到 hibernate.cfg.xml 文件: cd /opt/tomcat/latest/webapps/xwiki/WEB-INF ls -l hibernate.cfg.xml如果文件存在,您可以继续编辑它。如果不存在&#xff…

KaiwuDB 参编的《分析型数据库技术要求》标准正式发布

近期,中国电子工业标准化技术协会正式发布团体标准《分析型数据库技术要求》(项目号:T-CESA 2023-006)。该标准由中国电子技术标准化研究院、KaiwuDB(上海沄熹科技有限公司) 等国内 16 家企业联合起草&…

Win11安装Docker Desktop运行Oracle 11g 【详细版】

oracle docker版本安装教程 步骤拉取镜像运行镜像进入数据库配置连接数据库,修改密码Navicat连接数据库 步骤 拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g运行镜像 docker run -d -p 1521:1521 --name oracle11g registry.cn-ha…

《QT实用小工具·六十二》基于QT实现贝塞尔曲线画炫酷的波浪动画

1、概述 源码放在文章末尾 该项目实现了通过贝塞尔曲线画波浪动画,可控制 颜色密度速度加速度 安装与运行环境 语言:C 框架:Qt 11.3 平台:Windows 将屏幕水平平均分为10块,在一定范围内随机高度的12个点(…

提取网页元数据的Python库之lassie使用详解

概要 Lassie是一个用于提取网页元数据的Python库,它能够智能地抓取网页的标题、描述、关键图像等内容。Lassie的设计目的是为了简化从各种类型的网页中提取关键信息的过程,适用于需要预览链接内容的应用场景。 安装 安装Lassie非常简单,可以通过Python的包管理器pip进行安…

如何自定义Markdown中插入图片的位置

工作中常常需要在VsCode下写Markdown笔记,在写笔记的过程中不免需要插入图片。  Markdown中插入笔记的操作往往是比较繁琐的,比如:在文档中引用本地某个文件夹下的图片,首先需要你先保存图片到本地路径,然后需要你在文…

多模态模型Mini-Gemini:代码模型数据均开源,MiniCPM小钢炮2.0全家桶四连发,可以在Android 手机端上运行的大模型,效果还不错

多模态模型Mini-Gemini:代码模型数据均开源,MiniCPM小钢炮2.0全家桶四连发,可以在Android 手机端上运行的大模型,效果还不错。 多模态模型Mini-Gemini:代码模型数据均开源 香港中文大学终身教授贾佳亚团队提出多模态模…