[linux内存管理] 第015篇 理解Linux内核中的memblock和ioremap机制

0. 前言

Linux驱动开发中,设备寄存器的物理地址如何被内核管理并映射到虚拟地址空间,是一个非常核心的知识点。本文将从memblockioremap的机制入手,梳理相关流程和原理。

1. 什么是memblock?

memblock 是 Linux 内核在启动阶段管理物理内存的核心工具。它的主要作用是记录和管理物理内存的分布情况,并确保特定的物理地址范围不被错误分配。

memblock 的功能

  • 内存管理:
    • 记录系统中所有的物理内存块(memory)。
    • 标记已分配或保留的内存块(reserved)。
  • 设备寄存器保留:
    -通过 memblock_reserve() 标记设备寄存器所在的物理地址范围为 reserved,防止这些地址被动态分配器(如 kmalloc())分配。
  • 分配的时机:
    • 引导阶段:在内核初始化期间使用,启动完成后交由更高级的内存管理器(如 buddy allocator)接管。

详细请查看:[linux内存管理] 第008篇 memblock子系统详解

2. 什么是ioremap?

ioremap 是 Linux 内核用于将物理地址映射到虚拟地址的函数。由于现代内核只能通过虚拟地址访问内存,设备寄存器的物理地址必须先映射到内核虚拟地址空间,驱动才能访问这些寄存器。

ioremap 的功能

  • 物理到虚拟地址映射:
    • 将一个指定的物理地址范围(如设备寄存器地址)映射到内核的虚拟地址空间。
  • 设置缓存属性:
    • 为映射的地址指定合适的缓存属性(如不可缓存、强制写入等),以确保设备操作的正确性。
  • 动态虚拟地址分配:
    • 分配一个新的虚拟地址范围,用于指向指定的物理地址。

3. memblock和ioremap的关系?

memblock 和 ioremap 是内核在不同阶段管理设备寄存器的两种机制:

阶段 作用
内核引导阶段 使用 memblock 将设备寄存器的物理地址标记为 reserved,避免分配冲突。
驱动运行时 使用 ioremap 将这些物理地址映射到内核虚拟地址空间,驱动通过虚拟地址访问寄存器。

核心区别

  1. memblock 的作用:

    • 记录物理地址的分布,标记保留的地址范围。
    • 只管理物理地址,不提供直接的访问能力。
  2. ioremap 的作用:

    • 将物理地址映射为虚拟地址。
    • 驱动程序通过映射后的虚拟地址访问设备寄存器。

4. 设备寄存器映射的完整流程

以下是设备寄存器从物理地址到虚拟地址映射的完整流程:

4.1 设备描述

在设备树中定义设备寄存器的物理地址和大小:

1
2
3
4
ipcc@208000 {
reg = <0x00208000 0x1000>;
compatible = "qcom,ipcc";
};

4.2 内核启动阶段

  • 解析设备树,通过 memblock_reserve() 将物理地址范围标记为 reserved。
  • 确保这些地址不被普通内存分配器使用。

注意:此部分的内容,详细查看:[linux内存管理] 第008篇 memblock子系统详解

4.3 驱动加载

在设备驱动的 probe() 函数中,通过函数(如 platform_get_resource()of_address_to_resource())获取设备的物理地址范围。

4.4 地址映射

使用 ioremap() 或其变体(如 of_iomap()),将物理地址映射到内核虚拟地址空间

1
void __iomem *base = ioremap(phys_addr, size);

4.5 访问寄存器

映射完成后,驱动通过虚拟地址访问设备寄存器

1
2
writel(value, base + offset);
readl(base + offset);

5. 总结

  1. memblock分配的是物理地址,在开机初期解析设备树中的节点,将内存分reservedmemory两种类型来标记,确保不会这些地址的内存被当作普通内存分配使用
  2. ioremap是将物理地址映射到虚拟地址空间,MMU起来后,内核访问尽量都会使用虚拟地址来进行。
  3. memblock确保内存的安全性,ioremap实现实际的地址的访问能力。