Device tree (ADT)
The Apple-format device tree the loader builds for XNU, and what is in it.
XNU boots from an Apple Device Tree (ADT), not a Linux one. mkadt.py writes a minimal ADT: only what the early boot path
reads, with every MMIO address taken from the phone’s own tree. The result goes into the payload. The
iPhone X user space reads the platform’s identity from it, so most of the root’s properties are identity, not hardware.
Running it
mkadt.py OUT.adt [--spaced [--ufs] [--haptics|--audio] [--torch] [--camera] [--resize]] [--canvas=WxH] [--dump]. In the build,
device.conf’s adt line gives the flags; the spaced line is --spaced --ufs --audio --torch (and --resize when resize 1).
The /product node is copied from the iPhone X’s own device tree, which the script reads from a file you extract from your
copy of the IPSW (D22AP_ADT): it is Apple’s and kept out of every repository. Without it the script warns and writes no
/product.
The tree
| Node | What it holds |
|---|---|
/ | compatible D22AP, iPhone10,3, mapple,platform, qcom,sm7150, AppleARM; model iPhone10,3; target-type D22, target-sub-type D22AP; with --spaced the serial-number placeholder, model-number and regulatory-model-number RMX3151 |
/chosen | dram-base, dram-size, random-seed, embedded-panic-log-size, boot-manifest-hash, crypto-hash-method, display-scale (3), the synthetic unique-chip-id and chip-id (0x8015), the security status values, the two MAC addresses, mapple-resize with --resize |
/chosen/memory-map | empty; mkpayload.py --ramdisk adds RAMDisk |
/chosen/asmb | lp-sip0 0x6f, lp-sip1 1: the local boot policy |
/defaults | no-effaceable-storage |
/cpus | cpu0…cpu7, reg = core << 8 (the MPIDR), one homogeneous cluster, timebase-frequency from the SoC |
/arm-io | ranges from 0x01000000; gic (with virtual-timer-intid), wdt, disp0, then the phone’s devices |
/mapple-fbcon | LK’s framebuffer: reg, width, height, stride |
/mapple-ufs | the UFS host LK leaves running, absolute reg |
/buttons | button-names, home-button-type 2 (no Home button), opposed-power-vol-buttons |
/pram | the panic log: the last MiB of the range, outside dram-size |
/product | from the iPhone X’s tree; product-name becomes the phone’s; haptics with --audio or --haptics, camera flash with --torch |
The panic log is carved from the top of the range because, without it, check_for_panic_log() leaves gPanicBase at 0 and
the kernel hangs after the “kdp_core zlib memory” line.
The devices under /arm-io on spaced
Each has its own IOKit or BSD driver; the property names and values are the ones the driver reads.
| Node | Hardware | Notes |
|---|---|---|
keypad | MediaTek keypad, 0x10010000, SPI 73 edge | keymap <1, volume down>: volume down is bit 1 of KP_MEM1; power and volume up are the PMIC’s |
eint | external interrupts, 0x1000b000, SPI 186 | an interrupt controller under the GIC; children use <EINT flags> |
pwrap > pmic > keys | PMIC wrapper 0x1000d000; the PMIC (mt6366-pmic, EINT 144) and its keys | keymap <0 power, 1 volume up> |
gpio | 0x10005000 | output pins only: SPI4’s pins 13, 144, 145 for the touch screen, and 164 with --audio |
i2c3 | with --audio: the speaker amplifier’s bus | bus-id 3, 400 kHz |
i2c5 | with --torch: the flash LED chip’s bus | bus-id 5 |
i2c2, i2c4, isp | with --camera | isp’s camera-rear is what MobileGestalt asks |
touch | ilitek,ili7807s, spi-gpios 13, 14, 144, 145; EINT 12 falling | max-x 2047, max-y 2047, panel-size 1080 x 2412; the firmware is sent by mtkloader |
gpu | Mali-G57 MC2, 0x13000000, SPI 274 to 276 | with the power blocks it drives; the driver does nothing without mp_gpu |
wlan | CONNSYS Wi-Fi | local-mac-address, wifi-vendor; launchd starts wifid only when a node named wlan exists |
What comes from where
The constants for spaced in mkadt.py: RAM 0xc0000000 to 0x13e000000, framebuffer 0x771b0000 (stride 4320, 2412 rows),
GIC 0x0c000000/0x0c040000, timer 13 MHz and INTID 27, UFS 0x11270000 (size 0x4000, 16 KB pages). The
setup script writes the same numbers, read from a phone’s own trees, as adt-input.conf;
mkadt.py does not read that file yet.
Source: tools/mkadt.py of mapple_build at f7431bb; tools/mkpayload.py for RAMDisk.
Applies to realme 8i (spaced), release 1 · Updated 15 November 2026