Skip to content

Userdata image ​

The userdata image supplies the root file system to XNU. It holds the unchanged OS and Cryptex1,SystemOS disk images from the target IPSW behind a manifest that the kernel reads.

Build ​

sh
./unixnu build userdata --ipsw /path/to/restore.ipsw

The step extracts the IPSW components named in [userdata] windows, reads each disk image with hdiutil, and writes a raw image to out/<board>/userdata/userdata-root.img.

The report userdata-root.json records the window offsets, sizes and hashes, the partition capacity and the flash command.

A dry run checks the IPSW and the partition size without writing the image:

sh
./unixnu build userdata --dry-run

Partition ​

board.toml describes the GPT entry:

toml
[userdata]
first_lba = 0x2f3840
last_lba = 0x3d0abfa
lba_bytes = 4096
windows = [
  { name = "OS", component = "OS" },
  { name = "SystemOS", component = "Cryptex1,SystemOS" },
]

first_lba and last_lba come from the GPT entry named userdata on the device. lba_bytes is the logical block size of the partition.

The image size is the sum of the windows, each aligned to 1 MiB, plus the 1 MiB header region. The step rejects an image larger than the partition.

Layout ​

0x000000  SHNGROOT manifest, 4096 bytes, zero padded to 1 MiB
0x100000  OS window, whole disk image
....      SystemOS window, whole disk image

The manifest is little endian:

OffsetField
0SHNGROOT
8version, 32-bit, value 1
12window count, 32-bit
16image size, 64-bit
24window entries, 128 bytes each
4064SHA-256 of bytes 0 to 4063

Each window entry contains a 32-byte name, a 64-bit offset, a 64-bit size, a 32-bit block size, a 32-bit flags field, a 32-byte SHA-256 and 40 reserved bytes.

Flash ​

sh
fastboot flash userdata out/<board>/userdata/userdata-root.img

The driver prints the command in the report. The device repository can provide a wrapper script that checks the image and partition before flashing.

Root selection ​

The kernel mounts the root volume by UUID:

toml
[payload.adt]
root_match_volume_uuid = "00000000-0000-0000-0000-000000000000"

The ADT generator writes a /chosen/root-matching dictionary with IOProviderClass = IOMedia and the UUID. The native block driver publishes the userdata partition, the partition scheme publishes the volumes, and XNU selects the IOMedia with the matching UUID.

Data volume ​

The writable Data volume comes from the Data ramdisk seed in the payload. The seed is an input to the payload step:

sh
./unixnu build payload --data-ramdisk data.img

--skip-setup marks Setup as done in a copy of the seed. The payload report records the seed hash and the resulting image hash. See Skip Setup for the preference changes.

Next steps ​

Released under the BSD-2-Clause-Patent License.