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

Linux 驱动开发与内核通信机制——超详细教程

Linux 驱动开发与内核通信机制——超详细教程

在 Linux 驱动开发中,经常会遇到两个让初学者头疼的概念:内核空间与用户空间驱动与应用的交互。如果你刚开始学习驱动编程,可能会被各种 copy_from_userioremapmknod 弄晕。本教程将带你从零开始,一步步拆解这些知识点,结合实际例子,让你能自己写出一个简单的字符设备驱动。


内核空间与用户空间

为什么要区分?

Linux 把虚拟内存划分为两部分:

  • 用户空间(User Space)

    • 程序员写的应用程序运行的地方。
    • 可以通过系统调用(openreadwrite 等)间接操作内核。
    • 如果应用崩溃,只会影响自己,不会影响整个系统。
  • 内核空间(Kernel Space)

    • 存放 Linux 内核代码和驱动程序。
    • 能直接操作硬件、管理内存、调度进程。
    • 如果内核代码出错,可能导致系统崩溃(kernel panic)。

这种隔离的最大好处就是保护系统稳定性。比如你写了一个有 bug 的应用,最多应用自己崩溃,不会让整个系统挂掉。


内核与用户空间的通信方式

驱动开发的关键任务之一,就是让用户空间的应用程序能够与内核交互。常见的通信方式有以下几种:

1. copy_from_usercopy_to_user

这是一对最常见的 API:

  • copy_from_user():从用户空间拷贝数据到内核空间。
  • copy_to_user():从内核空间拷贝数据到用户空间。

它们常用在驱动的 read()write() 函数中。

代码示例:

static ssize_t my_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos) {char kernel_buf[100];if (count > sizeof(kernel_buf))return -EINVAL;if (copy_from_user(kernel_buf, buf, count)) {return -EFAULT;}printk("内核收到数据: %s\n", kernel_buf);return count;
}

2. /proc 文件系统

  • 驱动程序可以在 /proc 下注册一个文件。
  • 用户只需 cat /proc/mydev 就能读取信息。

**优点:**实现简单,适合调试。
**缺点:**功能较弱,不适合复杂的数据交换。


3. sysfs 文件系统

  • /sys 目录下的文件是内核导出的信息。
  • 用户可以通过读写 /sys 文件和驱动交互。

**适用场景:**导出驱动参数、硬件属性(如设备 ID、工作模式)。


4. mmap 内存映射

有时用户程序需要频繁访问驱动的大块数据,比如图像缓冲区。为了效率,可以用 mmap 将内核内存直接映射到用户空间。

关键点:

  • 用户调用 mmap()
  • 驱动在 file_operations 里实现 mmap() 回调。
  • 内核和用户共享同一块物理内存,省去了数据拷贝。

5. 信号(Signal)

  • 内核可以主动给进程发送信号(如 SIGKILL)。
  • 常用于通知用户程序发生了某个事件。

6. 自定义协议 / 套接字

  • 适合复杂通信,比如网络驱动。
  • 驱动与应用通过 socket 通信。

字符设备驱动基础

Linux 驱动分为三类:字符设备、块设备、网络设备。初学者最常接触的就是字符设备。

字符设备的特点

  • 数据流是按字节处理的。
  • 典型设备:键盘、串口。

字符设备的核心结构:file_operations

驱动中最重要的结构就是 struct file_operations,它定义了驱动能提供的功能。

struct file_operations {ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);int (*open)   (struct inode *, struct file *);int (*release)(struct inode *, struct file *);
};

解释:

  • open:用户调用 open("/dev/mydev") 时触发。
  • read:用户调用 read() 时触发。
  • write:用户调用 write() 时触发。
  • release:用户 close() 设备时触发。

注册字符设备

驱动必须告诉内核:“我有一个设备了”。有两种注册方式:

方法一:现代方式(推荐)
struct cdev my_cdev;
cdev_init(&my_cdev, &fops);
cdev_add(&my_cdev, dev, 1);
方法二:早期方式
register_chrdev(major, "mydev", &fops);

主设备号与次设备号

Linux 中每个设备都有一个设备号,由 主设备号次设备号组成:

  • 主设备号(major):标识驱动。
  • 次设备号(minor):区分同一个驱动下的不同设备。

创建设备节点:

mknod /dev/mydev c 250 0
  • c → 字符设备;
  • 250 → 主设备号;
  • 0 → 次设备号。

内存映射与硬件寄存器访问

驱动经常需要访问外设的寄存器,而寄存器地址是物理地址,必须映射到虚拟地址后才能访问。

API:ioremap

void __iomem *ioremap(unsigned long phys_addr, unsigned long size);

示例:

void __iomem *reg_base;
reg_base = ioremap(0x12340000, 0x100); // 映射外设寄存器
writel(0x1, reg_base + 0x04);         // 写寄存器

常见调试方法

  1. printk

    • 类似于 printf,输出到 dmesg
    • 常用于调试驱动。
  2. strace

    • 跟踪用户程序调用的系统调用。
  3. sysfs/proc

    • /sys/proc 下导出信息。
  4. gdb + qemu

    • 在虚拟机里调试内核,适合进阶学习。

进程与线程相关知识

进程的五种状态

  1. 新建(new)
  2. 就绪(ready)
  3. 运行(running)
  4. 阻塞(blocked)
  5. 终止(terminated)

内核线程 vs 用户线程

  • 用户线程:内核不可见,切换快,但一个线程阻塞会影响整个进程。
  • 内核线程:由内核调度,阻塞不会影响其他线程,但切换开销大。

僵尸进程与守护进程

僵尸进程

  • 子进程退出,但父进程未调用 wait()
  • 占用 PID,过多会导致系统无法创建新进程。

解决:

  • 在父进程中调用 wait()
  • 或者杀死父进程。

守护进程

  • 运行在后台,脱离终端,常用于服务(如 sshd)。

总结

本教程从内核与用户空间的区别讲起,详细介绍了 Linux 驱动开发的几个关键点:

  • 内核与用户空间通信的多种方式;
  • 字符设备驱动的基本框架与 file_operations
  • 主设备号、次设备号的作用;
  • 内存映射与寄存器访问;
  • 常见调试手段;
  • 进程、线程、僵尸进程等基础操作系统知识。

学完本文,你已经能理解一个简单的字符驱动是如何工作的了。

http://www.dtcms.com/a/426777.html

相关文章:

  • 【langgraph】本地部署方法及实例分析
  • Linux入门指南:从零掌握基础指令
  • 做笔记的网站源码江永网站建设
  • 是时候重启了:AIGC将如何重构UI设计师的学习路径与知识体系?
  • uniapp 请求接口封装和使用
  • AIGC重构数据可视化:你是进化中的“驯兽师”还是被替代的“画图工”?
  • Apache Doris 内部数据裁剪与过滤机制的实现原理
  • 专业做网站流程小程序开发步骤大全
  • C语言基础之指针2
  • 淘客网站怎么做 知乎wordpress淘宝联盟插件
  • flink工作流程
  • openHarmony之storage_daemon:分区挂载与设备节点管理机制讲解
  • 建站怎么赚钱个人官方网站怎么建设
  • 学习笔记093——Windows系统如何定时备份远程服务器的mysql文件到本地?
  • 操作系统内核架构深度解析:从单内核、微内核到鸿蒙分布式设计
  • MySQL 架构全景解析
  • .NET MVC中实现后台商品列表功能
  • oracle logwr,ckpt,dbwn 如何协同工作的
  • C# 网络通讯核心知识点笔记
  • Ubuntu之apt安装ClickHouse数据库
  • 在线音乐网站开发现状网站全屏弹出窗口
  • 泛型在Java集合框架中的应用有哪些?
  • 服务器中使用Docker部署前端项目
  • mysql之二进制日志
  • 【完整源码+数据集+部署教程】染色体图像分割系统: yolov8-seg-KernelWarehouse
  • Docker MySQL 使用全流程
  • Visual Studio主题、字体、快捷键、开发环境设置,自用
  • 火山 19 混音伴音 接口
  • Bean精细化控制属性序列化反序列化
  • 前端权限模型——RBAC