80 lines
3.6 KiB
Markdown
80 lines
3.6 KiB
Markdown
# Bad Apple for UEFI (Rust)
|
||
|
||
Firmware payload that plays the Bad Apple animation directly from a UEFI image. The project uses the [`uefi`](https://github.com/rust-osdev/uefi-rs) 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 (`app` contains assets, graphics, audio, timing, and player logic).
|
||
- `assets/` – tiny demo clip/audio used as an embedded fallback.
|
||
- `tools/` – helper utilities, notably `process_badapple.py` for 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
|
||
|
||
1. Ensure you have a recent stable Rust toolchain with the UEFI target installed:
|
||
```bash
|
||
rustup target add aarch64-unknown-uefi
|
||
```
|
||
2. Build the binary:
|
||
```bash
|
||
cargo build --release --target aarch64-unknown-uefi
|
||
```
|
||
The resulting image will be at `target/aarch64-unknown-uefi/release/badapple-uefi.efi`.
|
||
|
||
Using Nix instead? Enter the dev shell or boot straight from the flake:
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
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:
|
||
```bash
|
||
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.
|