地址空间的归纳总结

来源:互联网 发布:安卓6.0 移动数据开关 编辑:程序博客网 时间:2024/03/29 18:28

url: http://alanwu.blog.51cto.com/3652632/1082195

通常X86系统中会存在四大地址空间:进程地址空间、内核地址空间、物理地址空和PCI地址空间。这几大地址空间有些是硬件领域的相关内容,例如PCI地址空间,PCI Hole;有些是软件研发需要了解的。这几大地址空间有什么不同?他们之间是如何联系在一起的呢?

下图是进程地址空间、内核地址空间以及物理地址空间之间的联系,下面对几大地址空间的联系进行阐述。
 
 

 

 
进程地址空间大家比较熟悉,很多人都知道通过虚拟内存机制,在32位平台上每个进程都可以获得4GB大小的地址空间。在32位Linux系统中,高1GB空间是每个进程共享的内核地址空间,0~3GB的空间是每个进程独享的地址空间。进程地址空间通过页表与物理地址空间建立联系,为了减少这种映射带来的开销损失,X86处理器硬件提供了TLB页表Cache。由于访存具有很高的时空局部性,因此TLB Cache的命中率很高,为虚拟内存机制的工程应用奠定了基础。从硬件上讲,进程虚拟地址映射最重要的模块是MMU,只有拥有MMU的处理器才可以支持虚拟地址机制。从软件上来讲,虚拟地址最重要的是页表管理。操作系统需要为虚拟内存建立页表,当TLB Cache Miss的时候,处理器会产生中断,然后进行页表映射,并且加载页表。在进程的用户空间,很多时候也希望直接对PCI的设备内存空间直接进行操作,例如很多应用程序想直接操作显卡内存,获得性能上的优势。为了达到这种目的,需要将处理器域PCI设备内存地址映射至进程地址空间。在Linux中提供了mmap函数实现IO地址与虚拟地址之间的映射。这种映射本质上与物理内存的映射是一样的,同样需要建立页表。
 
OS内核地址空间占据了3~4GB,共1GB大小的地址空间。其中,绝大部分地址(3G~Vmalloc_end)都是通过线性映射的方式进行映射,起始的一段物理内存空间被直接映射至内核空间。因此,内核空间的这种线性映射的地址也称为逻辑地址,这种地址无需页表进行映射,物理地址和逻辑地址之间的转换可以通过简单的偏移运算即可完成。内核空间中也存在虚拟地址,这段地址空间为Vmalloc_end~4GB。内核空间通过Vmalloc函数为这段虚拟地址空间建立页表,与物理内存建立联系。另外,在实际的系统中,除了物理内存之外,PCI设备同样占据处理器物理地址空间,内核空间想要访问PCI设备内存时,需要通过ioremap函数将处理器域PCI设备内存地址映射到内核空间。这种映射与vmalloc的方式一样,同样需要建立页表。我们可以看到,实际上,在32位Linux中,虚拟地址空间不是很大,默认情况下只有几百兆的空间。那么,如果用户想映射一块非常大的PCI设备内存空间至内核,怎么办呢?我想如果用户有这方面的需求,那么只能通过调整vmalloc_end参数将虚拟地址空间扩大。另外,在ARM嵌入式系统中,由于系统的内存资源有限,32位Linux预留的内核空间地址足够,而且物理内存通常会小于1GB,因此,PCI物理地址空间往往会落在1GB以内。在这种情况下,PCI设备内存的映射可以采用内核空间逻辑地址映射的方式,直接通过偏移操作进行物理地址和IO虚拟地址的转换,而无需调用ioremap进行页表操作(ARM嵌入式系统中会定义_REG宏实现虚实地址转换)。
 

 

CPU物理地址空间理解上比较容易,就是处理器访问内存的地址空间。但是,值得注意的是,处理器内存地址空间并非全部用于物理内存的访问(DIMM),其中有一部分用于访问PCI设备地址空间。因此,如果处理器地址总线宽度为32位,拥有4GB地址空间,那么,其中只有一部分地址是用于访问物理内存的。因此,32位的地址总线无法支持4GB大内存。为了解决这个问题,Intel和AMD处理器在推出64位处理器之前采用了PAE技术,即Intel处理器将地址总线扩展到36位;AMD处理器扩展到40位。在软件的处理上,对页表也进行了修改,实现32位虚拟地址与36/40位物理地址的映射。从上图我们可以看出,当系统中安装的物理内存比较少时,例如只安装了1GB内存,那么物理地址空间还会存在空闲地址,4GB的顶端地址空间会分配给PCI设备,并且PCI设备地址空间与物理内存空间没有交叉。前几年这样的系统大量存在。但是,伴随着物理内存的日益廉价,大内存的系统大量出现,例如很多系统都配备大于4GB的内存。这样的系统会存在一个问题:PCI设备地址和物理内存存在地址交叉,处理器无法访问被PCI地址空间覆盖的物理内存。这也就在物理内存空间形成了一个地址空洞,这个空洞通常被称为PCI Hole。为了解决这个问题,芯片组提供了一组寄存器将被PCI设备地址覆盖的那部分物理内存重新映射到其它地址空间,从而实现将这部分遗失的内存回收。这种映射是通过硬件实现的。目前,在64位处理器上依然存在PCI Hole的问题,主要考虑到兼容性的问题。未来如果把PCI设备地址空间直接放到64位地址空间的顶端,PCI Hole这个问题也就不存在了。
 

 

很多人在开发PCI设备的时候很疑惑,什么是PCI地址空间?PCI地址和处理器地址是一回事吗?其实在X86系统中,PCI地址和处理器地址在数值方面是相同的,但是这两个地址仍然属于两个不同的地址域。上面讨论的物理地址所指的就是处理器域的物理地址,是站在处理器的角度来看待访问地址的。PCI地址不是站在处理器角度的地址,而是PCI总线域的地址,是站在PCI桥、PCI设备看到的地址。如上图所示,PCI总线域地址和处理器域地址是通过PCI主桥(Host或者Complex)进行映射转换的。位于处理器的软件如果想访问PCI设备,那么直接采用处理器域的PCI设备地址,当然位于内核的驱动程序需要采用ioremap之后的虚拟地址进行访问。位于设备端的DMA控制器需要进行数据传输时,需要采用PCI总线域的地址。有趣的是,X86处理器对这两个空间的地址进行等值映射,所以看到的值是相同的,但是PowerPC则进行了线性映射,两个值是不相同的。
 
这里对计算机系统中的几个地址进行了说明,希望对大家有所帮助,如有不对的地方请指正,在此谢过。
0 0
原创粉丝点击