ReviewOS

home-lang/home-os

EPIC: HomeOS Media Center on Raspberry Pi 5 — an Apple-TV-class living-room OS built only from our own stack (Home, Craft, stx, crosswind, pantry)

#113
Open chris opened this 8 days ago ·
8 days ago

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 rpi5 exits 1 by design; the compiler's kernel codegen is x86-only; arch/arm64/arm64.home MMIO 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-image

Critical 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)

GateIssue
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/image packages (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 T lowering on aarch64)
  • #54 build.sh: a real rpi5 pipeline (Home compile → assemble boot → link linker-rpi5.ld → objcopy → kernel_2712.img) and removal of the fake all/unified steps
  • #55 CI: mvk-compiles-aarch64 ratchet and boot-qemu-aarch64 gate (-M virt, PL011 serial) — the ARM regression wall before any hardware
  • #56 Make pi-hardware-test.yml truthful: 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.s for BCM2712 (EL2→EL1, stack, BSS, DTB in x0, park cores 1–3, jump to Home kernel_main) + corrected config.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 @ptrFromInt derefs)
  • #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 dangling libs/craft/craft.home import so apps/ 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 at 0x1F_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.home hardware-neutral and fast: remove the hardcoded 0xFD000000, 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 image package (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 / image packages 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 home output format for stx's craft-compiler that emits Craft component trees, signal bindings and event handlers as .home source (build-time, zero JS on device)
  • #90 crosswind → HIG tokens: resolve utility classes in .stx to hig-tokens.home values 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.zig semantics 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.home are 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.local and _homeos-remote._tcp, browse _smb._tcp/_nfs._tcp/_http._tcp for 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.

Sign in to comment on this issue.