Core Concepts
Relevant source files
This document explains the fundamental abstractions that enable page_table_multiarch
to provide a unified page table interface across multiple processor architectures. These core concepts form the foundation that allows the same high-level API to work with x86_64, AArch64, RISC-V, and LoongArch64 page tables.
For architecture-specific implementations of these concepts, see Architecture Support. For the high-level PageTable64 API that builds on these concepts, see PageTable64 Implementation.
Abstraction Architecture
The system achieves architecture independence through a layered abstraction model built on three core traits and several supporting types. This design separates architecture-specific details from the generic page table logic.
flowchart TD subgraph subGraph3["Architecture Implementations"] X86_MD["X64PagingMetaData"] ARM_MD["A64PagingMetaData"] RV_MD["Sv39MetaData"] LA_MD["LA64MetaData"] X86_PTE["X64PTE"] ARM_PTE["A64PTE"] RV_PTE["Rv64PTE"] LA_PTE["LA64PTE"] end subgraph subGraph2["Supporting Types"] MF["MappingFlags"] PS["PageSize"] PE["PagingError"] TLB["TlbFlush<M>"] end subgraph subGraph1["Abstraction Traits"] PMD["PagingMetaData"] GPTE["GenericPTE"] PH["PagingHandler"] end subgraph subGraph0["Generic Layer"] PT64["PageTable64<M,PTE,H>"] API["map() unmap() walk()"] end API --> MF API --> PE API --> PS API --> TLB GPTE --> ARM_PTE GPTE --> LA_PTE GPTE --> RV_PTE GPTE --> X86_PTE PMD --> ARM_MD PMD --> LA_MD PMD --> RV_MD PMD --> X86_MD PT64 --> GPTE PT64 --> PH PT64 --> PMD
Sources: page_table_multiarch/src/lib.rs(L11 - L19) page_table_multiarch/src/lib.rs(L42 - L92)
Architecture Independence Traits
Three core traits provide the interface between generic page table logic and architecture-specific implementations.
PagingMetaData Trait
The PagingMetaData
trait encapsulates architecture-specific constants and behaviors that vary between processor families.
classDiagram class PagingMetaData { +LEVELS: usize +PA_MAX_BITS: usize +VA_MAX_BITS: usize +PA_MAX_ADDR: usize +VirtAddr: MemoryAddr +paddr_is_valid(paddr: usize) bool +vaddr_is_valid(vaddr: usize) bool +flush_tlb(vaddr: Option~VirtAddr~) } class X64PagingMetaData { +LEVELS = 4 +PA_MAX_BITS = 52 +VA_MAX_BITS = 48 } class A64PagingMetaData { +LEVELS = 4 +PA_MAX_BITS = 48 +VA_MAX_BITS = 48 } class Sv39MetaData { +LEVELS = 3 +PA_MAX_BITS = 56 +VA_MAX_BITS = 39 } PagingMetaData --|> X64PagingMetaData PagingMetaData --|> A64PagingMetaData PagingMetaData --|> Sv39MetaData
Key responsibilities include:
- Page table structure:
LEVELS
defines the number of translation levels - Address space limits:
PA_MAX_BITS
andVA_MAX_BITS
specify supported address ranges - Address validation:
paddr_is_valid()
andvaddr_is_valid()
enforce architecture constraints - TLB management:
flush_tlb()
handles cache invalidation
Sources: page_table_multiarch/src/lib.rs(L42 - L79)
GenericPTE Trait
The GenericPTE
trait provides a unified interface for manipulating page table entries across different architectures.
classDiagram class GenericPTE { +new_page(paddr: PhysAddr, flags: MappingFlags, is_huge: bool) Self +new_table(paddr: PhysAddr) Self +paddr() PhysAddr +flags() MappingFlags +set_paddr(paddr: PhysAddr) +set_flags(flags: MappingFlags, is_huge: bool) +bits() usize +is_unused() bool +is_present() bool +is_huge() bool +clear() } class X64PTE { +bits: usize } class A64PTE { +bits: usize } class Rv64PTE { +bits: usize } GenericPTE --|> X64PTE GenericPTE --|> A64PTE GenericPTE --|> Rv64PTE
The trait supports two types of entries:
- Page entries: Created with
new_page()
, point to actual memory pages - Table entries: Created with
new_table()
, point to next-level page tables
Sources: page_table_entry/src/lib.rs(L38 - L68)
PagingHandler Trait
The PagingHandler
trait abstracts OS-dependent memory management operations.
Method | Purpose | Return Type |
---|---|---|
alloc_frame() | Allocate a 4K physical frame | Option |
dealloc_frame(paddr) | Free an allocated frame | () |
phys_to_virt(paddr) | Convert physical to virtual address | VirtAddr |
This trait allows the page table implementation to work with different memory allocators and virtual memory layouts without being tied to a specific operating system.
Sources: page_table_multiarch/src/lib.rs(L83 - L92)
Memory Management Types
MappingFlags
The MappingFlags
bitflags provide a generic representation of memory permissions and attributes that gets translated to architecture-specific page table entry bits.
flowchart TD subgraph subGraph1["Architecture Translation"] X86_BITS["x86_64 PTE bits"] ARM_BITS["AArch64 descriptor bits"] RV_BITS["RISC-V PTE bits"] end subgraph subGraph0["Generic MappingFlags"] READ["READ (1<<0)"] WRITE["WRITE (1<<1)"] EXECUTE["EXECUTE (1<<2)"] USER["USER (1<<3)"] DEVICE["DEVICE (1<<4)"] UNCACHED["UNCACHED (1<<5)"] end DEVICE --> ARM_BITS DEVICE --> RV_BITS DEVICE --> X86_BITS EXECUTE --> ARM_BITS EXECUTE --> RV_BITS EXECUTE --> X86_BITS READ --> ARM_BITS READ --> RV_BITS READ --> X86_BITS UNCACHED --> ARM_BITS UNCACHED --> RV_BITS UNCACHED --> X86_BITS USER --> ARM_BITS USER --> RV_BITS USER --> X86_BITS WRITE --> ARM_BITS WRITE --> RV_BITS WRITE --> X86_BITS
Sources: page_table_entry/src/lib.rs(L12 - L36)
PageSize Enumeration
The PageSize
enum defines supported page sizes across architectures:
Size | Value | Usage |
---|---|---|
Size4K | 0x1000 (4 KB) | Standard page size |
Size2M | 0x20_0000 (2 MB) | Huge page (x86_64, AArch64) |
Size1G | 0x4000_0000 (1 GB) | Giant page (x86_64) |
The enum provides utility methods:
is_huge()
: Returns true for sizes larger than 4Kis_aligned(addr)
: Checks address alignmentalign_offset(addr)
: Calculates alignment offset
Sources: page_table_multiarch/src/lib.rs(L95 - L128)
Error Handling
The PagingError
enum defines standard error conditions:
flowchart TD PE["PagingError"] NM["NoMemoryCannot allocate memory"] NA["NotAlignedAddress not page-aligned"] NMP["NotMappedMapping not present"] AM["AlreadyMappedMapping already exists"] HP["MappedToHugePagePTE is huge but target is 4K"] PE --> AM PE --> HP PE --> NA PE --> NM PE --> NMP
Sources: page_table_multiarch/src/lib.rs(L22 - L38)
TLB Management
Translation Lookaside Buffer (TLB) management is handled through two RAII types that ensure proper cache invalidation.
TlbFlush and TlbFlushAll
Both types are marked with #[must_use]
to ensure TLB invalidation is explicitly handled. Callers must either:
- Call
.flush()
or.flush_all()
to invalidate TLB entries - Call
.ignore()
if TLB flushing will be handled elsewhere
Sources: page_table_multiarch/src/lib.rs(L130 - L172)
Integration Model
The abstractions work together to provide a cohesive system where generic logic operates through trait interfaces while architecture-specific implementations handle the details.
flowchart TD subgraph Hardware/OS["Hardware/OS"] MEM_ALLOC["Memory allocator"] TLB_HW["TLB hardware"] PT_HW["Page table hardware"] end subgraph subGraph2["Trait Implementations"] MD_CHECK["M::vaddr_is_valid()"] PTE_NEW["PTE::new_page()"] FLAGS_CONV["flags → PTE bits"] TLB_FLUSH["M::flush_tlb()"] end subgraph PageTable64<M,PTE,H>["PageTable64<M,PTE,H>"] PT64_IMPL["Page table traversal logic"] ALLOC["H::alloc_frame()"] CONVERT["H::phys_to_virt()"] end subgraph subGraph0["Application Code"] APP["map(vaddr, paddr, flags)"] end ALLOC --> MEM_ALLOC APP --> PT64_IMPL FLAGS_CONV --> PT_HW MD_CHECK --> TLB_FLUSH PT64_IMPL --> ALLOC PT64_IMPL --> CONVERT PT64_IMPL --> MD_CHECK PT64_IMPL --> PTE_NEW PTE_NEW --> FLAGS_CONV TLB_FLUSH --> TLB_HW
This design allows the same PageTable64
implementation to work across all supported architectures by delegating architecture-specific operations to trait implementations while maintaining type safety and performance.
Sources: page_table_multiarch/src/lib.rs(L11 - L19) page_table_multiarch/src/bits64.rs