linux内存地址空间[一]

linux内存地址空间[一]

Posted by Albert on August 15, 2020

Linux内存地址空间[一]

原文作者兰新宇, 原文地址, 本文仅在原文的基础上进行了部分格式调整,对部分自己感觉文字较多的地方配上图片,以便于自己后续能够更好的理解。

Linux的进程地址空间[一]

​ 所谓进程地址空间(process address space),就是从进程的视角看到的地址空间,是进程运行时所用到的虚拟地址的集合。

一、32位系统的进程地址空间

​ 以IA-32处理器为例,其虚拟地址为32位,因此其虚拟地址空间的范围为 [公式] ,Linux系统将地址空间按3:1比例划分,其中用户空间(user space)占3 GB,内核空间(kernel space)占1 GB。

​ 假设物理内存也是4 GB(事实上,虚拟地址空间的范围不一定需要和物理地址空间的大小相同),则虚拟地址空间和物理地址空间的转换如下图所示:

img

​ 因为内核的虚拟地址空间只有1 GB,但它需要访问整个4 GB的物理空间,因此从物理地址0~896 MB的部分(ZONE_DMA+ZONE_NORMAL),直接加上3 GB的偏移(在Linux中用PAGE_OFFSET表示),就得到了对应的虚拟地址,这种映射方式被称为线性/直接映射(Direct Map)。

​ 而896 M~4 GB的物理地址部分(ZONE_HIGHMEM)需要映射到(3 G+896 M)~4 GB这128 MB的虚拟地址空间,显然也按线性映射是不行的。

​ 采用的是做法是,ZONE_HIGHMEM中的某段物理内存和这128 M中的某段虚拟空间建立映射,完成所需操作后,需要断开与这部分虚拟空间的映射关系,以便ZONE_HIGHMEM中其他的物理内存可以继续往这个区域映射,即动态映射的方式。

​ 用户空间的进程只能访问整个虚拟地址空间的0~3 GB部分,不能直接访问3 G~4 GB的内核空间部分,但出于对性能方面的考虑,Linux中内核使用的地址也是映射到进程地址空间的(被所有进程共享),因此进程的虚拟地址空间可视为整个4 GB(虽然实际只有3 GB)。

img

二、64位系统的进程地址空间

​ 在64位系统中,进程地址空间的大小就不固定了,以ARMv8-A为例,它的page大小可以是4 KB, 16 KB或者64 KB(默认为4 KB,选一种来用,不要混用),可采用3级页表或4级页表,因此可以有多种组合的形式。

​ 以采用4 KB的页,4级页表,虚拟地址为48位的系统为例(从ARMv8.2架构开始,支持虚拟地址和物理地址的大小最多为52位),其虚拟地址空间的范围为 [公式] ,按照1:1的比例划分,内核空间和用户空间各占128 TB。

img

​ 256 TB已经很大很大了,但是面对64位系统所具备的16 EB的地址范围,根本就用不完。为了以后扩展的需要(比如虚拟地址扩大到56位),用户虚拟空间和内核虚拟空间不再是挨着的,但同32位系统一样,还是一个占据底部,一个占据顶部,所以这时user space和kernel space之间偌大的区域就空出来了。

​ 但这段空闲区域也不是一点用都没有,它可以辅助进行地址有效性的检测。如果某个虚拟地址落在这段空闲区域,那就是既不在user space,也不在kernel space,肯定是非法访问了。使用48位虚拟地址,则kernel space的高16位都为1,如果一个试图访问kernel space的虚拟地址的高16位不全为1,则可以判断这个访问也是非法的。同理,user space的高16位都为0。这种高位空闲地址被称为canonical。

img

​ 在64位系统中,内核空间的映射变的简单了,因为这时内核的虚拟地址空间已经足够大了,即便它要访问所有的物理内存,直接映射就是,不再需要ZONE_HIGHMEM那种动态映射机制了。

img

​ 64位系统中用户空间的映射和32位系统没有太大的差别。

img

​ ARM公司宣称64位的ARMv8是兼容32位的ARM应用的,所有的32位应用都可以不经修改就在ARMv8上运行。那32位应用的虚拟地址在64位内核上是怎么分布的呢?事实上,64位内核上的所有进程都是一个64位进程。要运行32位的应用程序, Linux内核仍然从64位init进程创建一个进程, 但将用户地址空间限制为4 GB。通过这种方式, 我们可以让64位Linux内核同时支持32位和64位应用程序。

img

​ 要注意的是, 32位应用程序仍然对应128 TB的内核虚拟地址空间, 并且不与内核共享自己的4 GB虚拟地址空间, 此时用户应用程序具有完整的4 GB虚拟地址。而32位内核上的32位应用程序只有3 GB真正意义上的虚拟地址空间。

img

​ 那进程地址空间到底是由哪些元素构成的呢?请看下文分解。

三、参考

http://jake.dothome.co.kr/pt64/,里面对ARM64的各种page size和页表级数的组合做了详尽介绍。

https://www.kernel.org/doc/Documentation/arm64/memory.txt

http://thinkiii.blogspot.com/2014/02/arm64-linux-kernel-virtual-address-space.html, 这是本文后半部分的图片来源和主要参考。