Address Types and Operations

Relevant source files

This document covers the foundational address handling types and operations provided by the memory_addr crate. These types provide type-safe abstractions for physical and virtual memory addresses, along with comprehensive alignment and arithmetic operations. For information about address ranges and iteration, see Address Ranges and Page Iteration.

Core Architecture

The address system is built around the MemoryAddr trait, which provides a common interface for all memory address types. The crate includes two concrete address types (PhysAddr and VirtAddr) and utilities for creating custom address types.

Address Type Hierarchy

classDiagram
note for MemoryAddr "Auto-implemented for types that are:Copy + From + Into + Ord"
class MemoryAddr {
    <<trait>>
    
    +align_down(align) Self
    +align_up(align) Self
    +align_offset(align) usize
    +is_aligned(align) bool
    +align_down_4k() Self
    +align_up_4k() Self
    +offset(offset) Self
    +add(rhs) Self
    +sub(rhs) Self
    +checked_add(rhs) Option~Self~
    +checked_sub(rhs) Option~Self~
}

class PhysAddr {
    -usize: usize
    +from_usize(addr) PhysAddr
    +as_usize() usize
}

class VirtAddr {
    -usize: usize
    +from_usize(addr) VirtAddr
    +as_usize() usize
    +from_ptr_of~T~(*const T) VirtAddr
    +as_ptr() *const u8
    +as_ptr_of~T~() *const T
    +as_mut_ptr() *mut u8
}

MemoryAddr  ..|>  PhysAddr : implements
MemoryAddr  ..|>  VirtAddr : implements

Sources: memory_addr/src/addr.rs(L12 - L263)  memory_addr/src/addr.rs(L450 - L461) 

Address Types

PhysAddr

PhysAddr represents a physical memory address. It is a transparent wrapper around usize that provides type safety to prevent mixing physical and virtual addresses.

MethodDescriptionReturn Type
from_usize(addr)Creates from raw address valuePhysAddr
as_usize()Converts to raw address valueusize
pa!(addr)Convenience macro for creationPhysAddr

VirtAddr

VirtAddr represents a virtual memory address with additional pointer conversion capabilities beyond the base MemoryAddr trait.

MethodDescriptionReturn Type
from_ptr_of(ptr)Creates from typed pointerVirtAddr
from_mut_ptr_of(ptr)Creates from mutable pointerVirtAddr
as_ptr()Converts to byte pointer*const u8
as_ptr_of()Converts to typed pointer*const T
as_mut_ptr()Converts to mutable byte pointer*mut u8
as_mut_ptr_of()Converts to mutable typed pointer*mut T
va!(addr)Convenience macro for creationVirtAddr

Sources: memory_addr/src/addr.rs(L450 - L461)  memory_addr/src/addr.rs(L463 - L500)  memory_addr/src/addr.rs(L502 - L516) 

Address Type Operations Flow

flowchart TD
subgraph Results["Results"]
    new_addr["New Address"]
    offset_val["usize offset"]
    ptr_result["*const/*mut T"]
    bool_result["bool"]
end
subgraph Operations["Operations"]
    align["Alignment Operations"]
    arith["Arithmetic Operations"]
    convert["Conversion Operations"]
end
subgraph subGraph1["Address Types"]
    PhysAddr["PhysAddr"]
    VirtAddr["VirtAddr"]
end
subgraph Creation["Creation"]
    usize["usize value"]
    ptr["*const/*mut T"]
    macro_pa["pa!(0x1000)"]
    macro_va["va!(0x2000)"]
end

PhysAddr --> align
PhysAddr --> arith
VirtAddr --> align
VirtAddr --> arith
VirtAddr --> convert
align --> bool_result
align --> new_addr
align --> offset_val
arith --> new_addr
arith --> offset_val
convert --> ptr_result
macro_pa --> PhysAddr
macro_va --> VirtAddr
ptr --> VirtAddr
usize --> PhysAddr
usize --> VirtAddr

Sources: memory_addr/src/addr.rs(L450 - L500)  memory_addr/src/addr.rs(L502 - L516) 

Alignment Operations

The MemoryAddr trait provides comprehensive alignment functionality for working with page boundaries and custom alignments.

Core Alignment Methods

MethodDescriptionExample Usage
align_down(align)Rounds down to alignment boundaryaddr.align_down(0x1000)
align_up(align)Rounds up to alignment boundaryaddr.align_up(0x1000)
align_offset(align)Returns offset within alignmentaddr.align_offset(0x1000)
is_aligned(align)Checks if address is alignedaddr.is_aligned(0x1000)

4K Page Alignment Shortcuts

MethodDescriptionEquivalent To
align_down_4k()Aligns down to 4K boundaryalign_down(4096)
align_up_4k()Aligns up to 4K boundaryalign_up(4096)
align_offset_4k()Offset within 4K pagealign_offset(4096)
is_aligned_4k()Checks 4K alignmentis_aligned(4096)

Alignment Operation Examples

flowchart TD
subgraph align_up_4k()["align_up_4k()"]
    result4["0x3000"]
    result5["0x3000"]
    result6["0x4000"]
end
subgraph align_down_4k()["align_down_4k()"]
    result1["0x2000"]
    result2["0x3000"]
    result3["0x3000"]
end
subgraph subGraph0["Input Addresses"]
    addr1["0x2fff"]
    addr2["0x3000"]
    addr3["0x3001"]
end

addr1 --> result1
addr1 --> result4
addr2 --> result2
addr2 --> result5
addr3 --> result3
addr3 --> result6

Sources: memory_addr/src/addr.rs(L27 - L94) 

Arithmetic Operations

The trait provides extensive arithmetic operations with multiple overflow handling strategies.

Basic Arithmetic

MethodDescriptionOverflow Behavior
offset(isize)Signed offset additionPanics
add(usize)Unsigned additionPanics
sub(usize)Unsigned subtractionPanics
sub_addr(Self)Address differencePanics

Wrapping Arithmetic

MethodDescriptionOverflow Behavior
wrapping_offset(isize)Signed offset additionWraps around
wrapping_add(usize)Unsigned additionWraps around
wrapping_sub(usize)Unsigned subtractionWraps around
wrapping_sub_addr(Self)Address differenceWraps around

Checked Arithmetic

MethodDescriptionReturn Type
checked_add(usize)Safe additionOption
checked_sub(usize)Safe subtractionOption
checked_sub_addr(Self)Safe address differenceOption

Overflowing Arithmetic

MethodDescriptionReturn Type
overflowing_add(usize)Addition with overflow flag(Self, bool)
overflowing_sub(usize)Subtraction with overflow flag(Self, bool)
overflowing_sub_addr(Self)Address difference with overflow flag(usize, bool)

Arithmetic Operations Decision Tree

flowchart TD
start["Need Address Arithmetic?"]
signed["Signed Offset?"]
overflow["Overflow Handling?"]
offset_op["offset(isize)wrapping_offset(isize)"]
panic_ops["add(usize)sub(usize)sub_addr(Self)"]
wrap_ops["wrapping_add(usize)wrapping_sub(usize)wrapping_sub_addr(Self)"]
check_ops["checked_add(usize)checked_sub(usize)checked_sub_addr(Self)"]
over_ops["overflowing_add(usize)overflowing_sub(usize)overflowing_sub_addr(Self)"]

overflow --> check_ops
overflow --> over_ops
overflow --> panic_ops
overflow --> wrap_ops
signed --> offset_op
signed --> overflow
start --> signed

Sources: memory_addr/src/addr.rs(L99 - L258) 

Address Type Creation

The crate provides macros for creating custom address types with the same capabilities as PhysAddr and VirtAddr.

def_usize_addr! Macro

The def_usize_addr! macro generates new address types with automatic implementations:

  • Basic traits: Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq
  • Conversion traits: From<usize>, Into<usize>
  • Arithmetic operators: Add<usize>, Sub<usize>, Sub<Self>
  • Utility methods: from_usize(), as_usize()

def_usize_addr_formatter! Macro

The def_usize_addr_formatter! macro generates formatting implementations:

  • Debug trait with custom format string
  • LowerHex and UpperHex traits

Custom Address Type Creation Flow

sequenceDiagram
    participant Developer as "Developer"
    participant def_usize_addr as "def_usize_addr!"
    participant def_usize_addr_formatter as "def_usize_addr_formatter!"
    participant CustomAddressType as "Custom Address Type"

    Developer ->> def_usize_addr: "Define type CustomAddr"
    def_usize_addr ->> CustomAddressType: "Generate struct with usize field"
    def_usize_addr ->> CustomAddressType: "Implement required traits"
    def_usize_addr ->> CustomAddressType: "Add conversion methods"
    def_usize_addr ->> CustomAddressType: "Add arithmetic operators"
    Developer ->> def_usize_addr_formatter: "Set format string"
    def_usize_addr_formatter ->> CustomAddressType: "Implement Debug trait"
    def_usize_addr_formatter ->> CustomAddressType: "Implement Hex traits"
    CustomAddressType ->> Developer: "Ready for use with MemoryAddr"

Sources: memory_addr/src/addr.rs(L302 - L448) 

MemoryAddr Trait Implementation

The MemoryAddr trait is automatically implemented for any type meeting the required bounds, providing a blanket implementation that enables consistent behavior across all address types.

Automatic Implementation Requirements

flowchart TD
subgraph Result["Result"]
    unified["Unified Interface"]
    type_safety["Type Safety"]
    rich_api["Rich API"]
end
subgraph subGraph1["Automatic Implementation"]
    memory_addr["MemoryAddr trait"]
    alignment["Alignment Methods"]
    arithmetic["Arithmetic Methods"]
end
subgraph subGraph0["Required Bounds"]
    copy["Copy"]
    from_usize["From"]
    into_usize["Into"]
    ord["Ord"]
end

alignment --> unified
arithmetic --> type_safety
copy --> memory_addr
from_usize --> memory_addr
into_usize --> memory_addr
memory_addr --> alignment
memory_addr --> arithmetic
ord --> memory_addr
unified --> rich_api

Sources: memory_addr/src/addr.rs(L261 - L263)