瀏覽代碼

feat(prototyper): implemented `sbi_pmu_counter_get_info` and other functions

Signed-off-by: guttatus <[email protected]>
guttatus 1 月之前
父節點
當前提交
09df7d189a

+ 13 - 0
prototyper/prototyper/src/devicetree.rs

@@ -15,6 +15,8 @@ pub struct Tree<'a> {
     pub memory: NodeSeq<'a>,
     /// CPU information.
     pub cpus: Cpus<'a>,
+    /// PMU information
+    pub pmu: Option<Pmu<'a>>,
 }
 
 /// CPU information container.
@@ -52,6 +54,17 @@ pub struct Memory<'a> {
     pub reg: Reg<'a>,
 }
 
+#[derive(Deserialize)]
+pub struct Pmu<'a> {
+    pub compatible: StrSeq<'a>,
+    #[serde(rename = "riscv,event-to-mhpmevent")]
+    pub event_to_mhpmevent: Option<Reg<'a>>,
+    #[serde(rename = "riscv,event-to-mhpmcounters")]
+    pub event_to_mhpmcounters: Option<Reg<'a>>,
+    #[serde(rename = "riscv,raw-event-to-mhpmcounters")]
+    pub raw_event_to_mhpmcounters: Option<Reg<'a>>,
+}
+
 /// Errors that can occur during device tree parsing.
 pub enum ParseDeviceTreeError {
     /// Invalid device tree format.

+ 16 - 0
prototyper/prototyper/src/platform/mod.rs

@@ -145,6 +145,22 @@ impl Platform {
             self.info.model = model.to_string();
         }
 
+        //
+        // WARN: Test PMU Parser, Should be delete
+        //
+        if tree.pmu.is_some() {
+            let pmu = tree.pmu.unwrap();
+            for device_id in pmu.compatible.iter() {
+                info!("PMU: {}", device_id);
+            }
+            // if pmu.event_to_mhpmcounters.is_some() {
+            //     let e_t_m = pmu.event_to_mhpmcounters.unwrap();
+            //     for value in e_t_m.iter() {
+            //         info!("{}",value);
+            //     }
+            // }
+        }
+
         // TODO: Need a better extension initialization method
         extension_detection(&tree.cpus.cpu);
 

+ 132 - 74
prototyper/prototyper/src/riscv/csr.rs

@@ -1,79 +1,137 @@
 #![allow(unused)]
 
-/// CSR addresses for timer registers.
-///
-/// Time value (lower 32 bits).
-pub const CSR_TIME: u32 = 0xc01;
-/// Time value (upper 32 bits).
-pub const CSR_TIMEH: u32 = 0xc81;
-/// Supervisor timer compare value.
-pub const CSR_STIMECMP: u32 = 0x14D;
-pub const CSR_MCOUNTEREN: u32 = 0x306;
-pub const CSR_MCOUNTINHIBIT: u32 = 0x320;
-pub const CSR_MENVCFG: u32 = 0x30a;
-/* Machine Counters/Timers */
-pub const CSR_MCYCLE: u32 = 0xb00;
-pub const CSR_MINSTRET: u32 = 0xb02;
-pub const CSR_MHPMCOUNTER3: u32 = 0xb03;
-pub const CSR_MHPMCOUNTER4: u32 = 0xb04;
-pub const CSR_MHPMCOUNTER5: u32 = 0xb05;
-pub const CSR_MHPMCOUNTER6: u32 = 0xb06;
-pub const CSR_MHPMCOUNTER7: u32 = 0xb07;
-pub const CSR_MHPMCOUNTER8: u32 = 0xb08;
-pub const CSR_MHPMCOUNTER9: u32 = 0xb09;
-pub const CSR_MHPMCOUNTER10: u32 = 0xb0a;
-pub const CSR_MHPMCOUNTER11: u32 = 0xb0b;
-pub const CSR_MHPMCOUNTER12: u32 = 0xb0c;
-pub const CSR_MHPMCOUNTER13: u32 = 0xb0d;
-pub const CSR_MHPMCOUNTER14: u32 = 0xb0e;
-pub const CSR_MHPMCOUNTER15: u32 = 0xb0f;
-pub const CSR_MHPMCOUNTER16: u32 = 0xb10;
-pub const CSR_MHPMCOUNTER17: u32 = 0xb11;
-pub const CSR_MHPMCOUNTER18: u32 = 0xb12;
-pub const CSR_MHPMCOUNTER19: u32 = 0xb13;
-pub const CSR_MHPMCOUNTER20: u32 = 0xb14;
-pub const CSR_MHPMCOUNTER21: u32 = 0xb15;
-pub const CSR_MHPMCOUNTER22: u32 = 0xb16;
-pub const CSR_MHPMCOUNTER23: u32 = 0xb17;
-pub const CSR_MHPMCOUNTER24: u32 = 0xb18;
-pub const CSR_MHPMCOUNTER25: u32 = 0xb19;
-pub const CSR_MHPMCOUNTER26: u32 = 0xb1a;
-pub const CSR_MHPMCOUNTER27: u32 = 0xb1b;
-pub const CSR_MHPMCOUNTER28: u32 = 0xb1c;
-pub const CSR_MHPMCOUNTER29: u32 = 0xb1d;
-pub const CSR_MHPMCOUNTER30: u32 = 0xb1e;
-pub const CSR_MHPMCOUNTER31: u32 = 0xb1f;
-pub const CSR_MCYCLEH: u32 = 0xb80;
-pub const CSR_MINSTRETH: u32 = 0xb82;
-pub const CSR_MHPMCOUNTER3H: u32 = 0xb83;
-pub const CSR_MHPMCOUNTER4H: u32 = 0xb84;
-pub const CSR_MHPMCOUNTER5H: u32 = 0xb85;
-pub const CSR_MHPMCOUNTER6H: u32 = 0xb86;
-pub const CSR_MHPMCOUNTER7H: u32 = 0xb87;
-pub const CSR_MHPMCOUNTER8H: u32 = 0xb88;
-pub const CSR_MHPMCOUNTER9H: u32 = 0xb89;
-pub const CSR_MHPMCOUNTER10H: u32 = 0xb8a;
-pub const CSR_MHPMCOUNTER11H: u32 = 0xb8b;
-pub const CSR_MHPMCOUNTER12H: u32 = 0xb8c;
-pub const CSR_MHPMCOUNTER13H: u32 = 0xb8d;
-pub const CSR_MHPMCOUNTER14H: u32 = 0xb8e;
-pub const CSR_MHPMCOUNTER15H: u32 = 0xb8f;
-pub const CSR_MHPMCOUNTER16H: u32 = 0xb90;
-pub const CSR_MHPMCOUNTER17H: u32 = 0xb91;
-pub const CSR_MHPMCOUNTER18H: u32 = 0xb92;
-pub const CSR_MHPMCOUNTER19H: u32 = 0xb93;
-pub const CSR_MHPMCOUNTER20H: u32 = 0xb94;
-pub const CSR_MHPMCOUNTER21H: u32 = 0xb95;
-pub const CSR_MHPMCOUNTER22H: u32 = 0xb96;
-pub const CSR_MHPMCOUNTER23H: u32 = 0xb97;
-pub const CSR_MHPMCOUNTER24H: u32 = 0xb98;
-pub const CSR_MHPMCOUNTER25H: u32 = 0xb99;
-pub const CSR_MHPMCOUNTER26H: u32 = 0xb9a;
-pub const CSR_MHPMCOUNTER27H: u32 = 0xb9b;
-pub const CSR_MHPMCOUNTER28H: u32 = 0xb9c;
-pub const CSR_MHPMCOUNTER29H: u32 = 0xb9d;
-pub const CSR_MHPMCOUNTER30H: u32 = 0xb9e;
-pub const CSR_MHPMCOUNTER31H: u32 = 0xb9f;
+/// CSR addresses
+pub const CSR_STIMECMP: u16 = 0x14D;
+pub const CSR_MCOUNTEREN: u16 = 0x306;
+pub const CSR_MCOUNTINHIBIT: u16 = 0x320;
+pub const CSR_MENVCFG: u16 = 0x30a;
+pub const CSR_MCYCLE: u16 = 0xb00;
+pub const CSR_MINSTRET: u16 = 0xb02;
+pub const CSR_MHPMCOUNTER3: u16 = 0xb03;
+pub const CSR_MHPMCOUNTER4: u16 = 0xb04;
+pub const CSR_MHPMCOUNTER5: u16 = 0xb05;
+pub const CSR_MHPMCOUNTER6: u16 = 0xb06;
+pub const CSR_MHPMCOUNTER7: u16 = 0xb07;
+pub const CSR_MHPMCOUNTER8: u16 = 0xb08;
+pub const CSR_MHPMCOUNTER9: u16 = 0xb09;
+pub const CSR_MHPMCOUNTER10: u16 = 0xb0a;
+pub const CSR_MHPMCOUNTER11: u16 = 0xb0b;
+pub const CSR_MHPMCOUNTER12: u16 = 0xb0c;
+pub const CSR_MHPMCOUNTER13: u16 = 0xb0d;
+pub const CSR_MHPMCOUNTER14: u16 = 0xb0e;
+pub const CSR_MHPMCOUNTER15: u16 = 0xb0f;
+pub const CSR_MHPMCOUNTER16: u16 = 0xb10;
+pub const CSR_MHPMCOUNTER17: u16 = 0xb11;
+pub const CSR_MHPMCOUNTER18: u16 = 0xb12;
+pub const CSR_MHPMCOUNTER19: u16 = 0xb13;
+pub const CSR_MHPMCOUNTER20: u16 = 0xb14;
+pub const CSR_MHPMCOUNTER21: u16 = 0xb15;
+pub const CSR_MHPMCOUNTER22: u16 = 0xb16;
+pub const CSR_MHPMCOUNTER23: u16 = 0xb17;
+pub const CSR_MHPMCOUNTER24: u16 = 0xb18;
+pub const CSR_MHPMCOUNTER25: u16 = 0xb19;
+pub const CSR_MHPMCOUNTER26: u16 = 0xb1a;
+pub const CSR_MHPMCOUNTER27: u16 = 0xb1b;
+pub const CSR_MHPMCOUNTER28: u16 = 0xb1c;
+pub const CSR_MHPMCOUNTER29: u16 = 0xb1d;
+pub const CSR_MHPMCOUNTER30: u16 = 0xb1e;
+pub const CSR_MHPMCOUNTER31: u16 = 0xb1f;
+pub const CSR_MCYCLEH: u16 = 0xb80;
+pub const CSR_MINSTRETH: u16 = 0xb82;
+pub const CSR_MHPMCOUNTER3H: u16 = 0xb83;
+pub const CSR_MHPMCOUNTER4H: u16 = 0xb84;
+pub const CSR_MHPMCOUNTER5H: u16 = 0xb85;
+pub const CSR_MHPMCOUNTER6H: u16 = 0xb86;
+pub const CSR_MHPMCOUNTER7H: u16 = 0xb87;
+pub const CSR_MHPMCOUNTER8H: u16 = 0xb88;
+pub const CSR_MHPMCOUNTER9H: u16 = 0xb89;
+pub const CSR_MHPMCOUNTER10H: u16 = 0xb8a;
+pub const CSR_MHPMCOUNTER11H: u16 = 0xb8b;
+pub const CSR_MHPMCOUNTER12H: u16 = 0xb8c;
+pub const CSR_MHPMCOUNTER13H: u16 = 0xb8d;
+pub const CSR_MHPMCOUNTER14H: u16 = 0xb8e;
+pub const CSR_MHPMCOUNTER15H: u16 = 0xb8f;
+pub const CSR_MHPMCOUNTER16H: u16 = 0xb90;
+pub const CSR_MHPMCOUNTER17H: u16 = 0xb91;
+pub const CSR_MHPMCOUNTER18H: u16 = 0xb92;
+pub const CSR_MHPMCOUNTER19H: u16 = 0xb93;
+pub const CSR_MHPMCOUNTER20H: u16 = 0xb94;
+pub const CSR_MHPMCOUNTER21H: u16 = 0xb95;
+pub const CSR_MHPMCOUNTER22H: u16 = 0xb96;
+pub const CSR_MHPMCOUNTER23H: u16 = 0xb97;
+pub const CSR_MHPMCOUNTER24H: u16 = 0xb98;
+pub const CSR_MHPMCOUNTER25H: u16 = 0xb99;
+pub const CSR_MHPMCOUNTER26H: u16 = 0xb9a;
+pub const CSR_MHPMCOUNTER27H: u16 = 0xb9b;
+pub const CSR_MHPMCOUNTER28H: u16 = 0xb9c;
+pub const CSR_MHPMCOUNTER29H: u16 = 0xb9d;
+pub const CSR_MHPMCOUNTER30H: u16 = 0xb9e;
+pub const CSR_MHPMCOUNTER31H: u16 = 0xb9f;
+/* User Counters/Timers */
+pub const CSR_CYCLE: u16 = 0xc00;
+pub const CSR_TIME: u16 = 0xc01;
+pub const CSR_INSTRET: u16 = 0xc02;
+pub const CSR_HPMCOUNTER3: u16 = 0xc03;
+pub const CSR_HPMCOUNTER4: u16 = 0xc04;
+pub const CSR_HPMCOUNTER5: u16 = 0xc05;
+pub const CSR_HPMCOUNTER6: u16 = 0xc06;
+pub const CSR_HPMCOUNTER7: u16 = 0xc07;
+pub const CSR_HPMCOUNTER8: u16 = 0xc08;
+pub const CSR_HPMCOUNTER9: u16 = 0xc09;
+pub const CSR_HPMCOUNTER10: u16 = 0xc0a;
+pub const CSR_HPMCOUNTER11: u16 = 0xc0b;
+pub const CSR_HPMCOUNTER12: u16 = 0xc0c;
+pub const CSR_HPMCOUNTER13: u16 = 0xc0d;
+pub const CSR_HPMCOUNTER14: u16 = 0xc0e;
+pub const CSR_HPMCOUNTER15: u16 = 0xc0f;
+pub const CSR_HPMCOUNTER16: u16 = 0xc10;
+pub const CSR_HPMCOUNTER17: u16 = 0xc11;
+pub const CSR_HPMCOUNTER18: u16 = 0xc12;
+pub const CSR_HPMCOUNTER19: u16 = 0xc13;
+pub const CSR_HPMCOUNTER20: u16 = 0xc14;
+pub const CSR_HPMCOUNTER21: u16 = 0xc15;
+pub const CSR_HPMCOUNTER22: u16 = 0xc16;
+pub const CSR_HPMCOUNTER23: u16 = 0xc17;
+pub const CSR_HPMCOUNTER24: u16 = 0xc18;
+pub const CSR_HPMCOUNTER25: u16 = 0xc19;
+pub const CSR_HPMCOUNTER26: u16 = 0xc1a;
+pub const CSR_HPMCOUNTER27: u16 = 0xc1b;
+pub const CSR_HPMCOUNTER28: u16 = 0xc1c;
+pub const CSR_HPMCOUNTER29: u16 = 0xc1d;
+pub const CSR_HPMCOUNTER30: u16 = 0xc1e;
+pub const CSR_HPMCOUNTER31: u16 = 0xc1f;
+pub const CSR_CYCLEH: u16 = 0xc80;
+pub const CSR_TIMEH: u16 = 0xc81;
+pub const CSR_INSTRETH: u16 = 0xc82;
+pub const CSR_HPMCOUNTER3H: u16 = 0xc83;
+pub const CSR_HPMCOUNTER4H: u16 = 0xc84;
+pub const CSR_HPMCOUNTER5H: u16 = 0xc85;
+pub const CSR_HPMCOUNTER6H: u16 = 0xc86;
+pub const CSR_HPMCOUNTER7H: u16 = 0xc87;
+pub const CSR_HPMCOUNTER8H: u16 = 0xc88;
+pub const CSR_HPMCOUNTER9H: u16 = 0xc89;
+pub const CSR_HPMCOUNTER10H: u16 = 0xc8a;
+pub const CSR_HPMCOUNTER11H: u16 = 0xc8b;
+pub const CSR_HPMCOUNTER12H: u16 = 0xc8c;
+pub const CSR_HPMCOUNTER13H: u16 = 0xc8d;
+pub const CSR_HPMCOUNTER14H: u16 = 0xc8e;
+pub const CSR_HPMCOUNTER15H: u16 = 0xc8f;
+pub const CSR_HPMCOUNTER16H: u16 = 0xc90;
+pub const CSR_HPMCOUNTER17H: u16 = 0xc91;
+pub const CSR_HPMCOUNTER18H: u16 = 0xc92;
+pub const CSR_HPMCOUNTER19H: u16 = 0xc93;
+pub const CSR_HPMCOUNTER20H: u16 = 0xc94;
+pub const CSR_HPMCOUNTER21H: u16 = 0xc95;
+pub const CSR_HPMCOUNTER22H: u16 = 0xc96;
+pub const CSR_HPMCOUNTER23H: u16 = 0xc97;
+pub const CSR_HPMCOUNTER24H: u16 = 0xc98;
+pub const CSR_HPMCOUNTER25H: u16 = 0xc99;
+pub const CSR_HPMCOUNTER26H: u16 = 0xc9a;
+pub const CSR_HPMCOUNTER27H: u16 = 0xc9b;
+pub const CSR_HPMCOUNTER28H: u16 = 0xc9c;
+pub const CSR_HPMCOUNTER29H: u16 = 0xc9d;
+pub const CSR_HPMCOUNTER30H: u16 = 0xc9e;
+pub const CSR_HPMCOUNTER31H: u16 = 0xc9f;
 
 /// Machine environment configuration register (menvcfg) bit fields.
 pub mod menvcfg {

+ 3 - 3
prototyper/prototyper/src/sbi/early_trap.rs

@@ -59,7 +59,7 @@ pub(crate) unsafe extern "C" fn expected_trap() {
     }
 }
 
-pub(crate) unsafe fn csr_read_allow<const CSR_NUM: u32>(trap_info: *mut TrapInfo) -> usize {
+pub(crate) unsafe fn csr_read_allow<const CSR_NUM: u16>(trap_info: *mut TrapInfo) -> usize {
     let tinfo = trap_info as usize;
     let mut ret: usize;
     // Backup old mtvec
@@ -83,7 +83,7 @@ pub(crate) unsafe fn csr_read_allow<const CSR_NUM: u32>(trap_info: *mut TrapInfo
     ret
 }
 
-pub(crate) unsafe fn csr_write_allow<const CSR_NUM: u32>(trap_info: *mut TrapInfo, value: usize) {
+pub(crate) unsafe fn csr_write_allow<const CSR_NUM: u16>(trap_info: *mut TrapInfo, value: usize) {
     let tinfo = trap_info as usize;
     // Backup old mtvec
     let mtvec = mtvec::read().bits();
@@ -105,7 +105,7 @@ pub(crate) unsafe fn csr_write_allow<const CSR_NUM: u32>(trap_info: *mut TrapInf
     }
 }
 
-pub(crate) unsafe fn csr_swap<const CSR_NUM: u32>(val: usize) -> usize {
+pub(crate) unsafe fn csr_swap<const CSR_NUM: u16>(val: usize) -> usize {
     let ret: usize;
 
     unsafe {

+ 6 - 6
prototyper/prototyper/src/sbi/features.rs

@@ -4,7 +4,7 @@ use serde_device_tree::buildin::NodeSeq;
 use crate::riscv::csr::*;
 use crate::riscv::current_hartid;
 use crate::sbi::early_trap::{TrapInfo, csr_read_allow, csr_write_allow};
-use crate::sbi::trap_stack::hart_context;
+use crate::sbi::trap_stack::{hart_context, hart_context_mut};
 
 use super::early_trap::csr_swap;
 
@@ -77,7 +77,7 @@ pub fn extension_detection(cpus: &NodeSeq) {
                 hart_exts[ext.index()] = isa.contains(ext.as_str());
             })
         }
-        hart_context(hart_id).features.extension = hart_exts;
+        hart_context_mut(hart_id).features.extension = hart_exts;
     }
 }
 
@@ -94,7 +94,7 @@ fn privileged_version_detection() {
             }
         }
     }
-    hart_context(current_hartid()).features.privileged_version = current_priv_ver;
+    hart_context_mut(current_hartid()).features.privileged_version = current_priv_ver;
 }
 
 fn mhpm_detection() {
@@ -102,7 +102,7 @@ fn mhpm_detection() {
     let mut current_mhpm_mask: u32 = 0b111;
     let mut trap_info: TrapInfo = TrapInfo::default();
 
-    fn check_mhpm_csr<const CSR_NUM: u32>(trap_info: *mut TrapInfo, mhpm_mask: &mut u32) {
+    fn check_mhpm_csr<const CSR_NUM: u16>(trap_info: *mut TrapInfo, mhpm_mask: &mut u32) {
         unsafe {
             let old_value = csr_read_allow::<CSR_NUM>(trap_info);
             if (*trap_info).mcause == usize::MAX {
@@ -126,9 +126,9 @@ fn mhpm_detection() {
         m_check_mhpm_csr!(csr_num, &mut trap_info, &mut current_mhpm_mask);
     });
 
-    hart_context(current_hartid()).features.mhpm_mask = current_mhpm_mask;
+    hart_context_mut(current_hartid()).features.mhpm_mask = current_mhpm_mask;
     // TODO: at present, rustsbi prptotyper only supports 64bit.
-    hart_context(current_hartid()).features.mhpm_bits = 64;
+    hart_context_mut(current_hartid()).features.mhpm_bits = 64;
 }
 
 pub fn hart_features_detection() {

+ 5 - 0
prototyper/prototyper/src/sbi/hart_context.rs

@@ -6,6 +6,8 @@ use core::sync::atomic::AtomicU8;
 use fast_trap::FlowContext;
 use riscv::register::mstatus;
 
+use super::pmu::PmuState;
+
 /// Context for managing hart (hardware thread) state and operations.
 pub(crate) struct HartContext {
     /// Trap context for handling exceptions and interrupts.
@@ -18,6 +20,8 @@ pub(crate) struct HartContext {
     pub ipi_type: AtomicU8,
     /// Supported hart features.
     pub features: HartFeatures,
+    /// PMU State
+    pub pmu_state: PmuState,
 }
 
 impl HartContext {
@@ -26,6 +30,7 @@ impl HartContext {
     pub fn init(&mut self) {
         self.hsm = HsmCell::new();
         self.rfence = RFenceCell::new();
+        self.pmu_state = PmuState::new();
     }
 
     /// Get a non-null pointer to the trap context.

+ 4 - 14
prototyper/prototyper/src/sbi/hsm.rs

@@ -11,6 +11,8 @@ use crate::riscv::current_hartid;
 use crate::sbi::hart_context::NextStage;
 use crate::sbi::trap_stack::ROOT_STACK;
 
+use super::trap_stack::hart_context;
+
 /// Special state indicating a hart is in the process of starting.
 const HART_STATE_START_PENDING_EXT: usize = usize::MAX;
 
@@ -152,24 +154,12 @@ impl<T: core::fmt::Debug> RemoteHsmCell<'_, T> {
 
 /// Gets the local HSM cell for the current hart.
 pub(crate) fn local_hsm() -> LocalHsmCell<'static, NextStage> {
-    unsafe {
-        ROOT_STACK
-            .get_unchecked_mut(current_hartid())
-            .hart_context()
-            .hsm
-            .local()
-    }
+    unsafe { hart_context(current_hartid()).hsm.local() }
 }
 
 /// Gets a remote view of the current hart's HSM cell.
 pub(crate) fn local_remote_hsm() -> RemoteHsmCell<'static, NextStage> {
-    unsafe {
-        ROOT_STACK
-            .get_unchecked_mut(current_hartid())
-            .hart_context()
-            .hsm
-            .remote()
-    }
+    hart_context(current_hartid()).hsm.remote()
 }
 
 /// Gets a remote view of any hart's HSM cell.

+ 5 - 15
prototyper/prototyper/src/sbi/ipi.rs

@@ -4,12 +4,14 @@ use crate::riscv::current_hartid;
 use crate::sbi::features::{Extension, hart_extension_probe};
 use crate::sbi::hsm::remote_hsm;
 use crate::sbi::rfence;
-use crate::sbi::trap_stack::ROOT_STACK;
+use crate::sbi::trap_stack::hart_context;
 use alloc::boxed::Box;
 use core::sync::atomic::Ordering::Relaxed;
 use rustsbi::{HartMask, SbiRet};
 use spin::Mutex;
 
+use super::hart_context;
+
 /// IPI type for supervisor software interrupt.
 pub(crate) const IPI_TYPE_SSOFT: u8 = 1 << 0;
 /// IPI type for memory fence operations.
@@ -230,24 +232,12 @@ impl SbiIpi {
 
 /// Set IPI type for specified hart.
 pub fn set_ipi_type(hart_id: usize, event_id: u8) -> u8 {
-    unsafe {
-        ROOT_STACK
-            .get_unchecked_mut(hart_id)
-            .hart_context()
-            .ipi_type
-            .fetch_or(event_id, Relaxed)
-    }
+    hart_context(hart_id).ipi_type.fetch_or(event_id, Relaxed)
 }
 
 /// Get and reset IPI type for current hart.
 pub fn get_and_reset_ipi_type() -> u8 {
-    unsafe {
-        ROOT_STACK
-            .get_unchecked_mut(current_hartid())
-            .hart_context()
-            .ipi_type
-            .swap(0, Relaxed)
-    }
+    hart_context(current_hartid()).ipi_type.swap(0, Relaxed)
 }
 
 /// Clear machine software interrupt pending for current hart.

+ 228 - 8
prototyper/prototyper/src/sbi/pmu.rs

@@ -1,27 +1,95 @@
-use crate::{riscv::current_hartid, sbi::features::hart_mhpm_mask};
 use rustsbi::{Pmu, SbiRet};
-use sbi_spec::{binary::SharedPtr, pmu::shmem_size::SIZE};
+use sbi_spec::binary::SharedPtr;
+use sbi_spec::pmu::shmem_size::SIZE;
+use sbi_spec::pmu::*;
+
+use crate::riscv::csr::CSR_CYCLE;
+use crate::{riscv::current_hartid, sbi::features::hart_mhpm_mask};
 
 use super::trap_stack::hart_context;
 
 const HARDWARE_COUNTER_MAX: usize = 32;
 const FIRMWARE_COUNTER_MAX: usize = 16;
 
+/// PMU activation event and firmware counters
 pub struct PmuState {
-    active_event: [i64; HARDWARE_COUNTER_MAX + FIRMWARE_COUNTER_MAX],
+    active_event: [usize; HARDWARE_COUNTER_MAX + FIRMWARE_COUNTER_MAX],
+    // Firmware counter status mask, each bit represents a firmware counter.
+    // A bit set to 1 indicates that the corresponding firmware counter starts counting
     fw_counter_state: usize,
-    fw_counter: [i64; FIRMWARE_COUNTER_MAX],
+    fw_counter: [u64; FIRMWARE_COUNTER_MAX],
+}
+
+impl PmuState {
+    pub fn new() -> Self {
+        Self {
+            active_event: [0; HARDWARE_COUNTER_MAX + FIRMWARE_COUNTER_MAX],
+            fw_counter_state: 0,
+            fw_counter: [0; FIRMWARE_COUNTER_MAX],
+        }
+    }
+
+    pub fn get_event_idx(&self, counter_idx: usize, firmware_event: bool) -> Option<EventIdx> {
+        let mhpm_mask = hart_mhpm_mask(current_hartid());
+        let hw_counters_num = mhpm_mask.count_ones() as usize;
+        let total_counters_num = hw_counters_num + FIRMWARE_COUNTER_MAX;
+        if counter_idx >= total_counters_num {
+            return None;
+        }
+        if firmware_event && counter_idx <= hw_counters_num {
+            return None;
+        }
+        return Some(EventIdx::new(self.active_event[counter_idx]));
+    }
+
+    pub fn get_fw_counter(&self, counter_idx: usize) -> u64 {
+        // TODO: maybe need to check the validity of counter_idx
+        let hw_counters_num = hart_mhpm_mask(current_hartid()).count_ones() as usize;
+        return self.fw_counter[counter_idx - hw_counters_num];
+    }
 }
 
 struct SbiPmu;
 
+fn get_hpm_csr_offset(counter_idx: usize, mhpm_mask: u32) -> Option<u16> {
+    let mut count = 0;
+    for offset in 0..32 {
+        if (mhpm_mask >> offset) & 1 == 1 {
+            if count == counter_idx {
+                return Some(offset as u16);
+            }
+            count += 1;
+        }
+    }
+    None
+}
+
 impl Pmu for SbiPmu {
     fn num_counters(&self) -> usize {
         hart_mhpm_mask(current_hartid()).count_ones() as usize + FIRMWARE_COUNTER_MAX
     }
 
     fn counter_get_info(&self, counter_idx: usize) -> SbiRet {
-        todo!()
+        let mhpm_mask = hart_mhpm_mask(current_hartid());
+        let hw_counters_num = mhpm_mask.count_ones() as usize;
+        let total_counters_num = hw_counters_num + FIRMWARE_COUNTER_MAX;
+        let mut counter_info = CounterInfo::default();
+        if counter_idx >= total_counters_num {
+            return SbiRet::invalid_param();
+        }
+
+        if counter_idx < hw_counters_num {
+            let o_csr_offset = get_hpm_csr_offset(counter_idx, mhpm_mask);
+            if let Some(csr_offest) = o_csr_offset {
+                counter_info.set_hardware_info(CSR_CYCLE + csr_offest, 63);
+            } else {
+                return SbiRet::invalid_param();
+            }
+        } else {
+            counter_info.set_firmware_info();
+        }
+
+        SbiRet::success(counter_info.inner)
     }
 
     fn counter_config_matching(
@@ -55,11 +123,32 @@ impl Pmu for SbiPmu {
     }
 
     fn counter_fw_read(&self, counter_idx: usize) -> SbiRet {
-        todo!()
+        let o_event_id = hart_context(current_hartid())
+            .pmu_state
+            .get_event_idx(counter_idx, true);
+        if let Some(event_id) = o_event_id {
+            if !event_id.firmware_event_validate() {
+                return SbiRet::invalid_param();
+            }
+
+            if event_id.event_code() == firmware_event::PLATFORM {
+                // TODO: Platform PMU events need to be handled here
+                return SbiRet::invalid_param();
+            }
+
+            let fw_counter_value = hart_context(current_hartid())
+                .pmu_state
+                .get_fw_counter(counter_idx) as usize;
+            return SbiRet::success(fw_counter_value);
+        } else {
+            return SbiRet::invalid_param();
+        }
     }
 
-    fn counter_fw_read_hi(&self, counter_idx: usize) -> SbiRet {
-        todo!()
+    fn counter_fw_read_hi(&self, _counter_idx: usize) -> SbiRet {
+        // The Specification states the this function  always returns zero in sbiret.value for RV64 (or higher) systems.
+        // Currently RustSBI Prototyper only supports RV64 systems
+        SbiRet::success(0)
     }
 
     fn snapshot_set_shmem(&self, shmem: SharedPtr<[u8; SIZE]>, flags: usize) -> SbiRet {
@@ -68,3 +157,134 @@ impl Pmu for SbiPmu {
         SbiRet::not_supported()
     }
 }
+
+struct CounterInfo {
+    inner: usize,
+}
+
+impl Default for CounterInfo {
+    fn default() -> Self {
+        Self { inner: 0 }
+    }
+}
+
+impl CounterInfo {
+    fn set_csr(&mut self, csr_num: u16) {
+        self.inner = (self.inner & !0xFFF) | (csr_num as usize & 0xFFF);
+    }
+
+    fn set_width(&mut self, width: u8) {
+        self.inner = (self.inner & !(0x3F << 12)) | ((width as usize & 0x3F) << 12);
+    }
+
+    fn set_hardware_info(&mut self, csr_num: u16, width: u8) {
+        self.inner = 0;
+        self.set_csr(csr_num);
+        self.set_width(width);
+    }
+
+    fn set_firmware_info(&mut self) {
+        self.inner = 1 << (size_of::<usize>() - 1);
+    }
+}
+
+struct EventToCounterMap {
+    counters_mask: u32,
+    event_start_idx: u32,
+    event_end_id: u32,
+}
+
+struct RawEventToCounterMap {
+    counters_mask: u32,
+    raw_event_select: u64,
+    select_mask: u64,
+}
+
+struct EventIdx {
+    inner: usize,
+}
+
+impl EventIdx {
+    fn new(event_idx: usize) -> Self {
+        Self { inner: event_idx }
+    }
+
+    fn event_type(&self) -> usize {
+        (self.inner >> 16) & 0xF
+    }
+
+    fn event_code(&self) -> usize {
+        self.inner & 0xFFFF
+    }
+
+    fn cache_id(&self) -> usize {
+        (self.inner >> 3) & 0x1FFF
+    }
+
+    fn cache_op_id(&self) -> usize {
+        (self.inner >> 1) & 0x3
+    }
+
+    fn cache_result_id(&self) -> usize {
+        self.inner & 0x1
+    }
+
+    fn validate(&self) -> bool {
+        let event_type = self.event_type();
+        let event_code = self.event_code();
+        match event_type {
+            event_type::HARDWARE_GENERAL => {
+                if event_code > hardware_event::REF_CPU_CYCLES {
+                    return false;
+                }
+            }
+            event_type::HARDWARE_CACHE => {
+                let cache_id = self.cache_id();
+                let cache_op_id = self.cache_op_id();
+                let cache_result_id = self.cache_result_id();
+                if cache_id > cache_event::NODE
+                    || cache_op_id > cache_operation::PREFETCH
+                    || cache_result_id > cache_result::MISS
+                {
+                    return false;
+                }
+            }
+            event_type::HARDWARE_RAW | event_type::HARDWARE_RAW_V2 => {
+                if event_code != 0 {
+                    return false;
+                }
+            }
+            event_type::FIRMWARE => {
+                if (event_code > firmware_event::HFENCE_VVMA_ASID_RECEIVED
+                    && event_code < firmware_event::PLATFORM)
+                    || event_code > firmware_event::PLATFORM
+                {
+                    return false;
+                }
+                if event_code == firmware_event::PLATFORM {
+                    // TODO: should check platform's pmu config
+                    return false;
+                }
+            }
+            _ => {
+                return false;
+            }
+        }
+        true
+    }
+
+    fn firmware_event_validate(&self) -> bool {
+        let event_type = self.event_type();
+        let event_code = self.event_code();
+        if event_type != event_type::FIRMWARE {
+            return false;
+        }
+        if (event_code > firmware_event::HFENCE_VVMA_ASID_RECEIVED
+            && event_code < firmware_event::PLATFORM)
+            || event_code > firmware_event::PLATFORM
+        {
+            return false;
+        }
+        true
+    }
+}

+ 1 - 0
prototyper/prototyper/src/sbi/rfence.rs

@@ -10,6 +10,7 @@ use core::arch::asm;
 
 use core::sync::atomic::{AtomicU32, Ordering};
 
+
 /// Cell for managing remote fence operations between harts.
 pub(crate) struct RFenceCell {
     // Queue of fence operations with source hart ID

+ 1 - 1
prototyper/prototyper/src/sbi/trap/handler.rs

@@ -157,7 +157,7 @@ pub extern "C" fn illegal_instruction_handler(raw_ctx: EntireContext) -> EntireR
 
     let inst = decode(mtval::read() as u32);
     match inst {
-        Ok(Instruction::Csrrs(csr)) => match csr.csr() {
+        Ok(Instruction::Csrrs(csr)) => match csr.csr() as u16 {
             CSR_TIME => {
                 save_reg_x(
                     &mut ctx,

+ 15 - 4
prototyper/prototyper/src/sbi/trap_stack.rs

@@ -42,10 +42,15 @@ pub(crate) fn prepare_for_trap() {
     };
 }
 
-pub fn hart_context(hart_id: usize) -> &'static mut HartContext {
-    unsafe { ROOT_STACK.get_mut(hart_id).unwrap().hart_context() }
+pub fn hart_context_mut(hart_id: usize) -> &'static mut HartContext {
+    unsafe { ROOT_STACK.get_mut(hart_id).unwrap().hart_context_mut() }
 }
 
+pub fn hart_context(hart_id: usize) -> &'static HartContext {
+    unsafe { ROOT_STACK.get(hart_id).unwrap().hart_context() }
+}
+
+
 /// Stack type for each hart.
 ///
 /// Memory layout:
@@ -62,15 +67,21 @@ impl Stack {
 
     /// Gets mutable reference to hart context at bottom of stack.
     #[inline]
-    pub fn hart_context(&mut self) -> &mut HartContext {
+    pub fn hart_context_mut(&mut self) -> &mut HartContext {
         unsafe { &mut *self.0.as_mut_ptr().cast() }
     }
 
+    /// Gets immutable reference to hart context at bottom of stack.
+    #[inline]
+    pub fn hart_context(&self) -> &HartContext {
+        unsafe { &*self.0.as_ptr().cast() }
+    }
+
     /// Initializes stack for trap handling.
     /// - Sets up hart context.
     /// - Creates and loads FreeTrapStack with the stack range.
     fn load_as_stack(&'static mut self) {
-        let hart = self.hart_context();
+        let hart = self.hart_context_mut();
         let context_ptr = hart.context_ptr();
         hart.init();