firmware: .ipod transport-format packaging (Phase 1 PR #2) - #42
Open
BrandonDedolph wants to merge 7 commits into
Open
firmware: .ipod transport-format packaging (Phase 1 PR #2)#42BrandonDedolph wants to merge 7 commits into
BrandonDedolph wants to merge 7 commits into
Conversation
`make hw` now also emits `core.bin` (objcopy -O binary on the ELF); `make ipod` wraps it as `core.ipod` — the ipodpatcher-style transport format the host installer / updater pushes to the device. Format is 4-byte BE additive checksum (model seed + sum-of-bytes, 32-bit wrap) + 4-byte model name (`ipvd`) + raw image, per core/docs/hw/08-boot-dock.md. Bits: - `firmware.WriteIPodFile` / `ReadIPodFile` in core/cli/internal/firmware/. Both are streaming-friendly; the reader returns the image bytes alongside ErrIPodChecksumMismatch so recovery tools can inspect corrupt images. - `core firmware pack <bin> -o <ipod>` / `core firmware unpack <ipod> -o <bin>` subcommands wired into the existing CLI tree. Roundtrip verified end-to-end against the actual ARM ELF from PR #1. - Meson custom_target invokes the cross-toolchain objcopy on the ELF to produce the flat binary as a build_by_default byproduct, so `core.bin` is always available next to `core.elf`. - Makefile gains `make ipod` (depends on hw). It shells out via `go run ./cmd/core firmware pack` for now; once the CLI ships as a release binary we'll switch to that. Test coverage in core/cli/internal/firmware/ipodfile_test.go: header layout, roundtrip, checksum mismatch (returns bytes anyway), truncated header, empty input, empty image. Existing checksum tests already cover the wrap-at-2^32 case. Sim build + all 4 suites unaffected (codec-kat, tcdb-reader, tag-mp3, sim-audio-playback). Stacked on phase1/hw-build-skeleton (#40). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three changes: - Status table now reflects that Phase 1 has started: drops a new "Phase 1 hw bringup" row on the working-today side (cross-build + .ipod packaging) and softens the pending side from "Bootable ARM image (Phase 1)" to "Boots on hardware (UART → LCD → scheduler)" — the more honest description of what's still missing now that the build pipeline exists. - Adds a "Quick start (hardware build)" section with `make hw` / `make ipod` and a readelf sanity check. Calls out that the kernel still spins, so flashing is gated on the install flow landing. - Adds a "Firmware image packaging" section mirroring the existing tagcache one — `core firmware pack` / `unpack` examples and a link to the format spec. Also drops the literal "55 commits on main" line since it rotates fast; replaced with a one-liner that points at STATUS.md.
…ndoff Review finding (confirmed against core/docs/hw/08-boot-dock.md): the bootloader hands off with SDRAM at its native 0x10000000, NOT remapped to 0x00000000 as crt0.S claimed — so an image linked at 0x0 would crash on its first literal-pool load on real hardware. crt0 now copies a self-contained remap stub to IRAM, programs MMAP0_PHYSICAL/MMAP0_LOGICAL from there (so the remap doesn't pull the rug out from under the executing code), and enters the remapped image via a literal inside the copied stub. Everything pre-remap is position-independent (immediates, PC-relative, IRAM addresses only) — verified by objdump inspection. Also drops the misleading ".data copy in subsequent PRs" promise: with VMA == LMA and the whole image RAM-loaded, .data arrives in place and no copy is ever needed. TODO before first hardware boot: verify the MMAP0 flags nibble (doc says 0x0F84; upstream Rockbox crt0-pp.S may use 0x3F84 — looks like a 32 MB vs 64 MB window mask, which matters on the 64 MB 5.5G). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review findings (confirmed): - unpack hardcoded ModelIPodVideo (0x05) as the checksum seed, so any intact non-Video .ipod (e.g. nano, seed 0x04) reported a false checksum mismatch — contradicting the README's "inspect third-party images" use case. ReadIPodFile now derives the seed from the embedded 4-byte model name via ModelNumForName; unknown names get a distinct ErrUnknownModelName that still returns name + bytes (same recovery- tool philosophy as the existing mismatch path). - pack/unpack silently overwrote --out via os.Create/os.WriteFile, diverging from the CLI's established safety pattern. Both now use O_EXCL-by-default with a --force flag, mirroring tagcache build. New tests: nano round-trip (seed 0x04), unknown-name sentinel, ModelNumForName mapping. go vet + go test ./... green; pack→unpack→cmp round-trip and --force gating smoke-verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The new O_EXCL-by-default overwrite guard on `core firmware pack` made a second `make ipod` fail on the previous run's core.ipod. Rebuilding over your own build artifact is the expected case in a make target. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verified against Rockbox crt0-pp.S + pp5020.h (master, 2026-06-10): the window-size mask lives in the LOGICAL register, not the physical flags — 0x3C00 = 64 MB window (what every Rockbox iPod Video build writes, 32 MB 5Gs included; RAM size is probed at runtime), 0x3E00 = 32 MB. We were writing 0x00000000: mask bits all clear, a value no known firmware ever writes. The earlier 0x0F84-vs-0x3F84 suspicion was aimed at the wrong register — 0x0F84 is confirmed correct for PP502x (0x3F84 is the PP5002 value); resolved that TODO. Also matches Rockbox's write order (logical first, physical second) and corrects 01-soc-pp5022.md: the remap section now documents the mask semantics, and the memory-map intro no longer claims the bootloader performs the remap (ipodloader2 restores the Apple-ROM MMAP state and jumps at native 0x10000000 — confirmed from its loader.c/interrupts.c — so the remap is the loaded image's job, matching what crt0.S now does). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The handoff contract says only the CPU runs, but Rockbox parks the second core at _start defensively — and the clicky emulator's HLE boot proved why: it enters both cores, and the unparked COP raced the CPU through BSS-zero and uart_init (doubled every UART character, interleaved CPU/COP PROCESSOR_ID reads). Same failure mode would apply on hardware to any loader that wakes both cores. PROCESSOR_ID low-byte check (0x55 CPU / 0xAA COP), busy-spin park, immediates + fixed MMIO only so the pre-remap position-independence invariant holds. The scheduler PR replaces this with a proper COP_CTL sleep + wake protocol. Found via the clicky (github.com/daniel5151/clicky) PP emulator, evaluated 2026-06-11 as a no-hardware regression rig: it models the MMAP0 remap, the SER0 UART (TX -> stdout), and boots our unmodified core.bin to the full banner. Repro recipe in STATUS.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Builds the host-side
.ipodpackager that turns the ARM ELF from #40 into a flashable artifact. Stacked onphase1/hw-build-skeleton; rebase tomainonce #40 merges.core/docs/hw/08-boot-dock.md):[BE32 checksum][4-byte model name "ipvd"][raw image]. Checksum is the additive model-seed + sum-of-bytes, 32-bit wrap.firmware.Checksum(already shipped) does the math; newfirmware.WriteIPodFile/ReadIPodFiledo the file layout.core firmware pack <bin> -o <out.ipod>/core firmware unpack <ipod> -o <out.bin>. Reader returns image bytes alongsideErrIPodChecksumMismatchso recovery tools can inspect corrupt input.core.binas abuild_by_defaultbyproduct;make ipod(new target) wrapscore.bin→core.ipodviago run ./cmd/core firmware pack.core/cli/internal/firmware/ipodfile_test.gocovers header layout, roundtrip, checksum mismatch, truncated header, empty input, empty image. Existing checksum tests already cover wrap-at-2^32.End-to-end output for the PR #1 spin kernel: 60 image bytes + 8 header bytes = 68-byte
.ipod. Checksum verified bycore firmware unpack(noErrIPodChecksumMismatch); unpacked bytes arecmp-identical to the originalcore.bin.Test plan
cd core && make ipodproducesbuild-hw/core.ipod(68 bytes for the current spin kernel)xxd build-hw/core.ipod | head -1showsipvdat bytes 4–7cd core && go run ./cli/cmd/core firmware unpack build-hw/core.ipod -o /tmp/u.bin && cmp /tmp/u.bin build-hw/core.bin— roundtrip cleancd core/cli && go test ./...— all packages green (firmware now includes the .ipod cases)cd core && make sim && meson test -C build-sim— 4/4 green, sim build unaffected🤖 Generated with Claude Code