Files
LithosAnanake/boards/BRINGUP.md
T
rajamesandClaude Opus 5.5 79db0e8d88 build: v4 is the default build -- every kernel boots v4; acceptance is v4 on three ISAs and the 32-bit build
Captain Bob, 2026-10-14: "v4 is the default build", "no, qemu to v4
too ... we are effectively trying to retire v3", "the 32 bit build needs
to go into the acceptance test too", "i don't care about v3".

- STARFORTH_V4 defaults on (Kconfig default y) and V4_DEFAULT=1
  everywhere: every kernel carries v4 and v3 and boots v4; system=v3 boots
  v3; STARFORTH_V4=0 builds v3 alone.  Board images write system=v4.
- Acceptance (CLAUDE.md): the three ISAs as built (v4, POST passed,
  V4_SYSTEM dict_hash equal) and make -C v4 test-32.  v3 is not part of
  it.

Acceptance run: amd64, aarch64, riscv64 -- PARITY:V4_POST 538/538,
dict_hash=0xe5a57f3eb72ff94a on all three, no unknown word; test-32: 30
suites, 0 failures.  The SER5 image under OVMF boots v4 as built, v3 after
the one-word edit.  README, BRINGUP, FABRIC-3 XLIII, the register updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:21:13 -04:00

21 KiB

Board bring-up checklist

Written 2026-10-13, before any of the four boards has been booted. It is what to do on the day a board is on the bench, and what has to be true before that day is worth having.

Nothing here has been done on hardware. Every statement about the code was checked in the code on the date above; where it comes from a document instead, the document is named. When a board has been booted, its results go in docs/fabric/FABRIC-3.md (sections III, IV, V) and its README.md here, and this file is corrected.

The four boards: SER5 (amd64), RASPI (Pi 5, aarch64), MILKV (Mars, riscv64), ZYNQ7020 (ARMv7, no port yet). See boards/README.md for what each image is.


1. What stands between today and a first boot

Found while writing this checklist. Items marked blocks first boot will stop a board showing anything, or stop it being typed to; they are worth closing before the bench day. None has been fixed: each needs your word.

1.1 All boards

# What Where Effect on hardware
A1 Fixed 2026-10-14. The USB controller was matched by QEMU's own IDs (1B36:000D) on PCI bus 0 alone. Now: found by its PCI class (0C/03/30) on any bus, slot and function; its register window mapped at the size its BAR reports; taken from the firmware through the USB Legacy Support capability (SMIs off); and 64-byte contexts (CSZ=1, common on real controllers) laid out instead of refused. Every controller is driven, up to 8 (since 2026-10-14, FABRIC-3.md XLII): a stick or keyboard may be in any port. kernel/src/usb/xhci.c, kernel/src/pci/pci.c; FABRIC-3.md XL Rehearsed in QEMU with another vendor's controller behind a bridge, all three ISAs. Not rehearsable: the firmware handoff and 64-byte contexts (QEMU's controller has neither).
A2 No prompt without a login. The production default, EMERGENCY_CONSOLE_ENABLED=n, keeps the system headless until an identity logs in by thumbdrive. Kconfig.heartbeat:68; FABRIC-3.md VIII.1 With A1, the v3 system never shows a prompt on hardware. A bring-up build must set EMERGENCY_CONSOLE_ENABLED=1.
A3 Fixed 2026-10-14. A USB boot-protocol keyboard is driven (xHCI interrupt endpoint, SET_PROTOCOL(boot)), its reports become the same key events as the PS/2 and virtio keyboards, and the console treats a full keyboard as one: Caps Lock and Num Lock as toggles shown on the keyboard's lights, the keypad as digits or navigation, the arrows and navigation block mapped (the line editor itself still has no cursor movement). While a USB keyboard runs, the console services its reports every timer tick. kernel/src/usb/usb_kbd.c, kernel/src/usb/xhci.c, kernel/src/repl.c; FABRIC-3.md XLI Rehearsed in QEMU on all three ISAs; on amd64 with the USB keyboard the only keyboard. Limits: a keyboard whose first interface is not the keyboard is not used; no key repeat. Several keyboards, on any controllers, each its own.
A4 The only disk driver is virtio. kernel/src/virtio/virtio_blk.c; kernel_main.c:493 On hardware Artemis finds no disk ("Artemis: no virtio-blk disk"). What the fleet then does has not been tried even in QEMU: see step 3.3.
A5 Entropy: RDRAND on amd64 only. aarch64 and riscv64 have virtio-rng alone. kernel/src/rng/rng.c Pi 5 and Mars print the "no entropy backend available" warning; anything that needs random bytes is refused. Minting needs them.
A6 Fixed 2026-10-14. Every board image carries both systems, v3 and v4, and the boot arguments choose: system=v4 (as built: v4 is the default) or system=v3 -- one word in starforth.cfg on the SER5's and the Mars's stick or card, in cmdline.txt on the Pi 5's card. No rebuild to switch. root Makefile, kernel/Makefile, kernel/src/kernel_main.c, kernel/src/boot/cmdline.c; FABRIC-3.md XLIII The SER5 image itself, booted under OVMF: v3 as built, v4 after the one-word edit. The boot says which system runs and why ("System: ...").

1.2 SER5

# What Where Effect
S1 HPET address fixed at 0xFED00000, not read from ACPI. FABRIC-3.md III item 6, finding 1 Wrong only on a machine that puts it elsewhere. Most do not.
S2 Local APIC address fixed at 0xFEE00000; the MADT's override entry is not parsed. finding 2 The same.
S3 Half fixed 2026-10-14. The i8042: a PC without one (port 0x64 reads 0xFF) hung the kernel at boot, in a drain loop that never ended -- found rehearsing A3 with QEMU's i8042=off. Now detected and skipped, every drain bounded. Still open: the legacy PIC is written to with no check that it exists. kernel/src/arch/amd64/i8042.c; finding 3; FABRIC-3.md XLI A legacy-free SER5 no longer stops at the I/O APIC. The PIC: unknown on a machine without one.
S4 BYE resets through the i8042, not the ACPI reset register. finding 4 BYE may do nothing. It does not hang.
S5 Whether the SER5 has a serial header is not known. FABRIC-3.md III Without one, and with A3, the SER5 can be watched over HDMI and not typed to.

The loader probes COM1 before using it, and since 2026-10-13 so does the kernel's console. Before that, on a board with no COM1 the status port read all ones: writes went nowhere, and the prompt was told a key was waiting on every poll and read 0xFF for ever.

1.3 Raspberry Pi 5

# What Where Effect
R1 Fixed 2026-10-13. Every character the console printed was also written to a PL011 at 0x09000000, QEMU's address, which on a Pi 5 is ordinary RAM. The console now finds its serial line from the devicetree's /chosen/stdout-path: on the Pi 5 that is serial10, the debug connector, a PL011 at 0x107d001000. kernel/src/hal/console.c, kernel/src/hal/fdt_uart.c; tools/fdt_uart_test.c reads the board's real devicetree Checked off the board only. The first run is the board's.
R2 Fixed 2026-10-14. Entry is at EL2 with the MMU off, where every access is Device memory: unaligned accesses and atomics fault, nothing is cached. The entry stub now cleans the cache over the image, turns the MMU and caches on before any C (identity map: the image's GiB Normal in 2 MiB blocks, the rest Device), and routes interrupts to EL2; C then makes the rest of the devicetree's RAM Normal. Rehearsing it found and fixed three more: the PL011 register shift, the GIC address (not carried through /soc's ranges), and the EL2 timer interrupt never being taken. native_rpi5_entry.S, rpi5_mmu.c, fdt.c (fdt_reg_address), apic.c; FABRIC-3.md XXXIX Rehearsed on QEMU virt at EL2 (section 3.2): POST passes, same parity hash. Not yet on the board.
R3 Partly fixed 2026-10-14. The address returned is now carried through the devicetree's dma-ranges (on the Pi 5 it is already physical; the old & 0x3FFFFFFF was the Pi 4's rule), every mailbox wait gives up after one second, the request buffer is cleaned to RAM and back around the exchange, and the framebuffer is mapped uncached. Still unverified: the size field of the allocate tag. The mode is fixed at 1920x1080x32. rpi5_mailbox.c, rpi5_mmu.c; FABRIC-3.md IV.3 item 3, XXXIX QEMU virt has no mailbox: none of this runs before the board. No picture shows as no framebuffer, not a hang.
R4 USB, Ethernet and GPIO are behind the RP1 chip on PCIe, which needs a Broadcom-specific driver that is not written. FABRIC-3.md IV.3 item 5 No USB on the Pi 5 whatever is done about A1.
R5 No hardware entropy source is known for the BCM2712. FABRIC-3.md IV.2 A5 stands.

1.4 Milk-V Mars

# What Where Effect
M1 Fixed 2026-10-13. The console, and the UEFI loader before it, wrote to a 16550 at 0x10000000 with registers one byte apart. The JH7110's UART is at that address with reg-shift = <2> and reg-io-width = <4> (mainline jh7110.dtsi): the loader would have waited for ever on its first character. Both now take the layout from the devicetree. kernel/src/hal/console.c, kernel/src/boot/uefi_loader.c Rehearsed in QEMU through U-Boot, which hands over a devicetree: "serial line is a 16550 at 0x10000000 (named by the devicetree)". QEMU's UART is byte-spaced, so the four-byte layout itself is checked by the host test only.
M2 The display depends on U-Boot offering a framebuffer to the EFI loader. boards/milkv/README.md Unknown. With M1 unfixed there is then no channel at all.
M3 USB is behind the JH7110's PCIe controller; whether that is plain ECAM has not been looked up. FABRIC-3.md V.3 item 5 No USB until it is.
M4 FABRIC-3.md V describes a native entry at 0x40000000; the image built today is the UEFI loader run by U-Boot's bootefi. The README here is the newer and is what the build does. boards/milkv/README.md None; noted so the two are not confused on the day.
M5 Whether the U74 has the entropy instruction is not known. FABRIC-3.md V.2 A5 stands.

1.5 Zynq-7020

No image can be built. Needed first, in order: the board chosen (it fixes BOOT.BIN); an ARMv7 port, kernel/src/arch/armv7 (entry, MMU, GIC, private timer); and the four files that use __int128 or have no ARMv7 branch (boards/zynq7020/README.md names them). It is the host for the v4 mesh, so it also waits on A6.

1.6 Found in rehearsal, and fixed, 2026-10-13: the bring-up build flooded its prompt

Built with EMERGENCY_CONSOLE_ENABLED=1 and booted with no thumbdrive, the prompt printed ok> ok without end: 1.4 million times in 200 seconds. The line reader (kernel/src/repl.c, sk_console_readline()) gave up at once whenever no identity was logged in, which the production build answers by going silent; the bring-up build took it as an empty line and asked again. It now gives up only in the production build. Rehearsed on riscv64 (logs/20261013-235129): one prompt, which waits, and three typed lines answered.

1.7 What I would close before the bench day

In this order, each as a design for approval first:

  1. R1 and M1: a console that finds its UART from the devicetree, and does nothing when there is none. Done 2026-10-13, and 1.6, the flood.
  2. A6: the v4 switch in the board images. The v4 node needs only a console to reach a prompt; it has no login, no fleet and no disk to wait for, so it is the shorter road to a first prompt on each board.
  3. A1: find the USB controller by its class code, not one vendor's number. That gives the SER5 thumbdrives. The Pi 5 and the Mars need R4 and M3 as well.
  4. A serial cable for every board (section 2).

2. Before the day

To have on the bench

  • A USB-to-serial adapter with 3.3 V logic levels, and jumper wires. It is the one channel that survives a framebuffer failure, and with A3 it is the one way to type. FABRIC-3 decided HDMI only for the Pi 5 and the Mars because no adapter was to hand; that decision is worth revisiting before the day.
  • HDMI display and cable (micro-HDMI for the Pi 5).
  • A USB stick for the SER5; a microSD card each for the Pi 5 and the Mars; a card reader.
  • A PS/2 keyboard if the SER5 turns out to have a PS/2 port; otherwise serial.
  • A camera, for the screen: when there is no serial log, photographs are the record.
  • The identity thumbdrives (disk/README.md), once A1 is closed.

To know before starting

  • SER5: Secure Boot is off (FABRIC-3.md III says it is on this unit); which key opens the firmware's boot menu; whether there is a serial header.
  • Pi 5: the EEPROM firmware is recent enough to honour kernel_address and os_check (boot Raspberry Pi OS once and note the version).
  • Mars: the SPI flash holds a U-Boot that scans the SD card for an EFI loader; the boot switches select SPI flash. Stop U-Boot at its prompt once and save printenv, then fdt addr ${fdtcontroladdr} and the output of fdt print /soc/serial@10000000: that settles M1.

3. Build, and rehearse in QEMU

3.1 Build

make boot_image TARGET=SER5   EMERGENCY_CONSOLE_ENABLED=1
make boot_image TARGET=RASPI  EMERGENCY_CONSOLE_ENABLED=1
make boot_image TARGET=MILKV  EMERGENCY_CONSOLE_ENABLED=1
  • make clean TARGET=<board> first. make boot_image now cleans its ISA's kernel objects itself (2026-10-14): make does not see a change of compile flags, and an image built over old objects booted headless (2026-10-13) or would have lacked v4.
  • The images boot v4. To boot v3 instead: change system=v4 to system=v3 in starforth.cfg (SER5, Mars) or cmdline.txt (Pi 5) on the medium. The boot prints "System: ..." with the choice.
  • Each ends with its image in build/boards/<board>/. Record sha256sum of each.
  • Confirm the switch took: the image booted in QEMU (3.2) shows a prompt with no thumbdrive attached. After a clean build it does (tried on MILKV).
  • The Pi 5 build fetches the board's DTB once from the pinned firmware release; with no network, pass RPI5_DTB=/path/to/bcm2712-rpi-5-b.dtb.
  • Put back v3/include/version.h and capsules/BLOCK_MAP.md afterwards: the build rewrites both.

3.2 Rehearse each image as its own disk

One QEMU at a time. Use a copy of the image: the kernel writes to its disk.

  • SER5: q35 with OVMF, the image as the only disk, no -cdrom, no virtio disk, no thumbdrive. This is the machine the README's "booted in QEMU" refers to.
  • MILKV: the command in boards/milkv/README.md (OpenSBI, U-Boot, bootefi).
  • RASPI: there is no QEMU model of the Pi 5, but its native path -- raw image, entry at EL2 with the MMU off, devicetree in x0 -- is rehearsed on QEMU virt: make -f kernel/Makefile ARCH=aarch64 RPI5_NATIVE_BASE=0x40080000 rpi5-rehearsal (log under logs/<TS>/aarch64-rpi5/). Not rehearsed: the mailbox and framebuffer, the Pi 5's own UART and GIC addresses (checked against its real devicetree by tools/fdt_uart_test.c instead), and PCI (virt's needs ACPI, the Pi 5's is R4).

3.3 What to settle in the rehearsal

  • With no virtio disk and no thumbdrive, how far does the v3 system get, and what does it print? (A4. Not tried.)
  • Note the verdict lines of that boot (section 5). They are what the board is compared with.
  • Type a line over the serial port. If it is not taken in QEMU it will not be on the board.

4. On the bench

Do one board at a time, in this order: SER5, then the Mars, then the Pi 5. The SER5's path is the one QEMU exercises most closely, and the Pi 5's can be rehearsed only in part (3.2).

4.1 Writing the media, every board

  • lsblk before and after inserting the stick or card. Write down the device name and its size. dd to the wrong device destroys a disk.
  • sudo dd if=build/boards/<board>/<image> of=/dev/sdX bs=4M conv=fsync status=progress
  • Read it back and compare: sudo cmp -n $(stat -c %s <image>) <image> /dev/sdX.

4.2 SER5

  • Serial, if there is a header: 115200 8N1, logged to a file from before power-on.
  • HDMI and keyboard connected. Stick in a rear port.
  • Power on, open the boot menu, choose the stick.
  • Watch for, in order: StarKernel UEFI Loader; GOP: linear framebuffer found; LithosAnanke v...; PMM initialized.; VMM initialized; APIC: init done; Timer: init done; Kernel heap initialized.; Stadium: ...; POST; the verdict lines.
  • rng: backend = rdrand. In QEMU it says virtio-rng; this line is new on hardware.
  • The timer lines differ from QEMU's by design: no hypervisor, so the HPET path runs for the first time. S1 is the finding to remember if it stops there.

4.3 Milk-V Mars

  • Serial on the 40-pin header's UART, 115200 8N1, logged from before power-on. U-Boot talks on it, so it shows whether the board reached U-Boot even if the kernel prints nothing.
  • Card in, HDMI connected, power on.
  • U-Boot finds EFI/BOOT/BOOTRISCV64.EFI and starts it. If it does not, at its prompt: load mmc 1:1 ${kernel_addr_r} EFI/BOOT/BOOTRISCV64.EFI then bootefi ${kernel_addr_r} ${fdtcontroladdr} (the device number may differ: mmc list).
  • The lines of 4.2, with PLIC: in place of APIC:. For the first time the interrupt controller's address and the timer's frequency should come from the devicetree: the QEMU lines "no DTB PLIC node" and "FALLBACK, no devicetree" should not appear.
  • satp.MODE is printed at entry. Under U-Boot it may be 0 where QEMU shows 0xa.

4.4 Raspberry Pi 5

  • Serial on the debug connector between the HDMI ports (needs the Pi debug probe or a matching cable), 115200 8N1. The firmware prints there before the kernel runs.
  • Card in, HDMI in the port nearest the USB-C socket, power on.
  • The firmware loads kernel_2712.img at 0x80000. If the screen stays on the firmware's diagnostic page, the firmware did not accept the image: note what it says.
  • Then the lines of 4.2 from LithosAnanke v... on (there is no UEFI loader), with GICv2: in place of APIC:. The line "no DTB GIC node -- using QEMU virt-machine defaults" should not appear.
  • Expect PCI: MCFG parse failed on aarch64 -- no ECAM: that is R4 and is not a failure of the boot.

5. What counts as a pass

Record which level each board reached. A board is not "booted" on the strength of level 1.

Level What was seen Compared with
1 The kernel's first line, on any channel -
2 Every milestone line through Kernel heap initialized. The QEMU log of the same build
3 POST: PASSED and PARITY:OK The same test count as QEMU
4 The PARITY:M7.1a line's word_count and hash equal QEMU's for the same ISA The rehearsal boot of 3.2
5 A prompt, and a typed line answered: 1 2 + . gives 3 -
6 Entropy from hardware; an identity minted on a thumbdrive and attached again after a power cycle The gates of FABRIC-3.md III, IV, V

Level 4 is the one that says the board runs the same system as QEMU. Levels 5 and 6 wait on section 1: today no board can reach 6, and only the SER5 with a serial header can reach 5.

For the v4 node, once A6 is built, the lines are PARITY:V4_POST tests=538 pass=538 fail=0, PARITY:V4_SYSTEM word_count=... dict_hash=... equal to the hosted programs', PARITY:OK, POST: PASSED, and the prompt ok> .


6. If it stops

What is seen Look at
Nothing at all, any board Is the firmware reaching the image? Serial shows the firmware's own output on the Mars and the Pi 5. On the SER5, try the UEFI shell: startup.nsh is in the image.
Pi 5: firmware runs, then nothing R1, then R2, then R3.
Mars: U-Boot starts the loader, then nothing on serial M1. HDMI may still show the boot if M2 holds.
SER5: stops in the Timer: lines S1.
Stops at APIC / GICv2 / PLIC The controller's address: S2 on the SER5; on the others, whether the devicetree node was found (the line says).
Runs through POST, then silence A2: the build is headless. Rebuild with EMERGENCY_CONSOLE_ENABLED=1.
A prompt that takes no keys A3. Type over serial.
Artemis: no virtio-blk disk A4. Expected on every board today.
rng: WARNING -- no entropy backend available A5. Expected on the Pi 5 and the Mars today.

Write down the last line shown, exactly, and photograph the screen. Do not change two things between attempts.


7. What to keep

  • The serial transcript of every attempt, passed or failed, under logs/ with the date, the board and the image's sha256 in its name. Logs are kept and committed, as QEMU's are.
  • Photographs of the screen where there was no serial.
  • The firmware versions: SER5 BIOS, Pi 5 EEPROM, Mars U-Boot and OpenSBI.
  • The Mars's printenv and devicetree, and the Pi 5's DTB as used.
  • The results written into FABRIC-3.md (each section ends with "update this section with results") and each board's README.md status line.

8. Before the builds are cut

The administrative work that is yours to call, listed so it is not found on the day:

  • The kernel's release number. kernel/Makefile holds a table that gives each hardware gate its own number (SER5, then the Pi 5, then the Mars); it is still to be ruled.
  • The uncommitted change to kernel/Makefile that adds the ISA to the version line: it needs a three-ISA acceptance run in the v3 configuration before it is committed.
  • CHANGELOG.md: nothing between 2026-08-18 and the uncommitted entry of 2026-10-09.
  • sbom.spdx and sbom.spdx.json brought up to date.
  • The merge of StarForth-v4.0.0 to master, and the tags LithosAnanke v2.0.0 and StarForth v4.0.0: only when you say.
  • .claude/CLAUDE.md still describes the build before boards/ existed.