Skip to content

Boot payload ​

The payload is a FAT volume that becomes the ramdisk of the Android boot image. UniXNU reads the configuration from it, and DarwinBoot reads the kernel, the ADT and the optional trust cache from it.

Volume layout ​

/EFI/UniXNU/unixnu.toml
/EFI/UniXNU/Payloads/kernel.macho
/EFI/UniXNU/Payloads/kernel.macho.adt
/EFI/UniXNU/Payloads/kernel.macho.trustcache
/EFI/UniXNU/Payloads/scratch-data.img

The payload step writes the volume with mformat and mcopy. Timestamps are fixed at 1980-01-01, so the volume is reproducible for the same inputs. The ADT contains a random seed, so two payload builds differ.

Configuration ​

The payload step writes this configuration:

toml
version = 1

[boot]
timeout = 3
default = "xnu"

[kits]
autoload = false

[[entry]]
id = "xnu"
title = "UniXNU"
type = "xnu"
path = "Payloads/kernel.macho"
initrd = "Payloads/scratch-data.img"
args = "-v serial=3"

initrd is present when a Data seed is supplied. args is the joined [payload] kernel_args and --kernel-arg values.

ADT sidecar ​

The ADT uses Apple's flattened node encoding. The board script named in [payload.adt] tool generates it. The payload step calls the tool with:

OptionSource
--outputPayloads/kernel.macho.adt
--dram-size[payload] dram_size
--owned-memory-size[payload.adt] owned_memory_size
--root-match-volume-uuid[payload.adt] root_match_volume_uuid
--chip-id[payload.adt] chip_id
--cpu-regs[payload.adt] cpu_regs
--psci-method[payload.adt] psci_method
--unique-chip-id--unique-chip-id or UNIXNU_UNIQUE_CHIP_ID
--packed-data-ramdisk[payload.adt] packed_data_ramdisk
--data-ramdiska Data seed without packed delivery
--trust-cachea trust cache bundle
--ipad-identity[payload.adt] ipad_identity

The ADT must reserve the following properties when the matching input exists:

PropertyPurpose
/chosen/memory-map/RAMDiskDarwinBoot writes the ramdisk address and size
/chosen/memory-map/PackedRAMDiskDarwinBoot writes the packed ramdisk address and size
/chosen/memory-map/TrustCacheDarwinBoot writes the trust cache address and size
/chosen/darwinboot-memory-sizeRequests a contiguous window larger than 256 MiB

DarwinBoot requires the placeholder to exist for every input it receives. A mismatch is EFI_COMPROMISED_DATA.

Kernel arguments ​

The payload checks the command line before writing the volume:

  • Every argument matches [A-Za-z0-9_.\-]+ with an optional =value of [A-Za-z0-9_.,\-]+.
  • The joined line is at most 1000 bytes. DarwinBoot copies it into a 1024-byte buffer.

The command line is stored in unixnu.toml as args. DarwinBoot copies it into boot_args without modification.

Trust cache ​

The trust cache bundle is validated by DarwinBoot:

  • A 32-bit count from 1 to 128.
  • One offset table entry per cache.
  • Every cache starts with version 2.
  • Every entry is 24 bytes.
  • Every hash type is 1 to 4.
  • Hashes are sorted in ascending order.

The bundle is copied into the kernel window and its address and size replace the TrustCache placeholder.

Data ramdisk ​

A Data seed can be delivered in two forms:

FormADT placeholderBehavior
DenseRAMDiskDarwinBoot copies the whole image
PackedPackedRAMDiskDarwinBoot validates the DBRDISK1 extent table and copies the extents

The packed form carries a header with the magic DBRDISK1, version 1, the page size, the expanded size and an extent table of (offset, length) pairs. Omitted ranges are zeroed RAM.

Determinism ​

The boot image is deterministic for a given firmware volume, device tree and ramdisk. The ADT random seed makes each payload build differ. The payload report records the kernel, ADT, trust cache, Data seed and payload hashes.

Next steps ​

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