Sfoglia il codice sorgente

fix(prototyper): fixed the bug that only can parse the pmu node under the root of the device tree

Signed-off-by: guttatus <[email protected]>
guttatus 1 settimana fa
parent
commit
69b8ae0272

+ 11 - 2
prototyper/prototyper/src/devicetree.rs

@@ -16,8 +16,6 @@ pub struct Tree<'a> {
     pub memory: NodeSeq<'a>,
     /// CPU information.
     pub cpus: Cpus<'a>,
-    /// PMU information
-    pub pmu: Option<Pmu<'a>>,
 }
 
 /// CPU information container.
@@ -103,3 +101,14 @@ pub fn get_compatible_and_range<'de>(node: &Node) -> Option<(StrSeq<'de>, Range<
         None
     }
 }
+
+pub fn get_compatible<'de>(node: &Node) -> Option<StrSeq<'de>> {
+    let compatible = node
+        .get_prop("compatible")
+        .map(|prop_item| prop_item.deserialize::<StrSeq<'de>>());
+    if let Some(compatible) = compatible {
+        Some(compatible)
+    } else {
+        None
+    }
+}

+ 17 - 3
prototyper/prototyper/src/platform/mod.rs

@@ -90,7 +90,7 @@ impl Platform {
         // Get clint and reset device, init sbi ipi, reset, hsm and rfence.
         self.sbi_init_ipi_reset_hsm_rfence(&root);
         // Initialize pmu extension
-        self.sbi_init_pmu(&tree);
+        self.sbi_init_pmu(&root);
         // Get other info
         self.sbi_mics_init(&tree);
 
@@ -160,8 +160,22 @@ impl Platform {
         self.sbi_rfence_init();
     }
 
-    fn sbi_init_pmu(&mut self, tree: &Tree) {
-        if let Some(ref pmu) = tree.pmu {
+    fn sbi_init_pmu(&mut self, root: &serde_device_tree::buildin::Node) {
+        let mut pmu_node: Option<Pmu> = None;
+        let mut find_pmu = |node: &serde_device_tree::buildin::Node| {
+            let info = get_compatible(node);
+            if let Some(compatible_strseq) = info {
+                let compatible_iter = compatible_strseq.iter();
+                for compatible in compatible_iter {
+                    if compatible == "riscv,pmu" {
+                        pmu_node = Some(node.deserialize::<Pmu>());
+                    }
+                }
+            }
+        };
+        root.search(&mut find_pmu);
+
+        if let Some(ref pmu) = pmu_node {
             let sbi_pmu = self.sbi.pmu.get_or_insert_default();
             if let Some(ref event_to_mhpmevent) = pmu.event_to_mhpmevent {
                 let len = event_to_mhpmevent.len();

+ 48 - 5
prototyper/test-kernel/src/main.rs

@@ -10,6 +10,7 @@ use core::{
     arch::{asm, naked_asm},
     ptr::null,
 };
+use riscv::register::cycle;
 use sbi_spec::{
     binary::{CounterMask, HartMask, SbiRet},
     pmu::firmware_event,
@@ -115,7 +116,7 @@ extern "C" fn rust_main(hartid: usize, dtb_pa: usize) -> ! {
     };
     let test_result = testing.test();
 
-    // pmu test, only valid on qemu-system-riscv64 platform
+    // PMU test, only available in qemu-system-riscv64 single core
     let counters_num = sbi::pmu_num_counters();
     println!("[pmu] counters number: {}", counters_num);
     for idx in 0..counters_num {
@@ -133,10 +134,8 @@ extern "C" fn rust_main(hartid: usize, dtb_pa: usize) -> ! {
         }
     }
 
-    // Hardware event
+    /* PMU test for hardware event */
     let counter_mask = CounterMask::from_mask_base(0x7ffff, 0);
-    let result = sbi::pmu_counter_config_matching(counter_mask, Flag::new(0b110), 0x1, 0);
-    assert!(result.is_ok());
     let result = sbi::pmu_counter_config_matching(counter_mask, Flag::new(0b110), 0x2, 0);
     assert!(result.is_ok());
     let result = sbi::pmu_counter_config_matching(counter_mask, Flag::new(0b110), 0x10019, 0);
@@ -148,7 +147,51 @@ extern "C" fn rust_main(hartid: usize, dtb_pa: usize) -> ! {
     let result = sbi::pmu_counter_config_matching(counter_mask, Flag::new(0b110), 0x3, 0);
     assert_eq!(result, SbiRet::not_supported());
 
-    // Firmware  event
+    // `SBI_PMU_HW_CPU_CYCLES` event test
+    let result = sbi::pmu_counter_config_matching(counter_mask, Flag::new(0b010), 0x1, 0);
+    assert!(result.is_ok());
+    // the counter index should be 0(mcycle)
+    assert_eq!(result.value, 0);
+    let cycle_counter_idx = result.value;
+    let cycle_num = cycle::read64();
+    assert_eq!(cycle_num, 0);
+    // Start counting `SBI_PMU_HW_CPU_CYCLES` events
+    let start_result = sbi::pmu_counter_start(
+        CounterMask::from_mask_base(0x1, cycle_counter_idx),
+        Flag::new(0x1),
+        0xffff,
+    );
+    assert!(start_result.is_ok());
+    let cycle_num = cycle::read64();
+    assert!(cycle_num >= 0xffff);
+    // Stop counting `SBI_PMU_HW_CPU_CYCLES` events
+    let stop_result = sbi::pmu_counter_stop(
+        CounterMask::from_mask_base(0x1, cycle_counter_idx),
+        Flag::new(0x0),
+    );
+    assert!(stop_result.is_ok());
+    let old_cycle_num = cycle::read64();
+    let mut _j = 0;
+    for i in 0..1000 {
+        _j += i
+    }
+    let new_cycle_num = cycle::read64();
+    assert_eq!(old_cycle_num, new_cycle_num);
+    // Restart counting `SBI_PMU_HW_CPU_CYCLES` events
+    let start_result = sbi::pmu_counter_start(
+        CounterMask::from_mask_base(0x1, cycle_counter_idx),
+        Flag::new(0x0),
+        0,
+    );
+    assert!(start_result.is_ok());
+    let mut _j = 0;
+    for i in 0..1000 {
+        _j += i
+    }
+    let restart_cycle_num = cycle::read64();
+    assert!(restart_cycle_num > new_cycle_num);
+
+    /* PMU test for firmware  event */
     let counter_mask = CounterMask::from_mask_base(0x7ffffffff, 0);
 
     // Mapping a counter to the `SBI_PMU_FW_ACCESS_LOAD` event should result in unsupported