设备地址,物理地址和虚拟地址之间有什么区别?
实际上我在驱动程序中尝试mmap
,我坚持这个概念。
答案 0 :(得分:7)
内核通常使用虚拟地址。返回的任何地址 kmalloc(),vmalloc()和类似的接口是一个虚拟地址,可以 存储在" void *"。
中虚拟内存系统(TLB,页表等)转换虚拟 地址到CPU物理地址,存储为" phys_addr_t"要么 " resource_size_t&#34 ;.内核像寄存器一样管理设备资源 物理地址。这些是/ proc / iomem中的地址。身体上的 地址对驱动程序没有直接用处;它必须使用ioremap()来映射 空间并产生一个虚拟地址。
I / O设备使用第三种地址:"总线地址"或" DMA地址"。 如果器件在MMIO地址处有寄存器,或者它执行DMA读取 或写入系统存储器,设备使用的地址是总线地址。 在某些系统中,总线地址与CPU物理地址相同,但是 一般来说,他们不是。 IOMMU和主桥可以产生任意性 物理地址和总线地址之间的映射。
这是一张图片和一些例子:
CPU CPU Bus Virtual Physical Address Address Address Space Space Space +-------+ +------+ +------+ | | |MMIO | Offset | | | | Virtual |Space | applied | | C +-------+ --------> B +------+ ----------> +------+ A | | mapping | | by host | | +-----+ | | | | bridge | | +--------+ | | | | +------+ | | | | | CPU | | | | RAM | | | | Device | | | | | | | | | | | +-----+ +-------+ +------+ +------+ +--------+ | | Virtual |Buffer| Mapping | | X +-------+ --------> Y +------+ <---------- +------+ Z | | mapping | RAM | by IOMMU | | | | | | | | +-------+ +------+
在枚举过程中,内核会了解I / O设备和 他们的MMIO空间和将它们连接到系统的主桥。对于 例如,如果PCI设备有BAR,则内核读取总线地址(A) 从BAR转换为CPU物理地址(B)。地址B. 存储在struct资源中,通常通过/ proc / iomem公开。当一个 驱动程序声称一个设备,它通常使用ioremap()来映射物理地址 B在虚拟地址(C)。然后它可以使用例如ioread32(C)来访问 器件在总线地址A处注册。
如果设备支持DMA,则驱动程序使用kmalloc()或设置缓冲区 一个类似的接口,它返回一个虚拟地址(X)。虚拟 存储器系统将X映射到系统RAM中的物理地址(Y)。司机 可以使用虚拟地址X来访问缓冲区,但设备本身 不能,因为DMA没有通过CPU虚拟内存系统。
在一些简单的系统中,设备可以直接对物理地址执行DMA 是的。但在许多其他方面,有IOMMU硬件可以转换总线 地址到物理地址,例如,它将Z转换为Y.这是一部分 DMA API的原因:驱动程序可以给出虚拟地址X. 像dma_map_single()这样的接口,用于设置任何所需的IOMMU 映射并返回总线地址Z.然后驱动程序告诉设备 执行DMA到Z,IOMMU将它映射到系统中地址Y的缓冲区 RAM。