Browse Source

lib: memory address parameters and DBCN extension

luojia65 2 years ago
parent
commit
6469d0e4de
4 changed files with 166 additions and 0 deletions
  1. 1 0
      CHANGELOG.md
  2. 87 0
      src/console.rs
  3. 4 0
      src/lib.rs
  4. 74 0
      src/memory_range.rs

+ 1 - 0
CHANGELOG.md

@@ -12,6 +12,7 @@ Bump RISC-V SBI specification version to 2.0-rc1.
 ### Added
 
 - pmu: counter_fw_read_hi function in SBI 2.0-rc1
+- lib: memory address parameters and DBCN extension
 
 ### Modified
 

+ 87 - 0
src/console.rs

@@ -0,0 +1,87 @@
+use crate::memory_range::Physical;
+use spec::binary::SbiRet;
+
+/// Debug Console Extension
+///
+/// The debug console extension defines a generic mechanism for debugging
+/// and boot-time early prints from supervisor-mode software.
+///
+/// Kernel developers should switch to driver based console implementation
+/// instead of using this extension to prevent possible race conditions between
+/// the firmware and the kernel when drivers are ready.
+///
+/// If the underlying physical console has extra bits for error checking
+/// (or correction) then these extra bits should be handled by the SBI
+/// implementation.
+///
+/// *NOTE:* It is recommended that bytes sent/received using the debug
+/// console extension follow UTF-8 character encoding.
+pub trait Console {
+    /// Write bytes to the debug console from input memory.
+    ///
+    /// # Parameters
+    ///
+    /// The `bytes` parameter specifies the input memory, including its length
+    /// and memory physical base address (both lower and upper bits).
+    ///
+    /// # Non-blocking function
+    ///
+    /// This is a non-blocking SBI call and it may do partial/no writes if
+    /// the debug console is not able to accept more bytes.
+    ///
+    /// # Return value
+    ///
+    /// The number of bytes written is returned in `SbiRet.value` and the
+    /// possible return error codes returned in `SbiRet.error` are shown in
+    /// the table below:
+    ///
+    /// | Return code               | Description
+    /// |:--------------------------|:----------------------------------------------
+    /// | `SbiRet::success()`       | Bytes written successfully.
+    /// | `SbiRet::invalid_param()` | The memory pointed to by `bytes` does not satisfy the [requirements](struct.Physical.html#Requirements) described in shared memory physical address range.
+    /// | `SbiRet::failed()`        | Failed to write due to I/O errors.
+    fn write(&self, bytes: Physical<&[u8]>) -> SbiRet;
+    /// Read bytes from the debug console into an output memory.
+    ///
+    /// # Parameters
+    ///
+    /// The `bytes` parameter specifies the output memory, including the maximum
+    /// bytes which can be written, and its memory physical base address
+    /// (both lower and upper bits).
+    ///
+    /// # Non-blocking function
+    ///
+    /// This is a non-blocking SBI call and it will not write anything
+    /// into the output memory if there are no bytes to be read in the
+    /// debug console.
+    ///
+    /// # Return value
+    ///
+    /// The number of bytes read is returned in `SbiRet.value` and the
+    /// possible return error codes returned in `SbiRet.error` are shown in
+    /// the table below:
+    ///
+    /// | Return code               | Description
+    /// |:--------------------------|:----------------------------------------------
+    /// | `SbiRet::success()`       | Bytes read successfully.
+    /// | `SbiRet::invalid_param()` | The memory pointed to by `bytes` does not satisfy the [requirements](struct.Physical.html#Requirements) described in shared memory physical address range.
+    /// | `SbiRet::failed()`        | Failed to read due to I/O errors.
+    fn read(&self, bytes: Physical<&mut [u8]>) -> SbiRet;
+    /// Write a single byte to the debug console.
+    ///
+    /// # Blocking function
+    ///
+    /// This is a blocking SBI call and it will only return after writing
+    /// the specified byte to the debug console. It will also return, with
+    /// `SbiRet::failed()`, if there are I/O errors.
+    /// # Return value
+    ///
+    /// The `SbiRet.value` is set to zero and` and the possible return error
+    /// codes returned in `SbiRet.error` are shown in the table below:
+    ///
+    /// | Return code               | Description
+    /// |:--------------------------|:----------------------------------------------
+    /// | `SbiRet::success()`       | Byte written successfully.
+    /// | `SbiRet::failed()`        | Failed to write the byte due to I/O errors.
+    fn write_byte(&self, byte: u8) -> SbiRet;
+}

+ 4 - 0
src/lib.rs

@@ -547,6 +547,7 @@
 #[macro_use]
 pub mod legacy_stdio;
 mod base;
+mod console;
 #[cfg(feature = "singleton")]
 mod ecall;
 mod hart_mask;
@@ -554,6 +555,7 @@ mod hsm;
 #[cfg(not(feature = "legacy"))]
 mod instance;
 mod ipi;
+mod memory_range;
 mod pmu;
 mod reset;
 mod rfence;
@@ -588,6 +590,7 @@ const RUSTSBI_VERSION: usize =
 pub const VERSION: &str = env!("CARGO_PKG_VERSION");
 
 pub extern crate sbi_spec as spec;
+pub use console::Console;
 #[cfg(feature = "singleton")]
 pub use ecall::handle_ecall as ecall;
 pub use hart_mask::HartMask;
@@ -598,6 +601,7 @@ pub use ipi::Ipi;
 #[cfg(feature = "legacy")]
 #[doc(hidden)]
 pub use legacy_stdio::{legacy_stdio_getchar, legacy_stdio_putchar};
+pub use memory_range::Physical;
 pub use pmu::Pmu;
 pub use reset::Reset;
 pub use rfence::Rfence as Fence;

+ 74 - 0
src/memory_range.rs

@@ -0,0 +1,74 @@
+//! Shared memory physical address range parameter
+
+use core::marker::PhantomData;
+
+/// Shared memory physical address range with type annotation
+///
+/// This is a wrapper around a kind of pointer to represent that its value is
+/// indexed on physical address space.
+///
+/// This structure cannot be dereferenced directly with physical addresses,
+/// because on RISC-V systems the physical address space could be larger than the
+/// virtual ones. Hence, this structure describes physical memory range by
+/// two `usize` values: the upper `phys_addr_hi` and lower `phys_addr_lo`.
+///
+/// # Requirements
+///
+/// If an SBI function needs to pass a shared memory physical address range to
+/// the SBI implementation (or higher privilege mode), then this physical memory
+/// address range MUST satisfy the following requirements:
+///
+/// * The SBI implementation MUST check that the supervisor-mode software is
+///   allowed to access the specified physical memory range with the access
+///   type requested (read and/or write).
+/// * The SBI implementation MUST access the specified physical memory range
+///   using the PMA attributes.
+/// * The data in the shared memory MUST follow little-endian byte ordering.
+///
+/// *NOTE:* If the supervisor-mode software accesses the same physical memory
+/// range using a memory type different than the PMA, then a loss of coherence
+/// or unexpected memory ordering may occur. The invoking software should
+/// follow the rules and sequences defined in the RISC-V Svpbmt specification
+/// to prevent the loss of coherence and memory ordering.
+///
+/// It is recommended that a memory physical address passed to an SBI function
+/// should use at least two `usize` parameters to support platforms
+/// which have memory physical addresses wider than `XLEN` bits.
+#[derive(Clone, Copy)]
+pub struct Physical<P> {
+    num_bytes: usize,
+    phys_addr_lo: usize,
+    phys_addr_hi: usize,
+    _marker: PhantomData<P>,
+}
+
+impl<P> Physical<P> {
+    /// Create a physical memory range by length and physical address.
+    #[inline]
+    pub const fn new(num_bytes: usize, phys_addr_lo: usize, phys_addr_hi: usize) -> Self {
+        Self {
+            num_bytes,
+            phys_addr_lo,
+            phys_addr_hi,
+            _marker: core::marker::PhantomData,
+        }
+    }
+
+    /// Returns length of the physical address range.
+    #[inline]
+    pub const fn num_bytes(&self) -> usize {
+        self.num_bytes
+    }
+
+    /// Returns low part of physical address range.
+    #[inline]
+    pub const fn phys_addr_lo(&self) -> usize {
+        self.phys_addr_lo
+    }
+
+    /// Returns high part of physical address range.
+    #[inline]
+    pub const fn phys_addr_hi(&self) -> usize {
+        self.phys_addr_hi
+    }
+}