Browse Source

Add RFENCE; fix for IPI and ecall

luojia65 4 years ago
parent
commit
1e89aa9440

+ 3 - 0
CHANGELOG.md

@@ -8,8 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added
 - S-level Illegal instruction exception is now delegated into S-level software handler
 - Added a test kernel to test SBI function on RustSBI implementations
+- Support framework for RFENCE extension
 
 ### Modified
+- Function `rustsbi::ecall` now require 5 input parameters
 - Enhanced in-line code documents from SBI standard
 - Remove use of `global_asm` and `llvm_asm` in test kernel
 - Align to 4 bytes for interrupt handler on QEMU and test kernel
@@ -18,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed
 - Test kernel console now will lock before `println` line is finished
+- Non-legacy supervisor IPI extension is fixed
 
 ## [0.1.1] - 2021-02-01
 ### Added

+ 1 - 1
platform/k210/src/main.rs

@@ -391,7 +391,7 @@ extern "C" fn start_trap_rust(trap_frame: &mut TrapFrame) {
                     }
                 }
                 // Actual ecall handler which is common for all RustSBI platforms
-                let params = [trap_frame.a0, trap_frame.a1, trap_frame.a2, trap_frame.a3];
+                let params = [trap_frame.a0, trap_frame.a1, trap_frame.a2, trap_frame.a3, trap_frame.a4];
                 let ans = rustsbi::ecall(trap_frame.a7, trap_frame.a6, params);
                 trap_frame.a0 = ans.error;
                 trap_frame.a1 = ans.value;

+ 1 - 1
platform/qemu/src/main.rs

@@ -407,7 +407,7 @@ extern "C" fn start_trap_rust(trap_frame: &mut TrapFrame) {
     let cause = mcause::read().cause();
     match cause {
         Trap::Exception(Exception::SupervisorEnvCall) => {
-            let params = [trap_frame.a0, trap_frame.a1, trap_frame.a2, trap_frame.a3];
+            let params = [trap_frame.a0, trap_frame.a1, trap_frame.a2, trap_frame.a3, trap_frame.a4];
             // Call RustSBI procedure
             let ans = rustsbi::ecall(trap_frame.a7, trap_frame.a6, params);
             // Return the return value to TrapFrame

+ 8 - 4
rustsbi/src/ecall.rs

@@ -7,11 +7,12 @@ mod ipi;
 mod legacy;
 mod srst;
 mod timer;
+mod rfence;
 
 pub const EXTENSION_BASE: usize = 0x10;
 pub const EXTENSION_TIMER: usize = 0x54494D45;
 pub const EXTENSION_IPI: usize = 0x735049;
-// const EXTENSION_RFENCE: usize = 0x52464E43;
+pub const EXTENSION_RFENCE: usize = 0x52464E43;
 pub const EXTENSION_HSM: usize = 0x48534D;
 pub const EXTENSION_SRST: usize = 0x53525354;
 
@@ -27,6 +28,8 @@ const LEGACY_SHUTDOWN: usize = 0x08;
 
 /// Supervisor environment call handler function
 ///
+/// This function is used by platform runtime to handle environment call `ecall` instruction.
+///
 /// You should call this function in your runtime's exception handler.
 /// If the incoming exception is caused by supervisor `ecall`,
 /// call this function with parameters extracted from trap frame.
@@ -45,7 +48,7 @@ const LEGACY_SHUTDOWN: usize = 0x08;
 /// #[exception]
 /// fn handle_exception(ctx: &mut TrapFrame) {
 ///     if mcause::read().cause() == Trap::Exception(Exception::SupervisorEnvCall) {
-///         let params = [ctx.a0, ctx.a1, ctx.a2, ctx.a3];
+///         let params = [ctx.a0, ctx.a1, ctx.a2, ctx.a3, ctx.a4];
 ///         let ans = rustsbi::ecall(ctx.a7, ctx.a6, params);
 ///         ctx.a0 = ans.error;
 ///         ctx.a1 = ans.value;
@@ -58,9 +61,9 @@ const LEGACY_SHUTDOWN: usize = 0x08;
 /// Do not forget to advance `mepc` by 4 after an ecall is handled.
 /// This skips the `ecall` instruction itself which is 4-byte long in all conditions.
 #[inline]
-pub fn handle_ecall(extension: usize, function: usize, param: [usize; 4]) -> SbiRet {
+pub fn handle_ecall(extension: usize, function: usize, param: [usize; 5]) -> SbiRet {
     match extension {
-        EXTENSION_BASE => base::handle_ecall_base(function, param[0]),
+        EXTENSION_RFENCE => rfence::handle_ecall_rfence(function, param[0], param[1], param[2], param[3], param[4]),
         EXTENSION_TIMER => match () {
             #[cfg(target_pointer_width = "64")]
             () => timer::handle_ecall_timer_64(function, param[0]),
@@ -68,6 +71,7 @@ pub fn handle_ecall(extension: usize, function: usize, param: [usize; 4]) -> Sbi
             () => timer::handle_ecall_timer_32(function, param[0], param[1]),
         },
         EXTENSION_IPI => ipi::handle_ecall_ipi(function, param[0], param[1]),
+        EXTENSION_BASE => base::handle_ecall_base(function, param[0]),
         EXTENSION_HSM => hsm::handle_ecall_hsm(function, param[0], param[1], param[2]),
         EXTENSION_SRST => srst::handle_ecall_srst(function, param[0], param[1]),
         LEGACY_SET_TIMER => match () {

+ 5 - 2
rustsbi/src/ecall/ipi.rs

@@ -1,4 +1,6 @@
 use super::SbiRet;
+use crate::hart_mask::HartMask;
+use crate::ipi::{max_hart_id, send_ipi_many};
 
 const FUNCTION_IPI_SEND_IPI: usize = 0x0;
 
@@ -11,7 +13,8 @@ pub fn handle_ecall_ipi(function: usize, param0: usize, param1: usize) -> SbiRet
 }
 
 #[inline]
-fn send_ipi(_hart_mask: usize, _hart_mask_base: usize) -> SbiRet {
-    // todo: send software interrupt to another hart
+fn send_ipi(hart_mask: usize, hart_mask_base: usize) -> SbiRet {
+    let hart_mask = unsafe { HartMask::from_addr(hart_mask, hart_mask_base, max_hart_id()) };
+    send_ipi_many(hart_mask);
     SbiRet::ok(0)
 }

+ 2 - 1
rustsbi/src/ecall/legacy.rs

@@ -20,7 +20,8 @@ pub fn console_getchar() -> SbiRet {
 #[inline]
 pub fn send_ipi(hart_mask_addr: usize) -> SbiRet {
     // note(unsafe): if any load fault, should be handled by user or supervisor
-    let hart_mask = unsafe { HartMask::from_addr(hart_mask_addr, max_hart_id()) };
+    // base hart should be 0 on legacy
+    let hart_mask = unsafe { HartMask::from_addr(hart_mask_addr, 0, max_hart_id()) };
     send_ipi_many(hart_mask);
     SbiRet::ok(0) // the return value 0 is ignored in legacy
 }

+ 72 - 0
rustsbi/src/ecall/rfence.rs

@@ -0,0 +1,72 @@
+use super::SbiRet;
+
+const FUNCTION_RFENCE_REMOTE_FENCE_I: usize = 0x0;
+const FUNCTION_RFENCE_REMOTE_SFENCE_VMA: usize = 0x1;
+const FUNCTION_RFENCE_REMOTE_SFENCE_VMA_ASID: usize = 0x2;
+const FUNCTION_RFENCE_REMOTE_HFENCE_GVMA_VMID: usize = 0x3;
+const FUNCTION_RFENCE_REMOTE_HFENCE_GVMA: usize = 0x4;
+const FUNCTION_RFENCE_REMOTE_HFENCE_VVMA_ASID: usize = 0x5;
+const FUNCTION_RFENCE_REMOTE_HFENCE_VVMA: usize = 0x6;
+
+#[inline]
+pub fn handle_ecall_rfence(function: usize, param0: usize, param1: usize, param2: usize, param3: usize, param4: usize) -> SbiRet {
+    match function {
+        FUNCTION_RFENCE_REMOTE_FENCE_I => remote_fence_i(param0, param1),
+        FUNCTION_RFENCE_REMOTE_SFENCE_VMA => remote_sfence_vma(param0, param1, param2, param3),
+        FUNCTION_RFENCE_REMOTE_SFENCE_VMA_ASID => remote_sfence_vma_asid(param0, param1, param2, param3, param4),
+        FUNCTION_RFENCE_REMOTE_HFENCE_GVMA_VMID => remote_hfence_gvma_vmid(param0, param1, param2, param3, param4),
+        FUNCTION_RFENCE_REMOTE_HFENCE_GVMA => remote_hfence_gvma(param0, param1, param2, param3),
+        FUNCTION_RFENCE_REMOTE_HFENCE_VVMA_ASID => remote_hfence_vvma_asid(param0, param1, param2, param3, param4),
+        FUNCTION_RFENCE_REMOTE_HFENCE_VVMA => remote_hfence_vvma(param0, param1, param2, param3),
+        _ => SbiRet::not_supported(),
+    }
+}
+
+#[inline]
+fn remote_fence_i(hart_mask: usize, hart_mask_base: usize) -> SbiRet {
+    // todo
+    drop((hart_mask, hart_mask_base));
+    SbiRet::not_supported()
+}
+
+#[inline]
+fn remote_sfence_vma(hart_mask: usize, hart_mask_base: usize, start_addr: usize, size: usize) -> SbiRet {
+    // todo
+    drop((hart_mask, hart_mask_base, start_addr, size));
+    SbiRet::not_supported()
+}
+
+#[inline]
+fn remote_sfence_vma_asid(hart_mask: usize, hart_mask_base: usize, start_addr: usize, size: usize, asid: usize) -> SbiRet {
+    // todo
+    drop((hart_mask, hart_mask_base, start_addr, size, asid));
+    SbiRet::not_supported()
+}
+
+#[inline]
+fn remote_hfence_gvma_vmid(hart_mask: usize, hart_mask_base: usize, start_addr: usize, size: usize, vmid: usize) -> SbiRet {
+    // todo
+    drop((hart_mask, hart_mask_base, start_addr, size, vmid));
+    SbiRet::not_supported()
+}
+
+#[inline]
+fn remote_hfence_gvma(hart_mask: usize, hart_mask_base: usize, start_addr: usize, size: usize) -> SbiRet {
+    // todo
+    drop((hart_mask, hart_mask_base, start_addr, size));
+    SbiRet::not_supported()
+}
+
+#[inline]
+fn remote_hfence_vvma_asid(hart_mask: usize, hart_mask_base: usize, start_addr: usize, size: usize, asid: usize) -> SbiRet {
+    // todo
+    drop((hart_mask, hart_mask_base, start_addr, size, asid));
+    SbiRet::not_supported()
+}
+
+#[inline]
+fn remote_hfence_vvma(hart_mask: usize, hart_mask_base: usize, start_addr: usize, size: usize) -> SbiRet {
+    // todo
+    drop((hart_mask, hart_mask_base, start_addr, size));
+    SbiRet::not_supported()
+}

+ 1 - 1
rustsbi/src/extension.rs

@@ -6,7 +6,7 @@ pub fn probe_extension(extension: usize) -> bool {
         EXTENSION_BASE => true,
         EXTENSION_TIMER => crate::timer::probe_timer(),
         EXTENSION_IPI => crate::ipi::probe_ipi(),
-        // EXTENSION_RFENCE
+        EXTENSION_RFENCE => crate::rfence::probe_rfence(),
         EXTENSION_SRST => crate::reset::probe_reset(),
         EXTENSION_HSM => crate::hsm::probe_hsm(),
         // new extensions should be added here to be probed

+ 37 - 10
rustsbi/src/hart_mask.rs

@@ -4,21 +4,28 @@ use core::mem::size_of;
 #[derive(Debug, Clone)]
 pub struct HartMask {
     bit_vector: *const usize,
+    base: usize,
     max_hart_id: usize,
 }
 
 impl HartMask {
-    /// Construct a reference to a hart mask structure.
+    /// Construct a reference to hart mask from bit vector and starting hartid.
     ///
-    /// Caller should provide from its address from supervisor level,
-    /// and a maximum hart number for maximum hart limit.
+    /// # Parameters
+    ///
+    /// - The `vaddr` is a scalar bit-vector containing hartids. 
+    ///   Should return address from supervisor level.
+    /// - The `base` is the starting hartid from which bit-vector must be computed.
+    ///   If `base` equals `usize::max_value()`, that means `vaddr` is ignored and all available harts must be considered.
+    /// - The `max_hart_id` should be returned by SBI implementation for maximum hart id this hart mask supports.
     ///
     /// # Unsafety
     ///
     /// Caller must ensure all usize values in the bit vector is accessible.
-    pub unsafe fn from_addr(vaddr: usize, max_hart_id: usize) -> HartMask {
+    pub unsafe fn from_addr(vaddr: usize, base: usize, max_hart_id: usize) -> HartMask {
         HartMask {
             bit_vector: vaddr as *const usize,
+            base,
             max_hart_id,
         }
     }
@@ -26,7 +33,16 @@ impl HartMask {
     /// Check if the `hart_id` is included in this hart mask structure.
     pub fn has_bit(&self, hart_id: usize) -> bool {
         assert!(hart_id <= self.max_hart_id);
-        let (i, j) = split_index_usize(hart_id);
+        if self.base == usize::max_value() {
+            // If `base` equals `usize::max_value()`, 
+            // that means `vaddr` is ignored and all available harts must be considered.
+            return true;
+        }
+        if hart_id < self.base {
+            // `base` if the starting hartid
+            return false;
+        }
+        let (i, j) = split_index_usize(hart_id - self.base);
         let cur_vector = unsafe { get_vaddr_usize(self.bit_vector.add(i)) };
         cur_vector & (1 << j) != 0
     }
@@ -41,7 +57,18 @@ fn split_index_usize(index: usize) -> (usize, usize) {
 #[inline]
 unsafe fn get_vaddr_usize(vaddr_ptr: *const usize) -> usize {
     match () {
-        #[cfg(target_arch = "riscv64")]
+        #[cfg(target_pointer_width = "32")]
+        () => {
+            let mut ans: usize;
+            asm!("
+                li      {tmp}, (1 << 17)
+                csrrs   {tmp}, mstatus, {tmp}
+                lw      {ans}, 0({vmem})
+                csrw    mstatus, {tmp}
+            ", ans = lateout(reg) ans, vmem = in(reg) vaddr_ptr, tmp = out(reg) _);
+            ans
+        },
+        #[cfg(target_pointer_width = "64")]
         () => {
             let mut ans: usize;
             asm!("
@@ -52,21 +79,21 @@ unsafe fn get_vaddr_usize(vaddr_ptr: *const usize) -> usize {
             ", ans = lateout(reg) ans, vmem = in(reg) vaddr_ptr, tmp = out(reg) _);
             ans
         },
-        #[cfg(target_arch = "riscv32")]
+        #[cfg(target_pointer_width = "128")]
         () => {
             let mut ans: usize;
             asm!("
                 li      {tmp}, (1 << 17)
                 csrrs   {tmp}, mstatus, {tmp}
-                lw      {ans}, 0({vmem})
+                lq      {ans}, 0({vmem})
                 csrw    mstatus, {tmp}
             ", ans = lateout(reg) ans, vmem = in(reg) vaddr_ptr, tmp = out(reg) _);
             ans
         },
-        #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
+        #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64", target_pointer_width = "128")))]
         () => {
             drop(vaddr_ptr);
-            unimplemented!("not RISC-V instruction set architecture!");
+            unimplemented!("not RISC-V RV32, RV64 or RV128 architecture!");
         }
     }
 }

+ 1 - 0
rustsbi/src/lib.rs

@@ -31,6 +31,7 @@ mod privileged;
 #[doc(hidden)]
 pub mod reset;
 mod timer;
+mod rfence;
 
 const SBI_SPEC_MAJOR: usize = 0;
 const SBI_SPEC_MINOR: usize = 2;

+ 4 - 0
rustsbi/src/rfence.rs

@@ -0,0 +1,4 @@
+pub fn probe_rfence() -> bool {
+    false
+}
+// todo