# The release ISO — flashable boot media `zig build release-x86-64` produces **`zig-out/danos-x86-64.iso`**, the file you hand to someone who wants to try danos on a real machine: point [balenaEtcher](https://etcher.balena.io) (or Raspberry Pi Imager, or plain `dd`) at it, flash a USB stick, and boot the stick. The same file also burns to optical media. `zig build check-iso-image` validates it without booting. ``` zig build release-x86-64 # Etcher: select danos-x86-64.iso → select the stick → Flash # or: sudo dd if=zig-out/danos-x86-64.iso of=/dev/rdiskN bs=4m (macOS; triple-check N) ``` ## Why an ISO when danos-usb.img already boots `danos-usb.img` is a raw FAT32 **superfloppy** — a filesystem starting at sector 0, no partition table. UEFI firmware accepts that from a USB stick (it probes whole-disk FAT before giving up), which is why `dd`-ing the .img works and why QEMU and the test harness boot it directly. But it is a developer-shaped artifact: flashing apps expect an ISO, and a superfloppy can't be burned to a CD/DVD or carry a partition table for pickier firmware. The ISO wraps that same FAT image — bit-identical, built by the same `tools/make-fat-image.py` — in a container that boots everywhere release media gets consumed. One payload, two images: the .img stays the raw volume the QEMU harness mounts and boots, the .iso is what leaves the building. ## How a hybrid ISO boots twice The trick (the same one Linux distribution ISOs use, usually via `xorriso -isohybrid…`) is that ISO9660 reserves its first 32 KiB as a **system area** it never touches — exactly where an MBR lives on a disk. So one file can carry two tables of contents, both pointing at the same embedded FAT image: * **Flashed to USB (Etcher, dd):** firmware sees a disk whose sector 0 is an MBR with one partition of type `0xEF` (EFI System Partition) covering the embedded FAT image. It mounts that ESP and runs `\EFI\BOOT\BOOTX64.efi` — the standard removable-media path ([efi.md](efi.md)). * **Burned to optical media:** firmware reads the ISO9660 volume descriptors at sector 16 and finds an **El Torito** boot record. Its catalog has one entry, platform ID `0xEF` (EFI), whose start LBA is — again — the embedded FAT image. The firmware exposes that image as a virtual disk and runs the same `BOOTX64.efi` off it. Neither path involves the legacy BIOS boot-sector machinery: danos is UEFI-only ([system-requirements.md](../system-requirements.md)), so the MBR holds no boot code, just the partition entry, and the El Torito entry is EFI-class, not floppy emulation. One El Torito wrinkle: the catalog's sector-count field is 16-bit (units of 512 bytes), so it can name at most 32 MiB — less than the 64 MiB FAT image. That is fine in practice: firmware sizes the FAT filesystem from its own BPB, and the boot files sit in the first few MiB of the image (clusters are allocated from the front) either way. The USB path has no such cap. ## The builder `tools/make-iso-image.py` follows the house rule of [make-fat-image.py](../../tools/make-fat-image.py): pure Python 3 standard library, no external tools (no xorriso, mkisofs, or isohybrid), with a `--verify` mode the `check-iso-image` step runs — it checks that the MBR partition and the El Torito catalog agree on where the FAT image lives and that a FAT32 boot sector is actually there. Every timestamp field in the ISO is zeroed, so the build is reproducible byte-for-byte. The ISO9660 filesystem around the boot machinery is minimal but real: a root directory listing `BOOT.CAT` (the catalog) and `EFI.IMG` (the FAT image), so `file`, mount tools, and archive browsers can open the ISO and see what's in it.