XXNU Source Handbook Download offline version from here
Part 01 · Chapter 01.02

Architecture and object relationships

Guide index

One kernel, several object models

XNU combines Mach execution, IPC, and virtual memory with BSD process/filesystem/network semantics and the IOKit driver model. These components normally execute in the same kernel address space and call each other directly. “Mach subsystem” does not mean that every BSD operation becomes a message to a separate server. For example, BSD's process-creation code calls Mach task/thread creation, and filesystem-backed paging calls into the vnode pager. See fork implementation, task creation, and vnode pager.

Architecture and object relationships diagram
Architecture and object relationships diagram · Open SVG
Mermaid source
flowchart TB
    U[User processes and services]
    ABI[System calls and Mach traps]
    B[BSD processes and descriptors]
    F[VFS and filesystem operations]
    N[Sockets and networking]
    I[Mach IPC and kernel object ports]
    T[Tasks, threads, and scheduling]
    V[Virtual memory and allocators]
    D[IOKit services and drivers]
    S[Credentials, MAC, and code signing]
    H[Machine code and platform expert]
    U --> ABI
    ABI --> B
    ABI --> I
    B --> F
    B --> N
    B --> T
    B --> V
    I --> T
    I --> V
    I --> D
    F <--> V
    F --> D
    N --> D
    D --> V
    D --> T
    S -. checks .-> B
    S -. checks .-> F
    S -. checks .-> N
    S -. checks .-> I
    S -. checks .-> D
    T --> H
    V --> H
    D --> H

This is a dependency map, not a strict stack. For example, a device interrupt enters through machine code and can eventually wake a BSD thread; memory pressure can make VM ask BSD's process policy to reclaim a process. Networking's interface KPI also permits driver implementations outside this source tree. These reverse paths matter as much as calls originating in a syscall.

The objects to learn first

The key-structures section follows these declarations into allocation, accessors, checked updates and final release. Its process/task route includes ordinary creation, kernel bootstrap and corpse differences. Continue with thread storage and protected associations, credentials, MAC labels, IPC spaces and entries, and ports and kobjects to connect execution identity and capability lookup to their concrete representations.

For memory, follow map and entry storage, object backing, resident-page metadata and pmap/table storage. The memory-entry and copy companion connects those ownership rules to exported capabilities and transfer containers. A live range, a retained object, a resident frame and an installed translation are distinct states.

For files, follow the descriptor table into fileproc/fileglob storage, then vnode identity, UBC/pager associations and signature storage. Slot publication, shared open-file references, filesystem identity and signed-file backing each have their own lifetime.

For messages and networking, follow kmsg storage, sockets, socket-buffer records, Internet PCBs and mbuf backing. A queue header, protocol attachment, retained capability and shared packet-byte view have separate allocation and ownership rules.

Object Responsibility Principal source
proc BSD process identity, lifecycle, descriptor state, signal state, process relationships proc_internal.h
proc_ro Protected process/task association and selected process state proc_ro.h
task Mach resource container: VM map, IPC space, threads, policy, accounting task.h
thread, thread_ro, uthread Schedulable execution, protected associations, and per-thread BSD state thread.h, user.h
ucred, posix_cred, ucred_rw Shared identity value, embedded POSIX fields, and separate writable lifetime/hash bookkeeping ucred.h, kern_credential.c
MAC label Protected owner/slot representation for policy-specific values _label.h
processor, processor_set CPU execution and scheduling domains processor.h
vm_map, vm_map_entry Virtual-address ranges, protections, backing relationships vm_map_xnu.h
vm_object, vm_page Backing-store identity and resident physical-page metadata vm_object_xnu.h, vm_page.h
ipc_space, ipc_entry, ipc_port Task-local names and rights, and the kernel endpoints they designate ipc_space.h, ipc_entry.h, ipc_port.h
fileproc, fileglob Descriptor-level state and shared open-file state file_internal.h
vnode, mount A filesystem object and a mounted filesystem instance vnode_internal.h, mount_internal.h
socket, protosw, ifnet, mbuf Socket state, protocol dispatch, network interface state, packet storage socketvar.h, protosw.h, if_var_private.h, mbuf.h
IORegistryEntry, IOService, IOUserClient Device/service graph, driver lifecycle, and controlled user access IORegistryEntry.h, IOService.h, IOUserClient.h

The familiar phrase “a process has a task” is useful but incomplete for this version. The process and task participate in a combined allocation and share protected association state; Mach and BSD lifetimes still have distinct reference rules. Likewise, thread/BSD state must be reached through the current accessors, not an assumed historical bsd_info field. Read the process lifecycle guide before interpreting an old debugger script or copying an older XNU diagram. The actual accessors include proc_task(), get_threadtask(), and get_bsdthread_info() in kern_proc.c, thread.h, and their implementations.

Architecture and object relationships diagram
Architecture and object relationships diagram · Open SVG
Mermaid source
flowchart LR
    P[BSD proc] --- R[Protected proc_ro association]
    R --- T[Mach task]
    T --> M[VM map]
    T --> IS[IPC space]
    T --> TH[Threads]
    TH --- UT[BSD uthread state]
    P --> FD[Descriptor table]
    FD --> FP[fileproc]
    FP --> FG[fileglob]
    FG --> VN[vnode]
    FG --> SO[socket]
    IS --> IE[Name and rights entry]
    IE --> PORT[Mach port]
    PORT --> Q[Messages or kernel object association]

Edges indicate associations rather than C field names, exact pointer direction, or ownership. In particular, the diagram does not assert that a process owns every referenced vnode or that an IPC name is a pointer.

Three routes from user space

BSD system calls provide operations such as file access, sockets, process control, and kevent. The declarative entry list is syscalls.master. Architecture dispatchers decode the call and invoke an entry in the generated sysent table; per-thread uthread state carries syscall-related information. Start at ARM syscall dispatch or x86-64 dispatch.

Mach traps provide selected direct kernel entries, including message operations and selected VM/port operations. Their table is syscall_sw.c. A trap is not the same thing as an arbitrary Mach RPC: many APIs use a message to a port. libsyscall/mach and libsyscall/wrappers expose parts of the user side; some wrappers select a trap and then fall back to an RPC.

Messages to kernel objects arrive through Mach IPC and are dispatched to a kernel implementation. Mach .defs interfaces describe many RPCs; ipc_kobject.c and ipc_mig.c provide dispatch support. IOKit also exposes objects and user clients through this machinery; see IOUserClient.cpp and iokit_rpc.c. Possession of an appropriate port right and the operation's additional policy checks determine what the caller may do.

All three routes converge on shared objects. A BSD mmap and a Mach VM API manipulate VM; a BSD workqueue and a Mach-created thread are scheduled by the same execution machinery. Different entry conventions do not create independent kernels.

Interfaces between subsystems

Boundary What crosses it Why it matters
BSD ↔ Mach execution Process/task association, thread creation, exit, policy and exception handling PID identity, task lifetime, and thread scheduling answer different questions
VFS ↔ VM Vnode pager, memory-object control, UBC state, UPL page lists File contents can be accessed through read/write and virtual mappings
IPC ↔ VM Out-of-line message memory and memory-entry objects Message transfer includes ownership and mapping work, not just bytes in a queue
IPC ↔ scheduler Wait queues, turnstiles, importance and message delivery A receive can block; dependencies can affect effective priority
IOKit ↔ IPC Object ports and user-client RPCs A C++ driver object needs an access-controlled user interface
IOKit ↔ VM/platform Memory descriptors, mappings, DMA commands, interrupts CPU virtual addresses, physical pages, and device addresses are distinct
Networking ↔ event/runtime Socket wakeups, readiness filters, thread blocking Data arrival changes both buffer state and a waiting thread's eligibility to run
Security ↔ all public operations Credentials, labels, signatures, entitlements, audit context Authorization is distributed across operation-specific checks

The execution-path guide follows these boundaries with concrete source entry points. The ownership guide explains the reference and lock questions to ask at each crossing.

Platform and configuration are part of the design

osfmk/arm64, osfmk/arm, osfmk/i386, and osfmk/x86_64 contain machine-dependent execution and memory code. Directory names retain history: i386 includes code used for x86-64, and shared ARM code remains under arm. pexpert handles platform discovery and callbacks; IOKit consumes platform information and discovers services. See the platform guide.

The compiled kernel is selected from a larger tree. config/MASTER, architecture-specific configurations, subsystem conf/files* lists, and #if branches determine what exists in a particular build. In particular, scheduler policy, memory-pressure behavior, Skywalk features, Exclaves, and SPTM-related integration must not be assumed identical on all targets. Use the build guide before deciding that two apparent implementations both run on the same device.

Search the handbook

Search every chapter, interface and code excerpt.

    Diagram

    Source preview

    Open full file