Files
sgi-indy/docs/rom-map.md
T
opencode.energia.arti.ee 1dc99443b7 Map SGI Indy IP24 PROM 5.3 Rev B10
Fetch and verify the four MAME indy_4610 PROM dumps, wrap the newest
dump in an ELF32 BE MIPS image for Ghidra/REA, and record the resulting
structural map: image layout, exception vector table, boot flow,
function anchors and firmware feature clusters.
2026-11-02 11:04:39 +00:00

15 KiB

Indy IP24 PROM 5.3 Rev B10: structural map

This document maps the newest known SGI Indy boot PROM, ip24prom.070-9101-011.bin. All addresses are PROM addresses as mapped by the hardware; file offsets are address - 0x1FC00000.

Facts in this document come from three places:

  1. byte-level inspection of the dump (padding, strings, jump vectors);
  2. Ghidra 12.1.2 auto-analysis driven through REA 6.8.0;
  3. MAME's IP22/IP24 machine definitions for the surrounding address map.

Function names such as FUN_1fc02000 are Ghidra auto-generated. The interpretations attached to them are inferences from their code, call sites and the strings they reference; they are labelled as such.

Identity

Field Value
File ip24prom.070-9101-011.bin
Size 524,288 bytes (512 KiB)
Part number 070-9101-011
Version SGI Version 5.3 Rev B10 R4X00/R5000 IP24 Feb 12, 1996
SHA-1 ac663a4db68528e400487e98cbf901f620fb30ce
SHA-256 333a0b2e39bb828a28a758b6f633ae7290030129dc747297a1be68dc317b86ae
MAME set indy_4610
Load address 0x1FC00000
Analyzed functions 1,074
Analyzed strings 1,418

The SHA-1 matches MAME's src/mame/sgi/indy_indigo2.cpp ROM entry exactly.

The other dumps in the set

The indy_4610 set contains four PROM revisions. SHA-1 values below are the ones MAME records.

File Version SHA-1
ip24prom.070-9101-005.bin 5.1.2 Rev B4, 9 Dec 1993 28b769b28218a1fcd0400dceef9a284dcfbdda5b
ip24prom.070-9101-007.bin 5.0 Rev B6, 28 Sep 1994 ade54cd2ecb7064957f8602894f05685e2f4e8fb
ip24prom.070-9101-008.bin 5.3 Rev B7, 16 Feb 1995 a752a4aef7e2c6086b8b0244e9f064861a11870f
ip24prom.070-9101-011.bin 5.3 Rev B10, 12 Feb 1996 ac663a4db68528e400487e98cbf901f620fb30ce

011 is the newest, and the only one whose version string claims R4X00/R5000 support. MAME selects it as the default BIOS for both indy_4610 (R4600) and indy_5015 (R5000).

How the image was opened

The dump is headerless. REA's raw-binary lane has no MIPS architecture, so a minimal ELF wrapper is produced by tools/make-elf-wrapper.py:

  • ELF32, big-endian, ET_EXEC, EM_MIPS;
  • e_flags = 0x50000000 (EF_MIPS_ARCH_32, no ABI field);
  • no PT_MIPS_ABIFLAGS record;
  • one PT_LOAD at file offset 0x1000, virtual address 0x1FC00000;
  • entry 0x1FC00000.

REA admits this through its recordless legacy MIPS lane and pins Ghidra to MIPS:BE:32:default. The import log confirms that language. The ROM bytes are not modified.

The declared ABI is therefore absent by construction: o32 calling conventions are an analysis assumption of the lane, not a property recovered from the ROM. This affects parameter recovery in decompiled output, not instruction decoding or control flow.

Physical placement

MAME's IP24 map places the 512 KiB BIOS window at 0x1FC00000. Through the MIPS segments the same bytes are also visible at:

View Address
Physical / KUSEG 0x1FC00000
KSEG0 (cached) 0x9FC00000
KSEG1 (uncached) 0xBFC00000

Ghidra analyzed the physical mapping. The reset code itself uses KSEG0/KSEG1 addresses such as 0x9FC7DD18, 0x9FC4AAC8 and 0xBFA0xxxx; those appear in decompiled output as their unmapped KSEG forms.

Relevant neighbours from MAME (src/mame/sgi/indy_indigo2.cpp):

Range Device
0x00000000 - 0x0007FFFF Alias for first 512 KiB of RAM
0x08000000 - 0x17FFFFFF Low system memory
0x1F000000 - 0x1F3FFFFF GIO64 graphics
0x1F400000 - 0x1F5FFFFF GIO64 EXP0
0x1FA00000 - 0x1FA1FFFF Memory controller
0x1FB00000 - 0x1FB7FFFF HPC3 CHIP1
0x1FB80000 - 0x1FBFFFFF HPC3 CHIP0
0x1FC00000 - 0x1FFFFFFF BIOS (this ROM)
0x20000000 - 0x2FFFFFFF High system memory
0x80000000 - 0xFFFFFFFF EISA memory

The reset code touches 0xBFA00xxx/0xBFA01xxx (KSEG1 alias of the memory controller) and 0xBFBD9xxx/0xBFBBxxxx (KSEG1 alias inside HPC3 CHIP0).

Image layout

Page-level detail is in rom-map.json. The compressed view:

File offset PROM address Size Content
0x00000 - 0x003BF 0x1FC00000 - 0x1FC003BF 960 B 60-entry, 16-byte exception jump table
0x003C0 - 0x4A89F 0x1FC003C0 - 0x1FC4A89F ~298 KiB Reset handler, code and inline diagnostic strings; 1,074 functions, last one starting at 0x1FC4A7E0
0x4A8A0 - 0x5568F 0x1FC4A8A0 - 0x1FC5568F ~44 KiB Core message blob: boot sequence, diagnostics, monitor help, environment and ARCS strings
0x56000 - 0x6CFFF 0x1FC56000 - 0x1FC6CFFF 92 KiB Binary tables; no Ghidra-defined strings
0x6D000 - 0x6EA4C 0x1FC6D000 - 0x1FC6EA4C ~6.5 KiB Path-test strings and the environment variable/default table
0x6EA4D - 0x7BF8F 0x1FC6EA4D - 0x1FC7BF8F ~54 KiB Mostly zero/binary pages plus two isolated strings
0x7BF90 - 0x7C16B 0x1FC7BF90 - 0x1FC7C16B ~480 B SCSI tape drive name table
0x7C16C - 0x7F9FF 0x1FC7C16C - 0x1FC7F9FF ~14 KiB Remaining data tables
0x7FA00 - 0x7FFFF 0x1FC7FA00 - 0x1FC7FFFF 1536 B 0xFF padding

Only four 0xFF runs of 16 bytes or more exist; three are tiny alignment holes inside the string area, and the real padding is the final 1,536 bytes. The last non-0xFF byte is at file offset 0x7F9FF.

The code and message regions overlap at the page level: page 0x1FC4A000-0x1FC4AFFF holds the last nine functions and 64 strings, so the "code ends" boundary above is the end of executable content, not the start of all strings.

Exception vector table

The first 960 bytes are 60 cells of 16 bytes:

0x1FC00000 + (index * 0x10)

Each cell begins with an absolute MIPS J instruction followed by three NOPs. The reset handler lives at 0x1FC003C0, immediately after the table, so the final four 16-byte slots are not table entries.

Observed targets:

Cell address Index Target Count
0x1FC00000 0 0x1FC003C0 (reset handler) 1
0x1FC00200 32 0x1FC00F20 1
0x1FC00280 40 0x1FC00F28 1
0x1FC00300 48 0x1FC00F18 1
0x1FC00380 56 0x1FC00E40 1
all other cells - 0x1FC007C4 (shared handler) 55

The architectural MIPS R4000 vector offsets (0x080 TLB refill, 0x100 general exception, 0x180 XTLB refill, 0x200 cache error) fall inside this table. Of those, only 0x200 is special; the rest use the shared handler. The meaning of indices 32, 40, 48 and 56 is not established by this analysis. One plausible reading is an SGI dispatch table indexed by a cause-derived value rather than by the architectural vector offset, but that is an inference, not an observation.

The four special targets all land inside the block at 0x1FC00E40-0x1FC00F28. Ghidra did not split that block into separate functions; auto-analysis treats 0x1FC00DCC as the nearest function start. The bytes there are worth a focused follow-up with manual function creation.

Reset and boot flow

Reset handler, 0x1FC003C0

Observed instruction sequence (REA/Ghidra):

  1. lui v0, 0x3041; mtc0 v0, Status and clear Cause, PageMask, WatchLo, WatchHi.
  2. Config = 2, then test Config bit 15. If clear, call FUN_1fc0a810, which reads and rewrites a CP0 configuration value and writes 0xBFA00000 = 0x10000.
  3. Write memory-controller registers at 0xBFA000EC, 0xBFA000FC, 0xBFA00004, 0xBFA0000C, 0xBFA00084, 0xBFA000D4, 0xBFA000DC and 0xBFA0002C. The value stored at 0xBFA00084 is loaded from 0x9FC7DD18.
  4. Poll 0xBFA01004 until the counter advances by at least 0x271.
  5. Call 0x1FC00A3C, 0x1FC00BD0, 0x1FC00DCC, 0x1FC00D58.
  6. Set s8 = 0x9FC03660, then call 0x1FC039E0, 0x1FC03DE0, 0x1FC03EB0, 0x1FC01070.
  7. Sample 0xBFA000C4, test bits 0x2200, optionally set low bits of 0xBFA00004.
  8. Call 0x1FC009D4, then j 0x1FC02000.

The Ghidra decompiler renders the end of this function as an infinite loop because it does not model the final j as a return. The instruction listing is the authority here.

Cold-start main, 0x1FC02000

The function reached by the reset jump initializes HPC3/IOC registers around 0xBFBD9xxx, calls a long sequence of hardware setup routines, and then reads the diagmode environment variable at 0x9FC4AAC8.

Two paths follow:

  • diagnostics/menu path (FUN_1fc02a50) when the diagnostic state is set;
  • autoboot path (FUN_1fc0fb10) otherwise.

FUN_1fc0fb10 reads AutoLoad (0x1FC4D090) and NoAutoLoad (0x1FC4D09C). If autoload is enabled it prints the maintenance prompt To perform system maintenance instead, press <Esc> and attempts a boot; a failure prints Unable to boot; press any key to continue: and falls back through FUN_1fc00624.

FUN_1fc02a50 is the menu/boot loop. It reads VERBOSE and diskless, touches IOC interrupt-enable bits, and loops through the maintenance menu whose strings sit at 0x1FC4D99C:

  • Install System Software
  • Recover System
  • Enter Command Monitor
  • Select Keyboard Layout

The same area contains Autoboot failed, Diagnostics and Command Monitor. Type "exit" %sto return to the menu.

Boot-sequence messages

The ordered diagnostic strings beginning at 0x1FC4A8A0 describe the intended power-on sequence:

  1. Power switch released.
  2. Initializing primary/secondary caches.
  3. Secondary cache size is 0x%x (%d Kbytes)
  4. Initializing exception handlers.
  5. Initializing Status Register.
  6. Enabling PLP, ISDN B/A DMA channels.
  7. Selecting Gen Control register bits.
  8. Initialize Map Polarity.
  9. Deasserting VIDEO Reset.
  10. Playing startup tune.
  11. Initializing environment.
  12. Executing remainder of diagnostic.
  13. Initializing software and devices.
  14. All initialization and diagnostic completed.

Function anchors

Address Auto name Interpretation Basis
0x1FC00000 entry Table slot 0 thunk to the reset handler Ghidra symbol, thunk target
0x1FC003C0 FUN_1fc003c0 Reset handler CP0 init, memory-controller setup, jump to main
0x1FC00624 FUN_1fc00624 Shared exception/fallback path Vector-table default target; cache and memory scrub code
0x1FC00DCC FUN_1fc00dcc Short HPC3/cache stub Writes 0xBFB91004, 0xBFBC0003, 0xBFBC0007; nearest function for special vectors
0x1FC02000 FUN_1fc02000 Cold-start main Reached by reset jump; HPC3/IOC init; branches to diagnostics or autoboot
0x1FC02A50 FUN_1fc02a50 Menu/boot loop Reads VERBOSE/diskless; loops over maintenance menu
0x1FC0FB10 FUN_1fc0fb10 Autoboot policy Reads AutoLoad/NoAutoLoad; maintenance prompt and boot failure text

The full list of 1,074 function starts is in procedure-index.csv. The CSV has three columns: address,name,thunk_target.

Firmware feature map

Command monitor

Help strings at 0x1FC4ACE8-0x1FC4B054 enumerate the monitor commands:

autoboot (auto), boot, checksum, date, dump, exit, fill, get, go, help/?, initialize (init), inventory, passwd, printenv, put, reboot, resetenv, resetpw, setenv, single, unsetenv, version.

The banner is PROM Monitor %s (BE) at 0x1FC4B090, followed by the version string.

Boot targets

Strings at 0x1FC4AAF0-0x1FC4AB44 name the default load paths:

  • bootp()ide.IP24
  • sashIP24
  • bootp()sashIP24
  • bootp()unix.IP24

Elsewhere the image references sashARCS, part(8)sashARCS, /stand/ide, IDE distribution CD boot, and ARCS-style boot.

Diagnostics

Diagnostic result strings name the tests the PROM can run:

  • memory probe, memory data test, memory address test, walking-bit test;
  • cache diagnostic;
  • graphics diagnostic;
  • interrupt controller diagnostic;
  • SCSI controller, SCSI device/cable, WD SCSI0 path test;
  • RTC path test, INT path test, data path test;
  • PC keyboard/mouse controller, keyboard, mouse;
  • CPU base board, graphics board, CPU module, SIMM replacement prompts.

The display-side strings also expose the VDMA and DMA error registers (DMA_CAUSE, DMA_MEMADR, CPU_MEMACC, GIO_MEMACC, CPU_ERR_ADDR, CPU_ERR_STAT, GIO_ERR_ADDR, GIO_ERR_STAT) and the MIPS exception dump fields (ErrEPC, BadVaddr, Cause, Status, CacheErr, CpuParityErr, GioParityErr, LIOstatus0..2, CpuErrorAddr, GioErrorAddr).

Environment variables

The environment table around 0x1FC6E4F0-0x1FC6EA4C and the help strings around 0x1FC4CD00-0x1FC4E000 cover:

AutoLoad, NoAutoLoad, diagmode, console, diskless, VERBOSE, eaddr, netaddr, srvaddr, gateaddr, netinsthost, netinstfile, tapedevice, scsihostid, scsiretries, pagecolor, TimeZone, autopower, SystemPartition, OSLoader, OSLoadPartition, OSLoadFilename/OSLoadFileName, OSLoadOptions, ConsoleIn, ConsoleOut, ConsoleWarning, passwd_key, netpasswd_key.

The NVRAM path has its own messages: NVRAM checksum is incorrect: reinitializing., nvchecksum:, Checksum mismatch: is 0x%x, s/b 0x%x, Enter new password:, Confirm new password:, Password cleared. and the password-jumper warnings.

ARCS and SCSI tables

The string blob around 0x1FC5549C-0x1FC55524 contains the ARCS component names ExceptionBlock, SystemParameterBlock, FreeContiguous, FreeMemory, BadMemory, LoadedProgram, FirmwareTemporary and FirmwarePermanent.

The cluster at 0x1FC7BF90-0x1FC7C16B is a SCSI tape-drive name table: CIPHER, TANDBERG TDC 3660, ARCHIVE VIPER 150, VIPER 60, Python, EXABYTE and KENNEDY.

The sentinel value cafebabedeadbeef appears at 0x1FC6EA4C; it is likely an uninitialised-memory pattern used by the environment/NVRAM code, but that is an inference.

Confidence and limitations

  • Function boundaries and names come from Ghidra auto-analysis. There are no symbols in the image beyond the imported entry label.
  • The ELF wrapper declares no ABI. o32 is an analysis assumption, so recovered parameter counts and types are weaker than the control flow.
  • The vector table's 60 x 16-byte structure and observed targets are facts. What each index means is not established.
  • The decompiler output is heuristic. Where it conflicts with the instruction listing (for example the reset handler's final jump), the instruction listing is authoritative.
  • String inventory covers Ghidra-defined string data only (1,418 entries). Undefined or packed text may be missing, and an absent string is not proof that the text is absent from the artifact.
  • No code was executed. Nothing here establishes runtime behaviour.
  • Ghidra 12.1.2 was used; REA's bridge is verified against 12.1.4 and accepts other 12.1.x builds.

Reproduce

./tools/fetch-roms.sh
./tools/make-elf-wrapper.py \
  roms/ip24prom.070-9101-011.bin -o roms/indy-ip24-5.3-b10.elf

export GHIDRA_INSTALL_DIR=/opt/ghidra
rea analyze roms/indy-ip24-5.3-b10.elf --provider ghidra --json

The checked-in artifacts were produced with the REA MCP session described in rea-setup.md, then:

./tools/rom-map.py roms/ip24prom.070-9101-011.bin \
  --evidence evidence/rea-bundle.json \
  --output docs/rom-map.json \
  --procedures-csv docs/procedure-index.csv