Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

IRIX 7 — Boot Protocol (ROM ↔ Kernel)

Status: draft (the current assembly ROM does not emit BootInfo) Version: 1.0 Owner: boot Related: architecture.md §10, ../plan/milestones.md M1–M2.

1. Scope

This is the binary contract between the ROM (MIPS III assembly, executed directly from the PROM window at 0xBFC00000) and the IRIX 7 kernel (n32/MIPS III). It defines the handoff registers, the BootInfo structure, the memory map, the CPU/cache state, validation and failure behaviour.

The ROM is a stub, not a full firmware: it brings the machine up, LZ4-decompresses the kernel image from PROM into RAM and jumps to it. Everything the machine does afterwards — including the telnet console and the network stack — is the kernel’s.

It does not define the kernel’s own boot sequence, the boot bundle format or the root image; those are in image-format.md (planned) and architecture.md §10. Loadable modules are specified in modules.md.

2. Handoff

The ROM:

  1. initialises the CPU and invalidates the TLB;
  2. maps a probe window so the DRAM banks can be sized, then programs the memory controller to map them at LOMEM_BASE (0x0800_0000);
  3. tests every byte of DRAM, still with no stack and no RAM-resident state of its own;
  4. initialises the serial console (the Z85C30 in the IOC);
  5. LZ4-decompresses the embedded kernel payload from PROM to 0x8804_0000;
  6. writes the boot flag and jumps to the kernel entry with the registers below.
RegisterValue
$a0Physical address of BootInfo; 0 when the ROM has none (the kernel then falls back to the register handoff)
$a1Total RAM bytes the ROM found
$a2Physical base address of RAM (0x0800_0000)
$spValid stack in RAM, 16-byte aligned, at least 64 KiB
$ra0
$v00

CPU state at entry:

StateValue
EndiannessBig-endian
PrivilegeKernel mode (Status.KSU = 0)
InterruptsDisabled (Status.IE = 0, Status.IM = 0)
Exception levelStatus.EXL = 0, Status.BEV = 0
MMU/TLBOff; no kuseg mappings (Status.KUc/KUp clear)
CachesI-cache and D-cache enabled; kseg0 cacheable
FPUDisabled (Status.CU1 = 0)
WatchdogDisarmed
PCKernel _start

The current ROM passes $a0 = 0 (no BootInfo), $a1 = RAM bytes, $a2 = RAM base and $sp = the kernel stack top. The kernel falls back to that geometry, reserves 0x0800_0000..0x08B0_0000 and starts the frame allocator at 0x08B0_0000.

The kernel may re-enable or reconfigure anything after it has validated the handoff. It must not call ARCS after it takes over the TLB and caches; anything it needs from ARCS must be copied out of BootInfo first.

3. BootInfo layout

BootInfo is a binary contract, not a Rust ABI. It is #[repr(C, align(8))], 256 bytes, with fixed offsets. The current assembly ROM does not emit it; when a loader does, that loader and the n32 kernel must produce and consume the same bytes. Compile-time assertions in both codebases check the size and offsets.

OffsetSizeFieldNotes
0x004magic0x49374249 ("I7BI" big-endian)
0x042version_major1
0x062version_minor0
0x084size256
0x0C4checksumCRC32C over the 256 bytes with this field zeroed
0x108mem_map_physPhysical address of the memory-map array
0x184mem_map_countNumber of entries (≤ 64)
0x1C4mem_map_entry_size24
0x208kernel_physKernel load address
0x288kernel_sizeKernel size in bytes
0x3032kernel_sha256SHA-256 of the kernel
0x508bundle_physBoot bundle load address
0x588bundle_sizeBoot bundle size
0x6032bundle_sha256SHA-256 of the bundle
0x808cmdline_physPhysical address of a NUL-terminated string
0x884cmdline_lenLength including the NUL
0x8C4console_kind0 none, 1 UART, 2 framebuffer, 3 both
0x908console_physUART register base or framebuffer base
0x984console_widthFramebuffer width
0x9C4console_heightFramebuffer height
0xA04console_strideBytes per line
0xA44console_bpp8 or 24
0xA84console_baudUART baud
0xAC6macEthernet MAC
0xB22pad0Zero
0xB44ipIPv4 address, network order
0xB84netmaskIPv4 netmask
0xBC4gatewayIPv4 gateway
0xC04dnsIPv4 DNS
0xC44dhcp1 if DHCP was used
0xC84rtc_valid1 if the DS1386 clock is valid
0xCC4flagsSee §4
0xD08r2_url_physPhysical address of the NUL-terminated R2 base URL
0xD84r2_url_lenLength including the NUL
0xDC4cpu_hzMeasured or PROM-reported CPU clock
0xE08ram_sizeUsable RAM in bytes
0xE84board_id0 Indy, 1 Indigo2 IP22, 2 Indigo2 IP28, 3 unknown
0xEC4prom_versionARCS/PROM version, 0 if unknown
0xF04console_pollKseg1 virtual address of the resident console/network poll routine; 0 if absent
0xF44net_stateKseg1 virtual address of the live network/console state passed to console_poll; 0 if absent
0xF84seeq_stateKseg1 virtual address of the live Seeq device; 0 if absent
0xFC4reservedZero

BootInfo is followed by the memory map and the strings; the ROM places them in a reserved region and records their physical addresses.

3.1 Resident console service

The telnet console is the kernel’s own: the ROM is a stub that brings the machine up and hands over, so there is no ROM-resident console to poll. console_poll is 0 and the kernel does not call it.

The ROM and the kernel are still one program at two link addresses, and the rule that the kernel must not re-create state the ROM initialised still holds — it simply has no network state to inherit. The net_state and seeq_state fields are reserved for a future boot loader; the current kernel initialises Seeq and smoltcp itself.

3.2 Flags

BitMeaning
0D-cache enabled
1I-cache enabled
2MMU/TLB enabled (must be 0 at entry)
3Interrupts enabled (must be 0 at entry)
4Watchdog armed (must be 0 at entry)
5RTC valid
6Network configured
7Framebuffer console available
8Boot bundle present
9Kernel digest verified
10Bundle digest verified
11Boot was a fallback (PROM/local image)
12–31Reserved, zero

4. Memory map

Each entry is 24 bytes:

OffsetSizeFieldNotes
0x008basePhysical base
0x088sizeBytes
0x104kindSee below
0x144flags0 for now

Kinds:

ValueMeaning
0Usable RAM
1Reserved (do not use)
2PROM/ARCS
3MMIO
4Framebuffer
5BootInfo and strings
6Kernel image
7Boot bundle
8Configuration
9Persistent NVRAM

Rules:

  • The map may be unsorted; the kernel sorts it.
  • It must cover all usable RAM and every MMIO region the kernel needs.
  • The kernel must not assume that RAM is contiguous across 0x1800_0000.
  • The kernel copies the map and strings into its own memory before reusing the region.

5. Validation

The kernel validates, in order:

  1. magic == "I7BI".
  2. version_major == 1; minor is ignored if unknown.
  3. size >= 256 and mem_map_entry_size == 24.
  4. CRC32C matches with the checksum field zeroed.
  5. mem_map_count <= 64; every entry is within the 4 GiB physical map.
  6. kernel_phys/kernel_size and bundle_phys/bundle_size are inside usable RAM and do not overlap BootInfo or the stack.
  7. cmdline and r2_url are NUL-terminated within their declared lengths.
  8. The kernel and bundle digests match (the ROM already checked; the kernel checks again).

On failure, the kernel prints a diagnostic to the serial console and halts. It does not attempt to recover by guessing.

6. Versioning

  • Major version changes are incompatible; the kernel refuses an unknown major.
  • Minor versions add fields at the end or repurpose reserved bits; the kernel accepts a smaller size and zero-fills the rest.
  • Unknown flag bits are ignored.
  • The memory-map entry size is explicit; a future entry can grow.

7. Failure and fallback

The ROM’s own failure behaviour is:

FailureBehaviour
No DRAM foundPrint ROM: RAM TEST FAILED on the serial console and halt
RAM test mismatchPrint the failing address and halt
Kernel image will not decompressPrint a diagnostic and halt

The ROM does not fetch anything: the kernel image is embedded in the PROM image, so there is no link to lose and no digest to check. The failure modes that used to belong here — no DHCP, DNS failure, HTTP errors — belong to the kernel’s boot path, which owns the network.

8. Test plan

  • iris: ROM → kernel → serial marker, with the RAM test reporting the whole machine.
  • iris: ROM → kernel → full-screen boot log on the REX3 display.
  • The PS/2 scancode decoder is unit-tested on the host (kernel/tests/kbd.rs).
  • BootInfo size/offset assertions in the assembly ROM and n32 kernel.
  • CRC32C known-answer tests.
  • A stub kernel validates a synthetic BootInfo and prints the memory map.
  • iris: ROM → real kernel → M2 demo.
  • Real Indy: same, with the PROM as the fallback.
  • Corrupt magic, version, checksum, map count and overlapping regions are rejected.
  • A 256 MiB machine and a 32 MiB machine produce valid maps.

9. Open questions

  • Exact kernel load address (the current plan is a kseg0 address such as 0x8804_0000, mapping physical 0x0804_0000; the ROM and linker script must agree).
  • Whether the boot bundle is loaded by the ROM or fetched by the kernel after handoff.
  • Whether the R2 base URL belongs in BootInfo or in a separate config blob.
  • MCP token provisioning (not in BootInfo; the token must not be world-readable).
  • Watchdog ownership during the handoff (the ROM must leave it disarmed).

10. Kernel boot readiness

The ROM handoff in §2 is followed by the kernel’s own boot sequence. The kernel emits exactly one readiness line per boot, after the RTC, network and boot-time module autoload have run:

BOOT-READY v=1 boot=<unix> kernel=up network=<up|off> mcp=<listening|local|disabled>

network=off means the DS1386 environment set net=off and the kernel deliberately skipped the Seeq and DHCP. mcp=local means the module came from the local SCSI mcp.local source rather than the network. mcp=disabled on a network-off boot means there was no local module and none was required; this is the M1 single-node boot, and no unverified module is run. A network-up boot that cannot satisfy the module prerequisite emits a distinct line instead:

BOOT-NOT-READY v=1 boot=<unix> kernel=up network=<up|down|off> mcp=<disabled|failed> reason=<token>

boot is the RTC Unix second at which the marker was emitted, or 0 when the RTC has no valid time. It is monotonic across normal reboots but can repeat if the machine is reset within the same second. reason is one of no-mcp-url, autoload-failed or network-down.

The marker is written through the console service, so it appears on serial, in the MCP serial ring and on a connected telnet session. After the marker the kernel enters the native user image on SCSI target 2; if no image is attached, the loader error remains visible and the console continues. There is no boot menu.