arch: add mips32 support

This commit is contained in:
Amaan Qureshi 2026-04-17 12:52:15 -04:00
commit 277eec55b0
No known key found for this signature in database
4 changed files with 258 additions and 10 deletions

View file

@ -52,6 +52,11 @@ jobs:
# powerpc uses experimental asm features # powerpc uses experimental asm features
- target: powerpc-unknown-linux-gnu - target: powerpc-unknown-linux-gnu
toolchain: nightly toolchain: nightly
# mips is tier-3 and uses experimental asm features
- target: mips-unknown-linux-gnu
toolchain: nightly
components: rust-src
build_std: true
steps: steps:
- name: "Checkout" - name: "Checkout"
@ -77,7 +82,7 @@ jobs:
target: ${{ matrix.target }} target: ${{ matrix.target }}
- name: "Build" - name: "Build"
run: cargo build --verbose --target ${{ matrix.target }} ${{ matrix.build_std && '-Z build-std=core,alloc,panic_abort' || '' }} run: cargo build --verbose --target ${{ matrix.target }} ${{ matrix.build_std && '-Z build-std=core,alloc,panic_abort' || '' }} ${{ matrix.extra_args || '' }}
# tier-3 targets have no prebuilt std and tests are arch-agnostic, so # tier-3 targets have no prebuilt std and tests are arch-agnostic, so
# run them against the host toolchain instead of the cross target. # run them against the host toolchain instead of the cross target.

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),
//! `powerpc` (ppc32), and `sparc` (sparc32) architectures. //! `powerpc` (ppc32), `sparc` (sparc32), and `mips` (O32) architectures.
#![no_std] #![no_std]
#![cfg_attr( #![cfg_attr(
@ -16,7 +16,8 @@
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "sparc64", target_arch = "sparc64",
target_arch = "sparc", target_arch = "sparc",
target_arch = "mips64" target_arch = "mips64",
target_arch = "mips"
), ),
feature(asm_experimental_arch) feature(asm_experimental_arch)
)] )]
@ -35,12 +36,13 @@
target_arch = "mips64", target_arch = "mips64",
target_arch = "x86", target_arch = "x86",
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "sparc" target_arch = "sparc",
target_arch = "mips"
)))] )))]
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, powerpc, and sparc \ s390x, powerpc64, arm, riscv32, sparc64, mips64, x86, powerpc, sparc, and \
are supported" mips are supported"
); );
// Per-arch syscall implementations live in their own module files. // Per-arch syscall implementations live in their own module files.
@ -83,6 +85,9 @@ mod arch;
#[cfg(target_arch = "sparc")] #[cfg(target_arch = "sparc")]
#[path = "sparc.rs"] #[path = "sparc.rs"]
mod arch; mod arch;
#[cfg(target_arch = "mips")]
#[path = "mips.rs"]
mod arch;
/// Copies `n` bytes from `src` to `dest`. /// Copies `n` bytes from `src` to `dest`.
/// ///
@ -323,7 +328,8 @@ pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 {
target_arch = "x86", target_arch = "x86",
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "sparc", target_arch = "sparc",
target_arch = "mips64" target_arch = "mips64",
target_arch = "mips"
)))] )))]
pub struct StatfsBuf { pub struct StatfsBuf {
pub f_type: i64, pub f_type: i64,
@ -389,6 +395,28 @@ pub struct StatfsBuf {
pub _pad: [u32; 4], pub _pad: [u32; 4],
} }
/// mips (O32) uses `compat_statfs64`, same reordering with 32-bit words; see
/// https://github.com/torvalds/linux/blob/v6.19/arch/mips/include/uapi/asm/statfs.h
#[repr(C)]
#[cfg(target_arch = "mips")]
pub struct StatfsBuf {
pub f_type: u32,
pub f_bsize: u32,
pub f_frsize: u32,
_pad: u32,
pub f_blocks: u64,
pub f_bfree: u64,
pub f_files: u64,
pub f_ffree: u64,
pub f_bavail: u64,
pub f_fsid: [i32; 2],
pub f_namelen: u32,
pub f_flags: u32,
#[allow(clippy::pub_underscore_fields, reason = "This is not a public API")]
pub _pad2: [u32; 5],
}
/// mips reorders fields; see /// mips reorders fields; see
/// https://github.com/torvalds/linux/blob/v6.19/arch/mips/include/uapi/asm/statfs.h /// https://github.com/torvalds/linux/blob/v6.19/arch/mips/include/uapi/asm/statfs.h
#[repr(C)] #[repr(C)]
@ -484,7 +512,8 @@ pub fn read_file_fast(path: &str, buffer: &mut [u8]) -> Result<usize, i32> {
target_arch = "riscv32", target_arch = "riscv32",
target_arch = "x86", target_arch = "x86",
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "sparc" target_arch = "sparc",
target_arch = "mips"
)))] )))]
pub struct SysInfo { pub struct SysInfo {
pub uptime: i64, pub uptime: i64,
@ -514,7 +543,8 @@ pub struct SysInfo {
target_arch = "riscv32", target_arch = "riscv32",
target_arch = "x86", target_arch = "x86",
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "sparc" target_arch = "sparc",
target_arch = "mips"
))] ))]
pub struct SysInfo { pub struct SysInfo {
pub uptime: i32, pub uptime: i32,

196
crates/asm/src/mips.rs Normal file
View file

@ -0,0 +1,196 @@
//! Syscall implementations for `mips`.
use super::{StatfsBuf, SysInfo, UtsNameBuf};
pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 {
unsafe {
let ret: i32;
core::arch::asm!(
"syscall",
"beqz $7, 1f",
"nop",
"subu $2, $0, $2",
"1:",
inlateout("$2") 4000i32 + 5 => ret, // SYS_open
in("$4") path,
in("$5") flags,
in("$6") 0i32, // mode
lateout("$7") _,
lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _,
lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _,
lateout("$24") _, lateout("$25") _,
options(nostack)
);
ret
}
}
pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize {
unsafe {
let ret: i32;
core::arch::asm!(
"syscall",
"beqz $7, 1f",
"nop",
"subu $2, $0, $2",
"1:",
inlateout("$2") 4000i32 + 3 => ret, // SYS_read
in("$4") fd,
in("$5") buf,
in("$6") count,
lateout("$7") _,
lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _,
lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _,
lateout("$24") _, lateout("$25") _,
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!(
"syscall",
"beqz $7, 1f",
"nop",
"subu $2, $0, $2",
"1:",
inlateout("$2") 4000i32 + 4 => ret, // SYS_write
in("$4") fd,
in("$5") buf,
in("$6") count,
lateout("$7") _,
lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _,
lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _,
lateout("$24") _, lateout("$25") _,
options(nostack)
);
ret as isize
}
}
pub(super) unsafe fn sys_close(fd: i32) -> i32 {
unsafe {
let ret: i32;
core::arch::asm!(
"syscall",
"beqz $7, 1f",
"nop",
"subu $2, $0, $2",
"1:",
inlateout("$2") 4000i32 + 6 => ret, // SYS_close
in("$4") fd,
lateout("$7") _,
lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _,
lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _,
lateout("$24") _, lateout("$25") _,
options(nostack)
);
ret
}
}
pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 {
unsafe {
let ret: i32;
core::arch::asm!(
"syscall",
"beqz $7, 1f",
"nop",
"subu $2, $0, $2",
"1:",
inlateout("$2") 4000i32 + 122 => ret, // SYS_newuname
in("$4") buf,
lateout("$7") _,
lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _,
lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _,
lateout("$24") _, lateout("$25") _,
options(nostack)
);
ret
}
}
pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 {
unsafe {
let ret: i32;
core::arch::asm!(
"syscall",
"beqz $7, 1f",
"nop",
"subu $2, $0, $2",
"1:",
inlateout("$2") 4000i32 + 255 => ret, // SYS_statfs64
in("$4") path,
in("$5") core::mem::size_of::<StatfsBuf>(),
in("$6") buf,
lateout("$7") _,
lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _,
lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _,
lateout("$24") _, lateout("$25") _,
options(nostack)
);
ret
}
}
pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 {
unsafe {
let ret: i32;
core::arch::asm!(
"syscall",
"beqz $7, 1f",
"nop",
"subu $2, $0, $2",
"1:",
inlateout("$2") 4000_i32 + 116 => ret, // __NR_sysinfo
in("$4") info,
lateout("$7") _,
lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _,
lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _,
lateout("$24") _, lateout("$25") _,
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!(
"syscall",
"beqz $7, 1f",
"nop",
"subu $2, $0, $2",
"1:",
inlateout("$2") 4000i32 + 240 => ret, // __NR_sched_getaffinity
in("$4") pid,
in("$5") mask_size,
in("$6") mask,
lateout("$7") _,
lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _,
lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _,
lateout("$24") _, lateout("$25") _,
options(nostack)
);
ret
}
}
pub(super) unsafe fn sys_exit(code: i32) -> ! {
unsafe {
core::arch::asm!(
"syscall",
in("$2") 4000i32 + 1, // SYS_exit
in("$4") code,
options(noreturn, nostack)
);
}
}

View file

@ -6,7 +6,8 @@
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "sparc64", target_arch = "sparc64",
target_arch = "sparc", target_arch = "sparc",
target_arch = "mips64" target_arch = "mips64",
target_arch = "mips"
), ),
feature(asm_experimental_arch) feature(asm_experimental_arch)
)] )]
@ -280,6 +281,22 @@ extern "C" fn __atomic_store_1(ptr: *mut u8, val: u8, _order: i32) {
unsafe { core::ptr::write_volatile(ptr, val) } unsafe { core::ptr::write_volatile(ptr, val) }
} }
#[cfg(target_arch = "mips")]
#[unsafe(no_mangle)]
#[unsafe(naked)]
unsafe extern "C" fn _start() {
naked_asm!(
"move $a0, $sp", // first arg = original sp (argc/argv)
"addiu $sp, $sp, -24", // reserve 16-byte O32 shadow space + align
"jal {entry_rust}",
"nop", // delay slot
"move $a0, $v0", // exit code = entry_rust return value
"li $v0, 4001", // SYS_exit (4000 + 1)
"syscall",
entry_rust = sym entry_rust,
);
}
// Global allocator // Global allocator
#[global_allocator] #[global_allocator]
static ALLOCATOR: BumpAllocator = BumpAllocator::new(); static ALLOCATOR: BumpAllocator = BumpAllocator::new();