aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2022-05-01 17:50:00 +0200
committerJohannes Stoelp <johannes.stoelp@gmail.com>2022-05-01 17:50:00 +0200
commit4754b66f72a8fbfd48e30ae0bd12a44d13a4ce10 (patch)
tree16551dd04684ff6e7bdc1107927faaafb6ff9bd9 /src
downloadrv64i-linux-user-no-std-4754b66f72a8fbfd48e30ae0bd12a44d13a4ce10.tar.gz
rv64i-linux-user-no-std-4754b66f72a8fbfd48e30ae0bd12a44d13a4ce10.zip
initial commit
Build small no_std example for rv64i target. This code executes some linux syscalls as demo and therefore expects to be executed in rv64 linux.
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs105
-rw-r--r--src/main.rs20
2 files changed, 125 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..3191f8d
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,105 @@
+#![no_std]
+
+/// Raw file descriptor.
+///
+/// Instances of `Fd` can be constructed with [`stdout()`] and [`stderr()`].
+pub struct Fd(i32);
+
+impl core::fmt::Write for Fd {
+ fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
+ if sys::write(self.0, s.as_bytes()) != -1 {
+ Ok(())
+ } else {
+ Err(core::fmt::Error)
+ }
+ }
+}
+
+/// Construct raw file descriptor for `stdout`.
+pub fn stdout() -> Fd {
+ Fd(1)
+}
+
+/// Construct raw file descriptor for `stderr`.
+pub fn stderr() -> Fd {
+ Fd(2)
+}
+
+/// Write format string to `stdout`, swallowing any errors.
+#[macro_export]
+macro_rules! println {
+ () => ({
+ $crate::println!("")
+ });
+ ($($arg:tt)*) => ({
+ use core::fmt::Write;
+ let _ = writeln!(&mut $crate::stdout(), $($arg)*);
+ });
+}
+
+/// Write format string to `stderr`, swallowing any errors.
+#[macro_export]
+macro_rules! eprintln {
+ () => ({
+ $crate::eprintln!("")
+ });
+ ($($arg:tt)*) => ({
+ use core::fmt::Write;
+ let _ = writeln!(&mut $crate::stderr(), $($arg)*);
+ });
+}
+
+/// Wrapper to invoke `riscv` linux syscalls.
+///
+/// Syscalls are generated according to the linux [syscall(2)][man-syscall] abi.
+///
+/// # Invocation
+/// ```
+/// Arch/ABI Instruction System Ret Ret
+/// call # val val2
+/// ----------------------------------------
+/// riscv ecall a7 a0 a1
+/// ```
+///
+/// # Arguments
+/// ```
+/// Arch/ABI arg1 arg2 arg3 arg4 arg5 arg6
+/// --------------------------------------------
+/// riscv a0 a1 a2 a3 a4 a5
+/// ```
+///
+/// [man-syscall]: https://man7.org/linux/man-pages/man2/syscall.2.html
+#[cfg(target_arch = "riscv64")]
+pub mod sys {
+ use core::arch::asm;
+
+ // Include generated syscall numbers (build.rs).
+ include!(concat!(env!("OUT_DIR"), "/syscalls.rs"));
+
+ #[inline]
+ pub fn write(fd: i32, buf: &[u8]) -> i32 {
+ let mut ret;
+ unsafe {
+ asm!(
+ "ecall",
+ in("a7") SYS_WRITE,
+ inlateout("a0") fd => ret,
+ in("a1") buf.as_ptr(),
+ in("a2") buf.len(),
+ );
+ }
+ ret
+ }
+
+ #[inline]
+ pub fn exit(status: i32) -> ! {
+ unsafe {
+ asm!(
+ "ecall",
+ in("a7") SYS_EXIT,
+ in("a0") status,
+ options(noreturn),
+ );
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..f1ea8b0
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,20 @@
+#![no_std]
+#![no_main]
+
+use user_sw::{eprintln, println, sys};
+
+fn main() {
+ println!("Hello {} from rust main().", 1337);
+}
+
+#[no_mangle]
+pub extern "C" fn _start() -> ! {
+ main();
+ sys::exit(0);
+}
+
+#[panic_handler]
+fn panic_handler(info: &core::panic::PanicInfo) -> ! {
+ eprintln!("{}", info);
+ sys::exit(42);
+}