本章内容分为三个部分:
- 第一部分讲述了mmap系统调用的实现过程。将设备内存直接映射到用户进程的地址空间,尽管不是所有设备都需要,但是能显著的提高设备性能。
- 如何跨越边界直接访问用户空间的内存页,一些相关的驱动程序需要这种能力。在很多情况下,内核执行了该种映射,而无需驱动程序的参与。
- 直接内存访问(DMA)I/O操作,它使得外设具有直接访问系统内存的能力。
一、Linux的内存管理
关注Linux内存管理实现的主要特性,而非讲述操作系统中内存管理的理论。
地址类型
Linux是一个虚拟内存系统,意味着用户程序所使用的地址与硬件使用的物理地址是不同的。
虚拟内存是一个简介层,系统中运行的程序可以分配比物理内存更多的内存。甚至单独进程都拥有比系统物理内存更多的虚拟地址空间。
在任何情况下使用何种类型的地址,内核代码并未明确加以区分,因此程序对此要仔细处理。
- 用户虚拟地址:这是在用户空间程序所能看到的常规地址。用户地址或者32位的,或者是64位的
- 物理地址:该地址在处理器和系统内存之家使用。
- 总线地址:该地址在外围总线和内存之间使用。通常他们与处理器使用的物理地址相同,但这么做并不是必须的。一些计算机提供I/O内存管理(MMU),实现总线和主内存之间的重新映射。
- 但使用DMA时,MMU变成了一个额外的操作。
- 内核逻辑地址:内核逻辑地址组成了内核的常规地址空间。kmalloc返回的就是内核逻辑地址
- 内核虚拟地址:内核虚拟地址和内核逻辑地址,都将内核空间的地址映射到物理地址上。内核虚拟地址与物理地址的映射不是一一对应的。
物理地址和页
高端与低端内存
内存映射和页结构
页表
虚拟内存区
vm_area_struct结构
内存映射处理
二、mmap设备操作
使用remap_pfn_range
一个简单的实现
为VMA添加操作
使用nopage映射内存
重映射特定的I/O区域
重新映射RAM
使用nopage方法重映射RAM
重新映射内核虚拟地址
三、执行直接I/O访问
异步I/O
直接访问内存
DMA数据传输概览
分配DMA缓冲区
DIY分配
总线地址
通用DMA层
处理复杂的硬件
DMA映射
建立一致性DMA映射
DMA池
建立流式DMA映射
单页流式映射
分散/聚集映射
PCI双重地址周期映射
一个简单的PCI DMA例子
ISA设备的DMA
注册DMA
与DMA控制器通信