浏览代码

feat: 使 legacy stdio 的接口与其他模块一致

YdrMaster 2 年之前
父节点
当前提交
fccc98ec4a
共有 9 个文件被更改,包括 137 次插入94 次删除
  1. 0 2
      Cargo.toml
  2. 2 2
      src/hsm.rs
  3. 2 2
      src/ipi.rs
  4. 75 73
      src/legacy_stdio.rs
  5. 2 2
      src/pmu.rs
  6. 2 2
      src/reset.rs
  7. 2 2
      src/rfence.rs
  8. 2 2
      src/timer.rs
  9. 50 7
      src/util.rs

+ 0 - 2
Cargo.toml

@@ -18,8 +18,6 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-embedded-hal = "0.2.7"
-nb = "1.0"
 riscv = "0.8"
 
 [features]

+ 2 - 2
src/hsm.rs

@@ -190,9 +190,9 @@ pub trait Hsm: Send + Sync {
     }
 }
 
-use crate::util::AmoOncePtr;
+use crate::util::AmoOnceRef;
 
-static HSM: AmoOncePtr<dyn Hsm> = AmoOncePtr::new();
+static HSM: AmoOnceRef<dyn Hsm> = AmoOnceRef::new();
 
 pub fn init_hsm(hsm: &'static dyn Hsm) {
     if !HSM.try_call_once(hsm) {

+ 2 - 2
src/ipi.rs

@@ -1,6 +1,6 @@
 use crate::ecall::SbiRet;
 use crate::hart_mask::HartMask;
-use crate::util::AmoOncePtr;
+use crate::util::AmoOnceRef;
 
 /// Inter-processor interrupt support
 pub trait Ipi: Send + Sync {
@@ -19,7 +19,7 @@ pub trait Ipi: Send + Sync {
     }
 }
 
-static IPI: AmoOncePtr<dyn Ipi> = AmoOncePtr::new();
+static IPI: AmoOnceRef<dyn Ipi> = AmoOnceRef::new();
 
 pub fn init_ipi(ipi: &'static dyn Ipi) {
     if !IPI.try_call_once(ipi) {

+ 75 - 73
src/legacy_stdio.rs

@@ -1,9 +1,8 @@
 //! 这个模块的两个宏应该公开
 //! 如果制造实例的时候,给定了stdout,那么就会打印到这个stdout里面
-use crate::util::AmoMutex;
-use alloc::boxed::Box;
-use embedded_hal::serial::{Read, Write};
-use nb::block;
+
+use crate::util::{AmoMutex, NullableMut};
+use core::fmt;
 
 /// Legacy standard input/output
 pub trait LegacyStdio: Send {
@@ -13,85 +12,90 @@ pub trait LegacyStdio: Send {
     fn putchar(&mut self, ch: u8);
 }
 
-/// Use serial in `embedded-hal` as legacy standard input/output
-struct EmbeddedHalSerial<T> {
-    inner: T,
-}
-
-impl<T> EmbeddedHalSerial<T> {
-    /// Create a wrapper with a value
-    #[inline]
-    fn new(inner: T) -> Self {
-        Self { inner }
-    }
-}
-
-impl<T: Send> LegacyStdio for EmbeddedHalSerial<T>
-where
-    T: Read<u8> + Write<u8>,
-{
-    #[inline]
-    fn getchar(&mut self) -> u8 {
-        // 直接调用embedded-hal里面的函数
-        // 关于unwrap:因为这个是legacy函数,这里没有详细的处理流程,就panic掉
-        block!(self.inner.read()).ok().unwrap()
-    }
-
-    #[inline]
-    fn putchar(&mut self, ch: u8) {
-        // 直接调用函数写一个字节
-        block!(self.inner.write(ch)).ok();
-        // 写一次flush一次,因为是legacy,就不考虑效率了
-        block!(self.inner.flush()).ok();
-    }
-}
-
-struct Fused<T, R>(T, R);
+// /// Use serial in `embedded-hal` as legacy standard input/output
+// struct EmbeddedHalSerial<T> {
+//     inner: T,
+// }
+
+// impl<T> EmbeddedHalSerial<T> {
+//     /// Create a wrapper with a value
+//     #[inline]
+//     fn new(inner: T) -> Self {
+//         Self { inner }
+//     }
+// }
+
+// impl<T: Send> LegacyStdio for EmbeddedHalSerial<T>
+// where
+//     T: Read<u8> + Write<u8>,
+// {
+//     #[inline]
+//     fn getchar(&mut self) -> u8 {
+//         // 直接调用embedded-hal里面的函数
+//         // 关于unwrap:因为这个是legacy函数,这里没有详细的处理流程,就panic掉
+//         block!(self.inner.read()).ok().unwrap()
+//     }
+
+//     #[inline]
+//     fn putchar(&mut self, ch: u8) {
+//         // 直接调用函数写一个字节
+//         block!(self.inner.write(ch)).ok();
+//         // 写一次flush一次,因为是legacy,就不考虑效率了
+//         block!(self.inner.flush()).ok();
+//     }
+// }
+
+// struct Fused<T, R>(T, R);
+
+// // 和上面的原理差不多,就是分开了
+// impl<T, R> LegacyStdio for Fused<T, R>
+// where
+//     T: Write<u8> + Send + 'static,
+//     R: Read<u8> + Send + 'static,
+// {
+//     #[inline]
+//     fn getchar(&mut self) -> u8 {
+//         block!(self.1.read()).ok().unwrap()
+//     }
+
+//     #[inline]
+//     fn putchar(&mut self, ch: u8) {
+//         block!(self.0.write(ch)).ok();
+//         block!(self.0.flush()).ok();
+//     }
+// }
+
+static STDIO: AmoMutex<NullableMut<dyn LegacyStdio>> = AmoMutex::new(NullableMut::new());
 
-// 和上面的原理差不多,就是分开了
-impl<T, R> LegacyStdio for Fused<T, R>
-where
-    T: Write<u8> + Send + 'static,
-    R: Read<u8> + Send + 'static,
-{
-    #[inline]
-    fn getchar(&mut self) -> u8 {
-        block!(self.1.read()).ok().unwrap()
-    }
-
-    #[inline]
-    fn putchar(&mut self, ch: u8) {
-        block!(self.0.write(ch)).ok();
-        block!(self.0.flush()).ok();
-    }
+#[inline]
+pub fn init_legacy_stdio(stdio: &'static mut dyn LegacyStdio) {
+    STDIO.lock().set(stdio);
 }
 
-static LEGACY_STDIO: AmoMutex<Option<Box<dyn LegacyStdio>>> = AmoMutex::new(None);
-
-pub fn init_legacy_stdio_embedded_hal<T: Read<u8> + Write<u8> + Send + 'static>(serial: T) {
-    let serial = EmbeddedHalSerial::new(serial);
-    *LEGACY_STDIO.lock() = Some(Box::new(serial));
-}
+// pub fn init_legacy_stdio_embedded_hal<T: Read<u8> + Write<u8> + Send + 'static>(serial: T) {
+//     let serial = EmbeddedHalSerial::new(serial);
+//     *LEGACY_STDIO.lock() = Some(Box::new(serial));
+// }
 
-pub fn init_legacy_stdio_embedded_hal_fuse<T, R>(tx: T, rx: R)
-where
-    T: Write<u8> + Send + 'static,
-    R: Read<u8> + Send + 'static,
-{
-    let serial = Fused(tx, rx);
-    *LEGACY_STDIO.lock() = Some(Box::new(serial));
-}
+// pub fn init_legacy_stdio_embedded_hal_fuse<T, R>(tx: T, rx: R)
+// where
+//     T: Write<u8> + Send + 'static,
+//     R: Read<u8> + Send + 'static,
+// {
+//     let serial = Fused(tx, rx);
+//     *LEGACY_STDIO.lock() = Some(Box::new(serial));
+// }
 
 #[inline]
 pub fn legacy_stdio_putchar(ch: u8) {
-    if let Some(stdio) = LEGACY_STDIO.lock().as_mut() {
+    if let Some(stdio) = STDIO.lock().get() {
         stdio.putchar(ch)
     }
 }
 
 #[inline]
 pub fn legacy_stdio_getchar() -> usize {
-    if let Some(stdio) = LEGACY_STDIO.lock().as_mut() {
+    if let Some(stdio) = STDIO.lock().get() {
         stdio.getchar() as usize
     } else {
         // According to RISC-V SBI spec 0.3.1-rc1, Section 4.3, this function returns -1
@@ -100,14 +104,12 @@ pub fn legacy_stdio_getchar() -> usize {
     }
 }
 
-use core::fmt;
-
 struct Stdout;
 
 impl fmt::Write for Stdout {
     #[inline]
     fn write_str(&mut self, s: &str) -> fmt::Result {
-        if let Some(stdio) = LEGACY_STDIO.lock().as_mut() {
+        if let Some(stdio) = STDIO.lock().get() {
             for byte in s.as_bytes() {
                 stdio.putchar(*byte)
             }

+ 2 - 2
src/pmu.rs

@@ -1,5 +1,5 @@
 use crate::ecall::SbiRet;
-use crate::util::AmoOncePtr;
+use crate::util::AmoOnceRef;
 
 /// Performance Monitoring Unit Extension
 ///
@@ -199,7 +199,7 @@ pub trait Pmu: Send + Sync {
 
 // TODO: all the events here
 
-static PMU: AmoOncePtr<dyn Pmu> = AmoOncePtr::new();
+static PMU: AmoOnceRef<dyn Pmu> = AmoOnceRef::new();
 
 pub fn init_pmu(pmu: &'static dyn Pmu) {
     if !PMU.try_call_once(pmu) {

+ 2 - 2
src/reset.rs

@@ -1,5 +1,5 @@
 use crate::ecall::SbiRet;
-use crate::util::AmoOncePtr;
+use crate::util::AmoOnceRef;
 
 /// System Reset Extension
 ///
@@ -49,7 +49,7 @@ pub trait Reset: Send + Sync {
     }
 }
 
-static RESET: AmoOncePtr<dyn Reset> = AmoOncePtr::new();
+static RESET: AmoOnceRef<dyn Reset> = AmoOnceRef::new();
 
 #[doc(hidden)]
 #[allow(unused)]

+ 2 - 2
src/rfence.rs

@@ -1,6 +1,6 @@
 use crate::ecall::SbiRet;
 use crate::hart_mask::HartMask;
-use crate::util::AmoOncePtr;
+use crate::util::AmoOnceRef;
 
 /// Remote fence support
 ///
@@ -136,7 +136,7 @@ pub trait Rfence: Send + Sync {
     }
 }
 
-static RFENCE: AmoOncePtr<dyn Rfence> = AmoOncePtr::new();
+static RFENCE: AmoOnceRef<dyn Rfence> = AmoOnceRef::new();
 
 pub fn init_rfence(rfence: &'static dyn Rfence) {
     if !RFENCE.try_call_once(rfence) {

+ 2 - 2
src/timer.rs

@@ -1,4 +1,4 @@
-use crate::util::AmoOncePtr;
+use crate::util::AmoOnceRef;
 
 /// Timer programmer support
 pub trait Timer: Send + Sync {
@@ -12,7 +12,7 @@ pub trait Timer: Send + Sync {
     fn set_timer(&self, stime_value: u64);
 }
 
-static TIMER: AmoOncePtr<dyn Timer> = AmoOncePtr::new();
+static TIMER: AmoOnceRef<dyn Timer> = AmoOnceRef::new();
 
 pub fn init_timer(timer: &'static dyn Timer) {
     if !TIMER.try_call_once(timer) {

+ 50 - 7
src/util.rs

@@ -3,6 +3,7 @@
 use core::{
     arch::asm,
     cell::UnsafeCell,
+    marker::PhantomData,
     mem::MaybeUninit,
     ops::{Deref, DerefMut},
     ptr::Pointee,
@@ -23,7 +24,7 @@ impl<T> AmoMutex<T> {
     /// Create a new AmoMutex
     #[inline]
     pub const fn new(data: T) -> Self {
-        AmoMutex {
+        Self {
             lock: UnsafeCell::new(0),
             data: UnsafeCell::new(data),
         }
@@ -83,28 +84,33 @@ impl<'a, T: ?Sized> Drop for AmoMutexGuard<'a, T> {
     }
 }
 
-/// 只使用 AMO 指令的一次初始化指针
-pub struct AmoOncePtr<T: ?Sized> {
+/// 只使用 AMO 指令的一次初始化引用存储
+pub struct AmoOnceRef<'a, T: ?Sized> {
     /// As atomic bool, to check if it is the first time to set `ptr`.
     lock: UnsafeCell<u32>,
     ptr: UnsafeCell<*const ()>,
     meta: UnsafeCell<MaybeUninit<<T as Pointee>::Metadata>>,
+    _lifetime: PhantomData<&'a ()>,
 }
 
-unsafe impl<T: ?Sized + Send> Send for AmoOncePtr<T> {}
-unsafe impl<T: ?Sized + Send + Sync> Sync for AmoOncePtr<T> {}
+/// 如果 AmoOncePtr 保存的引用是静态的,自然可以随意移动。
+unsafe impl<T: ?Sized> Send for AmoOnceRef<'static, T> {}
+
+/// AmoOncePtr 不提供锁。
+unsafe impl<T: ?Sized + Sync> Sync for AmoOnceRef<'static, T> {}
 
-impl<T: ?Sized> AmoOncePtr<T> {
+impl<'a, T: ?Sized> AmoOnceRef<'a, T> {
     #[inline]
     pub const fn new() -> Self {
         Self {
             lock: UnsafeCell::new(0),
             ptr: UnsafeCell::new(core::ptr::null()),
             meta: UnsafeCell::new(MaybeUninit::uninit()),
+            _lifetime: PhantomData,
         }
     }
 
-    pub fn try_call_once(&self, r#ref: &'static T) -> bool {
+    pub fn try_call_once(&self, r#ref: &'a T) -> bool {
         let ptr = r#ref as *const T;
         let locked: u32;
         unsafe {
@@ -198,3 +204,40 @@ impl<T: ?Sized> AmoOncePtr<T> {
         &*core::ptr::from_raw_parts(ptr, (*self.meta.get()).assume_init())
     }
 }
+
+/// 分解一个胖指针,使之 Sized。
+pub struct NullableMut<'a, T: ?Sized> {
+    ptr: *mut (),
+    meta: MaybeUninit<<T as Pointee>::Metadata>,
+    _lifetime: PhantomData<&'a ()>,
+}
+
+impl<'a, T: ?Sized> NullableMut<'a, T> {
+    pub const fn new() -> Self {
+        Self {
+            ptr: core::ptr::null_mut(),
+            meta: MaybeUninit::uninit(),
+            _lifetime: PhantomData,
+        }
+    }
+
+    pub fn set(&mut self, r#ref: &'a mut T) {
+        let ptr = r#ref as *mut T;
+        self.ptr = ptr.cast();
+        self.meta = MaybeUninit::new(core::ptr::metadata(ptr));
+    }
+
+    pub fn get(&mut self) -> Option<&mut T> {
+        if !self.ptr.is_null() {
+            Some(unsafe { &mut *core::ptr::from_raw_parts_mut(self.ptr, self.meta.assume_init()) })
+        } else {
+            None
+        }
+    }
+}
+
+/// 如果 AmoOncePtr 保存的引用是静态的,自然可以随意移动。
+unsafe impl<T: ?Sized> Send for NullableMut<'static, T> {}
+
+/// AmoOncePtr 不提供锁。
+unsafe impl<T: ?Sized + Sync> Sync for NullableMut<'static, T> {}