| .cache | ||
| .cargo | ||
| ai | ||
| assets | ||
| src | ||
| tools | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
| test.patch | ||
Bad Apple for UEFI (Rust)
Firmware payload that plays the Bad Apple animation directly from a UEFI image. The project uses the uefi crate, renders video frames through GOP, and synthesises audio via the legacy PC speaker using a 1-bit sigma-delta stream. Everything fits inside a no_std Rust binary and can be driven under QEMU.
Repository layout
src/– modular firmware code (appcontains assets, graphics, audio, timing, and player logic).assets/– tiny demo clip/audio used as an embedded fallback.tools/– helper utilities, notablyprocess_badapple.pyfor converting the real video/audio into firmware-friendly blobs.ai/state.json– persistent JSON with personas/tasks as requested.flake.nix– reproducible Nix environment with Rust, ffmpeg, and QEMU.
Building the EFI binary
- Ensure you have a recent stable Rust toolchain with the UEFI target installed:
rustup target add aarch64-unknown-uefi - Build the binary:
The resulting image will be atcargo build --release --target aarch64-unknown-uefitarget/aarch64-unknown-uefi/release/badapple-uefi.efi.
Using Nix instead? Enter the dev shell or boot straight from the flake:
nix develop
# (rustup target add aarch64-unknown-uefi is invoked automatically in the shell)
# Build & boot in one go under QEMU (cross-emulates aarch64 firmware):
nix run .#qemu
Preparing real assets
The repository embeds a tiny placeholder clip so builds work immediately. To convert the actual Bad Apple video/audio:
python3 tools/process_badapple.py \
--input /path/to/badapple.mp4 \
--output-dir build/assets \
--width 320 --height 240 --fps 30 \
--sample-rate 44100
Copy the generated video.baa and audio.pdm onto the EFI system partition alongside the application under \EFI\BADAPPLE\. The firmware attempts to load external assets first, then falls back to the embedded demo when they are missing.
Asset format summary
video.baa: magic"BAA\0", header with width/height/fps/frame count, followed by 1-bit packed frames (LSB-first).audio.pdm: magic"BAP\0", header with sample rate and sample count, followed by 1-bit sigma-delta stream (LSB-first).
Running under QEMU
A minimal invocation after copying the EFI binary and assets to a FAT image might look like:
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a72 \
-m 1024 \
-drive if=pflash,format=raw,readonly=on,file=/path/to/AAVMF_CODE.fd \
-drive if=pflash,format=raw,file=/path/to/AAVMF_VARS.fd \
-drive file=fat:rw:esp,format=raw \
-device virtio-gpu-pci \
-device ramfb \
-serial mon:stdio
Make sure the esp directory contains EFI/BOOT/BOOTAA64.EFI (your compiled binary) plus the EFI/BADAPPLE assets. Audio output is currently disabled on non-x86 platforms because the legacy PC speaker is unavailable; video playback continues in sync.
Notes & limitations
- Audio playback uses the legacy PC speaker path on x86 machines; on aarch64 builds the backend is currently silent because that device is absent.
- Timing relies on TSC calibration during boot services. Firmware with non-constant TSCs may require additional guarding.
- Video rendering assumes the selected GOP mode exposes a writable framebuffer (non-BLT-only). Modes with vendor-specific bitmasks are supported via mask calculation.
Next steps
- Replace the placeholder clip with the full Bad Apple dataset via the tooling above.
- Consider double buffering and smarter frame pacing to reduce tearing.
- Experiment with richer audio backends (e.g. direct HDA/AC97 programming) if available on your platform.