A small installer for Rockchip RK3576 boards (the Flipper One and other RK3576 boards used for testing), designed to run from a Linux initramfs for on-device installs.
It can:
- Discover the running board from the device tree (
/proc/device-tree). - Enumerate local storage the RK3576 boot ROM can boot from (UFS, eMMC, SD) via sysfs.
- Query the image server for available U-Boot images and exported profile snapshots for the board.
- Search removable storage (SD / USB) for offline U-Boot images and profile snapshots.
- Present a TUI (Cursive + Crossterm) for serial-console operation.
- Present a GUI (Slint + LinuxKMS) on the Flipper One 256×144 DRM screen, driven by the on-device buttons (a Linux input event device).
- Run the installation:
blkdiscard, write a fresh GPT,mkfs.btrfswith a subvolume skeleton,btrfs receivethe selected profile snapshots, and install a kernel for each.
Both frontends are thin views over a single shared installer state:
┌──────────────────────────────┐
serial ─────▶│ TUI (cursive/crossterm) │─┐
console └──────────────────────────────┘ │ actions
▼
┌──────────────────────────────┐ Controller ── AppState
on-device ───▶│ GUI (slint/linuxkms) │─┐ (single source of truth)
buttons └──────────────────────────────┘ │ snapshots ▲
└────────────┘
core::model— plain data model (AppState, devices, images, snapshots).core::controller— ownsAppState, applies all mutations, and broadcasts immutable snapshots to every subscribed frontend so the TUI and GUI mirror each other live.core::board/core::storage/core::removable/core::server— discovery.core::install— the destructive install pipeline (honours--dry-run).tui/gui— the two frontends.
Built and tested with rustc 1.95.0 (via rustup). The GUI depends on
Slint 1.17, which sets a minimum of rustc 1.92; the TUI-only build has a
lower floor (its highest-MSRV dependency is uuid, at rustc 1.85).
This repository uses a git submodule for the on-device font
(flipctl-fonts, tracking the
dev branch). Clone recursively, or initialise it after cloning:
git clone --recurse-submodules <repo-url>
# or, in an existing checkout:
git submodule update --init --recursive# Default: both frontends, host build (for development).
cargo build
# Release build for the device (RK3576 is ARMv8):
rustup target add aarch64-unknown-linux-gnu
cargo build --release --target aarch64-unknown-linux-gnu
# Slim, TUI-only variant (no GUI shared-library dependencies):
cargo build --release --no-default-features --features tui \
--target aarch64-unknown-linux-gnuThe binary links dynamically against the system C library and, for the GUI,
against libinput, libudev, libxkbcommon, libfontconfig and libfreetype
(the last two pulled in by Slint for font discovery/rendering), all located via
pkg-config. These shared libraries must therefore be present in the initramfs
alongside the binary (the TUI-only build needs none of them). The drm crate
talks to the kernel directly via ioctls (pregenerated bindings), so no libdrm
is needed. Install the build tools and dev packages (Debian/Ubuntu):
sudo apt install pkg-config libinput-dev libudev-dev libxkbcommon-dev \
libfontconfig-dev libfreetype-devThe GUI's text is rendered with the compiled-in HaxrCorp 4090 (FlipCTL) pixel
font (vendored as the third_party/flipctl-fonts submodule and embedded by the
Slint compiler), so no system fonts are required on the device.
Cargo feature flags:
| Feature | Frontend |
|---|---|
tui |
Cursive/Crossterm (serial) |
gui |
Slint/LinuxKMS (on-device screen) |
# Both frontends concurrently (default), safe dry-run:
sudo ./flipperos-installer
# Serial console only:
sudo ./flipperos-installer --tui
# On-device screen only, real install, custom server:
sudo ./flipperos-installer --gui --no-dry-run \
--server https://images.flipperos.example \
--kms-device /dev/dri/by-path/platform-2acf0000.spi-cs-0-cardBy default the installer runs in dry-run mode: every destructive command is
logged but not executed. Pass --no-dry-run to actually flash.
The installer reads the image server's two-level catalog (default base
https://dl-linux-images.flipp.dev, override with --server):
- U-Boot:
/u-boot/manifest.jsonlists build directories; each build'smanifest.jsoncontains<board>/u-boot-rockchip.bin. The installer flashes<board>/u-boot-rockchip.binfor the detected board (flipper-one, elsegeneric). - Snapshots (rootfs):
/rootfs/manifest.jsonlists build directories; each build'smanifest.jsoncontains per-profile packs<Profile>_<build>_stock_pack.zst(full) and<Profile>_<build>_stock_inc_pack.zst(incremental delta vs. Minimal).
Both lists are presented newest first. The operator picks one U-Boot build
and one snapshot build. Minimal is always deployed (from its full pack); any
extra profiles the operator selects are streamed from their incremental packs
on top of Minimal. Packs are zstd-compressed btrfs send streams, decompressed
in-process and piped into btrfs receive.
A removable-media mirror of the same u-boot/ and rootfs/ tree is picked up
automatically and merged into the lists.
The shared, top-level Btrfs subvolume skeleton (boot, @home, @var-log,
@var-cache, @snapshots, with boot kept uncompressed and the journal dir
NODATACOW) is described by a small TOML file that mirrors the build recipe. See
config/flipperos-btrfs.toml.
At install time the installer prefers a btrfs-layout.toml shipped with the
images and falls back to the copy compiled into the binary. Per-profile roots
(@Minimal, @Desktop, …) are not listed there — they are received from the
selected snapshot packs.
This is an early scaffold: the architecture, discovery, both frontends and the
dry-run install pipeline are in place. GPT partitioning and the U-Boot write are
done in-process (gpt crate); the remaining destructive steps shell out to
blkdiscard, mkfs.btrfs, btrfs and chattr. Kernel installation is driven
by an embedded POSIX shell script
(scripts/flipperos-install-kernel.sh)
that chroots into each deployed profile and runs the profile's own
kernel-install for every installed kernel, writing into the shared /boot
subvolume. These tools (mount/umount, chroot, sh, and the profile's
kernel-install) must be present in the initramfs / profile.
The installer's own source in this repository is MIT-licensed (see
LICENSES/MIT.txt; the repository follows the
REUSE specification, so reuse lint is green).
However, the shipped binary links the Slint GUI toolkit, which we use under the GNU GPL v3.0 option of its tri-license (wehold no separate Slint agreement, and want the binary to be buildable purely from public sources). Linking GPL code makes the combined binary as a whole GPL-3.0-only. MIT is GPL-compatible, so our own sources are unaffected and may still be reused under MIT on their own.
Full license texts for every crate linked into the binary are collected in
THIRD-PARTY-LICENSES.md. Regenerate it from the
current Cargo.lock whenever dependencies change:
cargo install cargo-about --features cli # once
sh scripts/gen-third-party-licenses.shThe bundled fonts live in the third_party/flipctl-fonts submodule and carry
their own licenses (HaxrCorp 4090 — CC BY-SA 3.0; Born2bSportyV2 — The Unlicense;
Busy9px — MIT); see the LICENSE file in each font's folder.