XXNU Source Handbook Offline reading instructions
Part 04 · Chapter 04.01

Virtual memory and kernel allocation

Guide index · Architecture

XNU's VM subsystem manages address spaces, the objects supplying their contents, resident physical pages, and the work needed to make pages available under pressure. Its core is in osfmk/vm; process-level memory policy lives in BSD, hardware translation in architecture-specific pmap implementations, and small kernel allocations in osfmk/kern.

Start with maps, objects, pages, and faults, then follow one mapping from API request to CPU access. The detailed chapters below separate address-space policy, content ownership, and hardware translation while tracing their interfaces.

For worked operations spanning other subsystems, use a mapped file through an ARM64 fault and a user buffer through DMA completion. They carry concrete object offsets, virtual/physical/device addresses and resource ownership through the same VM mechanisms.

Detailed reading route

For allocation, field access and final storage release, use the VM structure route: maps and entries → objects → page descriptors → pmap and table storage → named entries and copies. These companions supply field and ownership maps for the operation chapters below.

For concrete clients of the allocator, the key-structures section follows proc and task from their combined allocation into a separate protected record. Writing protected object fields connects their update helpers to the RO-zone validation and ARM64 alias-write paths described below.

Question Guide
What happens during anonymous/file mmap, a first write, COW, mprotect, and munmap? Mapping walkthroughs
How do API addresses, lengths and protection masks become checked arguments? VM argument validation: wrapper types, page arithmetic, zero-size policies, compatibility rewriting and target-map authority
How does memory acquire or lose execute permission? Executable-memory policy: MAP_JIT admission, mobile/macOS branches, protection changes, monitor association, ARM64 faults and SPTM frame classification
How are ranges found, reserved, split, protected, copied, and removed? Virtual address maps: entry representation, B+tree storage, interlock/range/entry locks, submaps and APIs
Where do contents live, and what keeps them alive? Objects and resident pages: delayed-copy preservation/versioning, collapse versus bypass, resident/compressed backing, page states and object teardown
How does a fault obtain contents and safely install a translation? Fault resolution: fast/slow cases, COW, pager/compressor work, object/offset and copy-version revalidation, resilient-media recovery and pmap retries
What are the ARM64 tables and pmap structures? ARM64 pmap: 4 KiB/16 KiB geometry, PTEs, roots, physical apertures, PV/PTD metadata and nesting
How do concrete addresses become table indices, PTEs and physical bytes? Pmap translation walkthroughs: numeric 4 KiB/16 KiB walks, decoded PTEs, root selection and mapping changes through reuse
How are translations installed, changed, disconnected, and tables freed? Pmap mapping lifecycle: legacy/PPL and SPTM paths, locks, epochs, table pins and accounting
When can CPUs safely use a new translation or stop using an old one? Pmap TLB and cache operations: ASIDs, activation, access/dirty tracking, invalidation and completion
How does the x86 backend differ? x86_64 pmap: four-level tables, PV lists, root views, PCIDs, shootdowns and EPT boundaries
How does a file/device pager supply or preserve pages? Pagers and UPLs: object-control interfaces, vnode/UBC, page-in/writeback and completion
What survives a UPL gather, partial completion or vector error? UPL gathering and completion: busy/absent/wired pages, delayed page work, access blocking, commit/abort ranges, vector coordinates and child ownership
What happens when an I/O request addresses executable memory? Executable pages and UPL I/O: direction-dependent admission, temporary copying, byte/page coordinates and backing lifetime after the kernel mapping is removed
How do ordinary reads share file pages with mappings, and what invalidates those pages? File-data caching: resident hits, missing runs, read-ahead, truncation and UBC lifetime
How do cached file pages become eligible for executable mappings? Page-signature validation: offset/hash translation, validation/taint/NX masks, reuse, modification and monitor enforcement
How are pages wired or ranges exported to another task? Wiring and memory entries: wire counts, map copies, named capabilities and transfer ownership
What happens when a Mach message carries memory and rights and a later stage fails? Complex message conversion: owned VM copies, receiver alignment, port-array acquisition, partial publication and failed-send compensation
How does a copy replace existing bytes, and how can a remap cross page-size boundaries? Copy-overwrite and remapping: object substitution, physical-page revalidation, partial progress, source extraction and 4 KiB/16 KiB adjustment
What happens when copying overlaps replacement of its destination mapping? Concurrent-operation walkthroughs: retained pages, current-entry preflight, copy-version checks and completed-prefix accounting
How are physical pages recovered while logical mappings survive? Reclamation and pressure: disconnect, worker ownership, compression, swap and process policy
How does memory pressure select a process, freeze its contents, and later resume it? Memorystatus and freezer: health/actions, referenced candidates, task/map/object freeze, budgets, packed segments and distinct frozen states
How do kernel allocators select storage, isolate types, and release backing? Kernel allocation: index for zone caches, kalloc routing, compiler type metadata, heap/zone assignment, kmem guards and specialized allocators
How is type isolation enforced, and where does sharing remain? Typed allocation: fixed signature groups and zone budgets, variable heap assignment, runtime routing and compatible frees
How does MTE detect stale or out-of-allocation accesses, and who maintains its tags? MTE tagging and page lifetime: process policy, checked mappings and aliases, zone/free/SMR retagging, page copies/compression, fault recovery and physical tag-backing reuse
How did memory and tag checking become available before normal allocators existed? ARM64 bootstrap memory: early tables, physical/virtual cursors, page descriptors, MTE configuration/generator setup, early tagged zones and deferred static release
How do protected domains constrain mappings and page ownership? SPTM, TXM, and Exclaves memory: frame types, signing policy, protected calls, donation and shared mappings

The examples use page-size symbols where possible. Before following an address into pmap, identify the map's page size, system VM page size, and hardware translation granule; these are separate inputs in supported configurations.

The central distinction

A mapping describes what an address means. A resident page holds its current contents. A hardware translation allows a CPU to access those contents. These can exist independently: an untouched anonymous mapping can have neither a resident page nor a page-table entry; a file's cached pages can outlive a particular process mapping. The public vm_map_create documentation explicitly identifies the VM map as the source of truth for region configuration and the pmap as its machine-dependent cache.

Virtual memory and kernel allocation diagram
Virtual memory and kernel allocation diagram · Open SVG
Mermaid source
flowchart TD
    BSD[BSD mmap, fork, exec] --> MAP[vm_map and vm_map_entry]
    MACH[Mach VM APIs and memory entries] --> MAP
    MAP --> OBJ[vm_object plus object offset]
    MAP --> PMAP[pmap: CPU translations]
    OBJ --> PAGE[vm_page: resident contents]
    PAGE --> PMAP
    OBJ --> PAGER[memory_object pager]
    PAGER --> VNODE[Vnode pager / UBC / filesystem]
    PAGER --> COMP[Compressor pager / segments / optional swap]
    PAGER --> DEVICE[Device pager / IOKit]
    SCAN[Pageout scanner] --> PAGE
    SCAN --> COMP
    PRESSURE[BSD memorystatus and freezer] --> SCAN
    ALLOC[zones / kalloc / kmem] --> PAGE
    ALLOC --> MAP

The arrows summarize dependency and data flow, not a universal synchronous call chain. Pager dispatch is directly through operation tables in this checkout; do not assume every memory_object_* call sends an IPC message. See memory_object_data_request.

Follow one address in both directions

Virtual memory and kernel allocation diagram
Virtual memory and kernel allocation diagram · Open SVG
Mermaid source
flowchart LR
    VA[Task virtual address] --> E[Map entry and allowed protection]
    E --> O[Object and offset]
    O --> R[Resident vm_page or backing pager]
    R --> F[Physical frame selected by fault]
    VA --> PT[Pmap root and page-table walk]
    PT --> PTE[Leaf translation and permissions]
    PTE --> F
    F --> PV[Reverse mappings]
    PV --> PTE
    PTE --> TLB[CPU cached translation]

The upper route decides what contents an access is allowed to obtain. The lower route supplies the hardware translation once contents are ready. Reverse mappings let VM begin with a physical page and find affected translations during reclaim or protection changes. A PTE can temporarily grant less access than the map permits, for example to enforce COW or track writes. Replacing or removing a PTE must also honor invalidation completion before the old mapping's resources can be reused. Faults, mapping lifecycle, TLB completion.

Ownership and interfaces

Component Owns or describes Main source entry points
VM map Address ranges, permissions, inheritance, submaps, resource limits struct _vm_map, struct vm_map_entry, vm_map_enter
VM object Logical page contents indexed by object offset, pager and shadow relationships struct vm_object, vm_object_shadow
Resident-page system Physical-page descriptors, object lookup, free and replacement queues struct vm_page, vm_page_grab_options
Fault resolution Permission checks, lookup, zero fill, copying, pager requests, pmap insertion vm_fault, vm_fault_page
Pmap Machine translations, reference/modified tracking, mapping accounting ARM pmap, SPTM pmap, x86 pmap
Pager/UPL interface Supplying or returning contents; holding pages stable during I/O memory_object.c, vm_object_upl_request, vm_upl.c
Reclamation Selecting victims, compression, swap, process memory policy vm_pageout_scan, memorystatus_thread_internal
Kernel allocators Fixed objects, typed size classes, page-granularity kernel allocations zalloc_ext, kalloc_ext, kmem_alloc_guard_internal

The most useful cross-subsystem routes are BSD mmap to a vnode's UBC object, VM faults to filesystem page-in, pageout to filesystem writeback, and IOKit memory descriptors to wired pages/device mappings. Continue into the VFS documentation for filesystem operation dispatch. Process creation and termination determine map lifetime; scheduler waits and wakeups make faulting, pageout, and freezer work executable.

Read the selected pmap backend

arm/pmap.h selects the SPTM or legacy ARM representation. files.arm64 selects matching sources; files.x86_64 selects the x86 files. The same common API name is not evidence that all backends share one algorithm.

Backend Hardware state Principal update/lifetime mechanisms
Legacy ARM, optionally PPL Per-pmap geometry, root, hardware/software ASID state, reverse mappings and table descriptors Pmap reader/writer lock, PV-head protection, PPL allocation/retry boundaries when configured
ARM64 SPTM Geometry/root/ASID and reverse/table metadata coordinated with monitor-managed page tables Monitor update interface, PV-head locks, per-CPU epochs, leaf-table pins and condemnation before reclaim
x86_64 PML4 roots, lower table pages, physical alias lists, per-CPU PCID state Pmap reader/writer lock, PTE/PV synchronization, root activation and remote invalidation protocol

Definitions: legacy pmap, SPTM pmap, x86 pmap. SPTM's implementation cannot be explained by replacing a legacy PPL function call with a different entry instruction; its local concurrency and table-lifetime machinery also differ.

Pmap operation Direction and purpose
pmap_create_options / pmap_destroy Create and retire an address-translation context
pmap_enter_options_addr / pmap_enter_options Install a selected physical address/page at a virtual address with policy supplied by VM
pmap_protect* / pmap_remove* Change installed access or remove translations for a virtual range
pmap_page_protect* / pmap_disconnect* Begin from a physical page and affect its aliases
pmap_get_refmod / pmap_clear_refmod* Observe or reset access/dirty tracking used by VM
pmap_switch* / backend activation Select a context and satisfy address-space tag/coherency requirements
pmap_nest / pmap_unnest Share or detach selected lower-level hierarchy for supported nested mappings

Read these as interface families; argument types, helper names, fast paths, and completion contracts differ. common pmap interface, ARM lifecycle, x86 implementation.

Details specific to this checkout

Sources inspected and limits

“Deep” means the named data definitions and relevant multi-stage implementation paths were read, not that every line or configuration branch in a large file was audited.

Area Inspection What the documentation supports / limits
Executable memory Selected BSD admission, VM protection/association, fault policy and ARM64/SPTM classification MAP_JIT, mobile/macOS W+X distinctions, RW→RX outcomes, copied/remapped authority and 16 KiB examples; external MAC/monitor/JIT-runtime behavior remains bounded
Maps and ranges Deep: vm_map_xnu.h, map-store/range-lock implementation, selected allocate/map/protect/remove/fork/remap paths and kern_mman.c boundaries Entry representation, B+tree/hole lookup, lock preparation/restart, submaps and permission changes; no proof of every balancing or concurrent range operation
Objects and pages Deep: vm_object_xnu.h, vm_page.h, allocation/lookup/reference/activity/termination in vm_object.c and vm_resident.c Delayed-copy preservation/versioning, collapse/bypass proofs and resident/compressor/pager ownership, page states and deferred teardown; specialized objects/configurations remain bounded
Faults Deep selected vm_fault.c paths: map/submap lookup, resident/COW/zero-fill/compressor/pager work, try-lock relookup and nonblocking pmap insertion retry Common success/failure/concurrency paths; code-signing and MTE conditions are identified without claiming every policy branch
Copies, memory entries, wiring Deep: current copy representations and named-entry creation/mapping; VM map/page/pmap wiring and unwiring stages; overwrite substitution/physical-copy retries and remap granule adjustment Transfer ownership, partial-progress boundaries and residency protection; all API flag/overlapping-alias combinations and generated MIG code remain outside exhaustive review
File pager / UPL Deep selected bsd_vm.c, ubc_subr.c, memory_object.c, vm_pageout.c and vm_upl.c; UPL gather, commit/abort, partial/vector completion and release paths VM/VFS handoff, busy/absent/wire/activity ownership, access blocking and vector retirement; fast-gather/error-prefix cleanup coverage remains qualified, while full transpose/provider behavior is separate
Reclamation Deep scanner final ref/mod/disconnect decisions, queue-to-worker activity/busy ownership and compression cleanup in vm_pageout.c; page allocation in vm_resident.c Replacement policy and physical-lifetime boundary; tuning constants are not universal product defaults
Compressor / swap Deep pager put/get, slot/segment representation, nonblocking decompression, temporary physical mappings, and swap reserve/submit/complete paths Offset-to-slot-to-segment-to-page relationship; codec algorithms, every compaction state and swap encryption remain narrower
Process policy / freezer Deep health/action selection, priority/high-water candidate reference/restart, freeze eligibility/iterator, process/task/map/object path and packed-segment completion Focused chapter separates task and BSD frozen states, evaluation/execution, MiB/compressed-page counter units, work budgets and asynchronous I/O. All aging/aggressive-kill rules, throttle combinations, external recommendation policy and notification filters remain bounded.
Allocators Deep zone geometry/metadata/bitmap/cache/depot and refill/reclaim; kalloc classes, routing/free/realloc; fixed/variable compiler metadata and startup isolation policy; guarded kmem placement/population/free/resize; RO/SMR/perCPU/permanent modes and selected IOKit/BSD wrappers Separate chapters trace element, zone, VA, physical and protection lifetimes. Exact generated compiler output, live heap assignments, all sanitizer configurations and external monitor enforcement are outside source verification
ARM64 pmap Deep legacy/PPL and SPTM geometry, roots, PTEs/PV/PTD, enter/protect/remove/disconnect, table allocation/reclaim, ASIDs/nesting, epochs/pins, access tracking and TLB completion Source-visible mapping/lifetime contracts; external monitor bodies and every platform/mapping type are not reconstructed
MTE mitigation and physical backing Deep selected vm_mteinfo.c, map/object/fault, resident-page, SPTM pmap, allocator, exec/copyio/abort and compressor paths Companion connects pointer/storage tags, process/root policy, mapping provenance, allocator retagging, copies/compression and fault attribution to backing activation/deactivation and relocation; external monitor/AMFI/user-allocator bodies, every consumer/configuration and the complete codec remain outside the trace
x86_64 pmap Deep create/expand/enter/remove/protect/disconnect, rooted/hashed PV, root sharing, PCID activation and invalidation; selected nesting/EPT branches Current four-level mapping path; bootstrap, all cache-type changes, corruption heuristics and complete hypervisor behavior remain outside scope
Peripheral VM Focused I/O mapping and driver memory boundaries; sanitize and shared-region interfaces Shared-region/pager and deferred-reclamation paths are expanded in the companions below; complete IOMMU enforcement and external allocation/policy providers remain bounded

Useful original documentation includes pageout scan, memorystatus, freezer, shared region, VM sanitization, and allocator API guidance. Prefer implementation when an older narrative uses a superseded function or structure name.

Backing-store and reclaim companions

Search the handbook

Search every chapter, interface and code excerpt.

    Diagram

    Source preview

    Open full file