4
0
luojia65 4 жил өмнө
parent
commit
380ef0d5c3
6 өөрчлөгдсөн 220 нэмэгдсэн , 0 устгасан
  1. 2 0
      .gitignore
  2. 12 0
      Cargo.toml
  3. 34 0
      src/ecall.rs
  4. 65 0
      src/ecall/base.rs
  5. 47 0
      src/legacy_stdio.rs
  6. 60 0
      src/lib.rs

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/target
+Cargo.lock

+ 12 - 0
Cargo.toml

@@ -0,0 +1,12 @@
+[package]
+name = "rustsbi"
+version = "0.1.0"
+authors = ["luojia65 <me@luojia.cc>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+embedded-hal = "1.0.0-alpha.1"
+nb = "1.0"
+riscv = "0.6"

+ 34 - 0
src/ecall.rs

@@ -0,0 +1,34 @@
+//! 这是一个私有模块
+//! 它将会处理所有的SBI调用陷入
+
+// 你应该在riscv-rt或其它中断处理函数里,调用这个模块的内容
+mod base;
+
+const EXTENSION_BASE: usize = 0x10;
+
+/// You should call this function in your runtime's exception handler.
+/// If the incoming exception is caused by `ecall`, 
+/// call this function with parameters extracted from trap frame. 
+#[inline]
+pub fn handle_ecall(extension: usize, function: usize, param: [usize; 4]) -> SbiRet {
+    match extension {
+        EXTENSION_BASE => base::handle_ecall_base(function, param[0]),
+        _ => todo!()
+    }
+}
+
+/// Returned by handle_ecall function
+/// After `handle_ecall` finished, you should save returned `error` in `a0`, and `value` in `a1`.
+#[repr(C)]
+pub struct SbiRet {
+    /// Error number
+    pub error: usize,
+    /// Result value
+    pub value: usize,
+}
+
+impl SbiRet {
+    pub(crate) fn ok(value: usize) -> SbiRet {
+        SbiRet { error: 0, value }
+    }
+}

+ 65 - 0
src/ecall/base.rs

@@ -0,0 +1,65 @@
+//! base extension
+use super::SbiRet;
+use crate::{SBI_SPEC_MAJOR, SBI_SPEC_MINOR};
+use riscv::register::{mvendorid, marchid, mimpid};
+
+const FUNCTION_BASE_GET_SPEC_VERSION: usize = 0x0;
+const FUNCTION_BASE_GET_SBI_IMPL_ID: usize  = 0x1;
+const FUNCTION_BASE_GET_SBI_IMPL_VERSION: usize = 0x2;
+const FUNCTION_BASE_PROBE_EXTENSION: usize  = 0x3;
+const FUNCTION_BASE_GET_MVENDORID: usize    = 0x4;
+const FUNCTION_BASE_GET_MARCHID: usize      = 0x5;
+const FUNCTION_BASE_GET_MIMPID: usize       = 0x6;
+
+pub fn handle_ecall_base(function: usize, param0: usize) -> SbiRet {
+    match function {
+        FUNCTION_BASE_GET_SPEC_VERSION => get_spec_version(),
+        FUNCTION_BASE_GET_SBI_IMPL_ID => get_sbi_impl_id(),
+        FUNCTION_BASE_GET_SBI_IMPL_VERSION => get_sbi_impl_version(),
+        FUNCTION_BASE_PROBE_EXTENSION => probe_extension(param0),
+        FUNCTION_BASE_GET_MVENDORID => get_mvendorid(),
+        FUNCTION_BASE_GET_MARCHID => get_marchid(),
+        FUNCTION_BASE_GET_MIMPID => get_mimpid(),
+        _ => unimplemented!()
+    }
+}
+
+#[inline]
+fn get_spec_version() -> SbiRet {
+    let spec_version = ((SBI_SPEC_MAJOR << 24) | (SBI_SPEC_MINOR)).into();
+    SbiRet::ok(spec_version)
+}
+
+#[inline]
+fn get_sbi_impl_id() -> SbiRet {
+    let sbi_impl_id = 0; // todo: 可配置
+    SbiRet::ok(sbi_impl_id)
+}
+
+#[inline]
+fn get_sbi_impl_version() -> SbiRet {
+    let sbi_impl_version = 0; // todo: 可配置
+    SbiRet::ok(sbi_impl_version)
+}
+
+#[inline]
+fn probe_extension(extension_id: usize) -> SbiRet {
+    drop(extension_id); // todo use
+    let extension_return = 0; // todo: 可配置
+    SbiRet::ok(extension_return)
+}
+
+#[inline]
+fn get_mvendorid() -> SbiRet {
+    SbiRet::ok(mvendorid::read().map(|r| r.bits()).unwrap_or(0))
+}
+
+#[inline]
+fn get_marchid() -> SbiRet {
+    SbiRet::ok(marchid::read().map(|r| r.bits()).unwrap_or(0))
+}
+
+#[inline]
+fn get_mimpid() -> SbiRet {
+    SbiRet::ok(mimpid::read().map(|r| r.bits()).unwrap_or(0))
+}

+ 47 - 0
src/legacy_stdio.rs

@@ -0,0 +1,47 @@
+//! 这个模块的两个宏应该公开
+//! 如果制造实例的时候,给定了stdout,那么就会打印到这个stdout里面
+use embedded_hal::serial::{Read, Write};
+use nb::block;
+
+/// Legacy standard input/output
+pub trait LegacyStdio {
+    /// Get a character from legacy stdin
+    fn getchar(&mut self) -> u8;
+    /// Put a character into legacy stdout
+    fn putchar(&mut self, ch: u8);
+}
+
+/// Use serial in `embedded-hal` as legacy standard input/output
+pub struct EmbeddedHalSerial<T> {
+    inner: T
+}
+
+impl<T> EmbeddedHalSerial<T> {
+    /// Create a wrapper with a value
+    pub fn new(inner: T) -> Self {
+        Self { inner }
+    }
+
+    /// Unwrap the struct to get underlying value
+    pub fn into_inner(self) -> T {
+        self.inner
+    }
+}
+
+impl<T> LegacyStdio for EmbeddedHalSerial<T>
+where 
+    T: Read<u8> + Write<u8>
+{
+    fn getchar(&mut self) -> u8 {
+        // 直接调用embedded-hal里面的函数
+        // 关于unwrap:因为这个是legacy函数,这里没有详细的处理流程,就panic掉
+        block!(self.inner.try_read()).ok().unwrap()
+    }
+
+    fn putchar(&mut self, ch: u8) {
+        // 直接调用函数写一个字节
+        block!(self.inner.try_write(ch)).ok();
+        // 写一次flush一次,因为是legacy,就不考虑效率了
+        block!(self.inner.try_flush()).ok();
+    }
+}

+ 60 - 0
src/lib.rs

@@ -0,0 +1,60 @@
+/*
+
+这个库的功能:
+1. 在M特权运行,帮助用户搭建运行时,暴露为SBI接口使用的接口
+2. 提供简单的pmp配置
+
+设计应该像积木一样,允许用户自己选择模块,而不是提供一个运行时
+建议用户配合riscv-sbi-rt使用
+
+*/
+
+#![no_std]
+#![feature(naked_functions)] // 未来稳定后去掉
+
+pub mod legacy_stdio;
+pub mod ecall;
+
+const SBI_SPEC_MAJOR: usize = 0;
+const SBI_SPEC_MINOR: usize = 2;
+
+use legacy_stdio::LegacyStdio;
+
+/// RustSBI instance builder; only one hart should build the instance
+pub struct Builder<'b> {
+    legacy_stdio: Option<&'b dyn LegacyStdio>,
+}
+
+impl<'b> Builder<'b> {
+    /// Create a new instance builder
+    pub fn new() -> Self {
+        Builder {
+            legacy_stdio: None
+        }
+    }
+
+    /// Wrap a stdio handler for legacy `getchar` and `putchar` functions
+    pub fn legacy_stdio(mut self, stdio: &'b dyn LegacyStdio) -> Self {
+        self.legacy_stdio = Some(stdio);
+        self
+    }
+
+    /// Build the RustSBI instance
+    pub fn build(self) -> Instance<'b> {
+        todo!()
+    }
+}
+// todo: 修改API
+/// RustSBI instance
+pub struct Instance<'a> {
+    legacy_stdio: Option<&'a dyn LegacyStdio>,
+}
+
+impl<'a> Instance<'a> {
+    /// Start the instance; call and start the the supervisor
+    pub fn start(&mut self) {
+        // 这里如果设定了stdout,可以往里面打印一些字
+        // 可以用库的crate feature把这个功能关掉
+        todo!()
+    }
+}