Linux - MMIO 的映射和访问

发布网友

我来回答

1个回答

热心网友

MMIO,即Memory-Mapped I/O,是现代系统中最常用的I/O访问方式。其核心原理是将设备的寄存器或内存地址映射到CPU虚拟地址空间,这样CPU就可以像访问内存一样访问I/O设备。在启用MMU的系统中,CPU不能直接访问物理地址,而是通过映射机制实现。MMIO在CPU和I/O设备资源间建立了2x2的对应关系,其中MMIO属于这一关系的某一个象限。

从Linux角度出发,当CPU运行在内核态时,会通过ioremap系列函数完成内核态MMIO映射。首先,需要提供被映射的物理地址作为第一个参数,第二参数则是映射范围,函数最终返回一个虚拟地址。对于PCI设备,可以通过pci_resource_start()获取物理地址,而pci_ioremap_xx_bar()函数则提供了一个更简洁的使用方式,它在ioremap_xx()的基础上增加了针对PCI设备资源的校验。

实现过程主要涉及vmalloc和get_vm_area_node函数,它们负责分配vm_struct并建立页表。在x86-架构上,虚拟地址空间被划分为多个层次,包括TB、4TB和32TB等,而MMIO映射空间通常位于vmalloc_base之下。根据不同的内存类型,如ARM的UC、WC、WT以及GRE,以及针对ARM特有的"np"(non-posted write),在32位系统中可能需要额外的高内存映射机制来解决内存空间不足的问题。

建立映射后,访问MMIO地址时,需要使用read和write系列函数,分别用于读取和写入不同大小的数据块,包括1字节、2字节、4字节和8字节等。使用这些函数而不是直接使用指针访问,是因为它们帮助解决了底层复杂性问题,如大小端问题,同时生成更为正确的硬件操作代码,确保了更好的移植性和可靠性。

在ARM架构中,readl和writel函数的实现展示了其与x86架构的细微差异。ARM中使用了iormb和iowmb指令,这些指令被设计为outer sharable (osh)类型的memory barrier,用于确保内存访问顺序的正确性。这与x86中的内存屏障指令有所不同,进一步体现了不同架构在内存一致性控制上的差异。

对于用户态映射,MMIO可以映射到进程的地址空间中,通常通过VMA(Virtual Memory Allocation)形式实现。用户态MMIO映射通过io_remap_pfn_range或remap_pfn_range函数完成,这些函数同样依赖于建立页表的过程。针对MMIO属性的设置,用户态映射与内核态映射在设置方式上略有不同,例如在处理写合并特性时,用户需要明确指定。

对于PCI设备,通常会有专门的函数如pci_mmap_resource_range()提供映射服务,以适应设备驱动的特定需求。mmap函数与MMIO映射有密切关系,它允许用户程序通过映射文件(包括设备文件)来访问设备。在Linux中,mmap操作的实现有时会调用remap_pfn_range函数,特别是在针对设备驱动的映射场景。

总之,MMIO映射和访问是现代操作系统和设备驱动设计中的核心概念。通过合理映射和访问机制,系统能够高效地管理I/O资源,同时确保内存访问的一致性和程序的可移植性。

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com