mirror of
https://github.com/NotAShelf/microfetch.git
synced 2026-04-27 10:55:20 +00:00
arch: add s390x support
This commit is contained in:
parent
ce7a8553a8
commit
05fc3d8df9
5 changed files with 214 additions and 6 deletions
1
.github/workflows/rust.yml
vendored
1
.github/workflows/rust.yml
vendored
|
|
@ -21,6 +21,7 @@ jobs:
|
||||||
- aarch64-unknown-linux-gnu
|
- aarch64-unknown-linux-gnu
|
||||||
- riscv64gc-unknown-linux-gnu
|
- riscv64gc-unknown-linux-gnu
|
||||||
- loongarch64-unknown-linux-gnu
|
- loongarch64-unknown-linux-gnu
|
||||||
|
- s390x-unknown-linux-gnu
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@
|
||||||
//! What do you mean I wasted two whole hours to make the program only 100µs
|
//! What do you mean I wasted two whole hours to make the program only 100µs
|
||||||
//! faster?
|
//! faster?
|
||||||
//!
|
//!
|
||||||
//! Supports `x86_64`, `aarch64`, `riscv64`, and `loongarch64` architectures.
|
//! Supports `x86_64`, `aarch64`, `riscv64`, `loongarch64`, and `s390x`
|
||||||
|
//! architectures.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
|
@ -14,11 +15,12 @@
|
||||||
target_arch = "x86_64",
|
target_arch = "x86_64",
|
||||||
target_arch = "aarch64",
|
target_arch = "aarch64",
|
||||||
target_arch = "riscv64",
|
target_arch = "riscv64",
|
||||||
target_arch = "loongarch64"
|
target_arch = "loongarch64",
|
||||||
|
target_arch = "s390x"
|
||||||
)))]
|
)))]
|
||||||
compile_error!(
|
compile_error!(
|
||||||
"Unsupported architecture: only x86_64, aarch64, riscv64, and loongarch64 \
|
"Unsupported architecture: only x86_64, aarch64, riscv64, loongarch64, and \
|
||||||
are supported"
|
s390x are supported"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Per-arch syscall implementations live in their own module files.
|
// Per-arch syscall implementations live in their own module files.
|
||||||
|
|
@ -34,6 +36,9 @@ mod arch;
|
||||||
#[cfg(target_arch = "loongarch64")]
|
#[cfg(target_arch = "loongarch64")]
|
||||||
#[path = "loongarch64.rs"]
|
#[path = "loongarch64.rs"]
|
||||||
mod arch;
|
mod arch;
|
||||||
|
#[cfg(target_arch = "s390x")]
|
||||||
|
#[path = "s390x.rs"]
|
||||||
|
mod arch;
|
||||||
|
|
||||||
/// Copies `n` bytes from `src` to `dest`.
|
/// Copies `n` bytes from `src` to `dest`.
|
||||||
///
|
///
|
||||||
|
|
@ -267,6 +272,7 @@ pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 {
|
||||||
/// offsets on both architectures. Only the fields needed for disk usage are
|
/// offsets on both architectures. Only the fields needed for disk usage are
|
||||||
/// declared; the remainder of the 120-byte struct is covered by `_pad`.
|
/// declared; the remainder of the 120-byte struct is covered by `_pad`.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
#[cfg(not(target_arch = "s390x"))]
|
||||||
pub struct StatfsBuf {
|
pub struct StatfsBuf {
|
||||||
pub f_type: i64,
|
pub f_type: i64,
|
||||||
pub f_bsize: i64,
|
pub f_bsize: i64,
|
||||||
|
|
@ -284,6 +290,26 @@ pub struct StatfsBuf {
|
||||||
pub _pad: [i64; 4],
|
pub _pad: [i64; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// on s390x `f_type` and `f_bsize` are 32-bit.
|
||||||
|
#[repr(C)]
|
||||||
|
#[cfg(target_arch = "s390x")]
|
||||||
|
pub struct StatfsBuf {
|
||||||
|
pub f_type: u32,
|
||||||
|
pub f_bsize: u32,
|
||||||
|
pub f_blocks: u64,
|
||||||
|
pub f_bfree: u64,
|
||||||
|
pub f_bavail: u64,
|
||||||
|
pub f_files: u64,
|
||||||
|
pub f_ffree: u64,
|
||||||
|
pub f_fsid: [i32; 2],
|
||||||
|
pub f_namelen: u32,
|
||||||
|
pub f_frsize: u32,
|
||||||
|
pub f_flags: u32,
|
||||||
|
|
||||||
|
#[allow(clippy::pub_underscore_fields, reason = "This is not a public API")]
|
||||||
|
pub _pad: [u32; 5],
|
||||||
|
}
|
||||||
|
|
||||||
/// Direct `statfs(2)` syscall
|
/// Direct `statfs(2)` syscall
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
|
|
|
||||||
160
crates/asm/src/s390x.rs
Normal file
160
crates/asm/src/s390x.rs
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
//! Syscall implementations for `s390x`.
|
||||||
|
|
||||||
|
use super::{StatfsBuf, SysInfo, UtsNameBuf};
|
||||||
|
|
||||||
|
pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 {
|
||||||
|
unsafe {
|
||||||
|
let fd: i64;
|
||||||
|
core::arch::asm!(
|
||||||
|
"svc 0",
|
||||||
|
in("r1") 5i64, // SYS_open
|
||||||
|
in("r2") path,
|
||||||
|
in("r3") flags,
|
||||||
|
in("r4") 0i32, // mode
|
||||||
|
lateout("r2") fd,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
{
|
||||||
|
fd as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize {
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
core::arch::asm!(
|
||||||
|
"svc 0",
|
||||||
|
in("r1") 3i64, // SYS_read
|
||||||
|
in("r2") fd,
|
||||||
|
in("r3") buf,
|
||||||
|
in("r4") count,
|
||||||
|
lateout("r2") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
{
|
||||||
|
ret as isize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize {
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
core::arch::asm!(
|
||||||
|
"svc 0",
|
||||||
|
in("r1") 4i64, // SYS_write
|
||||||
|
in("r2") fd,
|
||||||
|
in("r3") buf,
|
||||||
|
in("r4") count,
|
||||||
|
lateout("r2") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
{
|
||||||
|
ret as isize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn sys_close(fd: i32) -> i32 {
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
core::arch::asm!(
|
||||||
|
"svc 0",
|
||||||
|
in("r1") 6i64, // SYS_close
|
||||||
|
in("r2") fd,
|
||||||
|
lateout("r2") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
{
|
||||||
|
ret as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 {
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
core::arch::asm!(
|
||||||
|
"svc 0",
|
||||||
|
in("r1") 122i64, // SYS_uname
|
||||||
|
in("r2") buf,
|
||||||
|
lateout("r2") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
{
|
||||||
|
ret as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 {
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
core::arch::asm!(
|
||||||
|
"svc 0",
|
||||||
|
in("r1") 99i64, // SYS_statfs
|
||||||
|
in("r2") path,
|
||||||
|
in("r3") buf,
|
||||||
|
lateout("r2") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
{
|
||||||
|
ret as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 {
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
core::arch::asm!(
|
||||||
|
"svc 0",
|
||||||
|
in("r1") 116_i64, // __NR_sysinfo
|
||||||
|
in("r2") info,
|
||||||
|
lateout("r2") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn sys_sched_getaffinity(
|
||||||
|
pid: i32,
|
||||||
|
mask_size: usize,
|
||||||
|
mask: *mut u8,
|
||||||
|
) -> i32 {
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
core::arch::asm!(
|
||||||
|
"svc 0",
|
||||||
|
in("r1") 240i64, // __NR_sched_getaffinity
|
||||||
|
in("r2") pid,
|
||||||
|
in("r3") mask_size,
|
||||||
|
in("r4") mask,
|
||||||
|
lateout("r2") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
{
|
||||||
|
ret as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn sys_exit(code: i32) -> ! {
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"svc 0",
|
||||||
|
in("r1") 1i64, // SYS_exit
|
||||||
|
in("r2") code,
|
||||||
|
options(noreturn, nostack)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -140,10 +140,15 @@ fn get_cpu_freq_mhz() -> Option<u32> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Fall back to cpuinfo fields
|
// Fall back to cpuinfo fields
|
||||||
let mut buf2 = [0u8; 2048];
|
let mut buf2 = [0u8; 4096];
|
||||||
let n = read_file_fast("/proc/cpuinfo", &mut buf2).ok()?;
|
let n = read_file_fast("/proc/cpuinfo", &mut buf2).ok()?;
|
||||||
let data = &buf2[..n];
|
let data = &buf2[..n];
|
||||||
for key in &[b"cpu MHz" as &[u8], b"cpu MHz dynamic", b"CPU MHz"] {
|
for key in &[
|
||||||
|
b"cpu MHz" as &[u8],
|
||||||
|
b"cpu MHz dynamic",
|
||||||
|
b"cpu MHz static",
|
||||||
|
b"CPU MHz",
|
||||||
|
] {
|
||||||
if let Some(val) = extract_field(data, key) {
|
if let Some(val) = extract_field(data, key) {
|
||||||
// Parse integer part of the MHz value (e.g. "5200.00" -> 5200)
|
// Parse integer part of the MHz value (e.g. "5200.00" -> 5200)
|
||||||
let mut mhz = 0u32;
|
let mut mhz = 0u32;
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,22 @@ unsafe extern "C" fn _start() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "s390x")]
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
#[unsafe(naked)]
|
||||||
|
unsafe extern "C" fn _start() {
|
||||||
|
naked_asm!(
|
||||||
|
"lgr %r2, %r15", // save original sp (argc/argv) as arg
|
||||||
|
"aghi %r15, -160", // allocate s390x mandatory stack frame
|
||||||
|
"lghi %r0, -16",
|
||||||
|
"ngr %r15, %r0", // align stack to 16 bytes
|
||||||
|
"brasl %r14, {entry_rust}",
|
||||||
|
"lghi %r1, 1", // SYS_exit
|
||||||
|
"svc 0",
|
||||||
|
entry_rust = sym entry_rust,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Global allocator
|
// Global allocator
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOCATOR: BumpAllocator = BumpAllocator::new();
|
static ALLOCATOR: BumpAllocator = BumpAllocator::new();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue