Kaynağa Gözat

feat: add invalid_parma return for send_ipi_by_fence

fix: remove clear msie when hsm stop

Signed-off-by: Woshiluo Luo <woshiluo.luo@outlook.com>
Woshiluo Luo 4 ay önce
ebeveyn
işleme
f7afda1f73
2 değiştirilmiş dosya ile 44 ekleme ve 12 silme
  1. 0 3
      prototyper/src/sbi/hsm.rs
  2. 44 9
      prototyper/src/sbi/ipi.rs

+ 0 - 3
prototyper/src/sbi/hsm.rs

@@ -211,9 +211,6 @@ impl rustsbi::Hsm for SbiHsm {
     #[inline]
     fn hart_stop(&self) -> SbiRet {
         local_hsm().stop();
-        unsafe {
-            BOARD.sbi.ipi.as_ref().unwrap().clear_msip(current_hartid());
-        }
         unsafe {
             riscv::register::mie::clear_msoft();
         }

+ 44 - 9
prototyper/src/sbi/ipi.rs

@@ -1,5 +1,5 @@
 use core::sync::atomic::{AtomicPtr, Ordering::Relaxed};
-use rustsbi::SbiRet;
+use rustsbi::{HartMask, SbiRet};
 
 use crate::board::BOARD;
 use crate::riscv_spec::{current_hartid, stimecmp};
@@ -69,18 +69,18 @@ impl<T: IpiDevice> rustsbi::Ipi for SbiIpi<T> {
     #[inline]
     fn send_ipi(&self, hart_mask: rustsbi::HartMask) -> SbiRet {
         let ipi_dev = unsafe { &*self.ipi_dev.load(Relaxed) };
+        let mut hart_mask = hart_mask;
 
         for hart_id in 0..=self.max_hart_id {
             if !hart_mask.has_bit(hart_id) {
                 continue;
             }
 
-            // There are 3 situation to return invalid_param
-            // 1. We can not get hsm, which usually means this hart_id is bigger than MAX_HART_ID
-            // 2. BOARD hasn't init or this hart_id is not enabled by device tree
-            // 3. this hart is not in a state which allow ipi
+            // There are 2 situation to return invalid_param:
+            // 1. We can not get hsm, which usually means this hart_id is bigger than MAX_HART_ID.
+            // 2. BOARD hasn't init or this hart_id is not enabled by device tree.
             // In the next loop, we'll assume that all of above situation will not happend and
-            // directly send ipi
+            // directly send ipi.
             let Some(hsm) = remote_hsm(hart_id) else {
                 return SbiRet::invalid_param();
             };
@@ -95,7 +95,7 @@ impl<T: IpiDevice> rustsbi::Ipi for SbiIpi<T> {
             }
 
             if !hsm.allow_ipi() {
-                return SbiRet::invalid_param();
+                hart_mask = hart_mask_clear(hart_mask, hart_id);
             }
         }
         for hart_id in 0..=self.max_hart_id {
@@ -130,18 +130,39 @@ impl<T: IpiDevice> SbiIpi<T> {
     ) -> SbiRet {
         let current_hart = current_hartid();
         let ipi_dev = unsafe { &*self.ipi_dev.load(Relaxed) };
+        let mut hart_mask = hart_mask;
 
-        // Send fence operations to target harts
         for hart_id in 0..=self.max_hart_id {
             if !hart_mask.has_bit(hart_id) {
                 continue;
             }
 
+            // There are 2 situation to return invalid_param:
+            // 1. We can not get hsm, which usually means this hart_id is bigger than MAX_HART_ID.
+            // 2. BOARD hasn't init or this hart_id is not enabled by device tree.
+            // In the next loop, we'll assume that all of above situation will not happend and
+            // directly send ipi.
             let Some(hsm) = remote_hsm(hart_id) else {
-                continue;
+                return SbiRet::invalid_param();
             };
 
+            if unsafe {
+                BOARD
+                    .info
+                    .cpu_enabled
+                    .is_none_or(|list| list.get(hart_id).is_none_or(|res| !(*res)))
+            } {
+                return SbiRet::invalid_param();
+            }
+
             if !hsm.allow_ipi() {
+                hart_mask = hart_mask_clear(hart_mask, hart_id);
+            }
+        }
+
+        // Send fence operations to target harts
+        for hart_id in 0..=self.max_hart_id {
+            if !hart_mask.has_bit(hart_id) {
                 continue;
             }
 
@@ -256,3 +277,17 @@ pub fn clear_all() {
         None => error!("SBI or IPI device not initialized"),
     }
 }
+
+pub fn hart_mask_clear(hart_mask: HartMask, hart_id: usize) -> HartMask {
+    let (mask, mask_base) = hart_mask.into_inner();
+    if mask_base == usize::MAX {
+        return HartMask::from_mask_base(mask & (!(1 << hart_id)), 0);
+    }
+    let Some(idx) = hart_id.checked_sub(mask_base) else {
+        return hart_mask;
+    };
+    if idx >= usize::BITS as usize {
+        return hart_mask;
+    }
+    HartMask::from_mask_base(mask & (!(1 << hart_id)), mask_base)
+}