Goal
Boot a Raspberry Pi 5 straight into a fast, quiet, remote-driven TV shell that plays local and NAS media (H.264 1080p in software, HEVC 4K in hardware), with artwork, subtitles, CEC/Bluetooth/phone remotes, and OTA updates with rollback — no Linux userland, no Kodi/Plex, everything in Home except boot assembly, with the UI authored in stx and compiled ahead of time to Craft.
Where we start (measured 2026-09-02)
- x86-64 QEMU: 55/55 init milestones, serial shell, ext2 round-trip, PSF framebuffer console, ring-3 ELF. That is everything that runs.
- ARM64:
build.sh rpi5exits 1 by design; the compiler's kernel codegen is x86-only;arch/arm64/arm64.homeMMIO is a no-op (S8). No Home code has ever executed on a Pi. - Media: decoders in this repo are stubs; the compiler repo's stdlib has ~168K lines of Zig codecs/demuxers/subtitles/images with Home bindings, never built freestanding or for ARM.
- UI: stx (TS) has a Craft-native compiler path but no renderer; HomeOS has its own Craft in Home (spec v0.3) and HIG tokens; fonts are 8×16 bitmaps only.
Architecture (device side, all Home)
┌──────────────── apps/tv (one Craft process) ────────────────┐
│ screens (.stx → generated .home) focus engine player lib │
├──────────── libs: craft · media bindings · tls · mdns ──────┤
│ kernel: compositor (UI plane 1080p, CPU+NEON) ─┐ │
│ HVS planes + HDMI + CEC + HDMI audio ──┤ BCM2712 │
│ HEVC HW decoder · SDHCI · PCIe → RP1 (xHCI, GEM, GPIO/I2S)
│ sched/mm/vfs/net (shared with x86) · arm64: MMU/GIC/timer
└─────────────────────────────────────────────────────────────┘
boot: boot.s (EL2→EL1) ← EEPROM bootloader ← kernel_2712.img + DTB
build (Mac/CI): home build --kernel --target=aarch64-freestanding · stx --format=home · icon/font atlases · pi-imageCritical path (serial)
#44 → #51 → #52 + #53 → #54 → #57 → #60 → #61 → #63 → #73 → #74 → #79 → #84 → #88.
Parallel-safe today (no compiler dependency; proven on x86 QEMU first)
#43, #45, #46, #47, #48, #50, #62, #65, #76, #89, #90, #91, #75 (x86 backend), #82 (x86 half), #83, #107, #68 (QEMU xHCI), #70 (QEMU), #69 (S3 via virtio first), #102, #56.
Gates (all must be green for v1; hardware ones run on the rig)
| Gate | Issue |
|---|---|
mvk-compiles-aarch64 70/70, boot-qemu-aarch64 | #55 |
boot-pi5-serial | #63 |
storage-roundtrip-pi5, net-echo (Pi) | #66, #69 |
fb-pi5-first-pixel, HVS 60 fps no-tear | #73, #74 |
hdmi-audio-tone | #79 |
| codec conformance ratchet | #83 |
playback-1080p-h264, playback-4k-hevc, soak-4h | #88 |
tv-ui-60fps, input-latency, boot-to-home-screen | #101 |
idle-budget, power-idle/play | #49 |
ota-roundtrip, install test | #109, #111 |
Budgets
Boot → home ≤ 8 s · idle ≤ 128 MB / ≤ 3 % CPU / ≤ 3 W · UI p99 ≤ 16.6 ms · input ≤ 50 ms · 1080p H.264 SW ≤ 60 % CPU · 4K HEVC HW 0 drops.
Sizing
MC0 S · MC1 XL (compiler; the long pole) · MC2 L · MC3 XL · MC4 XL · MC5 L · MC6 XL · MC7 XL · MC8 L · MC9 M. The compiler backend and the display driver are the two items with real technical risk; everything else is volume.
Issue index
MC0 — Product & decisions
- #43 ADR-MC1: Media-center product definition, non-goals, and budgets (the "Apple TV" spec)
- #44 ADR-MC2: aarch64 kernel codegen strategy — extend the direct emitter (mirror of the x86-64 kernel path), LLVM only as a revisit trigger
- #45 ADR-MC3: Media codecs — consume the Home stdlib
audio/video/imagepackages (Zig, in the compiler repo) via Home bindings; port-to-Home tracked under A7 - #46 ADR-MC4: UI stack — stx authored, compiled ahead-of-time to Craft/Home; zero JavaScript on the device; zig-js reserved for post-v1 plugins
- #47 ADR-MC5: Display architecture — HVS hardware planes, CPU-rasterised 1080p UI plane, native-resolution video plane, no V3D in v1
- #48 Hardware-in-the-loop rig for the Pi 5: bill of materials, wiring, host setup (Debug Probe, HDMI capture, power relay, TFTP boot)
- #49 Performance, memory and power budgets as CI gates (boot time, idle RSS/CPU, frame time, input latency, decode load, watts)
- #50 10-foot HIG addendum: TV type scale, focus & selection language, safe areas, motion, remote-key grammar
MC1 — Toolchain: aarch64
- #51 A6.1: aarch64 lowering for the kernel codegen path — a proof-of-life ladder mirroring Phase 0.5, ratcheted per Appendix-A file
- #52 A6.2:
home build --kernel --target=aarch64-freestanding— explicit target selection, ELF64/aarch64 object emission, relocations, cross-compile from macOS/x86 CI - #53 A3: volatile MMIO load/store semantics and barrier intrinsics in the Home language (dmb/dsb/isb, ldar/stlr,
*volatile Tlowering on aarch64) - #54 build.sh: a real
rpi5pipeline (Home compile → assemble boot → linklinker-rpi5.ld→ objcopy →kernel_2712.img) and removal of the fakeall/unifiedsteps - #55 CI:
mvk-compiles-aarch64ratchet andboot-qemu-aarch64gate (-M virt, PL011 serial) — the ARM regression wall before any hardware - #56 Make
pi-hardware-test.ymltruthful: stop probing the runner's Linux, pin the same Zig as ci.yml, fail red until a HomeOS image really boots
MC2 — Pi 5 bring-up
- #57 Pi 5 entry:
boot.sfor BCM2712 (EL2→EL1, stack, BSS, DTB in x0, park cores 1–3, jump to Homekernel_main) + correctedconfig.txt— and the very first UART banner on real hardware - #58 PL011 driver for the BCM2712 debug UART and serial console; consolidate the two serial implementations
- #59 Device-tree at boot: parse the firmware DTB for memory size, UART/GIC/RP1 bases, model string; consolidate the two duplicated FDT parsers
- #60 S8: de-stub
arch/arm64/arm64.home— real MMIO with barriers, sysreg access, wfe/wfi — and route every Pi driver through it (no more raw@ptrFromIntderefs) - #61 ARM64 core: MMU (4 KB granule, 40-bit PA, device vs normal memory), exception vectors, GICv3 (GIC-600), generic timer at 54 MHz, scheduler tick — the x86 init milestones reproduced on ARM
- #62 Consolidate the three overlapping Pi trees (
arch/arm64/,arch/arm64/rpi/,kernel/src/rpi/) into one BCM2712-first layout; park or delete Pi 3/4 code - #63 Gate
boot-pi5-serial: the full Home kernel boots on a real Pi 5 to the interactive serial shell, scripted from the Mac (Phase 7b's first half) - #64 SMP bring-up of all four Cortex-A76 cores, firmware mailbox (power, clocks, temperature, throttling), watchdog and cpufreq policy for the TV profile
- #65 Fix the 66 kernel files using
and the danglinglibs/craft/craft.homeimport soapps/and drivers can enter the compile ratchet
MC3 — Pi 5 platform drivers
- #66 SDHCI driver for the BCM2712 SD slot: real MMIO init, CMD/DATA state machine, DMA (ADMA2) reads/writes, block device → ext2/homefs root from SD
- #67 PCIe host controller (BCM2712
pcie@…) + RP1 southbridge enumeration: link training, BAR mapping at0x1F_0000_0000, interrupt routing for RP1 peripherals - #68 USB core (S6) + RP1 xHCI: enumeration, control/bulk/interrupt transfers, HID boot protocol (keyboard + remote), mass storage (BOT/SCSI) for USB media drives
- #69 RP1 Gigabit Ethernet (Cadence GEM MAC + PHY) driver and closing S3 (netdev RX) — a DHCP lease and a TCP echo on the real LAN
- #70 NVMe over the Pi 5 PCIe FPC connector (M.2 HAT) as the media-library disk — admin/IO queues, MSI-X, ext2/homefs mount, boot-from-NVMe option
- #71 Post-v1: CYW43455 Wi-Fi over SDIO and Bluetooth over UART (firmware-blob loader, SDIO transport, BT HCI for remotes)
- #72 RP1 GPIO, PWM, I2S and an optional GPIO IR receiver (NEC/RC5/RC6 decoding) for legacy remotes and DAC HATs
MC4 — Display & 2D
- #73 First pixel on the Pi 5: mailbox property-channel framebuffer (allocate, set physical/virtual size, depth, pitch) + the existing PSF console on HDMI — HIL gate
fb-pi5-first-pixel - #74 Native display driver in Home: HVS planes + HDMI encoder/PHY on BCM2712 — EDID, 1080p60/2160p60, hotplug, vsync flip, YUV video plane, HDR10 infoframe passthrough (stretch)
- #75 Make
video/compositor.homehardware-neutral and fast: remove the hardcoded0xFD000000, backend interface (bochs/mailbox/HVS), dirty rectangles, NEON blits, vsync pacing, frame-time histogram - #76 TrueType/OpenType rasterizer in Home (
text.home): glyf + CFF outlines, anti-aliased scanline fill, kerning/GPOS basics, shaping for Latin + fallback, glyph atlas cache - #77 Icons: build-time SVG rasterisation of the stx Iconify collections into per-size alpha atlases, plus a minimal on-device SVG path renderer for dynamic tints
- #78 Artwork and photos: PNG/JPEG/WebP decode on device via the Home stdlib
imagepackage (freestanding aarch64), progressive/downscaled decode, thumbnail cache
MC5 — Audio
- #79 HDMI audio output on BCM2712 (HDMI block audio interface + DMA): PCM 2.0/5.1 at 48 kHz, audio infoframe, sample-rate/clock config — HIL gate
hdmi-audio-tone - #80 I2S output via RP1 for DAC HATs (48/96 kHz, 16/24/32-bit), master/slave clocking, as an alternative audio sink selectable in Settings
- #81 Audio server in Home: mixer, resampler, ring buffers, master A/V clock, volume/mute/ducking for UI sounds, and later IEC61937 passthrough
MC6 — Media engine
- #82 Build the Home stdlib
audio/video/imagepackages freestanding for aarch64 (no libc, injected allocator, no OS threads, NEON) and expose them to HomeOS through Home bindings - #83 Codec and container conformance in CI (host x86, then ARM): H.264/HEVC/AAC/MP3/FLAC/Opus/Vorbis bitstreams, MP4/MKV/TS demux, subtitle formats — measured, not claimed
- #84 VideoCore VII HEVC hardware decoder driver in Home (BCM2712
hevc-dec): slice-level command submission, reference frame management, Main/Main10 up to 4Kp60, zero-copy into an HVS video plane - #85 Playback pipeline (
apps/tv/player/): source → demux → decode (SW/HW) → A/V sync → present; seek, chapters, trick play, gapless, resume points, track switching - #86 Subtitles: SRT/VTT/ASS(text-level styling)/PGS rendering into the OSD layer, timing against the master clock, font fallback, size/position settings
- #87 Network sources: HTTP(S) progressive with range/seek, HLS (VOD + live, fMP4 + TS segments, variant selection), DASH later; TLS via S5
- #88 Gates:
playback-1080p-h264(software, NEON),playback-4k-hevc(hardware),soak-4h, dropped-frame and RSS ceilings — the media-engine acceptance on the rig
MC7 — TV shell
- #89 stx → Home: a
homeoutput format for stx's craft-compiler that emits Craft component trees, signal bindings and event handlers as.homesource (build-time, zero JS on device) - #90 crosswind → HIG tokens: resolve utility classes in
.stxtohig-tokens.homevalues at compile time (spacing, type scale, colour roles, radii, motion); no CSS parser or stylesheet on the device - #91 Craft focus & navigation engine for D-pad input: spatial navigation, focus memory, long-press, back stack, on-screen keyboard traversal, focus animations (port of the
tv.zigsemantics to Home) - #92 TV shell (
apps/tv/): one long-running Craft process booted directly by init — home screen (hero/top shelf, app row, Continue Watching, Recently Added), app lifecycle, global state, crash recovery - #93 Library screens: Movies (grid/detail), TV Shows (series → seasons → episodes, next-up), Music (artists/albums/tracks/playlists, now-playing bar), Photos (albums/timeline/slideshow), Sources (browse folders on USB/NAS)
- #94 Player OSD: scrubber with thumbnails, chapters, time/remaining, audio & subtitle track pickers, info overlay (codec/bitrate/dropped frames), video/audio settings, idle auto-hide
- #95 Settings and first-run onboarding: display (mode, overscan, HDR), audio (device, channels, passthrough), network (Ethernet/Wi-Fi status, hostname), sources & libraries, remotes (CEC/BT/IR pairing), screensaver, updates, about/diagnostics
- #96 Screensaver, idle dimming, HDMI/CEC standby and wake, "still watching?" prompt, power-key behaviour
- #97 Search and on-screen keyboard: fuzzy search across the library (titles, people, albums), grid OSK optimised for D-pad, phone-remote text input, voice out of scope
- #98 HDMI-CEC in Home: remote key reception (user-control-pressed), TV power/volume/input control, One Touch Play, System Standby, device discovery — the default remote is the TV's own
- #99 Bluetooth and USB HID remotes/gamepads/keyboards: HID report-descriptor parser, Consumer Control page, gamepad mapping, pairing UI, per-device keymaps
- #100 Phone remote: mDNS-advertised HTTP + WebSocket control API on the device, and an stx web app (served by the device) with D-pad, text input, now-playing, and cast-to-device
- #101 Gate
tv-ui-60fps+input-latency+boot-to-home-screen: frame-time histogram thresholds, key-to-photon via capture, golden-frame screenshot suite in QEMU x86
MC8 — Library & services
- #102 Media scanner and library database: incremental scan of sources, filename/NFO parsing, watched state, resume points, thumbnails, on-disk DB with crash safety
- #103 Metadata providers over HTTPS: TMDB (movies/TV), TheTVDB optional, MusicBrainz + Cover Art Archive (music); matching heuristics, artwork download/cache, offline-first, user-supplied API key
- #104 NAS sources: SMB2/3 client and NFSv3 client made real (
net/smb.home,net/nfs.homeare 3,000 unrun lines), mount UI, credentials store, read-ahead tuned for 4K streams - #105 mDNS/DNS-SD responder and browser in Home: advertise
homeos-tv.localand_homeos-remote._tcp, browse_smb._tcp/_nfs._tcp/_http._tcpfor sources - #106 DLNA/UPnP: Media Renderer (phones/apps cast to the TV) and Media Server (browse the library from other devices); AirPlay/Google Cast receivers recorded as post-v1 research
- #107 S5 + TLS 1.3 client: real SHA-256/HMAC/AES-GCM/ChaCha20-Poly1305/X25519/Ed25519 in Home, certificate verification with a bundled root store, used by HTTPS sources, metadata, OTA signature checks
MC9 — Ship
- #108
build.sh pi-image --target=rpi5 --profile=tv: reproducible SD/NVMe image (FAT32 boot with DTBs + config + A/B kernel slots, root A/B partitions, data partition), first-boot provisioning (grow data, hostname, settings) - #109 OTA updates with rollback: signed image manifests on a pantry channel, A/B root + kernel slots via the Pi 5 bootloader
tryboot, health check → commit or automatic rollback, Settings UI - #110 Recovery/safe mode: hold-key or serial-triggered minimal shell with display, factory reset (keep/wipe library), reflash from a USB image, log export to USB
- #111 Self-hosted hardware-in-the-loop CI for the Pi 5 rig: nightly boot/serial/display/audio gates, weekly playback soak + perf + power + OTA round-trip, results into the status page
- #112 E2E test playbook
docs/testing/PI5_E2E.md: staged, copy-paste checklists for testing on the real Pi 5 (rig smoke → serial kernel → first pixel → audio → playback → soak → OTA) + docs realignment of the Pi 5 pages
E2E testing on the Pi
Step-by-step staged instructions live in #112 (docs/testing/PI5_E2E.md once merged); the rig is #48.