Implement system calls on RISC-V in libtock_runtime. This introduces `TockSyscalls`, which implements `libtock_platform::Syscalls` indirectly by directly implementing `libtock_platform::RawSyscalls`. I will implement ARM system calls in a future PR.
diff --git a/core/runtime/src/lib.rs b/core/runtime/src/lib.rs index d7ea623..b0daf03 100644 --- a/core/runtime/src/lib.rs +++ b/core/runtime/src/lib.rs
@@ -18,4 +18,11 @@ //! `no_auto_layout` feature on `libtock_runtime` to disable this functionality //! and provide its own layout file. +#![feature(asm)] #![no_std] + +/// TockSyscalls implements `libtock_platform::Syscalls`. +pub struct TockSyscalls; + +#[cfg(target_arch = "riscv32")] +mod syscalls_impl_riscv;
diff --git a/core/runtime/src/syscalls_impl_riscv.rs b/core/runtime/src/syscalls_impl_riscv.rs new file mode 100644 index 0000000..d58ce5e --- /dev/null +++ b/core/runtime/src/syscalls_impl_riscv.rs
@@ -0,0 +1,82 @@ +use libtock_platform::{OneArgMemop, RawSyscalls, YieldType, ZeroArgMemop}; + +impl RawSyscalls for crate::TockSyscalls { + // This yield implementation is currently limited RISC-V versions without + // floating-point registers, as it does not mark them clobbered. + #[cfg(not(any(target_feature = "d", target_feature = "f")))] + fn raw_yield(r0_in: YieldType) -> u32 { + let mut r0 = r0_in as u32; + let mut _a4 = 0; + unsafe { + asm!("ecall", + // x0 is a constant. + lateout("x1") _, // Return address + // x2-x4 are stack, global, and thread pointers. sp is + // callee-saved. + lateout("x5") _, + lateout("x6") _, + lateout("x7") _, + // x8 and x9 are callee-saved. + inlateout("x10") r0, + lateout("x11") _, + lateout("x12") _, + lateout("x13") _, + inlateout("x14") _a4, + lateout("x15") _, + lateout("x16") _, + lateout("x17") _, + // x18-27 (aka s2-s11) are callee-saved + lateout("x28") _, + lateout("x29") _, + lateout("x30") _, + lateout("x31") _, + ); + } + r0 + } + + unsafe fn four_arg_syscall( + mut r0: u32, + mut r1: u32, + mut r2: usize, + mut r3: usize, + class: u8, + ) -> (u32, usize, usize, usize) { + asm!("ecall", + inlateout("a0") r0, + inlateout("a1") r1, + inlateout("a2") r2, + inlateout("a3") r3, + in("a4") class, + options(preserves_flags, nostack), + ); + (r0, r1 as usize, r2, r3) + } + + fn zero_arg_memop(r0_in: ZeroArgMemop) -> (u32, usize) { + let mut r0 = r0_in as u32; + let r1; + unsafe { + asm!("ecall", + inlateout("a0") r0, + lateout("a1") r1, + in("a4") 5, + options(preserves_flags, nostack, nomem), + ); + } + (r0, r1) + } + + fn one_arg_memop(r0_in: OneArgMemop, mut r1: usize) -> (u32, usize) { + let mut r0 = r0_in as u32; + unsafe { + asm!("ecall", + inlateout("a0") r0, + inlateout("a1") r1, + in("a4") 5, + options(preserves_flags, nostack, nomem) + ); + } + (r0, r1) + } +}