arch: add sparc32 support

This commit is contained in:
Amaan Qureshi 2026-04-17 12:42:13 -04:00
commit 205e637d89
No known key found for this signature in database
3 changed files with 214 additions and 7 deletions

View file

@ -7,7 +7,7 @@
//! //!
//! Supports `x86_64`, `aarch64`, `riscv64`, `loongarch64`, `s390x`, //! Supports `x86_64`, `aarch64`, `riscv64`, `loongarch64`, `s390x`,
//! `powerpc64`, `arm` (armv7), `riscv32`, `sparc64`, `mips64`, `x86` (i686), //! `powerpc64`, `arm` (armv7), `riscv32`, `sparc64`, `mips64`, `x86` (i686),
//! and `powerpc` (ppc32) architectures. //! `powerpc` (ppc32), and `sparc` (sparc32) architectures.
#![no_std] #![no_std]
#![cfg_attr( #![cfg_attr(
@ -15,6 +15,7 @@
target_arch = "powerpc64", target_arch = "powerpc64",
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "sparc64", target_arch = "sparc64",
target_arch = "sparc",
target_arch = "mips64" target_arch = "mips64"
), ),
feature(asm_experimental_arch) feature(asm_experimental_arch)
@ -33,12 +34,13 @@
target_arch = "sparc64", target_arch = "sparc64",
target_arch = "mips64", target_arch = "mips64",
target_arch = "x86", target_arch = "x86",
target_arch = "powerpc" target_arch = "powerpc",
target_arch = "sparc"
)))] )))]
compile_error!( compile_error!(
"Unsupported architecture: only x86_64, aarch64, riscv64, loongarch64, \ "Unsupported architecture: only x86_64, aarch64, riscv64, loongarch64, \
s390x, powerpc64, arm, riscv32, sparc64, mips64, x86, and powerpc are \ s390x, powerpc64, arm, riscv32, sparc64, mips64, x86, powerpc, and sparc \
supported" are supported"
); );
// Per-arch syscall implementations live in their own module files. // Per-arch syscall implementations live in their own module files.
@ -78,6 +80,9 @@ mod arch;
#[cfg(target_arch = "powerpc")] #[cfg(target_arch = "powerpc")]
#[path = "powerpc.rs"] #[path = "powerpc.rs"]
mod arch; mod arch;
#[cfg(target_arch = "sparc")]
#[path = "sparc.rs"]
mod arch;
/// Copies `n` bytes from `src` to `dest`. /// 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 = "riscv32",
target_arch = "x86", target_arch = "x86",
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "sparc",
target_arch = "mips64" target_arch = "mips64"
)))] )))]
pub struct StatfsBuf { pub struct StatfsBuf {
@ -363,7 +369,8 @@ pub struct StatfsBuf {
target_arch = "arm", target_arch = "arm",
target_arch = "riscv32", target_arch = "riscv32",
target_arch = "x86", target_arch = "x86",
target_arch = "powerpc" target_arch = "powerpc",
target_arch = "sparc"
))] ))]
pub struct StatfsBuf { pub struct StatfsBuf {
pub f_type: u32, pub f_type: u32,
@ -476,7 +483,8 @@ pub fn read_file_fast(path: &str, buffer: &mut [u8]) -> Result<usize, i32> {
target_arch = "arm", target_arch = "arm",
target_arch = "riscv32", target_arch = "riscv32",
target_arch = "x86", target_arch = "x86",
target_arch = "powerpc" target_arch = "powerpc",
target_arch = "sparc"
)))] )))]
pub struct SysInfo { pub struct SysInfo {
pub uptime: i64, pub uptime: i64,
@ -505,7 +513,8 @@ pub struct SysInfo {
target_arch = "arm", target_arch = "arm",
target_arch = "riscv32", target_arch = "riscv32",
target_arch = "x86", target_arch = "x86",
target_arch = "powerpc" target_arch = "powerpc",
target_arch = "sparc"
))] ))]
pub struct SysInfo { pub struct SysInfo {
pub uptime: i32, pub uptime: i32,

165
crates/asm/src/sparc.rs Normal file
View file

@ -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::<StatfsBuf>(),
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)
);
}
}

View file

@ -5,6 +5,7 @@
target_arch = "powerpc64", target_arch = "powerpc64",
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "sparc64", target_arch = "sparc64",
target_arch = "sparc",
target_arch = "mips64" target_arch = "mips64"
), ),
feature(asm_experimental_arch) 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
#[global_allocator] #[global_allocator]
static ALLOCATOR: BumpAllocator = BumpAllocator::new(); static ALLOCATOR: BumpAllocator = BumpAllocator::new();