diff --git a/crates/asm/src/lib.rs b/crates/asm/src/lib.rs index 9dba972..4f213bc 100644 --- a/crates/asm/src/lib.rs +++ b/crates/asm/src/lib.rs @@ -7,7 +7,7 @@ //! //! Supports `x86_64`, `aarch64`, `riscv64`, `loongarch64`, `s390x`, //! `powerpc64`, `arm` (armv7), `riscv32`, `sparc64`, `mips64`, `x86` (i686), -//! and `powerpc` (ppc32) architectures. +//! `powerpc` (ppc32), and `sparc` (sparc32) architectures. #![no_std] #![cfg_attr( @@ -15,6 +15,7 @@ target_arch = "powerpc64", target_arch = "powerpc", target_arch = "sparc64", + target_arch = "sparc", target_arch = "mips64" ), feature(asm_experimental_arch) @@ -33,12 +34,13 @@ target_arch = "sparc64", target_arch = "mips64", target_arch = "x86", - target_arch = "powerpc" + target_arch = "powerpc", + target_arch = "sparc" )))] compile_error!( "Unsupported architecture: only x86_64, aarch64, riscv64, loongarch64, \ - s390x, powerpc64, arm, riscv32, sparc64, mips64, x86, and powerpc are \ - supported" + s390x, powerpc64, arm, riscv32, sparc64, mips64, x86, powerpc, and sparc \ + are supported" ); // Per-arch syscall implementations live in their own module files. @@ -78,6 +80,9 @@ mod arch; #[cfg(target_arch = "powerpc")] #[path = "powerpc.rs"] mod arch; +#[cfg(target_arch = "sparc")] +#[path = "sparc.rs"] +mod arch; /// Copies `n` bytes from `src` to `dest`. /// @@ -317,6 +322,7 @@ pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { target_arch = "riscv32", target_arch = "x86", target_arch = "powerpc", + target_arch = "sparc", target_arch = "mips64" )))] pub struct StatfsBuf { @@ -363,7 +369,8 @@ pub struct StatfsBuf { target_arch = "arm", target_arch = "riscv32", target_arch = "x86", - target_arch = "powerpc" + target_arch = "powerpc", + target_arch = "sparc" ))] pub struct StatfsBuf { pub f_type: u32, @@ -476,7 +483,8 @@ pub fn read_file_fast(path: &str, buffer: &mut [u8]) -> Result { target_arch = "arm", target_arch = "riscv32", target_arch = "x86", - target_arch = "powerpc" + target_arch = "powerpc", + target_arch = "sparc" )))] pub struct SysInfo { pub uptime: i64, @@ -505,7 +513,8 @@ pub struct SysInfo { target_arch = "arm", target_arch = "riscv32", target_arch = "x86", - target_arch = "powerpc" + target_arch = "powerpc", + target_arch = "sparc" ))] pub struct SysInfo { pub uptime: i32, diff --git a/crates/asm/src/sparc.rs b/crates/asm/src/sparc.rs new file mode 100644 index 0000000..a4cc3f7 --- /dev/null +++ b/crates/asm/src/sparc.rs @@ -0,0 +1,165 @@ +//! Syscall implementations for `sparc`. + +use super::{StatfsBuf, SysInfo, UtsNameBuf}; + +pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { + unsafe { + let ret: i32; + core::arch::asm!( + "mov {nr}, %g1", + "ta 0x10", + "bcs,a 1f", + "sub %g0, %o0, %o0", + "1:", + nr = in(reg) 5i32, // SYS_open + inlateout("o0") path => ret, + in("o1") flags, + in("o2") 0i32, // mode + options(nostack) + ); + ret + } +} + +pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { + unsafe { + let ret: i32; + core::arch::asm!( + "mov {nr}, %g1", + "ta 0x10", + "bcs,a 1f", + "sub %g0, %o0, %o0", + "1:", + nr = in(reg) 3i32, // SYS_read + inlateout("o0") fd => ret, + in("o1") buf, + in("o2") count, + options(nostack) + ); + ret as isize + } +} + +pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { + unsafe { + let ret: i32; + core::arch::asm!( + "mov {nr}, %g1", + "ta 0x10", + "bcs,a 1f", + "sub %g0, %o0, %o0", + "1:", + nr = in(reg) 4i32, // SYS_write + inlateout("o0") fd => ret, + in("o1") buf, + in("o2") count, + options(nostack) + ); + ret as isize + } +} + +pub(super) unsafe fn sys_close(fd: i32) -> i32 { + unsafe { + let ret: i32; + core::arch::asm!( + "mov {nr}, %g1", + "ta 0x10", + "bcs,a 1f", + "sub %g0, %o0, %o0", + "1:", + nr = in(reg) 6i32, // SYS_close + inlateout("o0") fd => ret, + options(nostack) + ); + ret + } +} + +pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { + unsafe { + let ret: i32; + core::arch::asm!( + "mov {nr}, %g1", + "ta 0x10", + "bcs,a 1f", + "sub %g0, %o0, %o0", + "1:", + nr = in(reg) 189i32, // SYS_newuname + inlateout("o0") buf => ret, + options(nostack) + ); + ret + } +} + +pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { + unsafe { + let ret: i32; + core::arch::asm!( + "mov {nr}, %g1", + "ta 0x10", + "bcs,a 1f", + "sub %g0, %o0, %o0", + "1:", + nr = in(reg) 234i32, // SYS_statfs64 + inlateout("o0") path => ret, + in("o1") core::mem::size_of::(), + in("o2") buf, + options(nostack) + ); + ret + } +} + +pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { + unsafe { + let ret: i32; + core::arch::asm!( + "mov {nr}, %g1", + "ta 0x10", + "bcs,a 1f", + "sub %g0, %o0, %o0", + "1:", + nr = in(reg) 214_i32, // __NR_sysinfo + inlateout("o0") info => ret, + options(nostack) + ); + i64::from(ret) + } +} + +pub(super) unsafe fn sys_sched_getaffinity( + pid: i32, + mask_size: usize, + mask: *mut u8, +) -> i32 { + unsafe { + let ret: i32; + core::arch::asm!( + "mov {nr}, %g1", + "ta 0x10", + "bcs,a 1f", + "sub %g0, %o0, %o0", + "1:", + nr = in(reg) 260i32, // __NR_sched_getaffinity + inlateout("o0") pid => ret, + in("o1") mask_size, + in("o2") mask, + options(nostack) + ); + ret + } +} + +pub(super) unsafe fn sys_exit(code: i32) -> ! { + unsafe { + core::arch::asm!( + "mov {nr}, %g1", + "ta 0x10", + nr = in(reg) 1i32, // SYS_exit + in("o0") code, + options(noreturn, nostack) + ); + } +} diff --git a/microfetch/src/main.rs b/microfetch/src/main.rs index 8f9fb23..84fce24 100644 --- a/microfetch/src/main.rs +++ b/microfetch/src/main.rs @@ -5,6 +5,7 @@ target_arch = "powerpc64", target_arch = "powerpc", target_arch = "sparc64", + target_arch = "sparc", target_arch = "mips64" ), feature(asm_experimental_arch) @@ -247,6 +248,38 @@ unsafe extern "C" fn _start() { ); } +#[cfg(target_arch = "sparc")] +#[unsafe(no_mangle)] +#[unsafe(naked)] +unsafe extern "C" fn _start() { + naked_asm!( + "mov %g0, %fp", + "add %sp, 64, %o0", // first arg = &argc (past the 64-byte window save) + "and %sp, -16, %sp", // align sp to 16 bytes + "sub %sp, 64, %sp", // reserve window save area + "call {entry_rust}", + "nop", // delay slot + "mov 1, %g1", // SYS_exit (code already in %o0) + "ta 0x10", + entry_rust = sym entry_rust, + ); +} + +// SPARC V8 has no 1-byte CAS, so rustc emits calls to libatomic for byte +// atomics. We're single-threaded with panic=abort, so a plain load/store is +// already correct. +#[cfg(all(not(test), target_arch = "sparc"))] +#[unsafe(no_mangle)] +extern "C" fn __atomic_load_1(ptr: *const u8, _order: i32) -> u8 { + unsafe { core::ptr::read_volatile(ptr) } +} + +#[cfg(all(not(test), target_arch = "sparc"))] +#[unsafe(no_mangle)] +extern "C" fn __atomic_store_1(ptr: *mut u8, val: u8, _order: i32) { + unsafe { core::ptr::write_volatile(ptr, val) } +} + // Global allocator #[global_allocator] static ALLOCATOR: BumpAllocator = BumpAllocator::new();