32位系统有HIGHMEM_ZONE而64位没有HIGHMEM_ZONE的原因

查阅过很多的blog或者相关书,都说64位系统的空间足够所以不需要HIGHMEM ZONE,对于这句话一直是一知半解,今天仔细看了下相关的config,理解如下:

高端内存的由来:

在32位系统中总的地址空间是4GB,按照地址划分3G~4G为内核空间,0~3G为用户空间,此时PAGE_OFFSET为0xC0000000.如果物理内存的size为4GB,则后面3GB内核就无法访问,为了满足此要求,在内核1GB空间分出了一定的空间来进行映射。

Linux将内核地址空间划分为三部分ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM,以手上某平台2GB RAM,32位系统的手机为例,通过开机的kernel log可以看到系统虚拟内存的映射如下:

[    0.000000] <0>    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000] <0>    fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
[    0.000000] <0>    vmalloc : 0xe1000000 - 0xff800000   ( 488 MB)
[    0.000000] <0>    lowmem  : 0xc0000000 - 0xe0800000   ( 520 MB)
[    0.000000] <0>    pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
[    0.000000] <0>    modules : 0xbf000000 - 0xbfe00000   (  14 MB)
[    0.000000] <0>      .text : 0xc0008000 - 0xc1000000   (16352 kB)
[    0.000000] <0>      .init : 0xc1600000 - 0xc1800000   (2048 kB)
[    0.000000] <0>      .data : 0xc1800000 - 0xc19a273c   (1674 kB)
[    0.000000] <0>       .bss : 0xc19a4000 - 0xc2545924   (11911 kB)
可以看到kernel空间的起始地址为0xC0000000也就是PAGE_OFFSET的值,而kernel的text段起始地址为0xC0008000的起始地址,也就是说TEXT_OFFSET为0x8000,而通过kernel的代码发现从0xC0000000~0xe0800000为低端内存区,也就是zone里面的normal zone,在低端内存区,内核地址映射采用的是一一映射的方法,将物理地址加上偏移,一一映射到线性地址空间,具体映射方法为x - PHYS_OFFSET + PAGE_OFFSET,这样kernel可以随时访问normal zone和DMA zone(如果有)。而高端内存区的范围为0xffffffff~0xe0800000。但是这里只是高端内存区而不是HIGHMEM ZONE,ZONE的大小实际为总的memory大小减掉normal zone的大小,其计算将在另外一篇文章中讲述。

高端内存HIGH_MEM地址空间范围为0xe0800000~ 0xffffffff(520MB~1024MB)。此时的剩下的504MB线性地址空间无法完全映射整个HIGHMEM ZONE,那么内核是如何借助504MB高端内存地址空间访问整个HIGHMEM ZONE呢?Linux采用动态映射的方法,从0xe08000000xffffffff地址空间范围内找一段相应大小空闲的逻辑地址空间,借用一会。借用这段逻辑地址空间,建立映射到想访问的那段物理内存(即填充内核PTE页面表),临时用一会,用完后归还。这样别人也可以借用这段地址空间访问其他物理内存,虽然存在效率问题,但是起码实现了使用有限的地址空间,访问所有所有物理内存。以下是手机物理内存实际的映射示意图:


例如内核想访问2G开始的一段大小为1MB的物理内存,即物理地址范围为0x80000000 ~ 0x800FFFFF。访问之前先找到一段1MB大小的空闲地址空间,假设找到的空闲地址空间为0xF8700000 ~ 0xF87FFFFF,用这1MB的逻辑地址空间映射到物理地址空间0x80000000 ~ 0x800FFFFF的内存。映射关系如下:

逻辑地址         物理内存地址
0xF8700000 0x80000000
0xF8700001 0x80000001
0xF8700002 0x80000002

0xF87FFFFF 0x800FFFFF

从上面的描述,我们可以知道高端内存的最基本思想:借一段地址空间,建立临时地址映射,用完后释放,达到这段地址空间可以循环使用,访问所有物理内存。

而在64位系统当中,以ARM64为例:

PAGE_OFFSET=0xffffffc000000000.

PHY_OFFSET=0x40000000.

PAGE_OFFSET为内核地址空间开始的地址,也可以理解为是内核空间和用户空间的分界线,PHY_OFFSET则为物理地址的偏移量。

比如一个4G的memory,则其物理地址范围为0x40000000~0x13fffffff,这个地址会一一映射到0xffffffc000000000 ~0xffffffc100000000的区域。

而内核从0xffffffc000000000开始的所有地址都可以被内核空间访问到,计算一下就是256GB的空间,现阶段基本可以访问到所有的物理地址空间,所以不需要有HIGHMEM ZONE。

猜你喜欢

转载自blog.csdn.net/zsj100213/article/details/79527225
今日推荐