LVC21-221: Large Virtual Address support (52-bit) in ARM64 kernel

Session Abstract

With ARMv8.2 architecture extensions becoming available in new / upcoming ARM64 CPUs, two new hardware extensions, namely - LVA (Large Virtual Addressing) and LPA (Large Physical Addressing) are also being supported in open-source software now. Starting from Linux kernel version 5.4, the 52-bit (Large) Virtual Address (VA) and Physical Address (PA) support was introduced for the ARM64 kernel.

Session Speakers

Bhupesh Sharma

Linaro (I work with Linaro as a part of Landing Team.)

I work with Red Hat and am I a part of the RH kernel team. I have been hacking on bootloaders and kernel used on arm architecture since past 13 years. I contribute to Linux, EFI/u-boot bootloader code base and also to user-space utilities like kexec-tools and crash-utility. Bringing up a Silicon (i.e. running the first SW on it) after hardware tapeout is my passion and I have interest in pre-silicon emulator and simulator design methodologies as well.

With ARMv8.2 architecture extensions becoming available in new / upcoming ARM64 CPUs, two new hardware extensions, namely - LVA (Large Virtual Addressing) and LPA (Large Physical Addressing) are also being supported in open-source software now.

Starting from Linux kernel version 5.4, the 52-bit (Large) Virtual Address (VA) and Physical Address (PA) support was introduced for the ARM64 kernel. Although the kernel documentation describes these features (see [1] for more details) and how they impact the new kernels running on older CPUs (which don’t support 52-bit VA extension in hardware) and the newer CPUs (which support 52-bit VA extension in hardware), it is still at-times complex for a normal user to understand the same and understand how one can “opt-in” for receiving VAs from a 52-bit space.

In this talk, I explain how: A. the kernel memory layout gets “flipped” for ARM64 after the support for these features were added, B. user-space applications, especially the ones which provide debugging support (e.g. kexec-tools, makedumpfile and crash-utility) get impacted because of the same, and C. how user-space applications can “opt-in” to receiving VAs from a 52-bit space by specifying an mmap hint parameter that is larger than 48-bit.

[1]. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm64/memory.rst [Kernel documentation describing the memory map]

ARMv8.2 architecture extensions - LVA and LPA:

  • ARMv8.2 architecture provides two important extensions - Large Virtual Addressing (LVA) and Large Physical Addressing (LPA).
  • ARMv8.2-LVA supports a larger VA space for each translation table base register of up to 52 bits when using the 64KB translation granule.
  • ARMv8.2-LPA:
  • Allows a larger intermediate physical address (IPA) and PA space of up to 52 bits when using the 64KB translation granule.
  • Allows a level 1 block size where the block covers a 4TB address range for the 64KB translation granule if the implementation support 52 bits of PA.

  • Currently the following ARM64 Cortex-A processors support ARMv8.2 extensions:
  • Cortex-A55
  • Cortex-A75
  • Cortex-A76

52-bit VA support in the kernel:

Since the newer kernels with the LVA support should run well on older CPUs (which don’t support LVA extension in hardware) and the newer CPUs (which support LVA extension in hardware), the design approach chosen is to have a single binary which supports 52-bit (which must also be able to fall back to 48-bit at early boot time if the hardware feature is not present).

This design approach requires the kernel to support the following variables for supporting the new virtual address space: VA_BITS constant the maximum VA space size vabits_actual variable the actual VA space size

So, while VA_BITS denotes the maximum VA space size, the actual VA space supported (depending on the switch made at boot-time) is indicated by vabits_actual.

Flipping the kernel memory layout:

The design approach of keeping a single kernel binary necessitates the kernel .text to be in the higher addresses such that they are invariant to 48/52-bit VAs.

In order to optimise phys_to_virt() and virt_to_phys(), the PAGE_OFFSET is kept constant at 0xFFF0000000000000 (corresponding to 52-bit), this obviates the need for an extra variable read. Consider the following physical vs virtual RAM address space conversion:

/*

  • The linear kernel range starts at the bottom of the virtual address
  • space. Testing the top bit for the start of the region is a
  • sufficient check and avoids having to worry about the tag. */

#define virt_to_phys(addr) ({
if (!(((u64)addr) & BIT(vabits_actual - 1)))
(((addr) & ~PAGE_OFFSET) + PHYS_OFFSET) })

#define phys_to_virt(addr) ((unsigned long)((addr) - PHYS_OFFSET) PAGE_OFFSET)

where: PAGE_OFFSET - the virtual address of the start of the linear map, PHYS_OFFSET - the physical address of the start of memory, and vabits_actual - the actual VA space size

Impact on user-space applications which are used to debug kernel:

A number of user-space applications are used to debug running / live kernels or to analyze the vmcore dump obtained from a crashing system - to determine the root-cause of the kernel crash, for example: kexec-tools, makedumpfile and crash-utility.

When these are used to debug the ARM64 kernel, we see an impact on these as well because of the ARM64 kernel memory map getting “flipped”. These applications also need to perform a translation table walk for determining a physical address corresponding to a virtual address (pretty much similar to how it is done in the kernel).

Accordingly, user-space applications need to be modified as they are broken upstream after the “flip” was introduced in the kernel memory map.

I have proposed fixes in the three affected user-space applications accordingly and while some of these have been accepted upstream, others are still pending (see [3], [4], [5] ).

NOTE: Unless these changes are made in user-space applications, they remain broken for debugging running / live kernels or for analyzing the vmcore dump obtained from a crashing system.

52-bit userspace VAs:

To maintain compatibility with user-space applications that relies on the ARMv8.0 VA space maximum size of 48-bits, the kernel will, by default, return virtual addresses to userspace from a 48-bit range.

User-space applications can “opt-in” to receiving VAs from a 52-bit space by specifying an mmap hint parameter that is larger than 48-bit.

For example:

maybe_high_address = mmap(~0UL, size, prot, flags,…);

[3]. http://lists.infradead.org/pipermail/kexec/2020-September/021372.html [Proposed Makedumpfile upstream fix] [4]. http://lists.infradead.org/pipermail/kexec/2020-September/021333.html [Proposed kexec-tools upstream fix] [5]. https://github.com/crash-utility/crash/commit/1c45cea02df7f947b4296c1dcaefa1024235ef10 [Fix accepted in crash-utility]

comments powered by Disqus

Recent Posts

Other Posts

Sign up. Receive Updates. Stay informed.

Sign up to our mailing list to receive updates on the latest Linaro Connect news!