AArch64 Implementation

Relevant source files

This document covers the AArch64-specific implementation of nested page tables within the axaddrspace crate. The AArch64 implementation provides VMSAv8-64 Stage 2 translation support for hypervisor environments, enabling guest physical address to host physical address translation on ARM 64-bit architectures.

This implementation specifically handles ARM's hypervisor-mode address translation. For information about other architecture implementations, see x86_64 Implementation and RISC-V Implementation. For the generic nested page table interface, see Architecture Selection.

Architecture Overview

The AArch64 implementation follows ARM's VMSAv8-64 specification for Stage 2 translation, which is used in hypervisor environments to translate Intermediate Physical Addresses (IPA) from guest virtual machines to Host Physical Addresses (HPA).

flowchart TD
subgraph subGraph3["Address Translation"]
    GPA["GuestPhysAddr"]
    HPA["HostPhysAddr"]
    IPARange["40-bit IPA Space"]
    PARange["48-bit PA Space"]
end
subgraph subGraph2["Memory Management"]
    MemType["MemType"]
    MappingFlags["MappingFlags"]
    TLBFlush["TLB Flush Operations"]
end
subgraph subGraph1["Core Components"]
    A64PTEHV["A64PTEHV"]
    A64Meta["A64HVPagingMetaData"]
    DescAttr["DescriptorAttr"]
end
subgraph subGraph0["AArch64 NPT Implementation"]
    NPT["NestedPageTable<H>"]
    A64PT["PageTable64<A64HVPagingMetaData, A64PTEHV, H>"]
end

A64Meta --> GPA
A64Meta --> IPARange
A64Meta --> PARange
A64Meta --> TLBFlush
A64PT --> A64Meta
A64PT --> A64PTEHV
A64PTEHV --> DescAttr
A64PTEHV --> HPA
A64PTEHV --> MappingFlags
DescAttr --> MemType
NPT --> A64PT

Sources: src/npt/arch/aarch64.rs(L1 - L253) 

The implementation provides a 3-level page table structure with:

  • 40-bit Intermediate Physical Address (IPA) space for guest addresses
  • 48-bit Physical Address (PA) space for host addresses
  • VMSAv8-64 Stage 2 translation table format

Page Table Entry Implementation

The A64PTEHV struct represents a single VMSAv8-64 translation table descriptor, implementing the GenericPTE trait to integrate with the generic page table framework.

flowchart TD
subgraph subGraph3["Attribute Management"]
    DescriptorAttr["DescriptorAttr"]
    ValidBit["VALID"]
    NonBlock["NON_BLOCK"]
    AccessFlag["AF"]
end
subgraph subGraph2["Physical Address Handling"]
    PhysMask["PHYS_ADDR_MASK0x0000_ffff_ffff_f000"]
    AddrBits["bits 12..48"]
end
subgraph subGraph1["GenericPTE Implementation"]
    NewPage["new_page()"]
    NewTable["new_table()"]
    GetPAddr["paddr()"]
    GetFlags["flags()"]
    SetPAddr["set_paddr()"]
    SetFlags["set_flags()"]
    IsPresent["is_present()"]
    IsHuge["is_huge()"]
end
subgraph subGraph0["A64PTEHV Structure"]
    PTE["A64PTEHV(u64)"]
    PTEBits["Raw 64-bit Value"]
end

DescriptorAttr --> AccessFlag
DescriptorAttr --> NonBlock
DescriptorAttr --> ValidBit
GetFlags --> DescriptorAttr
GetPAddr --> PhysMask
IsHuge --> NonBlock
IsPresent --> ValidBit
NewPage --> DescriptorAttr
NewTable --> DescriptorAttr
PTE --> GetFlags
PTE --> GetPAddr
PTE --> IsHuge
PTE --> IsPresent
PTE --> NewPage
PTE --> NewTable
PTE --> PTEBits
PTE --> SetFlags
PTE --> SetPAddr
PhysMask --> AddrBits
SetFlags --> DescriptorAttr
SetPAddr --> PhysMask

Sources: src/npt/arch/aarch64.rs(L144 - L211) 

Key Features

FeatureImplementationPurpose
Physical Address Mask0x0000_ffff_ffff_f000Extracts bits 12-48 for physical addressing
Page vs BlockNON_BLOCKbitDistinguishes between 4KB pages and large blocks
Access FlagAFbitRequired for all valid entries in ARM architecture
Valid BitVALIDbitIndicates if the descriptor is valid for translation

Memory Attribute Management

The AArch64 implementation uses the DescriptorAttr bitflags structure to manage VMSAv8-64 memory attributes and access permissions.

flowchart TD
subgraph subGraph2["Conversion Logic"]
    ToMapping["to MappingFlags"]
    FromMapping["from MappingFlags"]
    MemTypeConv["Memory Type Conversion"]
end
subgraph subGraph1["Memory Types"]
    Device["Device Memory"]
    Normal["Normal Memory"]
    NormalNC["Normal Non-Cacheable"]
end
subgraph subGraph0["DescriptorAttr Bitflags"]
    DescAttr["DescriptorAttr"]
    ValidFlag["VALID (bit 0)"]
    NonBlockFlag["NON_BLOCK (bit 1)"]
    AttrIndex["ATTR (bits 2-5)"]
    S2AP_RO["S2AP_RO (bit 6)"]
    S2AP_WO["S2AP_WO (bit 7)"]
    Shareable["SHAREABLE (bit 9)"]
    AF["AF (bit 10)"]
    XN["XN (bit 54)"]
end

AttrIndex --> Device
AttrIndex --> Normal
AttrIndex --> NormalNC
DescAttr --> AF
DescAttr --> AttrIndex
DescAttr --> FromMapping
DescAttr --> MemTypeConv
DescAttr --> NonBlockFlag
DescAttr --> S2AP_RO
DescAttr --> S2AP_WO
DescAttr --> Shareable
DescAttr --> ToMapping
DescAttr --> ValidFlag
DescAttr --> XN
Device --> MemTypeConv
Normal --> MemTypeConv
NormalNC --> MemTypeConv

Sources: src/npt/arch/aarch64.rs(L8 - L137) 

Memory Type Encoding

The implementation supports three memory types with specific attribute encodings:

Memory TypeEncodingCharacteristics
Device0b0000Device memory with shareability
Normal0b1111Write-back cacheable with shareability
NormalNonCache0b0111Inner cacheable, outer non-cacheable

Permission Mapping

The AArch64 Stage 2 access permissions are mapped to generic MappingFlags:

  • Read: Controlled by VALID bit
  • Write: Controlled by absence of S2AP_WO bit
  • Execute: Controlled by absence of XN bit
  • Device: Determined by memory attribute index

Paging Metadata Configuration

The A64HVPagingMetaData struct provides architecture-specific configuration for the AArch64 hypervisor page tables.

flowchart TD
subgraph subGraph2["EL2 vs EL1 Operations"]
    EL2Ops["EL2 Operationsvae2is, alle2is"]
    EL1Ops["EL1 Operationsvaae1is, vmalle1"]
    ArmEL2Feature["arm-el2 feature"]
end
subgraph subGraph1["TLB Management"]
    FlushTLB["flush_tlb()"]
    SingleFlush["Single Address Flush"]
    FullFlush["Full TLB Flush"]
end
subgraph A64HVPagingMetaData["A64HVPagingMetaData"]
    Levels["LEVELS = 3"]
    PABits["PA_MAX_BITS = 48"]
    VABits["VA_MAX_BITS = 40"]
    VirtAddr["VirtAddr = GuestPhysAddr"]
end

ArmEL2Feature --> EL1Ops
ArmEL2Feature --> EL2Ops
FlushTLB --> FullFlush
FlushTLB --> SingleFlush
FullFlush --> EL1Ops
FullFlush --> EL2Ops
Levels --> FlushTLB
PABits --> FlushTLB
SingleFlush --> EL1Ops
SingleFlush --> EL2Ops
VABits --> FlushTLB
VirtAddr --> FlushTLB

Sources: src/npt/arch/aarch64.rs(L213 - L253) 

TLB Flush Implementation

The TLB flush implementation supports both Exception Level 1 (EL1) and Exception Level 2 (EL2) operations:

EL2 Mode (with arm-el2 feature):

  • Single address: tlbi vae2is - Invalidate by VA in EL2
  • Full flush: tlbi alle2is - Invalidate all EL2 TLB entries

EL1 Mode (default):

  • Single address: tlbi vaae1is - Invalidate by VA, all ASID in EL1
  • Full flush: tlbi vmalle1 - Invalidate all EL1 TLB entries

All TLB operations include data synchronization barriers (dsb sy) and instruction synchronization barriers (isb) to ensure proper ordering.

Integration with Generic Framework

The AArch64 implementation integrates with the generic page table framework through type aliases and trait implementations.

ComponentType DefinitionPurpose
NestedPageTablePageTable64<A64HVPagingMetaData, A64PTEHV, H>Main page table type for AArch64
Page Table EntryA64PTEHVVMSAv8-64 descriptor implementation
MetadataA64HVPagingMetaDataArchitecture-specific configuration
Virtual AddressGuestPhysAddrGuest physical address type

Sources: src/npt/arch/aarch64.rs(L252 - L253) 

The implementation ensures compatibility with the generic nested page table interface while providing ARM-specific optimizations for hypervisor workloads, including proper Stage 2 translation semantics and efficient TLB management for virtualized environments.