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

[Linux] Linux 系统从启动到驱动加载

Linux 系统从启动到驱动加载

文章目录

  • Linux 系统从启动到驱动加载
    • 一、硬件上电与 BIOS/UEFI 阶段
      • 1. 1 硬件上电初始化
      • 1.2 BIOS/UEFI执行过程
      • 1.3 Bootloader加载细节
    • 二、Bootloader 阶段
    • 三、Linux 内核初始化
      • 3.1 架构相关初始化(setup_arch)
      • 3.2 核心子系统初始化
      • 3.3 虚拟文件系统(VFS)初始化
      • 3.4 内核线程创建
    • 四、驱动子系统初始化
      • 4.1 设备模型初始化(driver_init)
      • 4.2 总线子系统注册
      • 4.3 早期驱动初始化(early platform drivers)
      • 4.4 设备描述信息解析
    • 五、驱动加载与设备枚举
      • 5.1 总线驱动扫描硬件设备
      • 5.2 设备与驱动匹配
      • 5.3 驱动probe初始化
      • 5.4 创建设备节点
    • 六、用户空间初始化
      • 6.1 init 进程启动
      • 6.2 udev 设备管理
      • 6.3 驱动模块加载
      • 6.4 系统启动完成
    • 七、关键数据结构与函数
    • 八、典型驱动加载流程示例
    • 九、调试与故障排查
      • 9.1 查看内核启动日志(dmesg)
      • 9.2 检查 sysfs 设备信息(/sys/devices)
      • 9.3 使用 udevadm 监控设备事件
      • 9.4 动态加载/卸载驱动模块(insmod/rmmod)


一、硬件上电与 BIOS/UEFI 阶段

1. 1 硬件上电初始化

当计算机电源接通后:

  • 电源供应器完成自检,向主板发送Power Good信号
  • CPU从复位状态解除,寄存器被初始化为默认值(如x86架构的CS=0xF000,EIP=0xFFF0)
  • 主板时钟发生器开始工作,提供稳定的时钟信号

1.2 BIOS/UEFI执行过程

BIOS/UEFI固件执行的主要任务:

  • POST(Power-On Self Test)

    • 检测关键硬件:CPU、内存、显卡等
    • 声卡发出"滴"声表示检测通过(不同BIOS厂商的提示音编码不同)
    • 对检测到的硬件生成设备列表(如通过ACPI表)
  • 硬件初始化

    • 配置内存控制器和初始化RAM
    • 初始化基本输入输出设备(键盘、显示器)
    • 设置中断向量表(IVT)或高级中断控制器(APIC)
  • 引导设备选择

    • 按照CMOS中存储的启动顺序(如:硬盘→USB→网络)
    • 读取每个设备的引导扇区(MBR或GPT分区表的引导记录)
    • 对于UEFI系统,会查找ESP分区中的/EFI/BOOT/BOOTx64.EFI文件

1.3 Bootloader加载细节

当BIOS/UEFI找到有效启动设备后:

  • 传统BIOS会将MBR中的第一阶段引导程序(512字节)加载到内存0x7C00处
  • UEFI则直接加载EFI应用程序到内存
  • 对于GRUB2:
    • 第一阶段(boot.img)仅负责加载core.img
    • 第二阶段(core.img)包含基本文件系统驱动,用于定位/boot/grub
    • 最终加载grub.cfg配置文件并显示启动菜单

示例启动顺序:

  1. 检测到SATA硬盘
  2. 读取MBR中的引导代码
  3. 加载GRUB的stage1 → stage1.5 → stage2
  4. 显示GRUB菜单等待用户选择

二、Bootloader 阶段

  1. 引导加载器启动

    • 系统 BIOS/UEFI 完成硬件初始化后,将控制权交给存储在 MBR 或 EFI 分区中的引导加载器(如 GRUB2)
    • 常见的引导加载器包括:
      • GRUB (Grand Unified Bootloader)
      • Syslinux
      • LILO (Linux Loader)
      • systemd-boot (适用于 UEFI 系统)
  2. 内核加载过程

    • 引导加载器读取其配置文件(如 GRUB 的 grub.cfg)
    • 加载压缩的内核镜像(通常在 /boot 目录下,命名为 vmlinuz-<版本号>)到内存
    • 同时加载 initramfs(Initial RAM Filesystem)镜像
    • 典型文件示例:
      /boot/vmlinuz-5.4.0-91-generic
      /boot/initrd.img-5.4.0-91-generic
      
  3. 参数传递与内核启动

    • 引导加载器向内核传递启动参数,常见参数包括:
      • root=:指定根文件系统设备(如 root=/dev/sda1)
      • init=:指定初始化程序路径(替代默认的 /sbin/init)
      • quiet:减少启动时内核信息输出
      • splash:显示启动画面
    • 内核解压过程:
      • 首先解压缩 zImage 或 bzImage 格式的内核
      • 然后加载必要的驱动和初始化临时根文件系统
    • 最终控制权转移到内核的入口点 start_kernel() 函数(位于 init/main.c)
  4. initramfs 的作用

    • 提供早期用户空间环境
    • 包含必要的驱动程序(如磁盘控制器、文件系统驱动)
    • 挂载真正的根文件系统
    • 在嵌入式系统中可能直接作为最终根文件系统使用
  5. 特殊场景处理

    • 加密根分区:需要 initramfs 包含解密工具
    • RAID/LVM:需要加载相应的模块
    • 网络启动:需要包含网络驱动程序

三、Linux 内核初始化

3.1 架构相关初始化(setup_arch)

setup_arch() 是架构特定的初始化函数,主要负责:

  • 解析硬件信息(如通过设备树获取CPU类型、内存布局等)
  • 初始化物理内存管理(如建立memblock内存分配器)
  • 设置处理器特殊功能(如开启MMU、缓存等)
  • 架构相关的早期设备初始化(如SMP处理器初始化)

示例:在ARM架构中会初始化处理器异常向量表,x86架构则会检测和初始化ACPI。

3.2 核心子系统初始化

包括以下关键系统的初始化:

  • 页表初始化:建立内核地址空间映射,包括:
    • 内核代码段映射
    • 设备I/O空间映射
    • 早期内存分配区域映射
  • 中断控制器初始化
    • 探测并初始化本地APIC/IOAPIC(x86)
    • GIC初始化(ARM)
    • 设置中断描述符表(IDT)
  • 定时器子系统
    • 初始化高精度定时器(hrtimer)
    • 设置系统时钟源(如HPET、TSC)
    • 校准CPU频率(loops_per_jiffy)

3.3 虚拟文件系统(VFS)初始化

VFS初始化流程:

  1. 注册基础文件系统类型(如proc、sysfs、tmpfs)
  2. 初始化dentry缓存和inode缓存
  3. 挂载rootfs作为初始文件系统
  4. 创建标准文件描述符(stdin/stdout/stderr)
  5. 挂载实际根文件系统(通过root=内核参数指定)

3.4 内核线程创建

初始化的关键内核线程包括:

  • kthreadd(内核线程守护进程,pid=2)
    • 负责创建和管理其他内核线程
    • 通过kthread_create()请求创建新线程
  • 其他早期线程:
    • ksoftirqd(软中断处理线程)
    • kworker(工作队列线程)
    • migration(CPU迁移线程)
    • watchdog(看门狗监控线程)

这些初始化步骤完成后,内核将进入用户空间初始化阶段,启动第一个用户进程(通常是init或systemd)。


四、驱动子系统初始化

4.1 设备模型初始化(driver_init)

该阶段主要完成内核设备模型的核心数据结构初始化,包括:

  • kobject 子系统初始化,建立设备层次结构基础
  • 设备类和属性文件系统的创建(/sys/class/)
  • 内核对象引用计数机制的建立
  • 设备号分配器的初始化(devtmpfs)

4.2 总线子系统注册

分平台总线类型进行初始化:

  • platform_bus_init

    • 注册平台总线类型(platform_bus_type)
    • 初始化 platform_device 和 platform_driver 的匹配机制
    • 创建/sys/bus/platform/目录结构
    • 典型应用场景:SoC内置设备(如GPIO控制器、时钟模块)
  • pci_init

    • PCI总线探测和枚举
    • PCI设备资源分配(IO空间、内存空间)
    • 建立PCI设备树结构
    • PCI设备驱动匹配机制初始化

4.3 早期驱动初始化(early platform drivers)

在基本设备模型建立后立即加载的关键驱动:

  • 内存控制器驱动
  • 串口调试驱动(earlycon)
  • 时钟源驱动
  • 中断控制器驱动
    这些驱动通过early_platform_init机制注册,具有以下特性:
  • 在常规驱动加载前完成初始化
  • 使用简化版的资源获取接口
  • 通常通过命令行参数指定(如earlycon=uart8250,mmio,0xfe001000

4.4 设备描述信息解析

根据系统类型采用不同配置机制:

设备树(DT)系统

  • 解析/boot/dtb文件或U-Boot传递的设备树
  • 展开设备树节点为device_node结构
  • 将设备树节点转换为platform_device
  • 处理设备树中的中断映射、DMA范围等特殊属性

ACPI系统

  • 解析ACPI表(DSDT、SSDT等)
  • 转换ACPI设备为平台设备
  • 处理_PRT(中断路由)、_CRS(资源分配)等方法
  • 支持ACPI电源管理扩展功能

两种系统最终都会生成统一的设备资源描述,包括:

  • 内存映射区域
  • 中断号
  • DMA通道
  • 时钟源
  • 电源管理参数

五、驱动加载与设备枚举

5.1 总线驱动扫描硬件设备

总线驱动负责识别和扫描连接的硬件设备。常见方式包括:

  • PCI设备枚举:通过读取PCI配置空间(Configuration Space)获取设备Vendor ID、Device ID等信息
  • 设备树解析(DT node parsing):在ARM架构中解析设备树(Device Tree)的节点信息
  • ACPI枚举:x86架构通过ACPI表获取设备信息
  • USB总线枚举:通过USB协议发现连接的设备

示例:PCI枚举过程中会遍历所有总线号码(bus number),对每个设备/功能组合读取其配置寄存器。

5.2 设备与驱动匹配

内核通过driver_match_device()函数进行匹配,主要依据:

  • 设备树中的compatible属性
  • ACPI设备ID(HID/UID/CID)
  • PCI设备的Vendor/Device ID
  • 平台设备的名称匹配

匹配优先级通常为:设备树匹配 > ACPI匹配 > ID表格匹配 > 名称匹配。

5.3 驱动probe初始化

匹配成功后调用驱动的probe()函数进行:

  1. 资源分配(内存、IRQ、DMA等)
  2. 硬件初始化(寄存器配置、固件加载)
  3. 设备特定设置(时钟、电源管理)
  4. 子系统注册(如输入设备、网络设备等)

典型错误处理包括:检查资源可用性、逐步回滚失败操作。

5.4 创建设备节点

通过devtmpfs自动创建设备文件:

  • 内核调用device_add()将设备注册到系统
  • 根据设备类型(字符/块设备)创建/dev节点
  • 设置正确的设备号(major/minor)
  • 应用层可通过udev/mdev规则进一步配置节点属性

特殊设备可能还需要:

  • sysfs属性文件(/sys/class/...
  • debugfs接口
  • 用户空间通知机制(uevent)

六、用户空间初始化

6.1 init 进程启动

内核最后阶段会启动第一个用户空间进程 init(PID=1),根据系统配置选用不同的 init 系统:

  • systemd(现代主流发行版):采用并行化的服务启动方式,提供单元(unit)管理
    • 读取 /etc/systemd/system//usr/lib/systemd/system/ 下的单元文件
    • 启动基础目标(target)如 multi-user.targetgraphical.target
  • sysvinit(传统系统):串行执行 /etc/init.d/ 中的启动脚本
    • 通过运行级别(runlevel)控制启动阶段
    • 典型流程:先挂载文件系统,再启动基础服务

6.2 udev 设备管理

udev 守护进程负责动态设备管理:

  • 监听内核通过 netlink 发送的 uevent
  • 处理设备热插拔事件(如 USB 插入)
  • 根据 /etc/udev/rules.d/ 规则文件:
    • 创建设备节点(如 /dev/sda1
    • 设置设备权限和所有者
    • 触发关联的硬件初始化脚本

6.3 驱动模块加载

通过 modprobe 机制加载用户态驱动模块:

  • 读取 /etc/modprobe.d/ 配置文件
  • 自动解决模块依赖关系
  • 典型应用场景:
    • 加载文件系统驱动(如 ext4、ntfs)
    • 加载特殊硬件驱动(如 NVIDIA 显卡)
    • 加载网络协议栈模块

6.4 系统启动完成

完成所有初始化步骤后:

  • 启动登录管理器(如 gdm、lightdm)进入图形界面
  • 或显示文本登录提示符(tty1-6)
  • 记录启动日志到 /var/log/boot.log
  • 系统进入多用户模式,所有服务正常运行

七、关键数据结构与函数

Linux设备驱动模型中的两个核心数据结构及其关系:

/*** struct device_driver - 驱动对象的基本表示* @name: 驱动名称,用于sysfs显示和模块匹配* @bus: 指向驱动所属的总线类型,如platform_bus_type* @probe: 驱动探测回调函数,当设备与驱动匹配时调用* * 示例:当注册i2c_driver时,需要设置这些字段*/
struct device_driver {const char *name;struct bus_type *bus;int (*probe)(struct device *dev);
};/*** struct bus_type - 总线类型的抽象表示* @name: 总线名称,如"platform"、"pci"等* @match: 总线匹配函数,用于判断设备和驱动是否兼容* * 总线负责管理其下的设备和驱动,典型的匹配过程:* 1. 设备注册时,总线遍历所有驱动,调用match函数* 2. 驱动注册时,总线遍历所有设备,调用match函数* 3. 匹配成功则调用驱动的probe函数*/
struct bus_type {char *name;int (*match)(struct device *dev, struct device_driver *drv);
};

工作流程说明:

  1. 系统初始化时会注册各种总线类型(platform/pci/i2c等)
  2. 驱动开发者编写驱动时:
    • 定义device_driver结构体实例
    • 实现probe函数进行设备初始化
    • 向总线注册该驱动
  3. 当匹配发生时,总线层会:
    • 通过match函数验证设备和驱动的兼容性
    • 调用驱动的probe函数初始化设备
    • 建立sysfs中的设备-驱动关联

八、典型驱动加载流程示例

以下是一个完整的 PCI 设备驱动加载流程示例,展示了从驱动注册到设备初始化的关键步骤:

// 1. 定义设备ID表,用于匹配支持的PCI设备
static const struct pci_device_id my_pci_ids[] = {{ PCI_DEVICE(0x10AB, 0x1100), .driver_data = 0 },  // 厂商ID 0x10AB,设备ID 0x1100{ PCI_DEVICE(0x10AB, 0x1200), .driver_data = 0 },  // 另一个兼容设备{ 0, }  // 结束标记
};// 2. 定义驱动操作函数
static int my_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{int retval;// 使能PCI设备retval = pci_enable_device(pdev);if (retval) {dev_err(&pdev->dev, "Failed to enable PCI device\n");return retval;}// 获取设备资源(如内存区域、中断号等)// ...具体设备初始化代码...dev_info(&pdev->dev, "Device successfully initialized\n");return 0;
}static void my_remove(struct pci_dev *pdev)
{// 释放资源,关闭设备// ...清理代码...pci_disable_device(pdev);dev_info(&pdev->dev, "Device removed\n");
}// 3. 定义PCI驱动结构体
static struct pci_driver my_driver = {.name     = "my_device",      // 驱动名称.id_table = my_pci_ids,       // 设备匹配表.probe    = my_probe,         // 设备发现时的回调.remove   = my_remove,        // 设备移除时的回调// 可选:.suspend/.resume 等电源管理回调
};// 4. 注册PCI驱动
module_pci_driver(my_driver);// 5. 模块信息
MODULE_DEVICE_TABLE(pci, my_pci_ids);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Sample PCI Device Driver");

典型工作流程:

  1. 内核加载驱动模块时调用module_pci_driver宏注册驱动
  2. 内核遍历PCI总线,将每个设备与id_table进行匹配
  3. 找到匹配设备后,调用probe函数初始化设备
  4. 设备使用期间可能触发中断/处理请求
  5. 设备移除或模块卸载时调用remove函数清理资源

注意事项:

  • 必须实现基本的probe/remove函数对
  • 需要正确处理设备使能/禁用流程
  • 建议添加适当的错误处理和资源管理
  • 现代驱动通常还需要实现电源管理回调

九、调试与故障排查

9.1 查看内核启动日志(dmesg)

dmesg命令是排查驱动程序问题的首选工具,它显示内核环形缓冲区中的消息。典型使用场景包括:

  • 查看驱动加载时的初始化信息:dmesg | grep <驱动模块名>
  • 跟踪设备插拔事件:dmesg -w(实时监控)
  • 检查错误信息:dmesg --level=err,warn
  • 清空缓冲区:dmesg -c(需要root权限)

9.2 检查 sysfs 设备信息(/sys/devices)

sysfs文件系统提供了设备树的详细信息:

/sys/devices/
├── platform
│   └── <设备名>/
│       ├── driver -> ../../../bus/platform/drivers/<驱动名>
│       ├── modalias
│       └── power/

重要检查项:

  • 设备是否被正确识别:ls /sys/bus/<总线类型>/devices
  • 驱动绑定状态:查看设备目录下的driver符号链接
  • 设备参数:如/sys/class/gpio/gpio<N>/下的各种属性文件

9.3 使用 udevadm 监控设备事件

udev工具链的典型应用:

# 监控所有设备事件
udevadm monitor# 查看特定设备属性
udevadm info -a -p /sys/class/net/eth0# 触发设备重扫描
udevadm trigger

关键调试场景:

  • 检查规则匹配:udevadm test /sys/class/<设备类>/<设备名>
  • 验证热插拔事件处理
  • 调试udev规则执行过程

9.4 动态加载/卸载驱动模块(insmod/rmmod)

驱动模块管理操作流程:

# 加载模块(需.ko文件路径)
sudo insmod module.ko [参数名=参数值]# 查看已加载模块
lsmod | grep <模块名># 卸载模块(需确保无设备在使用)
sudo rmmod module# 更常用的modprobe工具
sudo modprobe module_name
sudo modprobe -r module_name

注意事项:

  • 模块参数可以通过/sys/module/<模块名>/parameters/查看或修改
  • 依赖关系处理:modprobe会自动解决依赖
  • 查看模块信息:modinfo <模块名>
  • 常见错误:模块版本不匹配、符号未导出、资源冲突等

研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)


相关文章:

  • 启动你的RocketMQ之旅(七)-Store存储原理
  • Linux系统配置Docker镜像加速
  • 定时任务:springboot集成xxl-job-core(二)
  • [学习] PID算法原理与实践(代码示例)
  • 彻底理解Spring三级缓存机制
  • 助力高校AI教学与科研:GpuGeek推出618算力支持活动
  • SAP学习笔记 - 开发18 - 前端Fiori开发 应用描述符(manifest.json)的用途
  • 【python基础知识】字典
  • C++多重继承详解与实战解析
  • 编程基础:通信
  • [SAP] 矩阵复制(Matrix Copy)
  • Linux开发追踪(IMX6ULL篇_第一部分)
  • 智语心桥:当AI遇上“星星的孩子”,科技如何点亮沟通之路?
  • 【办公类-22-05】20250601Python模拟点击鼠标上传CSDN12篇
  • 机器学习有监督学习sklearn实战二:六种算法对鸢尾花(Iris)数据集进行分类和特征可视化
  • 核心机制:TCP 断开连接(四次挥手)
  • 人工智能在智能能源管理中的创新应用与未来趋势
  • springboot中@Async做异步操作(Completable异步+ThreadPoolTaskExecutor线程池+@Async注解)
  • Leetcode 269. 火星词典
  • Python----目标检测(《SSD: Single Shot MultiBox Detector》论文和SSD的原理与网络结构)
  • 刷流水兼职日结1000/专业网站seo推广
  • 晨光科技+网站建设/深圳新闻最新事件
  • 网络推广员为什么做不长/重庆seo招聘
  • 九台市做网站的公司/百度之家
  • 北京网站建设icp有限公司/全球网站流量排名查询
  • 建设娱乐网站的要求/化妆品软文推广范文