mirror of
https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git
synced 2025-07-24 21:15:10 +03:00
This works around an issue where some armhf apps are compiled with instructions that are not compatible with aarch64, for example apk uses MCR, and that does not exist on aarch64 causing apk to fail in a chroot with SIGILL. It's impossible to build armhf images on aarch64 hosts, and this also fixes a crash when running `pmbootstrap zap -a`, since pmb zap will init an armhf chroot and blow up with apk generates a SIGILL. For reference, here's how I arrived at the conclusion that apk (and gdb, and probably others...) are executing invalid instructions on aarch64 when not using binfmt+qemu emulation: $ uname -m aarch64 $ file sbin/apk.static sbin/apk.static: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=997a8ef97b17cb4951a6220b7807a66fed67bc10, stripped $ gdb sbin/apk.static (gdb) r Starting program: /run/user/10000/foo/sbin/apk.static Program received signal SIGILL, Illegal instruction. 0x0012843c in ?? () (gdb) x /1i $pc => 0x12843c: mcr 15, 0, r0, cr7, cr10, {5}
131 lines
4 KiB
Python
131 lines
4 KiB
Python
# Copyright 2023 Oliver Smith
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
import fnmatch
|
|
import platform
|
|
import pmb.config
|
|
|
|
|
|
def alpine_native():
|
|
machine = platform.machine()
|
|
|
|
return machine_type_to_alpine(machine)
|
|
|
|
|
|
def from_chroot_suffix(args, suffix):
|
|
if suffix == "native":
|
|
return pmb.config.arch_native
|
|
if suffix in [f"rootfs_{args.device}", f"installer_{args.device}"]:
|
|
return args.deviceinfo["arch"]
|
|
if suffix.startswith("buildroot_"):
|
|
return suffix.split("_", 1)[1]
|
|
|
|
raise ValueError("Invalid chroot suffix: " + suffix +
|
|
" (wrong device chosen in 'init' step?)")
|
|
|
|
|
|
def alpine_to_qemu(arch):
|
|
"""
|
|
Convert the architecture to the string used in the QEMU packaging.
|
|
This corresponds to the package name of e.g. qemu-system-aarch64.
|
|
"""
|
|
|
|
mapping = {
|
|
"x86": "i386",
|
|
"x86_64": "x86_64",
|
|
"armhf": "arm",
|
|
"armv7": "arm",
|
|
"aarch64": "aarch64",
|
|
"riscv64": "riscv64",
|
|
}
|
|
for pattern, arch_qemu in mapping.items():
|
|
if fnmatch.fnmatch(arch, pattern):
|
|
return arch_qemu
|
|
raise ValueError("Can not map Alpine architecture '" + arch + "'"
|
|
" to the right Debian architecture.")
|
|
|
|
|
|
def alpine_to_kernel(arch):
|
|
"""
|
|
Convert the architecture to the string used inside the kernel sources.
|
|
You can read the mapping from the linux-vanilla APKBUILD for example.
|
|
"""
|
|
mapping = {
|
|
"aarch64*": "arm64",
|
|
"arm*": "arm",
|
|
"ppc*": "powerpc",
|
|
"s390*": "s390",
|
|
"riscv64*": "riscv",
|
|
}
|
|
for pattern, arch_kernel in mapping.items():
|
|
if fnmatch.fnmatch(arch, pattern):
|
|
return arch_kernel
|
|
return arch
|
|
|
|
|
|
def alpine_to_hostspec(arch):
|
|
"""
|
|
See: abuild source code/functions.sh.in: arch_to_hostspec()
|
|
"""
|
|
mapping = {
|
|
"aarch64": "aarch64-alpine-linux-musl",
|
|
"armel": "armv5-alpine-linux-musleabi",
|
|
"armhf": "armv6-alpine-linux-musleabihf",
|
|
"armv7": "armv7-alpine-linux-musleabihf",
|
|
"loongarch32": "loongarch32-alpine-linux-musl",
|
|
"loongarchx32": "loongarchx32-alpine-linux-musl",
|
|
"loongarch64": "loongarch64-alpine-linux-musl",
|
|
"mips": "mips-alpine-linux-musl",
|
|
"mips64": "mips64-alpine-linux-musl",
|
|
"mipsel": "mipsel-alpine-linux-musl",
|
|
"mips64el": "mips64el-alpine-linux-musl",
|
|
"ppc": "powerpc-alpine-linux-musl",
|
|
"ppc64": "powerpc64-alpine-linux-musl",
|
|
"ppc64le": "powerpc64le-alpine-linux-musl",
|
|
"riscv32": "riscv32-alpine-linux-musl",
|
|
"riscv64": "riscv64-alpine-linux-musl",
|
|
"s390x": "s390x-alpine-linux-musl",
|
|
"x86": "i586-alpine-linux-musl",
|
|
"x86_64": "x86_64-alpine-linux-musl",
|
|
}
|
|
if arch in mapping:
|
|
return mapping[arch]
|
|
|
|
raise ValueError("Can not map Alpine architecture '" + arch + "'"
|
|
" to the right hostspec value")
|
|
|
|
|
|
def cpu_emulation_required(arch):
|
|
# Obvious case: host arch is target arch
|
|
if pmb.config.arch_native == arch:
|
|
return False
|
|
|
|
# Other cases: host arch on the left, target archs on the right
|
|
not_required = {
|
|
"x86_64": ["x86"],
|
|
"armv7": ["armel", "armhf"],
|
|
"aarch64": ["armv7"],
|
|
}
|
|
if pmb.config.arch_native in not_required:
|
|
if arch in not_required[pmb.config.arch_native]:
|
|
return False
|
|
|
|
# No match: then it's required
|
|
return True
|
|
|
|
|
|
def machine_type_to_alpine(machine_type: str) -> str:
|
|
"""Translate a machine type to an Alpine architecture. A machine type can come from
|
|
for example `$ uname -m` or platform.machine() from Python's standard library."""
|
|
mapping = {
|
|
"i686": "x86",
|
|
"x86_64": "x86_64",
|
|
"aarch64": "aarch64",
|
|
"arm64": "aarch64",
|
|
"armv6l": "armhf",
|
|
"armv7l": "armv7",
|
|
"armv8l": "armv7",
|
|
}
|
|
if machine_type in mapping:
|
|
return mapping[machine_type]
|
|
raise ValueError(f"Can not map machine type '{machine_type}'"
|
|
" to the right Alpine Linux architecture")
|