XNU = “X is Not Unix”. A hybrid kernel combining the Mach microkernel (Carnegie Mellon), FreeBSD (POSIX), and IOKit (NeXT/Apple).


The Three Layers of XNU

Layer 1: Mach (osfmk/)

Microkernel core – manages low-level primitives.

Subsystem Function Key files
IPC Message passing, port management ipc/mach_msg.c, ipc/ipc_port.c
Tasks/Threads Execution units, scheduling kern/task.c, kern/thread.c
Virtual Memory Address spaces, pagers, page fault vm/vm_map.c, vm/vm_fault.c
Scheduling Thread scheduling, priorities kern/sched_prim.c
Zones Memory allocator (zalloc) kern/zalloc.c, kern/kalloc.c

Key concepts:

  • Mach treats everything as a port – communication happens via messages
  • Task = container for resources (address space, ports, threads)
  • Thread = unit of execution
  • VM subsystem manages virtual-to-physical mapping

Layer 2: BSD (bsd/)

POSIX compatibility layer – the APIs that userspace programs use.

Subsystem Function Key files
Process model pid, fork, exec, wait kern/kern_proc.c, kern/kern_fork.c
Credentials uid, gid, groups, entitlements kern/kern_credential.c
File Systems VFS, APFS, HFS+ vfs/vfs_syscalls.c
Networking Sockets, TCP/IP stack net/, netinet/
Syscalls POSIX system call interface kern/syscalls.master
Security MAC framework, sandbox hooks security/mac_base.c

Relationship with Mach:

  • BSD struct proc wraps Mach struct task – 1:1 mapping
  • BSD process = Mach task + BSD metadata (pid, credentials, file descriptors)
  • BSD syscalls = thin wrappers that call Mach primitives underneath

Layer 3: IOKit (iokit/)

Object-oriented driver framework – restricted C++ (no exceptions, no RTTI).

Component Function
IOService Base class for drivers, service matching
IOUserClient Interface between userspace and driver
IOMemoryDescriptor Memory management for drivers
IORegistryEntry Global registry (device tree)
IOWorkLoop Event-driven work queue
OSObject Reference-counted base class

Driver hierarchy:

IOService (root)
└── IOPlatformExpertDevice
    └── AppleARMPE
        └── IOPlatformDevice
            ├── AppleT8103 (SoC driver)
            ├── AGXAccelerator (GPU)
            ├── IOSurface (Graphics buffers)
            ├── AppleANS3 (NVMe/NAND)
            └── AppleUSBHostController (USB)

How the Three Layers Interact

Syscall Flow

                    User Space
════════════════════════════════════════════
                    Kernel Space

App calls read(fd, buf, len)
  │
  ├─→ SVC #0x80 (syscall instruction)
  │
  ▼
ARM64 Exception Vector (EL1)
  │
  ├─→ BSD syscall handler (bsd/dev/arm/systemcalls.c)
  │     └─→ sys_read() [bsd/kern/sys_generic.c]
  │           └─→ VFS layer → APFS driver
  │                 └─→ IOKit storage driver
  │
  ├─→ Mach trap handler (osfmk/arm64/trap.c)
  │     └─→ mach_msg_overwrite_trap()
  │           └─→ IPC subsystem
  │
  └─→ Machine-dependent trap
        └─→ thread_exception_return()

Memory Allocation Path

Userspace: malloc(size)
  → libsystem_malloc.dylib (userspace allocator)
    → mach_vm_allocate() (if needs pages from kernel)
      → vm_map_enter() (Mach VM)
        → pmap_enter() (ARM64 page tables)

Kernel internal: kalloc(size)
  → kalloc zone lookup
    → zalloc(zone)
      → zone_expand() if empty
        → kernel_memory_allocate()
          → pmap_enter() (map physical page)

IOKit UserClient Call Path

Userspace: IOConnectCallMethod(connection, selector, ...)
  → Mach message to IOKit port
    → is_iokit_rpc() [iokit/Kernel/IOUserClient.cpp]
      → IOUserClient::externalMethod(selector, args)
        → dispatch table lookup
          → Specific driver method

Kernel Startup Sequence

1. iBoot loads kernelcache into memory
2. Kernel entry point: start (osfmk/arm64/start.s)
   → arm_init() — setup MMU, page tables
   → machine_startup() — platform init
   → kernel_bootstrap() — init subsystems:
     ├── zone_init() — memory zones
     ├── ipc_init() — Mach IPC
     ├── vm_mem_bootstrap() — virtual memory
     ├── clock_init() — timekeeping
     └── IOKit init — driver matching
3. BSD init:
   ├── bsd_init() — BSD subsystem
   ├── vfs_mountroot() — mount root filesystem
   └── bsdinit_task() — launch /sbin/launchd (PID 1)
4. launchd starts system daemons

Kernel Address Space Layout (ARM64 iOS)

0xFFFFFE0000000000 ┐
                   │ Kernel virtual address space
                   │
                   ├── Kernelcache (__TEXT, __DATA, ...)
                   ├── Zone maps (kalloc zones)
                   ├── IOKit objects
                   ├── IPC port/message objects
                   ├── Page tables (pmap structures)
                   └── Device MMIO mappings
                   │
0xFFFFFFFFFFFFFFFF ┘

KASLR slide: random offset added to base address each boot
Typical: 0xFFFFFE0007004000 + slide (0x000000XXXX000000)

Resources