294 lines
15 KiB
Markdown
Executable File
294 lines
15 KiB
Markdown
Executable File
# OreBolt OS
|
||
|
||
A hackable firmware for the HiFiWalker H2 — a $30 MIPS digital audio player
|
||
that ships with a Linux userspace, a 320×320 LCD, and 64 MB of RAM.
|
||
|
||
> **New here?** Jump to [QUICKSTART.md](QUICKSTART.md) for the build-and-deploy
|
||
> walkthrough. This document is the project reference.
|
||
|
||
There is a particular class of consumer hardware that is cheap enough to be
|
||
disposable, yet capable enough to run a real operating system with real
|
||
peripherals. The HiFiWalker H2 sits squarely in that class. Under its
|
||
rubberized shell is an Ingenic X1000E SoC — a MIPS32r2 hard-float core
|
||
clocked at ~1.0 GHz, paired with 64 MB of DDR2 and an ESS ES9018K2M DAC that
|
||
was designed for serious audio. The stock firmware plays music. OreBolt OS
|
||
replaces it with a modular, LVGL-driven toolkit for hardware interrogation,
|
||
RF sensing, payload delivery, and forensic extraction — all running on a
|
||
device that fits in a shirt pocket and boots from a FAT32 MicroSD card.
|
||
|
||
The entire system is cross-compiled from an Arch Linux host using a
|
||
`mipsel-linux-musl` toolchain (the Rockbox prebuilt is recommended). Every
|
||
user-facing module is a single-position-independent `.mod` ELF binary that
|
||
dynamically links against a shared `liblvgl.so`. A fork/exec broker in the
|
||
master launcher (`h2_test`) loads them on demand, which means only one module's
|
||
code segment lives in RAM at a time — a hard constraint when your whole
|
||
working set is 64 MB and the kernel already claims its cut.
|
||
|
||
See [CHANGELOG.md](CHANGELOG.md) for the version history.
|
||
|
||
---
|
||
|
||
## The H2 hardware family
|
||
|
||
The HiFiWalker H2 is one of five rebadged devices built on the same
|
||
PCB — the **Aigo Eros Q** family. They are interchangeable from a
|
||
firmware perspective. OreBolt OS and the stock Hiby Player both boot
|
||
from the FAT32 MicroSD card; the SPI flash bootloader is never
|
||
modified.
|
||
|
||
| Brand / Model | Notes |
|
||
|---|---|
|
||
| HiFiWalker H2 | Most widely known; rubberized scroll wheel |
|
||
| Surfans F20 | Knurled metal scroll wheel |
|
||
| Aigo Eros Q | Original design base for the family |
|
||
| Phinistec Z6 | Common rebadged version |
|
||
| Agptek H3 | Same lineage of budget DAPs |
|
||
|
||
All share the X1000E SoC, ESS ES9018K2M DAC, and MAX97220 headphone amp.
|
||
Multiple hardware revisions exist — some have Micro-USB, newer ones have
|
||
USB-C. All share the same PCB and run the same OreBolt OS image.
|
||
|
||
## Architecture at a glance
|
||
|
||
The build pipeline is a single `./build.sh` invocation with eight phases:
|
||
dependency verification, workspace integrity check, overlay tree creation,
|
||
LVGL compilation, module compilation, hardware library archiving, artifact
|
||
validation (MIPS ELF + AGPL marker check), and optional SD card deployment.
|
||
The Makefile is split into a thin `Makefile` shell that delegates to
|
||
`Makefile.h2-core-v6.2`, which knows how to build the core runtime, LVGL,
|
||
and all modules in the correct dependency order.
|
||
|
||
At runtime the flow is: init scripts start the retro input mapper daemon
|
||
(`S98retro-input`), then the master launcher (`S99broker` / `h2_test`),
|
||
then the BLE input daemon. The launcher presents a scrollable LVGL menu of
|
||
all registered modules. Selecting one causes the broker to `fork()` + `execv()`
|
||
the corresponding `.mod` binary from `overlay/apps/`. When the module exits,
|
||
control returns to the launcher menu. Only one module runs at a time.
|
||
|
||
The platform ships three core artifacts besides the modules themselves:
|
||
`liblvgl.so` (LVGL v8.3.11, ~200 KB, MIT-licensed upstream), `liborebolt.a`
|
||
(a static archive of hardware-level routines linked into every module), and a
|
||
150-payload HID macro matrix split across Linux, macOS, and Windows profiles.
|
||
|
||
## Modules
|
||
|
||
Seventeen modules, each a self-contained `.mod` binary with its own LVGL
|
||
screen. They group into four operational categories plus one networking
|
||
module with a separate license tier.
|
||
|
||
### Offense / payload delivery
|
||
|
||
These modules exist because the H2's USB port can be reconfigured into
|
||
arbitrary gadget topologies through ConfigFS. That single capability —
|
||
presenting the device as whatever USB composite the operator needs — is the
|
||
foundation of the offense surface.
|
||
|
||
**`deploy.mod`** — Flash storage manager. Calls `statvfs("/")` to pull
|
||
total, used, and free bytes from the SD card and renders them as a live
|
||
storage dashboard. The PLAY button triggers a manual `sync()` flush. Not
|
||
exciting on its own, but every operator needs to know how much space is left
|
||
before dropping a 150-payload macro matrix onto a 2 GB card.
|
||
|
||
**`pauto.mod`** — Payload Automation, the HID keystroke injector. It parses
|
||
OreBolt's custom macro command language and injects keystrokes through
|
||
`/dev/hidg0`, the HID function endpoint exposed by the gadget subsystem.
|
||
Each `.dd` payload file encodes an OS-specific key sequence (delay, modifier,
|
||
scan code triples). The module selects the correct profile (Linux, macOS, or
|
||
Windows) and plays it back at USB-speed. This is the module that turns the H2
|
||
from a music player into a BadUSB-class device.
|
||
|
||
**`retro.mod`** — Retro game launcher. Scans `/data/roms/` recursively
|
||
for ROM files across 11 systems (NES, SNES, Game Boy, Genesis, SMS,
|
||
GameGear, PCE, Atari 2600, Neo Geo Pocket, and FDS/GBA), auto-detects the
|
||
target system by file extension, and displays a filterable LVGL picker
|
||
menu. Selecting a ROM forks the matching emulator binary (fceux, snes9x,
|
||
gambatte, gpsp, dgen, mednafen, or stella) and monitors it — BACK sends
|
||
SIGTERM to the emulator child. The companion `retro_input_mapper` daemon
|
||
runs at boot via `S98retro-input` and creates a virtual uinput gamepad
|
||
that maps the H2's rotary encoder and buttons to standard d-pad + ABXYLR
|
||
+ Start/Select, complete with a rotary-press axis toggle (vertical U/D
|
||
vs. horizontal L/R) that auto-reverts after 3 seconds of idle.
|
||
|
||
**`glitch.mod`** — Hardware glitch injector. Drives X1000E GPIO lines to
|
||
produce timed power and clock glitches against an externally-wired target.
|
||
The module exposes controls for glitch width, trigger delay, and repeat count
|
||
on the LVGL UI. It is the most hardware-dependent module in the stack — it
|
||
requires physical access to the target's power or clock rail and assumes the
|
||
operator has wired the glitch circuit correctly.
|
||
|
||
### Forensics & extraction
|
||
|
||
**`extract.mod`** — Mass storage extractor. Recursively copies files from
|
||
`/mnt/target_media` (a mount point for an attached USB mass storage device)
|
||
into `/data/loot_drop/extracted/`. It walks the directory tree, skips
|
||
symlinks (to avoid following loops into the host filesystem), copies in 4 KB
|
||
chunks, and displays running file, directory, and byte counts on the LVGL
|
||
screen. The forensic dispatch engine that selects which `.dd` payload to run
|
||
against a detected OS lives in `mod_forensics.c` within `liborebolt.a`.
|
||
|
||
**`vault.mod`** — Encrypted credentials and payload vault. Provides PIN-based
|
||
authentication and stores operator-curated quick-launch lists in
|
||
`Provision.txt`. Sensitive payload content is encrypted at rest. The vault
|
||
is the module you lock down before handing the device to someone else.
|
||
|
||
**`probe.mod`** — I2C bus scanner. Probes `/dev/i2c-0` across the full
|
||
address space (0x03–0x77) using `ioctl(I2C_SLAVE)` + `i2c_smbus_read_byte()`.
|
||
Responding devices are highlighted green on the LVGL display. On the H2 this
|
||
will typically enumerate the DAC, the audio codec, and any attached I2C
|
||
peripherals. Five seconds of runtime tells you exactly what is on the bus.
|
||
|
||
**`pwdb.mod`** — Password database with bcrypt and argon2 verification.
|
||
Stores operator-managed credential entries and supports verifying captured
|
||
hashes against the local database. The hashing implementations are linked
|
||
from `liborebolt.a` and run entirely on the MIPS core — no external crypto
|
||
library dependency.
|
||
|
||
### Reconnaissance & sensing
|
||
|
||
This is where the H2's Bluetooth radio and its (future) WiFi capability come
|
||
into play. The X1000E has an on-die BLE controller, and the recon
|
||
architecture supports WiFi scanning through `nl80211` once a driver is
|
||
available.
|
||
|
||
**`proxalarm.mod`** — The flagship recon module, built as a single `.mod`
|
||
binary with three internal layers to keep the RAM footprint tight on a 64 MB
|
||
device:
|
||
|
||
The **bledsp** layer handles RF scanning. It opens the BLE socket, pulls
|
||
advertisements, and runs the RSSI values through a rolling-average low-pass
|
||
filter implemented with MIPS DSP ASE intrinsics (`__builtin_mips_q31` mul
|
||
and shift operations) to smooth out the noise floor. A `bledsp_poll_wifi()`
|
||
stub is wired in and ready for future `nl80211` integration — when a WiFi
|
||
driver lands, the same smoothing pipeline handles WiFi RSSI with no
|
||
architectural change. The **NEXT** key cycles the RF source between BLE and
|
||
WiFi.
|
||
|
||
The **proxvec** layer is the kinematics engine. It maintains a target table
|
||
with unique device IDs, tracks per-target state machines (new / tracking /
|
||
stale / expired), and computes radial velocity from the rate of change in
|
||
smoothed RSSI over time (delta-distance divided by delta-time). This is not
|
||
GPS-accurate positioning — it is coarse proximity estimation based on RF
|
||
signal propagation, but on a device the size of a deck of cards, coarse is
|
||
what you get and coarse is useful.
|
||
|
||
The **radar_ui** layer renders a 320×320 LVGL canvas with a rotating sweep
|
||
line, four range rings, and color-coded blips for each tracked target. Blip
|
||
color encodes signal strength (bright green for close, dim red for far), and
|
||
velocity vectors show whether a target is approaching or receding. When a
|
||
target crosses the alarm threshold, the display flashes an overlay. The
|
||
**ROTATE** knob cycles through four sensitivity presets (−40 to −70 dBm
|
||
floor), **PLAY** toggles pause/resume, **BACK** exits.
|
||
|
||
One binary, one scan loop, one set of smoothing buffers — the entire
|
||
proximity sensing pipeline fits in a single module slot.
|
||
|
||
**`nettaps.mod`** — USB virtual network tap. Opens a raw `AF_PACKET` socket
|
||
on `usb0`, captures IP packets, and parses them into a live LVGL console. A
|
||
configurable time-window coalescer (30 s / 1 min / 2 min / 5 min / 10 min)
|
||
aggregates packet counts before flushing to disk — important because the H2's
|
||
SD card has limited write endurance. The flash-safe timed flush is the detail
|
||
that separates a toy packet sniffer from something you can leave running on
|
||
actual hardware.
|
||
|
||
**`rfid.mod`** — RFID/NFC reader. Drives an externally-attached reader over
|
||
UART or SPI, enumerates cards in range, and dumps tag memory contents to the
|
||
LVGL display. The module itself is straightforward; the complexity lives in
|
||
the physical layer — which reader board, which antenna, which frequency band
|
||
(125 kHz LF or 13.56 MHz HF).
|
||
|
||
### Environment & shell
|
||
|
||
**`vterm.mod`** — Virtual terminal with a FreeDOS bridge. Provides a
|
||
TTY-style shell rendered inside an LVGL text area. Ships a minimal FreeDOS
|
||
userland under `overlay/data/vterm/freedos/bin/` for x86 emulation scenarios.
|
||
On the H2's MIPS core this is necessarily slow, but it demonstrates that the
|
||
module system can host an entire foreign userland.
|
||
|
||
**`studio.mod`** — UAC2 Mixer Console. Four-channel mixer (GAME / DISCORD /
|
||
MIC / MUSIC) with per-channel volume bars. **NEXT** and **PREV** cycle the
|
||
active channel, **PLAY** toggles hardware mute. Volume adjustments are sent
|
||
as USB Consumer Control HID commands through `/dev/hidg1`. The module turns
|
||
the H2 into a physical audio mixer — plug it into a host, twist the scroll
|
||
wheel, and the host's volume changes.
|
||
|
||
**`noise.mod`** — True random number generator. Pulls 32-byte entropy blocks
|
||
from the kernel via `getrandom(GRND_RANDOM)` and pipes them to the host over
|
||
CDC ACM serial (`/dev/ttyGS0`) at 100 Hz. The entropy source is the hardware
|
||
TRNG on the X1000E, not a software PRNG — the output is suitable for
|
||
cryptographic seeding.
|
||
|
||
**`system.mod`** (file: reset.mod) — System Tools, inspired by Rockbox's
|
||
tools menu on the Aigo Eros Q platform. Four-option menu:
|
||
|
||
- **Purge** — Operational cleanup. Kills child processes (dosbox,
|
||
emulators), brings usb0 down, wipes `/data/loot_drop/`, calls
|
||
`sync()`. Does not touch any firmware files.
|
||
- **Hiby Player** — Restores the stock firmware from
|
||
`/data/stock_backup/` (created at deploy time with
|
||
`--backup-stock`), removes all OreBolt OS files, and reboots
|
||
into the original music player.
|
||
- **Rockbox** — If the user has separately installed Rockbox on the
|
||
SD card, this option reboots the device so Rockbox can load.
|
||
OreBolt OS does not ship or install Rockbox; the user manages it
|
||
independently. OreBolt OS files are not removed.
|
||
- **Reboot** — Standard warm reboot.
|
||
|
||
The Hiby Player and OreBolt OS coexist on the same hardware
|
||
through SD card file management alone. If the user has installed
|
||
Rockbox separately, it can also share the SD card.
|
||
|
||
### Networking
|
||
|
||
**`bitchat.mod`** — Mesh chat, and the only module under AGPL-3.0-only. An
|
||
independent C implementation of the BitChat wire protocol — not affiliated
|
||
with, sponsored by, or endorsed by Permissionless Tech, LLC. The name is
|
||
used under nominative fair use (see [LICENSE.md](LICENSE.md) section 8). It
|
||
implements the full `BITCHAT_MSG_*` message type set, advertises its Written
|
||
Offer URL on every mesh HELLO via `BITCHAT_MSG_LICENSE`, and uses
|
||
`mod_radio_input_multiplex` (BLE + LoRa + 433 MHz) as its transport layer.
|
||
The mesh implementation itself lives in `mod_bitchat_mesh.c` within
|
||
`liborebolt.a`, compiled with a mandatory `-DAGPL_BITCHAT` flag — the build
|
||
fails without it, enforced in `build.sh` Phase 7.
|
||
|
||
## Hardware library (`liborebolt.a`)
|
||
|
||
A static archive linked into every `.mod` binary. Source lives under
|
||
`src/modules/`. These are the low-level routines that modules call but do
|
||
not implement themselves.
|
||
|
||
| File | Purpose |
|
||
|---|---|
|
||
| `mod_core_hid.c` | HID descriptor tables shared by `pauto.mod` and `retro.mod` |
|
||
| `mod_forensics.c` | Forensic extraction engine — dispatches `.dd` payloads by OS profile |
|
||
| `mod_panic_purge.c` | Software panic purge — zeroes volatile state before hardware purge |
|
||
| `mod_panic_hardware_purge.c` | Hardware panic purge — GPIO-driven SD power cut and SPI flash WP |
|
||
| `mod_radio_input_multiplex.c` | Radio input multiplexer (BLE + LoRa + 433 MHz); bitchat transport |
|
||
| `mod_ui_frame_graphics.c` | RGB565 blitters, double-buffer management, scroll wheel routing |
|
||
| `mod_bitchat_mesh.c` | BitChat mesh networking (AGPL-3.0-only; `-DAGPL_BITCHAT` required) |
|
||
|
||
## Documentation
|
||
|
||
| Doc | What it covers |
|
||
|---|---|
|
||
| [QUICKSTART.md](QUICKSTART.md) | Build and deploy from scratch (~30 min) |
|
||
| [PREREQUISITES.md](PREREQUISITES.md) | Host setup, toolchain, kernel headers, SD card prep |
|
||
| [HEADERS.md](HEADERS.md) | Kernel headers strategy (FiiO M3K + XBurst BSP fallback) |
|
||
| [ARCHITECTURE.md](ARCHITECTURE.md) | Module layout, SoC details, build pipeline internals |
|
||
| [LICENSE.md](LICENSE.md) | Multi-tier licensing, AGPL boundary analysis, compliance |
|
||
| [CHANGELOG.md](CHANGELOG.md) | Version-to-version diff |
|
||
| [BUILD_MANIFEST.txt](BUILD_MANIFEST.txt) | Complete file inventory with SHA256 |
|
||
| [SHA256SUMS](SHA256SUMS) | Per-file integrity manifest |
|
||
|
||
## License
|
||
|
||
Multi-tier. Full analysis in [LICENSE.md](LICENSE.md).
|
||
|
||
- **bitchat mesh module**: AGPL-3.0-only
|
||
- **All other OreBolt OS code**: GPL-2.0-or-later
|
||
- **LVGL / lv_drivers**: MIT (upstream)
|
||
- **Documentation**: CC-BY-4.0
|
||
|
||
Modifying and deploying the bitchat module triggers AGPL v3 section 13 — you
|
||
must make your modified source available to anyone who interacts with your
|
||
node over the mesh. Replace the `BITCHAT_SOURCE_URL` placeholder in
|
||
`src/modules/mod_bitchat_mesh.c` before deploying. |