arm64 内存相关-线性空间下移-VMEMMAP_SIZE VMEMMAP_START
1、线性空间下移
4.X 内核中
线性映射区域 位于 内核地址空间的高位处。介绍文章举例: https://blog.csdn.net/u012142460/article/details/105867221/
线性映射区域下移
2019年8月的一个commit,将线性映射区域 下移了。
commit 14c127c957c1c6070647c171e72f06e0db275ebf Author: Steve Capper <steve.capper@arm.com> Date: Wed Aug 7 16:55:14 2019 +0100 arm64: mm: Flip kernel VA space In order to allow for a KASAN shadow that changes size at boot time, one must fix the KASAN_SHADOW_END for both 48 & 52-bit VAs and "grow" the start address. Also, it is highly desirable to maintain the same function addresses in the kernel .text between VA sizes. Both of these requirements necessitate us to flip the kernel address space halves s.t. the direct linear map occupies the lower addresses. This patch puts the direct linear map in the lower addresses of the kernel VA range and everything else in the higher ranges.
5.10 内核中的内存布局
来自 Documentation/arm64/memory.rst (以 48 bits VA 为例)
ffff000000000000 ffff7fffffffffff 128TB kernel logical memory map ffff800000000000 ffff9fffffffffff 32TB kasan shadow region ffffa00000000000 ffffa00007ffffff 128MB bpf jit region ffffa00008000000 ffffa0000fffffff 128MB modules ffffa00010000000 fffffdffbffeffff ~93TB vmalloc fffffdffbfff0000 fffffdfffe5f8fff ~998MB [guard region] fffffdfffe5f9000 fffffdfffe9fffff 4124KB fixed mappings fffffdfffea00000 fffffdfffebfffff 2MB [guard region] fffffdfffec00000 fffffdffffbfffff 16MB PCI I/O space fffffdffffc00000 fffffdffffdfffff 2MB [guard region] fffffdffffe00000 ffffffffffdfffff 2TB vmemmap ffffffffffe00000 ffffffffffffffff 2MB [guard region]
来自 https://zhuanlan.zhihu.com/p/207001939?utm_source=wechat_timeline
v5.10/arch/arm64/include/asm/memory.h 相关定义分析
VMEMMAP_SIZE
这一段的大小 需要 多大呢 ? 上面 Documentation/arm64/memory.rst 中展示的是 设定条件后 计算得到的结果。 memory.h 中展示的是 计算的 原理,所以还是需要了解的。
根据注释:这个size 大小,存放 struct page 对象数组,这个数组可以覆盖 整个 线性映射区域。 下面具体分析:
STRUCT_PAGE_MAX_SHIFT 即 struct page 这个结构体 需要的 shift bit 位数。include/linux/mm_types.h 中定义。
#define STRUCT_PAGE_MAX_SHIFT (order_base_2(sizeof(struct page)))
举例:sizeof struct page 为44个字节。 2^5 = 32 < 44 ; 2^6 = 64 > 44; 则 STRUCT_PAGE_MAX_SHIFT 为 6 。 shift 是移位, max 是最大。这么大的空间中,肯定可以存放的下一个 struct page 对象。
23/* 24 * VMEMMAP_SIZE - allows the whole linear region to be covered by 25 * a struct page array 26 * 27 * If we are configured with a 52-bit kernel VA then our VMEMMAP_SIZE 28 * needs to cover the memory region from the beginning of the 52-bit 29 * PAGE_OFFSET all the way to PAGE_END for 48-bit. This allows us to 30 * keep a constant PAGE_OFFSET and "fallback" to using the higher end 31 * of the VMEMMAP where 52-bit support is not available in hardware. 32 */ 33#define VMEMMAP_SIZE ((_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET) \ 34 >> (PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT))
_PAGE_END(VA_BITS_MIN) 这个计算 线性映射 区域 的 结尾地址。
PAGE_OFFSET 这个是 线性映射区域 的起始地址。
_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET 是 线性映射区域 的 size 。
一个struct page 描述一个 page ( PAGE_SHIFT )的信息。 _PAGE_END(VA_BITS_MIN) - PAGE_OFFSET 这么大的 区域,是多少个 page (即需要多少个 struct page 对象来描述)呢 ?
(_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET )/ 2 ^(PAGE_SHIFT) 个。
这么多个,需要占用的空间需要多大呢?
个数 * 每个占用的空间 = [(_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET )/ 2 ^(PAGE_SHIFT) ] * 2 ^(STRUCT_PAGE_MAX_SHIFT )
变形之后,可以得到
= (_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET ) / 【 2 ^(PAGE_SHIFT) / 2 ^(STRUCT_PAGE_MAX_SHIFT ) 】 = (_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET ) / 2 ^(PAGE_SHIFT -STRUCT_PAGE_MAX_SHIFT )
= (_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET ) >> (PAGE_SHIFT -STRUCT_PAGE_MAX_SHIFT )
VMEMMAP_START
53#define VMEMMAP_START (-VMEMMAP_SIZE - SZ_2M) 54#define VMEMMAP_END (VMEMMAP_START + VMEMMAP_SIZE)
53行,计算 VMEMMAP_START ,需要分为 两部分来看,
-VMEMMAP_SIZE ,计算机 数值 二进制表示方式, 看作 有符号 是的值 和 看作无符号 是的值,两值之间的关系,反向利用。 -VMEMMAP_SIZE 相当于 无符号最大值 向下移动 VMEMMAP_SIZE 。
- SZ_2M, 在上面移动后,再向下移动 2M。 这儿移动的 2M ,就是 ffffffffffe00000 ffffffffffffffff 2MB [guard region] 这个区域。
54行, VMEMMAP_END 就是 VMEMMAP_START + VMEMMAP_SIZE .