Author: geneblue
Blog: https://geneblue.github.io/
- 原文地址
- 翻译: GeneBlue
现在我们来讨论 64 位 ARM CPU 的 Linux 内核虚拟地址空间。在 ARM 官网上也可以找到一些关于 ARMv8 的信息。http://www.arm.com/products/processors/armv8-architecture.php
32 位 CPU 的最大问题就是虚拟地址空间只有 4GB 大小。即使一些平台支持 PAE (Physical Address Extension)扩展,该问题仍然存在,因为 PAE 主要关注物理地址的扩展问题,而不是虚拟地址。自从 64 位 CPU 问世后,情况就大为不同。AMD64 和 ARMv8 可以支持 2^64 次方的地址空间,这可是个相当大的数字。
实际上,2^64 次方太大了,Linux 内核只采用了 64 bits 的一部分(开启 CONFIG_ARM64_64K_PAGES 时使用 42 bits,页大小是 4K 时使用 39 bits),该文假设使用的页大小是 4K(VA_BITS = 39)
1 |
ARM64 上也有足够的虚拟地址了,用户空间和内核空间可以有各自的 2^39 = 512GB 的虚拟地址。
所有用户虚拟地址前 25 bits 均为 0,所有的内核虚拟地址前 25 bits 均为 1。用户与内核之间的地址不可使用。
内核空间
可以通过源码来了解 ARM64 的内核虚拟地址空间。
在 arch/arm64/include/asm/memory.h,可以看出一些差异。首先,lowmem 区不存在了,这是因为虚拟地址很大了,可以处理 lowmem 内存,不用再担心虚拟地址问题(但内核地址仍然有一些限制)。其次,不同内核的虚拟地址顺序改变了。
1 |
1 | pr_notice("Virtual kernel memory layout:\n" |
也可以看看 arch/arm64/mm/init.c 和 arch/arm64/include/asm/pgtable.h
pkmap 和 fixmap 不存在了,内核假设所有内存都有有效的内核虚拟地址,所以不再需要创建 pkmap 或者 fixmap。
用户空间
用户空间的虚拟地址布局和 ARM32 类似,因为用户地址空间增大到了 512GB ,所以可以在 64 位 CPU 上运行更大的应用。
ARMv8 是兼容 ARM 32 位应用的,所有的 32 位 ARM 应用都可以无需修改运行在 ARMv8 上。那在 64 位内核上,32 位应用的地址布局是怎样的呢?
实际上,64 位内核运行的进程都是 64 位的。为了运行 32 位 ARM 应用,Linux 内核仍然从 init 进程创建出一个 64 位的进程,当将其用户地址空间限制到 4GB。通过这种方式,64 位的 Linux 内核可以同时运行 32 位和 64 位的应用。
1 |
64 位 ARM 应用在 64 位 Linux 内核上的情况:
32 位 ARM 应用在 64 位 Linux 内核上的情况:
需要注意到,32 位应用仍然拥有 512GB 的内核虚拟地址空间,并且不与内核共享自己的 4GB 空间。但在 ARM32 上,32 位应用只有 3GB 的地址空间。
| ARM32 Linux | ARM64 Linux
--- | --- | --- 32 位用户虚拟地址空间大小 | 3GB | 4GB 64 位用户虚拟地址空间大小 | N/A | 512GB 内核虚拟地址空间大小 | 1GB | 512GB