diff --git a/lib/functions/rootfs/qemu-static.sh b/lib/functions/rootfs/qemu-static.sh index 865f5ccec236..48480ff3ea7d 100644 --- a/lib/functions/rootfs/qemu-static.sh +++ b/lib/functions/rootfs/qemu-static.sh @@ -193,35 +193,68 @@ function prepare_host_binfmt_qemu_cross() { } function prepare_host_binfmt_qemu_cross_arm64_host_armhf_target() { - display_alert "Trying to update binfmts - aarch64 mostly does 32-bit sans emulation, but Apple said no" "update-binfmts --enable qemu-${wanted_arch}" "debug" - run_host_command_logged update-binfmts --enable "qemu-${wanted_arch}" "&>" "/dev/null" "||" "true" # don't fail nor produce output, which can be misleading. + declare armhf_probe="/usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3" + + # If qemu-arm is already enabled in the kernel, the native probe + # below would route through qemu and lie about COMPAT. Trust the + # existing setup — admin or packaged service intended it. + if [[ -e /proc/sys/fs/binfmt_misc/qemu-arm ]] \ + && [[ "$(head -n1 /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null)" == "enabled" ]]; then + display_alert "qemu-arm already enabled in binfmt_misc" "trusting existing setup" "debug" + return 0 + fi + + # No active qemu-arm route. Probe CONFIG_COMPAT directly. `arch-test + # arm` was unreliable here (probes ARMv5 EABI; COMPAT runs armhf — + # EABI v5+; empirically broken on Ubuntu Noble / Ampere CAX). Direct + # exec of ld-linux-armhf (from gcc-arm-linux-gnueabihf, an armbian + # host build dep on aarch64) is authoritative. + if [[ -x "${armhf_probe}" ]] && "${armhf_probe}" --help > /dev/null 2>&1; then + display_alert "Host kernel can run armhf natively (CONFIG_COMPAT)" "no qemu-arm setup needed" "debug" + return 0 + fi + + # No native COMPAT — need qemu-arm. Prefer a packaged descriptor + # (qemu-user-binfmt on resolute installs `/usr/bin/qemu-arm`; + # qemu-user-static elsewhere uses the -static suffix). Overwriting + # it would break the resolute interpreter path. + if [[ -f /usr/share/binfmts/qemu-arm ]]; then + # `update-binfmts --enable` only loads the format if its registry + # thinks it's disabled; if the kernel entry was toggled to 0 + # externally, --enable is a no-op. Force-sync via /proc afterwards. + run_host_command_logged update-binfmts --enable qemu-arm || true + [[ -e /proc/sys/fs/binfmt_misc/qemu-arm ]] && echo 1 > /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null + if [[ -e /proc/sys/fs/binfmt_misc/qemu-arm ]] \ + && [[ "$(head -n1 /proc/sys/fs/binfmt_misc/qemu-arm 2> /dev/null)" == "enabled" ]]; then + display_alert "qemu-arm enabled via packaged descriptor" "leaving package-provided setup intact" "debug" + return 0 + fi + exit_with_error "/usr/share/binfmts/qemu-arm exists but qemu-arm could not be enabled — packaged interpreter likely missing. Reinstall qemu-user-binfmt (resolute) / qemu-user-static, or remove the descriptor and retry." + fi + + # Kernel entry exists but is disabled, no descriptor to re-enable. + if [[ -e /proc/sys/fs/binfmt_misc/qemu-arm ]]; then + exit_with_error "qemu-arm kernel entry present but disabled and no descriptor to re-enable from. 'echo 1 > /proc/sys/fs/binfmt_misc/qemu-arm' (or 'echo -1' to drop) and retry." + fi + + # Apple-Silicon-like (no COMPAT, no qemu pkg): hand-roll the descriptor. + display_alert "arm64 host can't run armhf natively (no CONFIG_COMPAT?)" "importing+enabling qemu-arm" "debug" + cat <<- BINFMT_ARM_MAGIC > /usr/share/binfmts/qemu-arm + package qemu-user-static + interpreter /usr/bin/qemu-arm-static + magic \x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00 + offset 0 + mask \xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff + credentials yes + fix_binary no + preserve yes + BINFMT_ARM_MAGIC + run_host_command_logged update-binfmts --import qemu-arm + run_host_command_logged update-binfmts --enable qemu-arm if [[ "${SHOW_DEBUG}" == "yes" ]]; then display_alert "Debugging arch-test" "full output" "debug" run_host_command_logged arch-test "||" true fi - - # to check, we use arch-test; if will return 0 if _either_ the host can natively run armhf, or if qemu-arm is correctly working. - if arch-test arm; then - display_alert "Host can run armhf natively or emulation is correctly setup already" "no need to enable qemu-arm" "debug" - else - display_alert "arm64 host can't run armhf natively" "importing enabling qemu-arm" "debug" - cat <<-BINFMT_ARM_MAGIC >/usr/share/binfmts/qemu-arm - package qemu-user-static - interpreter /usr/bin/qemu-arm-static - magic \x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00 - offset 0 - mask \xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff - credentials yes - fix_binary no - preserve yes - BINFMT_ARM_MAGIC - run_host_command_logged update-binfmts --import "qemu-${wanted_arch}" - run_host_command_logged update-binfmts --enable "qemu-${wanted_arch}" - - # Test again using arch-test. - display_alert "Checking if arm 32-bit emulation on arm64 works after enabling" "qemu-arm emulation" "info" - run_host_command_logged arch-test arm - display_alert "arm 32-bit emulation on arm64" "has been correctly setup" "cachehit" - fi + display_alert "arm 32-bit emulation on arm64" "has been set up via qemu-arm" "cachehit" }