How to build the firmware and its components with the flake. For what the pieces are, see architecture.md; for flashing the output, see flashing-and-recovery.md.
- Prerequisites
- Packages
- Build DAG
- Building the firmware image
- Pinned hashes
- Cross-compile notes
ax_*.kovermagic- Heavy builds & caching
- Nix with flakes enabled (
experimental-features = nix-command flakes). - A dev box that is
x86_64-linux(the default, cross-compiles to aarch64) oraarch64-linux(native). No exotic toolchain is required — stock nixpkgs aarch64 glibc GCC is sufficient. - Disk + patience for the heavy derivations (see below):
the base
.axpis a 1.4 GB fixed-output fetch and the rootfs de-sparses to a multi-GB ext4.
nix flake show # list all outputs
nix develop # dev shell: cross toolchain + SDK/image tooling + axdlAll are nix build .#<name>. State reflects the current tree.
| Package | Output | Notes |
|---|---|---|
axera-libs |
libax_*.so + V3.0.0 headers |
pinned blob install (msp repo) |
ax-ko-blobs |
prebuilt ax_*.ko |
pinned blob install |
kvm-encoder |
libkvm.so / .so.0 |
our from-source capture+encode backend |
nanokvm-web |
React dist/ bundle |
pnpm-hash pinned |
nanokvm-server |
NanoKVM-Server (aarch64) |
Go+cgo, links libkvm+libopus; vendorHash pinned |
kernel |
Image + dtbs + modules + lt6911_manage.ko |
Linux 4.19.125 |
dtb / dtb-sd |
patched board DTB (eMMC / SD-root) | reserved-mem + bootargs patch |
dtb-slot-image / -sd |
signed dtb.img partition |
ax_gzip -9 + 1 KB header |
kernel-slot-image |
signed kernel partition | ax_gzip -9 + 1 KB header |
boot / boot-sd |
full boot chain (UART0 / UART1 console) | SPL+ATF+OP-TEE+U-Boot |
boot-fsbl/atf/optee/uboot |
boot-chain subsets | selectors over boot |
base-axp |
pinned vendor v1.0.15 .axp |
1.4 GB FOD (overlay base) |
rootfs |
overlaid ubuntu_rootfs_sparse.ext4 |
vendor base + our libkvm + modules + service selection |
firmware-image |
…-selfbuilt.axp |
the flashable eMMC image (default output) |
sd-image |
…-sdcard.img |
non-destructive microSD boot image |
axdl |
axdl-cli host flasher |
built for the dev/host system, not cross |
toolchain |
cross-gcc bundle | convenience buildEnv |
axera-libs ─┬─> kvm-encoder ──> nanokvm-server ─┐
│ ├─> rootfs ──> firmware-image
ax-ko-blobs ┼──────────────────────> kernel ─────┤ ▲
│ nanokvm-web ─────┘ │
boot ───────┴──> {kernel,dtb}-slot-image ──────────────────────┘
nix flake check evaluates the whole tree without building the heavy leaves.
nix build .#firmware-image
# -> result/AX630C_emmc_arm64_k419_sipeed_nanokvm-selfbuilt.axpimage.nix does a streaming zip-rewrite of the pinned base .axp, swapping
in our from-source boot chain, signed kernel/dtb partitions, and the overlaid
rootfs — a pure userspace ZIP rewrite (no sudo/mount/chroot). It fails loudly if
any expected swap target is missing from the base .axp central directory.
Flash it per flashing-and-recovery.md.
Two fixed-output hashes must be regenerated when their inputs change (set the
field to pkgs.lib.fakeHash, rebuild, paste the printed hash back):
| Where | Field | Regenerate when |
|---|---|---|
pkgs/nanokvm-server.nix |
vendorHash |
server/go.mod / go.sum change |
pkgs/nanokvm-web.nix |
pnpmDeps.hash |
the web pnpm-lock.yaml changes |
The base-axp FOD hash changes only if you re-pin a different vendor release
(pkgs/base-axp.nix, version = "1.0.15").
- Outputs are keyed off the build/dev system;
crossPkgsispkgsCross.aarch64-multiplatformon x86_64, or a native no-op on aarch64. - Go/cgo: use
crossPkgs.buildGoModule(the cross-capablego). Overriding it with a nativepkgs.go_*breaks cgo (native go passes-m64to the aarch64 gcc).GOEXPERIMENT=boringcryptois kept for parity with upstreambuild.sh. - cgo link: the server links our real
libkvm.so(-L../dl_lib -lkvm) andlibopus.libkvmpulls in the full AX graph, so the build adds-Wl,-rpath-link,${axera-libs}/libsoldcan resolve the transitivelibax_engine(vialibax_proton) at link time without adding it asDT_NEEDEDto the server binary. On-device those libs load from/opt/lib. - libkvm rpath:
kvm-encoder.nixusespatchelf --force-rpathto emitDT_RPATH(transitive), notDT_RUNPATH. This is load-bearing — see architecture.md. - Vendor triples: the SDK Makefiles expect
aarch64-none-linux-gnu-; nixpkgs isaarch64-unknown-linux-gnu-.CROSS_COMPILEis passed explicitly.
The prebuilt Axera media modules must insmod into our from-source kernel, so
the kernel's vermagic (kernel version + key CONFIG_* + compiler) has to line up
with what the blobs were built against. kernel.nix builds against the vendor
axera_AX630C_emmc_arm64_k419_sipeed_nanokvm_defconfig for this reason;
rootfs.nix merges the blobs into /lib/modules/4.19.125/ and re-runs depmod
on a host staging tree so the dependency graph
(ax_venc → ax_base/ax_pool/ax_cmm/ax_sys, plus lt6911_manage) resolves on the
target with no on-device depmod. The build asserts those edges exist.
base-axpis a 1.4 GB fixed-output fetch;rootfsde-sparses it to a multi-GB raw ext4, edits it withdebugfs, then re-sparses. Budget disk + time.nix flake checkandnix buildof the light leaves (axera-libs,ax-ko-blobs,kvm-encoder,nanokvm-web) are fast and are the right inner-loop targets when iterating on the app/encoder layer.- riscv64 is irrelevant here (that's the other, SG2002 project); this target is plain aarch64 and builds with the standard nixpkgs cross set.