Skip to content

Commit

Permalink
Add RISC-V support (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
hack3ric authored May 17, 2023
1 parent d105d8a commit 3d79f11
Show file tree
Hide file tree
Showing 10 changed files with 1,736 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
- thumbv7neon-unknown-linux-gnueabihf
- aarch64-unknown-linux-gnu
- i686-unknown-linux-gnu
- riscv64gc-unknown-linux-gnu
#- sparc-unknown-linux-gnu
#- sparc64-unknown-linux-gnu
- x86_64-unknown-linux-gnu
Expand Down Expand Up @@ -88,6 +89,7 @@ jobs:
- mips64el-unknown-linux-gnuabi64
- powerpc-unknown-linux-gnu
#- powerpc64-unknown-linux-gnu
- riscv64gc-unknown-linux-gnu
- s390x-unknown-linux-gnu
- x86_64-unknown-linux-gnu
steps:
Expand Down
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ std = []

# Includes the syscall tables for all architectures.
all = [
"aarch64", "arm", "mips", "mips64", "powerpc", "powerpc64", "s390x",
"sparc", "sparc64", "x86", "x86_64"
"aarch64", "arm", "mips", "mips64", "powerpc", "powerpc64", "riscv32",
"riscv64", "s390x", "sparc", "sparc64", "x86", "x86_64"
]

# Enable syscall tables for individual architectures.
Expand All @@ -35,6 +35,8 @@ mips = []
mips64 = []
powerpc = []
powerpc64 = []
riscv32 = []
riscv64 = []
s390x = []
sparc = []
sparc64 = []
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,17 @@ yet stabilized for all architectures][asm_experimental_arch].
| `mips64` ||| No ❌ |
| `powerpc` ||| No ❌ |
| `powerpc64` ||| No ❌ |
| `riscv32` ||* | No ❌ |
| `riscv64` ||| Yes ✅ |
| `s390x` ||| No ❌ |
| `sparc` ||| N/A |
| `sparc64` ||| N/A |
| `x86` ||| Yes ✅ |
| `x86_64` ||| Yes ✅ |

\* Rust does not support riscv32 Linux targets, but syscall functions are
implemented.

## Updating the syscall list

Updates are pulled from the `.tbl` files in the Linux source tree.
Expand Down
10 changes: 10 additions & 0 deletions src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ pub mod mips64;
pub mod powerpc;
#[cfg(any(target_arch = "powerpc64", feature = "powerpc64"))]
pub mod powerpc64;
#[cfg(any(target_arch = "riscv32", feature = "riscv32"))]
pub mod riscv32;
#[cfg(any(target_arch = "riscv64", feature = "riscv64"))]
pub mod riscv64;
#[cfg(any(target_arch = "s390x", feature = "s390x"))]
pub mod s390x;
#[cfg(any(target_arch = "sparc", feature = "sparc"))]
Expand Down Expand Up @@ -42,6 +46,12 @@ pub use powerpc::*;
#[cfg(target_arch = "powerpc64")]
pub use powerpc64::*;

#[cfg(target_arch = "riscv32")]
pub use riscv32::*;

#[cfg(target_arch = "riscv64")]
pub use riscv64::*;

#[cfg(target_arch = "s390x")]
pub use s390x::*;

Expand Down
661 changes: 661 additions & 0 deletions src/arch/riscv32.rs

Large diffs are not rendered by default.

661 changes: 661 additions & 0 deletions src/arch/riscv64.rs

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ mod mips64;
mod powerpc;
#[cfg(target_arch = "powerpc64")]
mod powerpc64;
#[cfg(target_arch = "riscv32")]
mod riscv32;
#[cfg(target_arch = "riscv64")]
mod riscv64;
#[cfg(target_arch = "s390x")]
mod s390x;
#[cfg(target_arch = "sparc")]
Expand Down Expand Up @@ -44,6 +48,12 @@ pub use powerpc::*;
#[cfg(target_arch = "powerpc64")]
pub use powerpc64::*;

#[cfg(target_arch = "riscv32")]
pub use riscv32::*;

#[cfg(target_arch = "riscv64")]
pub use riscv64::*;

#[cfg(target_arch = "s390x")]
pub use s390x::*;

Expand Down
183 changes: 183 additions & 0 deletions src/syscall/riscv32.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// On riscv32, the following registers are used for args 1-6:
// arg1: %a0
// arg2: %a1
// arg3: %a2
// arg4: %a3
// arg5: %a4
// arg6: %a5
//
// %a7 is used for the syscall number.
//
// %a0 is reused for the syscall return value.
//
// No other registers are clobbered.
use core::arch::asm;

use crate::arch::riscv64::Sysno;

/// Issues a raw system call with 0 arguments.
///
/// # Safety
///
/// Running a system call is inherently unsafe. It is the caller's
/// responsibility to ensure safety.
#[inline]
pub unsafe fn syscall0(n: Sysno) -> usize {
let mut ret: usize;
asm!(
"ecall",
in("a7") n as usize,
out("a0") ret,
options(nostack, preserves_flags)
);
ret
}

/// Issues a raw system call with 1 argument.
///
/// # Safety
///
/// Running a system call is inherently unsafe. It is the caller's
/// responsibility to ensure safety.
#[inline]
pub unsafe fn syscall1(n: Sysno, arg1: usize) -> usize {
let mut ret: usize;
asm!(
"ecall",
in("a7") n as usize,
inlateout("a0") arg1 => ret,
options(nostack, preserves_flags)
);
ret
}

/// Issues a raw system call with 2 arguments.
///
/// # Safety
///
/// Running a system call is inherently unsafe. It is the caller's
/// responsibility to ensure safety.
#[inline]
pub unsafe fn syscall2(n: Sysno, arg1: usize, arg2: usize) -> usize {
let mut ret: usize;
asm!(
"ecall",
in("a7") n as usize,
inlateout("a0") arg1 => ret,
in("a1") arg2,
options(nostack, preserves_flags)
);
ret
}

/// Issues a raw system call with 3 arguments.
///
/// # Safety
///
/// Running a system call is inherently unsafe. It is the caller's
/// responsibility to ensure safety.
#[inline]
pub unsafe fn syscall3(
n: Sysno,
arg1: usize,
arg2: usize,
arg3: usize,
) -> usize {
let mut ret: usize;
asm!(
"ecall",
in("a7") n as usize,
inlateout("a0") arg1 => ret,
in("a1") arg2,
in("a2") arg3,
options(nostack, preserves_flags)
);
ret
}

/// Issues a raw system call with 4 arguments.
///
/// # Safety
///
/// Running a system call is inherently unsafe. It is the caller's
/// responsibility to ensure safety.
#[inline]
pub unsafe fn syscall4(
n: Sysno,
arg1: usize,
arg2: usize,
arg3: usize,
arg4: usize,
) -> usize {
let mut ret: usize;
asm!(
"ecall",
in("a7") n as usize,
inlateout("a0") arg1 => ret,
in("a1") arg2,
in("a2") arg3,
in("a3") arg4,
options(nostack, preserves_flags)
);
ret
}

/// Issues a raw system call with 5 arguments.
///
/// # Safety
///
/// Running a system call is inherently unsafe. It is the caller's
/// responsibility to ensure safety.
#[inline]
pub unsafe fn syscall5(
n: Sysno,
arg1: usize,
arg2: usize,
arg3: usize,
arg4: usize,
arg5: usize,
) -> usize {
let mut ret: usize;
asm!(
"ecall",
in("a7") n as usize,
inlateout("a0") arg1 => ret,
in("a1") arg2,
in("a2") arg3,
in("a3") arg4,
in("a4") arg5,
options(nostack, preserves_flags)
);
ret
}

/// Issues a raw system call with 6 arguments.
///
/// # Safety
///
/// Running a system call is inherently unsafe. It is the caller's
/// responsibility to ensure safety.
#[inline]
pub unsafe fn syscall6(
n: Sysno,
arg1: usize,
arg2: usize,
arg3: usize,
arg4: usize,
arg5: usize,
arg6: usize,
) -> usize {
let mut ret: usize;
asm!(
"ecall",
in("a7") n as usize,
inlateout("a0") arg1 => ret,
in("a1") arg2,
in("a2") arg3,
in("a3") arg4,
in("a4") arg5,
in("a5") arg6,
options(nostack, preserves_flags)
);
ret
}
Loading

0 comments on commit 3d79f11

Please sign in to comment.