How Amix Boots¶
Amix boots in two distinct worlds glued together at the very front of the disk. At power-on the "Superkickstart 1.4" bootstrap ROM decides whether to bring up AmigaOS or Amix; if it goes the Amix way it runs an AmigaDOS-style bootblock that contains a 68k bootstrap, which in turn loads and decompresses a checksummed Unix kernel into RAM and hands control to it β . The kernel and everything else live in a normal Unix partition layout that is wrapped in the Amiga Rigid Disk Block (RDB) scheme, including a small 2 MB boot partition whose only job is to hold the kernel image where the bootstrap can find it β .
This page traces that path end to end β ROM, bootblock, kernel decompression, the on-disk RDB layout, how the kernel is built and written to the boot partition, and what our own analysis of amix_21_boot.adf actually shows. For the byte-level dissection of the boot floppy see the boot.adf anatomy page; for partition/filesystem detail see filesystems and disks; for how a fresh kernel gets built and installed see kernel build and install.
The short version¶
- Power-on β Superkickstart 1.4 ROM. Default action boots Amix from the SCSI hard disk (or a boot floppy in DF0). Hold the right mouse button at power-on to load the AmigaOS Kickstart instead β .
- Bootblock β 68k bootstrap. The first sectors of the boot device are a valid AmigaDOS OFS bootblock (
DOS\0+ checksum + 68k code) so the ROM is willing to boot them β . - Bootstrap loads + decompresses the kernel. It reads the compressed kernel image, verifies its checksum, decompresses it into RAM, and jumps in. Failure paths print messages like
Kernel file checksum mismatch.β . - Kernel comes up using the 68030 MMU / HAT layer, mounts root, and runs
init.
On a real install, steps 2β4 read from the 2 MB boot partition on the SCSI disk; during installation they read from the boot floppy instead, which carries a special NFS/RPC-capable install kernel (see The install kernel).
Superkickstart and the dual-boot decision¶
Amix machines ship a special bootstrap ROM Commodore called "Superkickstart 1.4" β . It is what decides, at the very first instant of power-on, whether the machine becomes an AmigaOS box or a Unix workstation:
- Default (no button): boot Amix β from SCSI HD if present, otherwise from a boot floppy in DF0 β .
- Right mouse button held at power-on: load the normal AmigaOS Kickstart and boot AmigaOS β .
This is the canonical Amix "quirk" people remember: one machine, one button, two operating systems. It is documented as a hardware/firmware feature of the A3000UX and A2500UX, not something Amix's own software does. See also the quirks checklist and glossary entry for Superkickstart.
Note: The dual-boot choice is made before any disk is read, so it applies equally whether you intend to boot an installed system off the hard disk or a boot floppy.
The bootblock and the 68k bootstrap¶
Once Superkickstart commits to Amix, it boots the boot device exactly the way AmigaOS firmware boots any floppy or RDB-bootable partition: it reads the bootblock, validates the DOS signature and checksum, and executes the 68k code that follows β
.
What makes the Amix bootblock unusual is that there is no AmigaDOS filesystem behind it. The bootblock's 68k code is a self-contained secondary bootstrap; everything after it on the medium is raw bootstrap code plus the (compressed) kernel payload, not files in an AmigaDOS directory tree β . This is why ordinary AmigaDOS tooling can read the bootblock but not "list" the disk β see our evidence below.
The bootstrap's responsibilities:
- Identify and read the boot volume (string
Load boot volume %dβ ). - Locate the compressed kernel image (string
unix.β ). - Verify the kernel's checksum, decompress it into RAM, and transfer control.
What the Kickstart strap actually checks β ¶
Measured with bootblocks that each differ from a good one in a single field, on Kickstart 3.1 and
3.2.x, from DF0 and from an RDB UNI\0 partition behind four controllers (A3000 WD, Gayle IDE, an
A4091 on a 68030 and on a 68060) β the same result in every column β
(emulation; 96 cells):
| Bootblock change | Strap |
|---|---|
magic DOS\1 (any fourth byte) |
accepts β only the three bytes DOS are checked |
magic UNI\0 (the Amix partition's own DosType) or BAD\0 |
refuses: treated as no bootblock |
| checksum off by one | refuses |
| third longword 0 | accepts β not checked |
| last longword (the trailer) 0 | accepts β not checked by the strap (the A3000 SuperKickstart path reads it) |
On refusal, a disk partition gets Kickstart's insert-disk screen; DF0 is skipped and the next boot node is tried β . Holding both mouse buttons from reset opens Kickstart's early-startup boot menu; a lone left button does nothing in the stock chain β . The Z3660's own boot ROM has not been measured this way yet π΄.
A bootblock that returns failure. Behind the Z3660 boot ROM chain, Kickstart raises
AN_BootError and resets the machine about every 14 s instead of trying the next node β
(emulation).
A reset loop like that is unkind to a real 68060 (warm resets are not clean-state resets: quirk 49) π‘, so a loader should
stop and print rather than return to the strap.
Notes for loader writers β
(emulation):
- After a floppy change, trackdisk.device serves its cached track of the previous disk unless
the reader issues CMD_CLEAR and waits for TD_CHANGENUM to move: a naive re-read of block 0 sees
"volume 1" for ever.
- Code running from chip RAM on a 25 MHz 68030 competes with the display for the chip bus: an
inflate loop ran about 7Γ slower and CRC-32 about 25Γ slower than the same code in fast RAM π‘
(emulator chip-bus timing is approximate). For scale, the stock 1.0 LZW boot floppy took 31 s from
reset to the kernel's first prompt on a cycle-exact 25 MHz A3000 model β
.
- The 1992 console programs only OCS/ECS display registers. A loader that opened an AGA screen must
put FMODE, BPLCON3, BPLCON4 and the copper list back to their power-on state before the kernel
starts, or the Amix console comes up garbled on an AGA machine β
(quirk 85).
Booting from CD through an A4091/A4092 boot ROM β ¶
An A4091/A4092 boot ROM that carries a CD filesystem (the project's ROM builds include ODFileSystem;
whether a given release ROM has one must be checked) gives an ISO9660 data disc a boot node of
priority 2 when its System Identifier is AMIGA BOOT or CDTV, otherwise β1 β
(ROM mounter source).
That node has no boot blocks (de_BootBlocks 0) and the CD filesystem's DosType (CD01/CDVD),
so Kickstart boots AmigaDOS from the disc and runs its S/Startup-Sequence; no bootblock ever runs
β
. The ROM takes its RDB path only for a disc with no ISO9660 descriptor β
. The ROM's filesystem
prefers Rock Ridge names, then Joliet, then plain ISO9660, and a file without an owner-execute mode
gets no execute bit, so AmigaDOS refuses to run it β
. An installed disk at boot priority 2 ties with
the disc and wins; pick the CD from the early-startup menu β
(emulation).
That is how the amigaux 1.1 install CD boots Amix: the startup-sequence runs the project's second-stage loader built as an AmigaDOS program, which loads the kernel and a compressed miniroot as plain files and takes the machine over; AmigaOS is the carrier for about two seconds β (emulation; see loadable kernel modules). A machine without such a ROM boots the floppy pair instead.
Kernel decompression and checksum verification¶
The on-medium kernel is compressed and checksummed; the bootstrap decompresses it at boot time rather than loading a flat executable β
. We have since reverse-engineered the exact format: the kernel is a standard Unix compress (.Z, LZW -b16) stream at offset 0x2800 that decompresses to a 1,171,200-byte m68k ELF β
, and the checksum is a 16-bit folded sum whose mismatch is non-fatal (the bootstrap warns and boots anyway) β
. Full method, evidence, and the rebuild recipe: Reverse-Engineering the Boot Floppy. The diagnostic strings embedded in amix_21_boot.adf map the steps one-to-one:
| Embedded string β | Meaning |
|---|---|
Load boot volume %d |
Bootstrap is selecting/reading the boot volume |
Decompression failed! |
The compress/LZW kernel could not be unpacked (fatal) |
WARNING! Kernel decompression overrun. |
Decompressed image exceeded its expected size |
WARNING! Kernel file checksum mismatch. |
16-bit folded checksum differs β non-fatal; boots anyway |
Kernel may have been corrupted. |
Follow-up to a checksum/decompression failure |
hat_vtokp_prot: user addr in kernel space |
An SVR4 HAT/MMU panic message (kernel is now running) |
A raw binwalk scan finds no clean ELF header β only noise / false-positive hits β not because the format is opaque, but because binwalk doesn't flag a .Z stream; decode it in one step with tools/extract-kernel.sh β
. The hat_vtokp_prot HAT panic string (readable once decompressed) confirms the payload is a real SVR4 kernel using the 68030 MMU / HAT layer.
On-disk layout: the RDB and the partition table¶
An installed Amix disk uses the Amiga Rigid Disk Block (RDB) partitioning scheme β the same on-disk metadata format AmigaOS uses to describe a SCSI/IDE drive's geometry and partitions β . Amix slots its Unix partitions into RDB partition entries so the Superkickstart ROM can find and boot them.
The installer's default partition layout is four partitions β :
| Partition | Purpose | Notes |
|---|---|---|
/ (root) |
Root filesystem | s5 or UFS; installer defaults to s5 (prompt [s5], empty input β s5) β
, UFS recommended π‘ but must be typed |
| swap | Paging/swap | Larger when the disk is bigger than BREAKPT=120 MB β
|
| boot | Holds the bootable kernel image | 2 MB, fixed by BOOTSIZE (see below) β
|
| data | Remaining user space | Keep partitions β²1 GB π‘ |
Warning: The tape must be at SCSI ID 4 β hard-coded as the literal /dev/rmt/4h in the install scripts β
. The disk is ID 6 by convention: the installer prompts for the disk target and templates the boot partition from it (BPART=/dev/dsk/c${SCSI}d0s${BOOTPART}), so any target works, but the chosen ID is then baked into the device names in /etc/vfstab π‘. The old "keep Fast RAM β€ 16 MB, more mis-maps the SCSI drive" warning had the wrong mechanism: on the stock kernel a bigger A3000 motherboard bank loads the kernel below 0x07000000 and the internal SCSI is never registered (quirks Β§57) β
; kernels that probe for it run 64 MB, the 040/060 kernels 128 MB; see the RAM ceiling for the real, describable-RAM limit. All covered in hardware and the quirks checklist.
The RDB partition type IDs Amix stamps on each partition (via /etc/rdb -F) are now read directly from the installer script β
: boot 0x554e4900 (UNI\0), UNIX root 0x554e4901 (UNI\1), swap 0x72657376 (resv). The installer's own comment notes the Kickstart 2.04 boot-priority algorithm requires the bootable UNIX partition to be type 0x554e4900. Full decode on the root floppy anatomy page.
The 2 MB boot partition and BOOTLEN¶
The boot partition is intentionally tiny and exists only to hold the kernel image where the bootstrap can reach it. Its size is fixed by the installer at 2 MB, and the block count is derived from that β :
# From the root.adf install scripts (β
):
BOOTSIZE=2 # boot partition size in MB
BOOTLEN=$((BOOTSIZE * 2048)) # length in 512-byte blocks => 4096 blocks
So BOOTLEN = BOOTSIZE * 2048 = 4096 blocks of 512 bytes = 2 MB β
. This is the partition that make bootpart writes the kernel into (next section). It is separate from the AmigaOS-readable bootblock concept on the floppy β on the hard disk, the RDB marks this partition bootable and the ROM bootstrap reads the kernel out of it.
From kernel source to a bootable partition¶
Stock Amix is a monolithic SVR4 kernel with no loadable modules (one third-party exception) β drivers are statically linked in β so installing a new kernel (or a kernel with an added driver) means relinking /unix and rewriting the boot partition β
. The flow, from the Ditto driver paper and the modern driver repos:
# 1. Build the kernel in the kernel source tree.
cd /usr/sys
make # produces the kernel image
# 2. Stage it, then write it to the 2 MB boot partition.
cp relocunix /stand
cd /stand
make bootpart KERNEL=relocunix
# 3. Reboot into the new kernel.
shutdown -i6
rdbunix vs relocunix (a historical rename) π‘¶
The name of the kernel image changed over the life of the project:
- The 1990 Ditto paper calls the built kernel image
rdbunixβ (as cited in the paper). - Amix 2.1 systems and the modern driver repos call it
relocunixβ , and themake bootpartinvocation ismake bootpart KERNEL=relocunixβ .
Treat this as a historical rename and verify per version β rdbunix for the 1990-era toolchain, relocunix for 2.1 π‘. The hydra driver builds natively and relinks the kernel with make force (elf2brel converts the kernel to boot format in the process); see kernel build and install and the hydra case study.
Note: Always keep the old working /unix (or boot partition image) as a fallback before writing a freshly built kernel β a broken boot partition means a machine that won't come up β
.
The two boot2 lineages and the D245/RELA trap¶
The 2 MB boot partition's secondary loader (boot2, an 8192-byte blob at slice offset +0x600
inside the boot1|IBLK|boot2|IBLK|unix chain) exists in two incompatible lineages, and only
one of them can boot modern rebuilt kernels β
:
- The name-based boot2 (sha256
5ab360b1β¦; embedded strings.uvblock .kvsysseg .kvsegmap .kvsegu,"Text and data not contiguous!") resolves kernel sections by segment name. It is what the Amix 2.1 SVR4 installer lays down on every from-scratch install, and it cannot relocate standard flags-based ET_REL kernels (sections classified bySHF_EXECINSTR/WRITE/ALLOC) β it firesAlert('RELA'|AT_DeadEnd)= the D245 4C41 guru before the kernel ever runs β . - The flags-based boot2 (sha256
f287ff3aβ¦; string"No .text, .rodata, or .data!"), built from the sysroot sources, relocates flags-classified kernels cleanly β .
The D245/RELA gurus seen on hard-disk-deployed rebuilt kernels were caused by the foreign on-disk loader, not by the kernel's relocation records: a single-variable splice β replacing ONLY the 8192-byte boot2 (plus its recomputed IBLK checksum) in a byte-identical copy of a D245-failing disk β made the same kernel relocate and execute, reproduced in under 30 s on the bench and then validated 5/5 on the real A4000+Z3660 β .
Scope nuance: the hard-disk bootpart frames the raw ET_REL kernel (makeiblk; no
elf2brel) β the brel/e_type 0xff00 conversion is the boot-floppy path only. A raw
cross-linked ET_REL does not inherently D245 on the hard-disk path; under a name-based boot2 it
always does β
. Because core-2.1.pkg ships the name-based loader inside the stock file set,
any freshly installed system inherits this trap β the modern build pipeline laminates the
flags-based boot2 into /stand/boot2.boot and gates the whole chain with bootchain-verify.py
(see kernel build and install) β
.
Reframing the boot partition on a live system (upgrading the kernel) β ¶
The machine boots the kernel out of the raw UNI\0 boot slice, never /stand/unix β the /stand files are only the framing sources. So swapping in a new kernel means two steps: land the new /stand/unix (and, if it changed, /stand/boot2.boot), then reframe the boot slice β a pkgadd of a kernel package alone changes nothing bootable. The full live cycle was proven end-to-end (upgrade β reframe β cold-boot the new kernel) β
, and the operational details are not obvious:
/stand/CONFIGis absent on an installed box, so stockmake bootpartcannot run β drive the pipeline directly with the slice device supplied explicitly:makeiblkmust be invoked as./makeiblk(it is not onPATH), and the stock/stand/makeiblkis byte-for-byte conformant with the boot-chain contract β no re-implementation needed. The bootpart consumes an ELF ET_REL kernel uncompressed (ib_fullsize=0);elf2brel/compression is the floppy path only.- The flags-based
boot2.boothas a fixedsum -rfingerprint of14193β verify it before writing, because the name-based loader D245s (previous section). - After the
dd,syncand read the slice back to confirm the write landed.
Telling which kernel is actually running (there is no uname field for it): the SVR4 banner reads 2.1c for a cdfs-carrying kernel vs 2.1 for one without, and mount -F cdfs returns errno 22 (the GETFSIND lookup fails) when cdfs is not in the kernel β reliable in that direction β
.
The positive half of that probe is stale. β It used to be "
errno 5means cdfs is present", and that worked only becausecdfswas laundering four different failures into one errno. That was root-caused and fixed, so on a current cdfs kernel the value depends on the media state instead β one live probe of a no-media mount returnederrno 25π‘ (single observation). Read the negative (22= absent), or ask directly withsysfs(GETFSIND, "cdfs"), which is unambiguous both ways. Full account on filesystems and disks.
First boot: the whole stock setup dialog hangs on one exec bit β ¶
The stock first-boot node-name/timezone dialog is gated by a single mode bit. /etc/inittab runs /etc/sysinit at sysinit, which runs /usr/amiga/bin/system.setup iff that file is executable; system.setup ends by chmod -x-ing itself β that exec bit is the stock once-only mechanism. So an unattended/automated install disarms the interactive dialog simply by chmod -x /usr/amiga/bin/system.setup (mode only β the package content, and therefore the package database, is untouched) and drops its own additive /etc/rc2.d/S?? hook to bake identity. Proven across two cold boots: no dialog, identity applied exactly once β
.
Two disks: the boot priority picks the loader, the kernel picks the root¶
With more than one bootable disk attached, two different rules decide what happens, and they are easy to conflate:
- Which disk's boot code runs β AmigaOS's rule β
. The Kickstart strap runs the bootblock of the
highest-priority bootable node: boot ROMs register each bootable partition with
expansion.library'sAddBootNodeusing its RDB boot priority (de_BootPri), and ties go by the order the nodes were added. The Z3660's own boot ROM does the same β it reads each partition's bootable flag and priority from the RDB (non-bootable =-128) and callsAddBootNodewith it (Z3660 sources,scsi/scsi.candz3660-drivers/scsi/bootrom.asm). - Which filesystem becomes
/β the kernel's rule β . Amix'sboot1(stockamiga/boot/boot1.c) reads the info block andboot2through the strap's own I/O request, i.e. from the node AmigaOS chose, andboot2(boot2.c) loads the kernel sector by sector through the same request. Neither rescans, neither looks at priorities or units, and neither prefers a miniroot; thebootinfoblock handed to the kernel has no boot-device field at all (bootinfo.h). The public port's 68040/68060 loader changes (copyit.s,rel.c) do not touch any of this. So on a stock kernel β and on the project's kernels before the amigaux 1.0 (r6) release, below β the root comes solely from the kernel's compiled-inrootdev(below) β for example a kernel stampedc6d0s1(card 0, SCSI unit 6, slice 1;rootdev0x00480016).
Consequence on those kernels β
(measured 2026-10-03, A4000T + Z3660, the card's own boot ROM): with an installed
disk at unit 0 (UNIX_Boot priority 2) and an installer disk at unit 6 (priority 1), both carrying
the same c6d0s1 kernel, AmigaOS booted the higher-priority unit-0 node β and the system that came
up was the installer's miniroot at unit 6, because that is where the kernel's root points. The
boot priority chose whose copy of the kernel loaded, not which disk Amix ran from.
Rules (stock and pre-r6 kernels): an installed disk must sit at the unit its kernel is stamped
for. Booted alone from any other unit, its kernel looks for root at the stamped unit and finds
nothing there, so the root mount fails (ENXIO) π‘ (follows from the source; not separately
measured). With two bootable Amix disks attached, decide by unit, not by priority β or attach
one at a time.
The 1.0 (r6) kernels root the disk they were booted from¶
In the amigaux 1.0 kit the boot loader tells the kernel which disk it was started from, and the kernel roots that disk, so an installed disk boots from any unit β (the 1.0 release notes). A system whose root sits where the boot ROM cannot start it β a disk behind an A4092, whose ROM does not offer Amix partitions to Kickstart β boots from a small disk on the Z3660 that carries a root record naming the root disk. One console line at every boot says which root was used and why:
Without a usable hint the kernel falls back to its built-in root (Z3660 unit 6). A valid hint that
names an empty unit fails the mount by design, so the kernel never boots a disk you did not install
to; /sbin/bcheckrc takes the root from the mounted disk, not from /etc/vfstab. On metal, a disk
installed to unit 3 rooted c3d0s1, the same disk moved to unit 2 rooted c2d0s1, and a disk
behind an A4092 rooted c9d0s1 through its root record π‘ (one A4000 + Z3660; first-party record,
2026-10-11).
Finding the boot node from a loader: fssm_Device counts its NUL β
¶
A loader that wants to know which node it was booted from walks expansion.library's
eb_MountList. Each BootNode's bn_DeviceNode (BootNode offset 16) points to a DeviceNode, whose
dn_Startup (offset 28, a BPTR) points to a struct FileSysStartupMsg (NDK dos/filehandler.h) β
:
| Offset | Field | Type |
|---|---|---|
| 0 | fssm_Unit |
ULONG |
| 4 | fssm_Device |
BSTR (the exec device name) |
| 8 | fssm_Environ |
BPTR to a DosEnvec |
| 12 | fssm_Flags |
ULONG |
The strap opens the boot device from that message as a C string. In Kickstart 3.2.3
(A4000.47.115, $FD3F3Eβ$FD3F54) it loads fssm_Unit and fssm_Flags, turns fssm_Device into
a C-string pointer (BADDR + 1) and calls exec OpenDevice; it never reads the BSTR length β
(3.2.3; other releases are expected to be identical but were not read π‘).
The length byte of a MakeDosNode()-built fssm_Device counts the terminating NUL; dn_Name's
does not β
. MakeDosNode() (LVO β144) copies both C strings of its parameter packet into BSTRs
whose length excludes the NUL, then runs addq.b #1,(a0) on the device name's length byte only. A
boot node for foo.device therefore carries a length of 11, not 10, with the NUL as the last counted
byte. Read in full in Kickstart 3.2.3 (A4000.47.115: MakeDosNode at $F849FC, the addq.b at
$F84A78) and 3.1 r40.68 (A4000: $FCA6E4 / $FCA760).
- Scope β
: all 52 checked 512 KiB Kickstart images that carry
expansion.libraryhave the samemovea.l 4(a2),a0/bsr(the BSTR copy) /addq.b #1,(a0)sequence inMakeDosNode. They span 2.0 (r36.141) through 3.2.3 (47.115) on the A500+, A600, A1200, A3000, A4000, A4000T, CD32 and CDTV. The 256 KiB 1.x (V34) images were not checked π‘. - Consequence for a loader β
: compare
fssm_Devicewith a device's execln_Nameas a C string, so that a NUL inside the counted length ends the name (as the strap does). A compare over the full BSTR length reads one byte pastln_Name's NUL and passes or fails on whatever the driver stores there. The Z3660's SCSI driver stores its id string right after its name (z3660_scsi.device\0Z3660SCSI 1.5 β¦, inz3660_scsi.romandz3660_scsi.device) β , so on that driver such a compare never matches.
Booting Amix with root on an A4091 (and the rootdev dispatch trap)¶
Getting Amix to mount root on a Commodore A4091 (53C710) SCSI controller β a Zorro III board Amix shipped with no driver for β turned out to hinge not on the driver but on how the kernel turns the compiled-in root device number into a SCSI card. This section documents that dispatch path and the panic it produced. All findings here were reproduced locally in Amiberry on the real Amix 2.1c distribution unless tagged otherwise.
Where the root device comes from: /stand/CONFIG β rootdev¶
The root device is compiled into the kernel, not discovered at boot (on stock kernels; the 1.0 kernels add a boot-disk hint β above). It is declared in amiga/config/unix.c and fed from the system configuration (/stand/CONFIG) via -DROOTDEV β
:
A concrete config variant (amiga/config/c6s1unix.c) spells out the device numbers it builds β
:
#define C6D0S1 makedevice(18, 22)
dev_t rootdev = C6D0S1; /* root on card 0, target 6, slice 1 */
struct bootobj swapfile = { "", "/dev/dsk/c6d0s2", ... }; /* swap */
So rootdev = c6d0s1 = makedevice(18, 22) (block major 18, minor 22), and swap is c6d0s2. The cN in a device name is computed, not stored: cN = sdcard * 8 + sdunit β so c6d0s1 decodes to card 0, target 6, slice 1. The minor-number fields are decoded in amiga/alien/sd.h β
:
#define SDCARDS 2
#define sdunit(dev) ((dev)>>0 & 07) /* SCSI target id 0-7 */
#define sdcard(dev) ((dev)>>3 & 01) /* card index (queue[] slot) */
#define sdpart(dev) ((dev)>>4 & 07) /* slice/partition */
The sdcard field is the index into the SCSI driver's per-card queue table (only 0 or 1; SDCARDS = 2). Which physical board ends up at card 0 vs card 1 is decided at first root open β and that is exactly where the A4091 boot trap lived. For the full /dev major/minor scheme see the device list reference.
π΄ The mountroot panic was a dispatch bug, not a driver bug¶
π΄ A misleading signature: booting an A4091-only machine panicked at vfs_mountroot with s5mountroot VOP_OPEN error 5. It looks like an early-boot driver / sptalloc-timing problem β the 53C710 driver unable to read the disk that early in boot β but it is not: the A4091 driver reads perfectly post-boot (rc=0), and the panic produced zero driver diagnostics β meaning the driver was never called at all. β
π΄ What it actually is β the phantom A3000. autocon() (amiga/kernel/support.c) hardcoded a phantom A3000 internal SCSI at 0xDD0000 whenever the kernel's own end address lies above 0x07000000 β i.e. whenever the loader placed the kernel in the A3000's top motherboard bank (quirks Β§57) β regardless of whether that hardware exists β
:
sd.c init()/insert() sorts cards ascending by board base address. The phantom's 0xDD0000 sorts before the A4091's 0x40000000, so:
queue[0]= card 0 = phantom A3000 (no hardware) βa3091queuequeue[1]= card 1 = A4091 βa4091queue
The compiled-in rootdev = c6d0s1 decodes to sdcard = 0, so the kernel sent the root read to the non-existent A3000 (a3091queue, no hardware) β EIO β panic β never reaching a4091queue (which is why there were zero A4091 driver lines on the panic). β
This is documented in the Zorro III autoconfig page, which covers autocon() and the phantom-A3000 special case.
β
The fix. The phantom is replaced by a chipset-gated WD33C93 probe that makes the A4091 card 0 when no real A3000 SCSI is present. With the A4091 at card 0, the compiled-in rootdev = c6d0s1, swap = c6d0s2, and /etc/vfstab all resolve to the A4091, and Amix boots fully from the A4091 β root read/write, swap active, multi-user. β
See the detection logic on the Zorro III autoconfig page.
How the kernel picks the root filesystem β by probe, not by configuration¶
The Amiga port ships rootfstype as the empty string β
β where AT&T's generic SVR4 configuration names s5, Amix names nothing and lets the kernel try them all. vfs_mountroot therefore walks the vfssw[] table in order, asking each filesystem in turn to mount the root device, and takes the first that succeeds β
. s5mountroot declines politely with EINVAL when the device is not an s5 filesystem, so the walk continues rather than stopping β
; ufs sits at vfssw[2] in every kernel examined here, install kernels included β
.
Three consequences worth carrying:
- You cannot tell a disk's filesystem from the kernel's configuration, because the kernel does not know it either. A UFS-rooted disk and an s5-rooted disk boot the same kernel unchanged.
s5mountrootappearing in a boot message says nothing about the disk. It is simply the probe that ran first β see the panic below.- A genuine device failure looks like "no filesystem matched", because every probe fails for the same reason and the walk runs off the end of the table.
The mountroot fstype probe sequence¶
The panic surfaces through that same probe walk. The full console sequence is β :
s5mountroot VOP_OPEN error 5
WARNING: nfs_mountroot called
PANIC: vfs_mountroot: cannot mount root: errno 89
The first message comes from the s5 probe, the second from the nfs fallback, and errno 89 (ENOSYS/no more fstypes) is the final give-up. The important point for diagnosis: the EIO is a genuine device read failure (VOP_OPEN error 5 = EIO), surfaced by whichever fstype happens to probe first β not a filesystem-format mismatch. The real root filesystem is ufs, confirmed by /etc/vfstab β
. Seeing s5mountroot in the message does not mean the disk is s5; it means s5 was simply the first probe to hit the dead device. The VOP_OPEN error 6 (ENXIO) variant means the root device could not be opened at all, for example no controller at the root's card index, while error 5 (EIO) means it opened and the read failed β
.
The install kernel on boot.adf¶
During installation the kernel does not come from the hard disk's boot partition β it comes from the boot floppy (amix_21_boot.adf) in DF0. That floppy carries a special NFS/RPC-capable install kernel β
: alongside the decompression/checksum strings, the bootstrap region contains a full RPC/NFS client string table, consistent with an installer that can pull the distribution over the network as well as from tape. The normal end-to-end install sequence (boot floppy β s5 miniroot on root.adf β tape at SCSI ID 4 β make bootpart β reboot) is described in filesystems and disks and the install walkthrough.
What the real boot.adf actually contains¶
Everything below is reproduced from our own read-only analysis of amix_21_boot.adf using tools/inspect-adf.sh β
. (The ADF itself is proprietary Commodore material; obtain it from amigaunix.com or archive.org β do not commit it.)
Run the inspector against your own copy:
What it reports, and what each finding means:
- It is a valid AmigaDOS OFS bootblock. The first bytes are
44 4f 53 00=DOS\0, followed by the bootblock checksum and 68k bootstrap code β so the Superkickstart ROM is willing to boot it β . - There is no AmigaDOS filesystem.
xdftool listfails withInvalid Root Block @880, because the disk is bootblock + raw bootstrap + payload, not an AmigaDOS directory tree β . - The kernel is a Unix
compress(.Z, LZW) stream at0x2800that decompresses to a 1,171,200-byte m68k ELF; its 16-bit checksum is non-fatal (warns, boots anyway). Decode it withtools/extract-kernel.shβ . - It is an NFS/RPC install kernel. A full NFS/RPC client string table and the
hat_vtokp_prot: user addr in kernel spaceHAT/MMU panic string are present (readable once decompressed) β . binwalkshows only noise β not because the format is opaque but because it doesn't flag.Z; the stream decodes cleanly to ELF β .
For the full byte offsets, the equivalent root/patch-disk findings, and how to read the inspector output, see the boot.adf anatomy page.
See also¶
- Loadable kernel modules β the 1.1 loader that reads generations, and its CD and floppy paths.
- Anatomy of the boot ADF β byte-level dissection of
amix_21_boot.adf. - Filesystems and disks β RDB, s5 vs UFS, swap, and the full partition story.
- Kernel architecture β the monolithic SVR4 kernel, HAT/MMU layer, switch tables.
- Kernel build and install β
makeβrelocunixβmake bootpartin detail. - Hardware and requirements β Superkickstart ROM, SCSI ID 6/ID 4, the RAM envelope.
- Quirks checklist β the dual-boot button and other surprises in one place.
- Emulation Fidelity β the 68030 bus-error-frame semantics the demand-paging boot leans on, and the SCSI INT2 bootstrap-latency gotcha.
- Install walkthrough β running the whole flow under emulation.
- The A4091 (53C710) SCSI driver β the driver behind the root-on-A4091 boot.
- Zorro III autoconfig and
autocon()β the phantom-A3000 special case and the chipset-gated A4091 detection. - Device list reference β the SCSI
/devmajor/minor scheme behindcN d0 sN.
Sources¶
-
Stock sources, public β β the stock bootstrap in
amigaux/amix-system(7cba961):usr/sys/amiga/boot/boot1.c,usr/sys/amiga/boot/boot2.c,usr/sys/amiga/boot/bootinfo.h,usr/sys/amiga/boot/bootdata.h. -
The boot node vs root split (2026-10-03) β β the stock
amiga/boot/boot1.c(main(iob, β¦),readblocks(iob)for the info block andboot2),boot2.c(every read through the sameiob),bootinfo.h/bootdata.h(no boot-device field), read from a stock 2.1c source tree; the Z3660 sources (scsi/scsi.c: per-partition bootable flag and RDB priority,-128when not bootable;z3660-drivers/scsi/bootrom.asm:MakeDosNode+AddBootNodewith that priority); and a first-party A4000T run with two bootable disks on the Z3660 boot ROM (first-party record, 2026-10-03). - The
fssm_DeviceNUL count (2026-10-07) β β disassembly ofexpansion.libraryMakeDosNode(LVO β144) and of thestrapresident in Kickstart 3.2.3 (A4000.47.115) and 3.1 r40.68 (A4000), plus a mechanical check of the same three-instruction sequence across 52 Kickstart images from 2.0 to 3.2.3 (first-party record, 2026-10-07; ROM releases, offsets and instruction names only); thestruct FileSysStartupMsglayout from NDKdos/filehandler.h(theexpansion.library/MakeDosNodeautodoc documents the parameter packet, not the NUL count); the Z3660 driver binariesz3660_scsi.rom(data at ROM offset$21AC) andz3660_scsi.devicefor the bytes after the device name. - The 2026-09-29 stock-kernel RAM-layout measurement β
β on the emulated bench the same 64 MB A3000 motherboard bank boots a kernel that probes for the A3000 SCSI and stops the pinned stock kernel at
s5mountroot VOP_OPEN error 6(no card 0), symbolised against the stockautocon()load-address guess (first-party record, 2026-09-29; quirks Β§57). - The two boot2 lineages (first-party record, 2026-07-15/16): single-variable boot2 splice, loader forensics (sha
5ab360b1β¦vsf287ff3aβ¦), bench + 5/5 metal validation 2026-07-15. - The 1.0 (r6) root selection β
β Installer-NG (not public)
docs/release-notes-amigaux-1.0.md("One kernel per driver family; any target disk at install", "Installing from CD, and onto a disk behind the A4092": the boot-disk hint, theRTH1console line, the built-in fallback, the root record,/sbin/bcheckrc); the metal rootsc3d0s1, moved-diskc2d0s1and A4092c9d0s1on one A4000 + Z3660 (first-party record, 2026-10-11) π‘. - Research brief Β§3 (Boot process & disk layout) and Β§10 (boot.adf anatomy),
sources/research-brief.md. amix_21_boot.adfanalysis viatools/inspect-adf.sh:DOS\0OFS bootblock, failedxdftool list(Invalid Root Block @880), kernel decompression/checksum strings, NFS/RPC string table,hat_vtokp_protHAT panic string, no clean ELF.amix_21_root.adfinstall scripts (viatools/inspect-adf.sh):BOOTSIZE=2,BOOTLEN=BOOTSIZE*2048,BREAKPT=120,BPART=/dev/dsk/c${SCSI}d0s${BOOTPART}. The root-filesystem prompt is[s5]and empty input selects s5;ANS="ufs"appears only as a case branch reached when the user typesufs(corrected 2026-07-19 β previously recorded here as the default).- Michael Ditto, Writing Amix Device Drivers, 1990 European Amiga Developer's Conference (the
rdbunixkernel image name; statically linked monolithic kernel;makein/usr/sys). - Modern driver repos for the
relocunix/make bootpart KERNEL=relocunixflow: https://github.com/asokero/va2000-amix, https://github.com/isoriano1968/hydra-amix. - amigaunix.com (Superkickstart dual-boot via right mouse button, hardware requirements): https://www.amigaunix.com/.
- The A4091-on-Amix project, amix-a4091 β its
README.md(root on the A4091; the phantom-A3000 that stole card 0, reproduced locally β ) andsrc//tools/. amiga/config/unix.c(rootdev = ROOTDEV,-DROOTDEV) andamiga/config/c6s1unix.c(C6D0S1 = makedevice(18,22), swapc6d0s2);amiga/alien/sd.h(SDCARDS,sdunit/sdcard/sdpartmacros).- amix-a4091
src/kernel-patches/support.c.patchβ theautocon()phantom-A3000 heuristic replaced by the chipset-gated WD33C93 probe;driver.confβ the0x02020054 a4091queuerow, from which the build harness generates thesd.cregistry entry;src/a4091-wr.cβ the 53C710 READ+WRITE driver. - a4091.device open-source project: https://github.com/A4091/a4091-software (A4091 autoboot ROM + SCRIPTS assembler).
- The RAM-ceiling measurements (first-party record, 2026-08-12/14) β
β root-filesystem selection is by probe, not by configuration: the Amiga port ships
rootfstypeempty (AT&T generic sayss5),vfs_mountrootwalksvfssw[],s5mountrootreturnsEINVALpolitely so the walk continues, andufssits atvfssw[2]in every kernel including the install kernels. Same source for thecdfserrno de-laundering that makes the olderrno 5probe stale; the π‘ no-mediaerrno 25value is a single live probe (first-party record, 2026-08-14/15), carried unchanged. Cross-checked against thevfs_mountrootdisassembly recorded on building a kernel. - The Installer-NG install work (first-party record, 2026-07-22/24; not public) β a blank-diskβbootable-install effort that root-caused these platform behaviours on the Amiberry bench and the real A4000+Z3660 (acceptance-run captures, s5/UFS state reads, and the on-metal digest attestation) β (π‘ where tagged).
- The bootblock-strap measurement and the loader's failure path:
amigaux/amixkernel/dlm/docs/measurements/2026-10-26-m-ld1-m-ld3.md(96 emulated cells, Kickstart 3.1 and 3.2.x) β ; the CD-boot node facts:kernel/dlm/docs/spec/10-boot-loader.mdΒ§4.4, read from the A4091 ROM's mounter source (3rdparty/mounter/mounter.cin the a4091-software tree) β ; the trackdisk cache, the chip-RAM timings, the 31 s LZW reference, the AGA display state and the AN_BootError loop:kernel/dlm/CHANGELOG.md2026-10-25 entries and the kernel-module campaign (first-party record, 2026-10-25) β .