diff --git a/README.md b/README.md index b193ba8..7d24209 100644 --- a/README.md +++ b/README.md @@ -96,29 +96,31 @@ Here's a list of supported arch/ABI combinations accepted via `--arch` (values are case-insensitive). This information is also available running `systrack --arch help`. -| Value | Aliases | Arch | Kernel | Syscall ABI | Build based on | Notes | -|:----------------|:-------------------|:--------|:-------|:---------------|:------------------------------|:--------| -| `arm` | `arm-eabi`, `eabi` | ARM | 32-bit | 32-bit EABI | `multi_v7_defconfig` | *[2]* | -| `arm-oabi` | `oabi` | ARM | 32-bit | 32-bit OABI | `multi_v7_defconfig` | *[2,4]* | -| `arm64` | `aarch64` | ARM | 64-bit | 64-bit AArch64 | `defconfig` | | -| `arm64-aarch32` | `aarch32` | ARM | 64-bit | 32-bit AArch32 | `defconfig` | *[1]* | -| `mips` | `mips32`, `o32` | MIPS | 32-bit | 32-bit O32 | `defconfig` | | -| `mips64` | `n64` | MIPS | 64-bit | 64-bit N64 | `ip27_defconfig` | *[1]* | -| `mips64-n32` | `n32` | MIPS | 64-bit | 64-bit N32 | `ip27_defconfig` | *[1]* | -| `mips64-o32` | `o32-64` | MIPS | 64-bit | 32-bit O32 | `ip27_defconfig` | *[1]* | -| `powerpc` | `ppc`, `ppc32` | PowerPC | 32-bit | 32-bit PPC32 | `ppc64_defconfig` | | -| `powerpc64` | `ppc64` | PowerPC | 64-bit | 64-bit PPC64 | `ppc64_defconfig` | *[1]* | -| `powerpc64-32` | `ppc64-32` | PowerPC | 64-bit | 32-bit PPC32 | `ppc64_defconfig` | *[1]* | -| `powerpc64-spu` | `ppc64-spu`, `spu` | PowerPC | 64-bit | 64-bit "SPU" | `ppc64_defconfig` | *[1,5]* | -| `riscv` | `riscv32`, `rv32` | RISC-V | 32-bit | 32-bit "RV32" | `defconfig` + `32-bit.config` | *[3,6]* | -| `riscv64` | `rv64` | RISC-V | 64-bit | 64-bit "RV64" | `defconfig` | *[1,6]* | -| `riscv64-32` | `rv64-32` | RISC-V | 64-bit | 32-bit "RV32" | `defconfig` | *[1,6]* | -| `s390x` | | IBM Z | 64-bit | 64-bit s390x | `defconfig` | *[1]* | -| `s390` | | IBM Z | 64-bit | 32-bit s390 | `defconfig` | *[1]* | -| `x86` | `i386`, `ia32` | x86 | 32-bit | 32-bit IA32 | `i386_defconfig` | | -| `x86-64` | `x64` | x86 | 64-bit | 64-bit x86-64 | `x86_64_defconfig` | *[1]* | -| `x86-64-x32` | `x32` | x86 | 64-bit | 64-bit x32 | `x86_64_defconfig` | *[1]* | -| `x86-64-ia32` | `ia32-64` | x86 | 64-bit | 32-bit IA32 | `x86_64_defconfig` | *[1]* | +| Value | Aliases | Arch | Kernel | Syscall ABI | Build based on | Notes | +|:----------------|:-------------------|:----------|:-------|:---------------|:------------------------------|:--------| +| `arm` | `arm-eabi`, `eabi` | ARM | 32-bit | 32-bit EABI | `multi_v7_defconfig` | *[2]* | +| `arm-oabi` | `oabi` | ARM | 32-bit | 32-bit OABI | `multi_v7_defconfig` | *[2,4]* | +| `arm64` | `aarch64` | ARM | 64-bit | 64-bit AArch64 | `defconfig` | | +| `arm64-aarch32` | `aarch32` | ARM | 64-bit | 32-bit AArch32 | `defconfig` | *[1]* | +| `loongarch32` | `la32` | LoongArch | 32-bit | 32-bit "LA32" | `loongson32_defconfig` | *[7,8]* | +| `loongarch64` | `la64` | LoongArch | 64-bit | 64-bit "LA64" | `loongson64_defconfig` | *[7,8]* | +| `mips` | `mips32`, `o32` | MIPS | 32-bit | 32-bit O32 | `defconfig` | | +| `mips64` | `n64` | MIPS | 64-bit | 64-bit N64 | `ip27_defconfig` | *[1]* | +| `mips64-n32` | `n32` | MIPS | 64-bit | 64-bit N32 | `ip27_defconfig` | *[1]* | +| `mips64-o32` | `o32-64` | MIPS | 64-bit | 32-bit O32 | `ip27_defconfig` | *[1]* | +| `powerpc` | `ppc`, `ppc32` | PowerPC | 32-bit | 32-bit PPC32 | `ppc64_defconfig` | | +| `powerpc64` | `ppc64` | PowerPC | 64-bit | 64-bit PPC64 | `ppc64_defconfig` | *[1]* | +| `powerpc64-32` | `ppc64-32` | PowerPC | 64-bit | 32-bit PPC32 | `ppc64_defconfig` | *[1]* | +| `powerpc64-spu` | `ppc64-spu`, `spu` | PowerPC | 64-bit | 64-bit "SPU" | `ppc64_defconfig` | *[1,5]* | +| `riscv` | `riscv32`, `rv32` | RISC-V | 32-bit | 32-bit "RV32" | `defconfig` + `32-bit.config` | *[3,6]* | +| `riscv64` | `rv64` | RISC-V | 64-bit | 64-bit "RV64" | `defconfig` | *[1,6]* | +| `riscv64-32` | `rv64-32` | RISC-V | 64-bit | 32-bit "RV32" | `defconfig` | *[1,6]* | +| `s390x` | | IBM Z | 64-bit | 64-bit s390x | `defconfig` | *[1]* | +| `s390` | | IBM Z | 64-bit | 32-bit s390 | `defconfig` | *[1]* | +| `x86` | `i386`, `ia32` | x86 | 32-bit | 32-bit IA32 | `i386_defconfig` | | +| `x86-64` | `x64` | x86 | 64-bit | 64-bit x86-64 | `x86_64_defconfig` | *[1]* | +| `x86-64-x32` | `x32` | x86 | 64-bit | 64-bit x32 | `x86_64_defconfig` | *[1]* | +| `x86-64-ia32` | `ia32-64` | x86 | 64-bit | 32-bit IA32 | `x86_64_defconfig` | *[1]* | Notes: @@ -134,6 +136,9 @@ Notes: 6. "RV32" and "RV64" are not real ABIs, but rather ISAs. The RISC-V syscall ABI is the same for 32-bit and 64-bit (only register size differs). These names are only used for clarity. +7. "LA32" and "LA64" are not real ABIs, but rather ISAs. The LoongArch syscall ABI is the same + for 32-bit and 64-bit (only register size differs). These names are only used for clarity. +8. "Old-world" ABI is not and won't be supported. Runtime dependencies -------------------- diff --git a/src/systrack/arch/__init__.py b/src/systrack/arch/__init__.py index 5e62545..70e433a 100644 --- a/src/systrack/arch/__init__.py +++ b/src/systrack/arch/__init__.py @@ -7,6 +7,7 @@ from .arch_base import Arch from .arm import ArchArm from .arm64 import ArchArm64 +from .loongarch import ArchLoongArch from .mips import ArchMips from .powerpc import ArchPowerPC from .riscv import ArchRiscV @@ -16,6 +17,7 @@ ARCH_CLASSES = ( ArchArm, ArchArm64, + ArchLoongArch, ArchMips, ArchPowerPC, ArchRiscV, @@ -34,6 +36,8 @@ 'arm-oabi' : lambda v: ArchArm(v, abi='oabi'), 'arm64' : lambda v: ArchArm64(v, abi='aarch64'), 'arm64-aarch32': lambda v: ArchArm64(v, abi='aarch32'), + 'loongarch32' : lambda v: ArchLoongArch(v, abi='la32', bits32=True), + 'loongarch64' : lambda v: ArchLoongArch(v, abi='la64'), 'mips' : lambda v: ArchMips(v, abi='o32', bits32=True), 'mips64' : lambda v: ArchMips(v, abi='n64'), 'mips64-n32' : lambda v: ArchMips(v, abi='n32'), @@ -61,6 +65,8 @@ ('arm-oabi' , 'oabi' ), ('arm64' , 'aarch64' ), ('arm64-aarch32', 'aarch32' ), + ('loongarch32' , 'la32' ), + ('loongarch64' , 'la64' ), ('mips' , 'mips32' ), ('mips' , 'o32' ), ('mips64' , 'n64' ), @@ -83,35 +89,38 @@ SUPPORTED_ARCHS_HELP = '''\ Supported architectures and ABIs (values are case-insensitive): - Value Aliases Arch Kernel Syscall ABI Build based on Notes - ------------------------------------------------------------------------------------------------ - arm arm-eabi, eabi ARM 32-bit 32-bit EABI multi_v7_defconfig [2] - arm-oabi oabi ARM 32-bit 32-bit OABI multi_v7_defconfig [2,4] - ------------------------------------------------------------------------------------------------ - arm64 aarch64 ARM 64-bit 64-bit AArch64 defconfig - arm64-aarch32 aarch32 ARM 64-bit 32-bit AArch32 defconfig [1] - ------------------------------------------------------------------------------------------------ - mips mips32, o32 MIPS 32-bit 32-bit O32 defconfig - mips64 n64 MIPS 64-bit 64-bit N64 ip27_defconfig [1] - mips64-n32 n32 MIPS 64-bit 64-bit N32 ip27_defconfig [1] - mips64-o32 o32-64 MIPS 64-bit 32-bit O32 ip27_defconfig [1] - ------------------------------------------------------------------------------------------------ - powerpc ppc, ppc32 PowerPC 32-bit 32-bit PPC32 ppc64_defconfig - powerpc64 ppc64 PowerPC 64-bit 64-bit PPC64 ppc64_defconfig [1] - powerpc64-32 ppc64-32 PowerPC 64-bit 32-bit PPC32 ppc64_defconfig [1] - powerpc64-spu ppc64-spu, spu PowerPC 64-bit 64-bit "SPU" ppc64_defconfig [1,5] - ------------------------------------------------------------------------------------------------ - riscv riscv32, rv32 RISC-V 32-bit 32-bit "RV32" defconfig + 32-bit.config [3,6] - riscv64 rv64 RISC-V 64-bit 64-bit "RV64" defconfig [1,6] - riscv64-32 rv64-32 RISC-V 64-bit 32-bit "RV32" defconfig [1,6] - ------------------------------------------------------------------------------------------------ - s390x IBM Z 64-bit 64-bit s390x defconfig [1] - s390 IBM Z 64-bit 32-bit s390 defconfig [1] - ------------------------------------------------------------------------------------------------ - x86 i386, ia32 x86 32-bit 32-bit IA32 i386_defconfig - x86-64 x64 x86 64-bit 64-bit x86-64 x86_64_defconfig [1] - x86-64-x32 x32 x86 64-bit 64-bit x32 x86_64_defconfig [1] - x86-64-ia32 ia32-64 x86 64-bit 32-bit IA32 x86_64_defconfig [1] + Value Aliases Arch Kernel Syscall ABI Build based on Notes + ------------------------------------------------------------------------------------------------- + arm arm-eabi, eabi ARM 32-bit 32-bit EABI multi_v7_defconfig [2] + arm-oabi oabi ARM 32-bit 32-bit OABI multi_v7_defconfig [2,4] + ------------------------------------------------------------------------------------------------- + arm64 aarch64 ARM 64-bit 64-bit AArch64 defconfig + arm64-aarch32 aarch32 ARM 64-bit 32-bit AArch32 defconfig [1] + ------------------------------------------------------------------------------------------------- + loongarch32 la32 LoongArch 32-bit 32-bit "LA32" loongson32_defconfig [7,8] + loongarch64 la64 LoongArch 64-bit 64-bit "LA64" loongson64_defconfig [7,8] + ------------------------------------------------------------------------------------------------- + mips mips32, o32 MIPS 32-bit 32-bit O32 defconfig + mips64 n64 MIPS 64-bit 64-bit N64 ip27_defconfig [1] + mips64-n32 n32 MIPS 64-bit 64-bit N32 ip27_defconfig [1] + mips64-o32 o32-64 MIPS 64-bit 32-bit O32 ip27_defconfig [1] + ------------------------------------------------------------------------------------------------- + powerpc ppc, ppc32 PowerPC 32-bit 32-bit PPC32 ppc64_defconfig + powerpc64 ppc64 PowerPC 64-bit 64-bit PPC64 ppc64_defconfig [1] + powerpc64-32 ppc64-32 PowerPC 64-bit 32-bit PPC32 ppc64_defconfig [1] + powerpc64-spu ppc64-spu, spu PowerPC 64-bit 64-bit "SPU" ppc64_defconfig [1,5] + ------------------------------------------------------------------------------------------------- + riscv riscv32, rv32 RISC-V 32-bit 32-bit "RV32" defconfig + 32-bit.config [3,6] + riscv64 rv64 RISC-V 64-bit 64-bit "RV64" defconfig [1,6] + riscv64-32 rv64-32 RISC-V 64-bit 32-bit "RV32" defconfig [1,6] + ------------------------------------------------------------------------------------------------- + s390x IBM Z 64-bit 64-bit s390x defconfig [1] + s390 IBM Z 64-bit 32-bit s390 defconfig [1] + ------------------------------------------------------------------------------------------------- + x86 i386, ia32 x86 32-bit 32-bit IA32 i386_defconfig + x86-64 x64 x86 64-bit 64-bit x86-64 x86_64_defconfig [1] + x86-64-x32 x32 x86 64-bit 64-bit x32 x86_64_defconfig [1] + x86-64-ia32 ia32-64 x86 64-bit 32-bit IA32 x86_64_defconfig [1] [1] Building creates a kernel supporting all ABIs for this architecture. [2] Build based on "defconfig" for Linux <= v3.7. @@ -122,6 +131,9 @@ The ABI is really PPC64, but SPUs can only use a subset of syscalls. [6] "RV32" and "RV64" are not real ABIs, but rather ISAs. The RISC-V syscall ABI is the same for 32-bit and 64-bit (only register size differs). These names are only used for clarity. + [7] "LA32" and "LA64" are not real ABIs, but rather ISAs. The LoongArch syscall ABI is the same + for 32-bit and 64-bit (only register size differs). These names are only used for clarity. + [8] "Old-world" ABI is not and won't be supported. ''' def arch_from_name(name: str, kernel_version: KernelVersion) -> Arch: diff --git a/src/systrack/arch/loongarch.py b/src/systrack/arch/loongarch.py new file mode 100644 index 0000000..5f8b4c1 --- /dev/null +++ b/src/systrack/arch/loongarch.py @@ -0,0 +1,71 @@ +from typing import Tuple, List, Optional + +from ..elf import ELF, E_MACHINE, E_FLAGS +from ..kconfig_options import VERSION_INF +from ..type_hints import KernelVersion +from ..utils import VersionedDict + +from .arch_base import Arch + +class ArchLoongArch(Arch): + name = 'loongarch' + syscall_num_reg = 'a7' + syscall_arg_regs = ('a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6') + + kconfig = VersionedDict( + ( + # kexec_load + ((6, 1), VERSION_INF, 'KEXEC=y', ['MMU=y']), + # seccomp + ((5, 19), (5, 10), 'SECCOMP=y', []), + # mbind, {migrate.move}_pages, {get,set}_mempolicy + ((5, 19), VERSION_INF, 'NUMA=y', ['SMP=y']), + ) + ) + + def __init__(self, kernel_version: KernelVersion, abi: str, bits32: bool = False): + super().__init__(kernel_version, abi, bits32) + assert kernel_version >= (5, 19), ( + 'Mainline Linux only supports LoongArch from v5.19' + ) + assert self.abi in ('la32', 'la64') + + if self.abi == 'la32': + self.abi_bits32 = True + assert self.bits32 + + if self.bits32: + assert kernel_version >= (6, 19), ( + 'Mainline Linux only supports 32-bit LoongArch from v6.19' + ) + self.config_targets = ('loongson32_defconfig',) + else: + if kernel_version >= (6, 19): + self.config_targets = ('loongson64_defconfig',) + else: + self.config_targets = ('loongson3_defconfig',) + + # kexec_file_load + self.kconfig.add((6, 18), VERSION_INF, 'KEXEC_FILE=y', ['64BIT=y']) + + @staticmethod + def match(vmlinux: ELF) -> Optional[Tuple[bool, List[str]]]: + if vmlinux.e_machine != E_MACHINE.EM_LOONGARCH: + return None + + if vmlinux.bits32: + abis = ['la32'] + else: + abis = ['la64'] + + return vmlinux.bits32, abis + + def matches(self, vmlinux: ELF) -> bool: + assert not vmlinux.big_endian, 'Big-endian LoongArch kernel? WAT' + assert ((vmlinux.e_flags & E_FLAGS.EF_LOONGARCH_ABI_MASK) >> 6) == 1, ( + 'Unsupported ABI version' + ) + return ( + vmlinux.e_machine == E_MACHINE.EM_LOONGARCH + and vmlinux.bits32 == self.bits32 + ) diff --git a/src/systrack/elf.py b/src/systrack/elf.py index 28862e1..6739b95 100644 --- a/src/systrack/elf.py +++ b/src/systrack/elf.py @@ -12,19 +12,21 @@ # Only EM_* macros relevant for vmlinux ELFs class E_MACHINE(IntEnum): - EM_386 = 3 # x86 - EM_MIPS = 8 # MIPS R3000 (32 or 64 bit) - EM_PPC = 20 # PowerPC 32-bit - EM_PPC64 = 21 # PowerPC 64-bit - EM_S390 = 22 # IBM S/390 - EM_ARM = 40 # ARM 32-bit - EM_X86_64 = 62 # x86-64 - EM_AARCH64 = 183 # ARM 64-bit - EM_RISCV = 243 # RISC-V + EM_386 = 3 # x86 + EM_MIPS = 8 # MIPS R3000 (32 or 64 bit) + EM_PPC = 20 # PowerPC 32-bit + EM_PPC64 = 21 # PowerPC 64-bit + EM_S390 = 22 # IBM S/390 + EM_ARM = 40 # ARM 32-bit + EM_X86_64 = 62 # x86-64 + EM_AARCH64 = 183 # ARM 64-bit + EM_RISCV = 243 # RISC-V + EM_LOONGARCH = 258 # LoongArch # Only EF_* macros that we actually use class E_FLAGS(IntEnum): EF_ARM_EABI_MASK = 0xff000000 + EF_LOONGARCH_ABI_MASK = 0x000000c0 Section = namedtuple('Section', ('name', 'vaddr', 'off', 'size')) _Symbol = namedtuple('_Symbol', ('vaddr', 'real_vaddr', 'size', 'type', 'name')) @@ -79,7 +81,8 @@ def __init__(self, path: Union[str,Path]): assert self.file.seek(0x12) == 0x12 self.e_machine = unpack(unpack_endian + 'H', self.file.read(2))[0] - assert self.file.seek(0x24) == 0x24 + e_flags_offset = 0x24 if self.bits32 else 0x30 + assert self.file.seek(e_flags_offset) == e_flags_offset self.e_flags = unpack(unpack_endian + 'L', self.file.read(4))[0] @property