Skip to content

Commit

Permalink
s390x linux_raw support
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Oct 4, 2024
1 parent 613940f commit 403f3b2
Show file tree
Hide file tree
Showing 10 changed files with 339 additions and 11 deletions.
12 changes: 11 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
build: [powerpc64le-linux]
build: [powerpc64le-linux, s390x-linux]
include:
- build: powerpc64le-linux
os: ubuntu-latest
Expand All @@ -649,11 +649,21 @@ jobs:
qemu: qemu-ppc64le
qemu_args: -L /usr/powerpc64le-linux-gnu
qemu_target: ppc64le-linux-user
- build: s390x-linux
os: ubuntu-latest
rust: nightly
target: s390x-unknown-linux-gnu
gcc_package: gcc-s390x-linux-gnu
gcc: s390x-linux-gnu-gcc
qemu: qemu-s390x
qemu_args: -L /usr/s390x-linux-gnu
qemu_target: s390x-linux-user
env:
# -D warnings is commented out in our install-rust action; re-add it here.
RUSTFLAGS: --cfg rustix_use_experimental_asm -D warnings -D elided-lifetimes-in-paths
RUSTDOCFLAGS: --cfg rustix_use_experimental_asm
CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUSTFLAGS: --cfg rustix_use_experimental_asm
CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_RUSTFLAGS: --cfg rustix_use_experimental_asm
QEMU_BUILD_VERSION: 8.1.2
steps:
- uses: actions/checkout@v4
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ once_cell = { version = "1.5.2", optional = true }
# addition to the libc backend. The linux_raw backend is used by default. The
# libc backend can be selected via adding `--cfg=rustix_use_libc` to
# `RUSTFLAGS` or enabling the `use-libc` cargo feature.
[target.'cfg(all(not(rustix_use_libc), not(miri), target_os = "linux", target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64"))))'.dependencies]
[target.'cfg(all(not(rustix_use_libc), not(miri), target_os = "linux", any(target_endian = "little", target_arch = "s390x"), any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "s390x"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64"))))'.dependencies]
linux-raw-sys = { version = "0.4.14", default-features = false, features = ["general", "errno", "ioctl", "no_std", "elf"] }
libc_errno = { package = "errno", version = "0.3.8", default-features = false, optional = true }
libc = { version = "0.2.156", default-features = false, optional = true }
Expand All @@ -44,15 +44,15 @@ libc = { version = "0.2.156", default-features = false, optional = true }
#
# On all other Unix-family platforms, and under Miri, we always use the libc
# backend, so enable its dependencies unconditionally.
[target.'cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = "linux", target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64")))))))'.dependencies]
[target.'cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = "linux", any(target_endian = "little", target_arch = "s390x"), any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "s390x"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64")))))))'.dependencies]
libc_errno = { package = "errno", version = "0.3.8", default-features = false }
libc = { version = "0.2.156", default-features = false }

# Additional dependencies for Linux with the libc backend:
#
# Some syscalls do not have libc wrappers, such as in `io_uring`. For these,
# the libc backend uses the linux-raw-sys ABI and `libc::syscall`.
[target.'cfg(all(any(target_os = "android", target_os = "linux"), any(rustix_use_libc, miri, not(all(target_os = "linux", target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64")))))))'.dependencies]
[target.'cfg(all(any(target_os = "android", target_os = "linux"), any(rustix_use_libc, miri, not(all(target_os = "linux", any(target_endian = "little", target_arch = "s390x"), any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "s390x"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64")))))))'.dependencies]
linux-raw-sys = { version = "0.4.14", default-features = false, features = ["general", "ioctl", "no_std"] }

# For the libc backend on Windows, use the Winsock API in windows-sys.
Expand Down
3 changes: 2 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ fn main() {
|| !inline_asm_name_present
|| is_unsupported_abi
|| miri
|| ((arch == "powerpc64" || arch.starts_with("mips")) && !rustix_use_experimental_asm);
|| ((arch == "powerpc64" || arch == "s390x" || arch.starts_with("mips"))
&& !rustix_use_experimental_asm);
if libc {
// Use the libc backend.
use_feature("libc");
Expand Down
2 changes: 2 additions & 0 deletions src/backend/linux_raw/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#[cfg_attr(target_arch = "mips64r6", path = "mips64r6.rs")]
#[cfg_attr(target_arch = "powerpc64", path = "powerpc64.rs")]
#[cfg_attr(target_arch = "riscv64", path = "riscv64.rs")]
#[cfg_attr(target_arch = "s390x", path = "s390x.rs")]
#[cfg_attr(target_arch = "x86", path = "x86.rs")]
#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
pub(in crate::backend) mod asm;
Expand All @@ -47,6 +48,7 @@ pub(in crate::backend) mod asm;
target_arch = "mips64r6",
target_arch = "powerpc64",
target_arch = "riscv64",
target_arch = "s390x",
target_arch = "x86_64",
))]
pub(in crate::backend) use self::asm as choose;
Expand Down
287 changes: 287 additions & 0 deletions src/backend/linux_raw/arch/s390x.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
//! s390x Linux system calls.

use crate::backend::reg::{
ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0,
};
use core::arch::asm;

#[inline]
pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
lateout("r2") r0,
options(nostack, preserves_flags, readonly)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
options(nostack, preserves_flags)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall1_readonly(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
options(nostack, preserves_flags, readonly)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
asm!(
"svc 0",
in("r1") nr.to_asm(),
in("r2") a0.to_asm(),
options(nostack, preserves_flags, noreturn)
)
}

#[inline]
pub(in crate::backend) unsafe fn syscall2(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
options(nostack, preserves_flags)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall2_readonly(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
options(nostack, preserves_flags, readonly)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall3(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
a2: ArgReg<'_, A2>,
) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
in("r4") a2.to_asm(),
options(nostack, preserves_flags)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall3_readonly(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
a2: ArgReg<'_, A2>,
) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
in("r4") a2.to_asm(),
options(nostack, preserves_flags, readonly)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall4(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
a2: ArgReg<'_, A2>,
a3: ArgReg<'_, A3>,
) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
in("r4") a2.to_asm(),
in("r5") a3.to_asm(),
options(nostack, preserves_flags)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall4_readonly(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
a2: ArgReg<'_, A2>,
a3: ArgReg<'_, A3>,
) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
in("r4") a2.to_asm(),
in("r5") a3.to_asm(),
options(nostack, preserves_flags, readonly)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall5(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
a2: ArgReg<'_, A2>,
a3: ArgReg<'_, A3>,
a4: ArgReg<'_, A4>,
) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
in("r4") a2.to_asm(),
in("r5") a3.to_asm(),
in("r6") a4.to_asm(),
options(nostack, preserves_flags)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall5_readonly(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
a2: ArgReg<'_, A2>,
a3: ArgReg<'_, A3>,
a4: ArgReg<'_, A4>,
) -> RetReg<R0> {
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
in("r4") a2.to_asm(),
in("r5") a3.to_asm(),
in("r6") a4.to_asm(),
options(nostack, preserves_flags, readonly)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall6(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
a2: ArgReg<'_, A2>,
a3: ArgReg<'_, A3>,
a4: ArgReg<'_, A4>,
a5: ArgReg<'_, A5>,
) -> RetReg<R0> {
if nr.nr == linux_raw_sys::general::__NR_mmap as usize {
let mut a = [
a0.to_asm(),
a1.to_asm(),
a2.to_asm(),
a3.to_asm(),
a4.to_asm(),
a5.to_asm(),
];
return syscall1(nr, a.as_mut_ptr().into());
}
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
in("r4") a2.to_asm(),
in("r5") a3.to_asm(),
in("r6") a4.to_asm(),
in("r7") a5.to_asm(),
options(nostack, preserves_flags)
);
FromAsm::from_asm(r0)
}

#[inline]
pub(in crate::backend) unsafe fn syscall6_readonly(
nr: SyscallNumber<'_>,
a0: ArgReg<'_, A0>,
a1: ArgReg<'_, A1>,
a2: ArgReg<'_, A2>,
a3: ArgReg<'_, A3>,
a4: ArgReg<'_, A4>,
a5: ArgReg<'_, A5>,
) -> RetReg<R0> {
if nr.nr == linux_raw_sys::general::__NR_mmap as usize {
let a = [
a0.to_asm(),
a1.to_asm(),
a2.to_asm(),
a3.to_asm(),
a4.to_asm(),
a5.to_asm(),
];
return syscall1_readonly(nr, a.as_ptr().into());
}
let r0;
asm!(
"svc 0",
in("r1") nr.to_asm(),
inlateout("r2") a0.to_asm() => r0,
in("r3") a1.to_asm(),
in("r4") a2.to_asm(),
in("r5") a3.to_asm(),
in("r6") a4.to_asm(),
in("r7") a5.to_asm(),
options(nostack, preserves_flags, readonly)
);
FromAsm::from_asm(r0)
}
Loading

0 comments on commit 403f3b2

Please sign in to comment.