Skip to content

Commit cd7270b

Browse files
committed
feat(extensions): native-armhf-on-arm64 acceleration via runtime-disable of qemu-arm
Opt-in extension that disables qemu-arm in binfmt_misc for the duration of an armhf build on an aarch64 host. The kernel's binfmt_elf path then runs 32-bit ARM ELF binaries natively via CONFIG_COMPAT, removing the ~10× qemu-user-static overhead from mmdebstrap, chroot apt-get, dpkg --configure, and customize_image stages. Activate with ENABLE_EXTENSIONS=native-armhf-on-arm64. Scope: - host_pre_docker_launch hook: self-gates on ARCH=armhf and aarch64 host arch; refuses to run on hosts where qemu-arm is unregistered; probes arch-test armhf POST-disable with automatic rollback if the kernel cannot run armhf natively (no CONFIG_COMPAT); add_cleanup_handler on success so build exit restores qemu-arm. - No core changes. No global-state coordination claims. - Restrictions documented in the file header: NO CONCURRENT ARMBIAN BUILDS on the same host while the extension is active. Why an extension (and not a core feature): - The acceleration only applies to armhf-on-aarch64; no benefit for other ARCH/host combos. - Concurrent-safe coordination in core would require kernel-level flock dance on /proc/sys/fs/binfmt_misc/qemu-arm (see PR armbian#9769), which is large, hard to review and to test; extension scope makes the operator the source of truth for host serialization and lets the implementation stay ~80 lines. - Cleanup is best-effort: a SIGKILL'd build leaves qemu-arm disabled. Documented in the header with manual restore instructions. Validated: - aarch64 Ubuntu Noble kernel 6.8.x (Hetzner CAX), no COMPAT_VDSO needed in stock builds. Assisted-by: Claude:claude-opus-4.7
1 parent 761d04e commit cd7270b

1 file changed

Lines changed: 103 additions & 0 deletions

File tree

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env bash
2+
#
3+
# SPDX-License-Identifier: GPL-2.0
4+
#
5+
# Native armhf-on-aarch64 acceleration.
6+
#
7+
# Activate with ENABLE_EXTENSIONS=native-armhf-on-arm64.
8+
#
9+
# WHAT
10+
# On an aarch64 host building an armhf target, disable qemu-arm in
11+
# binfmt_misc for the duration of the build. The kernel's binfmt_elf
12+
# path then runs armhf ELF binaries natively via CONFIG_COMPAT — ~10×
13+
# faster than qemu-user-static emulation. mmdebstrap, chroot apt-get,
14+
# dpkg --configure, post-install scripts and customize_image all
15+
# benefit.
16+
#
17+
# REQUIREMENTS
18+
# * Host architecture aarch64.
19+
# * Host kernel with CONFIG_COMPAT=y (32-bit ARM EL0 support).
20+
# CONFIG_COMPAT_VDSO is not strictly required — full mmdebstrap +
21+
# post-customize runs were validated on stock Ubuntu Noble (6.8.x)
22+
# without COMPAT_VDSO.
23+
# * Build target ARCH=armhf (a no-op for any other ARCH).
24+
# * qemu-user-static (or qemu-user-binfmt) registered with qemu-arm
25+
# enabled in /proc/sys/fs/binfmt_misc/qemu-arm at build start.
26+
# The extension verifies this and refuses to run otherwise.
27+
# * CAP_SYS_ADMIN on host (the build already runs as root).
28+
#
29+
# RESTRICTIONS
30+
# * NO CONCURRENT ARMBIAN BUILDS on the same host while this extension
31+
# is active. The extension globally disables qemu-arm in binfmt_misc
32+
# for the build window. Any other parallel armhf-cross workload on
33+
# the host (CI runners, container builds depending on qemu-arm) will
34+
# have its armhf binaries routed through the kernel's binfmt_elf
35+
# fallback instead of qemu — which works on this host, but may
36+
# surprise code that depends on qemu being in the chain.
37+
# The operator owns the host while this extension runs.
38+
# * If the build is SIGKILL'd or the box crashes before the cleanup
39+
# handler fires, qemu-arm stays disabled. Re-enable manually:
40+
# sudo update-binfmts --enable qemu-arm
41+
# or
42+
# echo 1 | sudo tee /proc/sys/fs/binfmt_misc/qemu-arm
43+
#
44+
# DESIGN
45+
# No flock dance, no userspace coordination, no concurrent-safety
46+
# claims. The acceleration is mechanically simple: write 0 to the
47+
# binfmt_misc entry, write 1 back on cleanup. The in-core flock-based
48+
# variant lives at PR #9769 if you need acceleration that coexists
49+
# with concurrent armbian builds on the same host.
50+
51+
function host_dependencies_ready__native_armhf_on_arm64() {
52+
# Self-gate: target arch must be armhf. Anything else: no-op, silent.
53+
# (We can't pre-compute via extension_prepare_config — that hook runs
54+
# only inside the docker container, after the relaunch.)
55+
[[ "${ARCH}" == "armhf" ]] || return 0
56+
57+
declare host_arch
58+
host_arch="$(arch)"
59+
if [[ "${host_arch}" != "aarch64" ]]; then
60+
exit_with_error "${EXTENSION}: enabled but host arch '${host_arch}' is not aarch64; this extension only accelerates armhf on aarch64 hosts."
61+
fi
62+
63+
if [[ ! -e /proc/sys/fs/binfmt_misc/qemu-arm ]]; then
64+
exit_with_error "${EXTENSION}: qemu-arm is not registered in binfmt_misc on the host. Install qemu-user-static (or qemu-user-binfmt) and run 'update-binfmts --enable qemu-arm' before retrying."
65+
fi
66+
67+
declare qemu_arm_state
68+
qemu_arm_state="$(head -n1 /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null || true)"
69+
if [[ "${qemu_arm_state}" != "enabled" ]]; then
70+
display_alert "${EXTENSION}: qemu-arm already not enabled" "state='${qemu_arm_state}' — nothing to do, leaving alone" "info"
71+
return 0
72+
fi
73+
74+
# Probe-with-rollback: disable qemu-arm, verify the kernel can still
75+
# run armhf binaries natively, and re-enable + bail if it can't. This
76+
# catches misconfigured hosts (kernel without CONFIG_COMPAT) BEFORE
77+
# the docker container launches and starts an mmdebstrap that would
78+
# silently fail in chroot.
79+
display_alert "${EXTENSION}: disabling qemu-arm" "/proc/sys/fs/binfmt_misc/qemu-arm → 0" "info"
80+
if ! echo 0 > /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null; then
81+
exit_with_error "${EXTENSION}: cannot write to /proc/sys/fs/binfmt_misc/qemu-arm. CAP_SYS_ADMIN missing on host?"
82+
fi
83+
84+
if ! arch-test armhf > /dev/null 2>&1; then
85+
echo 1 > /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null || true
86+
exit_with_error "${EXTENSION}: host kernel cannot run armhf natively after disabling qemu-arm (no CONFIG_COMPAT?). Restored qemu-arm and aborting; disable this extension on this host."
87+
fi
88+
89+
declare -g _NATIVE_ARMHF_EXTENSION_DISABLED_QEMU_ARM=yes
90+
add_cleanup_handler trap_handler_native_armhf_on_arm64_restore
91+
display_alert "${EXTENSION}: armhf chroot execs will run natively via kernel binfmt_elf" "qemu-arm disabled for this build; will be restored on exit" "info"
92+
}
93+
94+
function trap_handler_native_armhf_on_arm64_restore() {
95+
[[ "${_NATIVE_ARMHF_EXTENSION_DISABLED_QEMU_ARM:-no}" == "yes" ]] || return 0
96+
[[ -e /proc/sys/fs/binfmt_misc/qemu-arm ]] || return 0
97+
if echo 1 > /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null; then
98+
display_alert "${EXTENSION}: qemu-arm restored" "/proc/sys/fs/binfmt_misc/qemu-arm → 1" "info"
99+
else
100+
display_alert "${EXTENSION}: failed to restore qemu-arm" "manual fix: echo 1 | sudo tee /proc/sys/fs/binfmt_misc/qemu-arm" "wrn"
101+
fi
102+
unset _NATIVE_ARMHF_EXTENSION_DISABLED_QEMU_ARM
103+
}

0 commit comments

Comments
 (0)