linux内存分布杂论--(32位虚拟内存分布,高端内存; 64位虚拟内存分布,寻址方式)

linux的寻址空间按照CPU的地址总线不同,分为两种:32位寻址空间和64位寻址空间。

(一) 32位linux寻址空间大致分布如下:(虚拟地址)
在这里插入图片描述
用户空间:0x0000_0000 ~ 0xBFFF_FFFF (0-3G)
内核空间:0xC000_0000 ~ 0xFFFF_FFFF(4G)

用户空间 大致分布如下:(虚拟地址由高到低)
在这里插入图片描述
linux中使用虚拟内存,虚拟内存和物理内存的转换通过MMU硬件来实现。
上图中都是按照虚拟地址来描述。

物理内存到虚拟内存的映射使用段映射机制(具体映射方法另一篇文章讲述)

如果物理内存小于等于4G,使用段映射,可实现32位CPU的寻址访问。但是如果物理内存大于4G,比如8G,我们想访问所有的内存空间,那么我们应该怎么办?(32位CPU最大可以访问4G的内存)

高端内存
高端内存用来解决上面的问题。
高端内存的基本思路为:借一段内核虚拟地址空间,建立临时的地址映射,用完后再释放。从而实心这段虚拟地址空间可以循环使用,访问所有的物理内存。

注意:
	是否使用 高端内存 不是取决于物理内存的大小,而是取决于虚拟映射。
	比如:
		物理内存共2G,其中一个1G通过段映射,映射到了0~4G.则剩余1G的物理内存,无法被访问,因为4个G的虚拟地址已经映射分配完毕。

linux将内核地址空间划分为三部分:ZONE_DMA、ZONE_NORMAL 和 ZONE_HIGHMEM。
ZONE_DMA、ZONE_NORMAL 对应内核虚拟地址空间为:0xC000_0000 ~ 0xF7FF_FFFF(896MB)
ZONE_HIGHMEM 对应的内核虚拟地址空间为:0xF800_0000 ~ 0xFFFF_FFFF (128MB,高端内存映射范围)
如图:
在这里插入图片描述

注意:
	高端内存的概念仅存在于内核空间,用户空间没有高端内存的概念。
	用户空间最多只能访问3G的物理内存。而内核可以通过高端内存访问所有的物理内存。

内核如何借助128MB的高端内存地址空间来实现访问所有的物理内存?
还是假如我们共有2G的物理内存,其中1G用于0~4G虚拟地址的映射。如果我们还想访问剩余1G的物理内存空间。比如:内核想访问1G开始的一段大小为1MB的物理内存,即物理内存地址范围为:0x4000_0000 ~ 0x400F_FFFF。访问之前先找到一段1MB大小的空闲内核虚拟地址空间,假设这段内核虚拟地址空间为:0xF870_0000 ~ 0xF87F_FFFF。将这个内核虚拟地址空间映射到0x4000_0000 ~ 0x400F_FFFF物理内存空间上。
当我们访问完0x4000_0000 ~ 0x400F_FFFF物理内存空间,则释放0xF870_0000 ~ 0xF87F_FFFF到0x4000_0000 ~ 0x400F_FFFF的映射关系。这样其他内核进程和代码也可以继续使用0xF870_0000 ~ 0xF87F_FFFF这段虚拟地址访问其他的物理内存。

linux将内核地址空间划分为三部分:ZONE_DMA、ZONE_NORMAL 和 ZONE_HIGHMEM。
而且还将高端内存部分再次划分为三部分:VMALLOC_START ~ VMALLOC_END、KMAP_BASE ~ FIXADDR_START 和 FIXADDR_START ~ 0xFFFF_FFFF。
如图:
在这里插入图片描述
高端内存在内核空间的具体分布如下:

在这里插入图片描述
下面摘抄两位大神解说:
(https://www.cnblogs.com/wuchanming/p/4360277.html)
对应高端内存的3部分,高端内存映射有三种方式:
映射到”内核动态映射空间”(noncontiguous memory allocation)
这种方式很简单,因为通过 vmalloc() ,在”内核动态映射空间”申请内存的时候,就可能从高端内存获得页面(参看 vmalloc 的实现),因此说高端内存有可能映射到”内核动态映射空间”中。
持久内核映射(permanent kernel mapping)
如果是通过 alloc_page() 获得了高端内存对应的 page,如何给它找个线性空间?
内核专门为此留出一块线性空间,从 PKMAP_BASE 到 FIXADDR_START ,用于映射高端内存。在 2.6内核上,这个地址范围是 4G-8M 到 4G-4M 之间。这个空间起叫”内核永久映射空间”或者”永久内核映射空间”。这个空间和其它空间使用同样的页目录表,对于内核来说,就是 swapper_pg_dir,对普通进程来说,通过 CR3 寄存器指向。通常情况下,这个空间是 4M 大小,因此仅仅需要一个页表即可,内核通过来 pkmap_page_table 寻找这个页表。通过 kmap(),可以把一个 page 映射到这个空间来。由于这个空间是 4M 大小,最多能同时映射 1024 个 page。因此,对于不使用的的 page,及应该时从这个空间释放掉(也就是解除映射关系),通过 kunmap() ,可以把一个 page 对应的线性地址从这个空间释放出来。
临时映射(temporary kernel mapping)
内核在 FIXADDR_START 到 FIXADDR_TOP 之间保留了一些线性空间用于特殊需求。这个空间称为”固定映射空间”在这个空间中,有一部分用于高端内存的临时映射。
这块空间具有如下特点:
(1)每个 CPU 占用一块空间
(2)在每个 CPU 占用的那块空间中,又分为多个小空间,每个小空间大小是 1 个 page,每个小空间用于一个目的,这些目的定义在 kmap_types.h 中的 km_type 中。
当要进行一次临时映射的时候,需要指定映射的目的,根据映射目的,可以找到对应的小空间,然后把这个空间的地址作为映射地址。这意味着一次临时映射会导致以前的映射被覆盖。通过 kmap_atomic() 可实现临时映射。

(https://blog.csdn.net/ibless/article/details/81545359)
在这里插入图片描述
(二)64位linux寻址空间大致分布如下:(虚拟地址)
64位CPU的寻址分三种(如图):
在这里插入图片描述
目前ARM64架构的处理器采用的是48位的物理寻址方式。用户空间和内核空间最大支持256TB的地址空间。
用户空间(48位):0x0000_0000_0000_0000 ~ 0x0000_FFFF_FFFF_FFFF (256TB)
非规范区域:0x0000_FFFF_FFFF_FFFF ~ 0xFFFF_0000_0000_0000 (未使用)
内核空间(48位):0xFFFF_0000_0000_0000 ~ 0xFFFF_FFFF_FFFF_FFFF (256TB)

64位的linux内核中没有高端内存这个概念(或者说暂时没有这个概念),因为48位的寻址空间已经足够大,更不用说56位和64寻址。

对于48位寻址的linux内核,又将256TB的内核空间做了详细划分:(虚拟地址由低到高)
1. Vmalloc区域:0xFFFF_0000_0000_0000 ~ 0xFFFF_7BFF_BFFF_0000 (126974GB).
2. Vmemmap区域:0xFFFF_7BFF_C000_0000 ~ 0xFFFF_7FFF_C000_0000 (4096GB).
3. PCI I/O区域:0xFFFF_7FFF_FAE0_0000 ~ 0xFFFF_7FFF_FBE0_0000 (16MB)
4. Modules区域:0xFFFF_7FFF_FC00_0000 ~ 0xFFFF_8000_0000_0000 (64MB)
5. Normal memory线性映射区:0xFFFF_8000_0000_0000 ~ 0xFFFF_FFFF_FFFF_FFFF (128TB)

如图:(64位cpu,48位寻址)
在这里插入图片描述
64cpu的寻址详细请查看:https://blog.csdn.net/ztguang/article/details/51014599

鸣谢:
https://www.cnblogs.com/wuchanming/p/4360277.html
http://www.360doc.com/content/17/0519/04/7775902_655156042.shtml
https://blog.csdn.net/qq_18144747/article/details/88089870
https://blog.csdn.net/pan337520/article/details/79927949

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值