diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 99668ae..6ef14a9 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -20,6 +20,7 @@ jobs: - x86_64-unknown-linux-gnu - aarch64-unknown-linux-gnu - riscv64gc-unknown-linux-gnu + - loongarch64-unknown-linux-gnu steps: - name: "Checkout" diff --git a/crates/asm/src/lib.rs b/crates/asm/src/lib.rs index 83052c8..66ad335 100644 --- a/crates/asm/src/lib.rs +++ b/crates/asm/src/lib.rs @@ -5,7 +5,7 @@ //! What do you mean I wasted two whole hours to make the program only 100µs //! faster? //! -//! Supports `x86_64`, `aarch64`, and `riscv64` architectures. +//! Supports `x86_64`, `aarch64`, `riscv64`, and `loongarch64` architectures. #![no_std] @@ -13,10 +13,12 @@ #[cfg(not(any( target_arch = "x86_64", target_arch = "aarch64", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "loongarch64" )))] compile_error!( - "Unsupported architecture: only x86_64, aarch64, and riscv64 are supported" + "Unsupported architecture: only x86_64, aarch64, riscv64, and loongarch64 \ + are supported" ); // Per-arch syscall implementations live in their own module files. @@ -29,6 +31,9 @@ mod arch; #[cfg(target_arch = "riscv64")] #[path = "riscv64.rs"] mod arch; +#[cfg(target_arch = "loongarch64")] +#[path = "loongarch64.rs"] +mod arch; /// Copies `n` bytes from `src` to `dest`. /// diff --git a/crates/asm/src/loongarch64.rs b/crates/asm/src/loongarch64.rs new file mode 100644 index 0000000..d5ab5ac --- /dev/null +++ b/crates/asm/src/loongarch64.rs @@ -0,0 +1,161 @@ +//! Syscall implementations for `loongarch64`. + +use super::{StatfsBuf, SysInfo, UtsNameBuf}; + +pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { + unsafe { + let fd: i64; + core::arch::asm!( + "syscall 0", + in("$a7") 56i64, // SYS_openat + in("$a0") -100i32, // AT_FDCWD + in("$a1") path, + in("$a2") flags, + in("$a3") 0i32, // mode + lateout("$a0") 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!( + "syscall 0", + in("$a7") 63i64, // SYS_read + in("$a0") fd, + in("$a1") buf, + in("$a2") count, + lateout("$a0") 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!( + "syscall 0", + in("$a7") 64i64, // SYS_write + in("$a0") fd, + in("$a1") buf, + in("$a2") count, + lateout("$a0") 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!( + "syscall 0", + in("$a7") 57i64, // SYS_close + in("$a0") fd, + lateout("$a0") 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!( + "syscall 0", + in("$a7") 160i64, // SYS_uname + in("$a0") buf, + lateout("$a0") 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!( + "syscall 0", + in("$a7") 43i64, // SYS_statfs + in("$a0") path, + in("$a1") buf, + lateout("$a0") 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!( + "syscall 0", + in("$a7") 179_i64, // __NR_sysinfo + in("$a0") info, + lateout("$a0") 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!( + "syscall 0", + in("$a7") 123i64, // __NR_sched_getaffinity + in("$a0") pid, + in("$a1") mask_size, + in("$a2") mask, + lateout("$a0") ret, + options(nostack) + ); + #[allow(clippy::cast_possible_truncation)] + { + ret as i32 + } + } +} + +pub(super) unsafe fn sys_exit(code: i32) -> ! { + unsafe { + core::arch::asm!( + "syscall 0", + in("$a7") 93i64, // SYS_exit + in("$a0") code, + options(noreturn, nostack) + ); + } +} diff --git a/microfetch/src/main.rs b/microfetch/src/main.rs index 338133f..c24e69a 100644 --- a/microfetch/src/main.rs +++ b/microfetch/src/main.rs @@ -57,6 +57,21 @@ unsafe extern "C" fn _start() { ); } +#[cfg(target_arch = "loongarch64")] +#[unsafe(no_mangle)] +#[unsafe(naked)] +unsafe extern "C" fn _start() { + naked_asm!( + "or $a0, $sp, $zero", + "bstrins.d $sp, $zero, 3, 0", + "bl {entry_rust}", + "or $a0, $a0, $zero", + "li.w $a7, 93", + "syscall 0", + entry_rust = sym entry_rust, + ); +} + // Global allocator #[global_allocator] static ALLOCATOR: BumpAllocator = BumpAllocator::new();