Browse Source

Count harts from device tree binary on QEMU

luojia65 4 years ago
parent
commit
36ca40b430
5 changed files with 63 additions and 10 deletions
  1. 1 0
      CHANGELOG.md
  2. 1 0
      platform/qemu/Cargo.toml
  3. 1 1
      platform/qemu/justfile
  4. 2 9
      platform/qemu/src/hal/clint.rs
  5. 58 0
      platform/qemu/src/main.rs

+ 1 - 0
CHANGELOG.md

@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added
 - Abstract support for HSM and SRST extensions
 - Support SRST extension using test device on QEMU
+- Count harts from device tree binary on QEMU platform
 
 ### Modified
 - Use '#[naked]' instead of global assembly in newer Rust version for RustSBI platforms

+ 1 - 0
platform/qemu/Cargo.toml

@@ -14,6 +14,7 @@ linked_list_allocator = "0.8"
 lazy_static = { version = "1", features = ["spin_no_std"] }
 spin = "0.7"
 riscv = { git = "https://github.com/rust-embedded/riscv", features = ["inline-asm"] }
+device_tree = { git = "https://github.com/rcore-os/device_tree-rs/" }
 
 # 这几个其实不用,应该使用对应的hal库实现
 embedded-hal = "1.0.0-alpha.1"

+ 1 - 1
platform/qemu/justfile

@@ -8,7 +8,7 @@ objdump := "riscv64-unknown-elf-objdump"
 objcopy := "rust-objcopy --binary-architecture=riscv64"
 gdb := "riscv64-unknown-elf-gdb"
 
-threads := "1"
+threads := "2"
 
 build: firmware
     @{{objcopy}} {{m-firmware-file}} --strip-all -O binary {{m-bin-file}}

+ 2 - 9
platform/qemu/src/hal/clint.rs

@@ -44,15 +44,8 @@ use rustsbi::{HartMask, Ipi, Timer};
 
 impl Ipi for Clint {
     fn max_hart_id(&self) -> usize {
-        /* todo: read from FDT node, instead of hard compile */
-        let ans: usize;
-        unsafe {
-            asm!("
-                lui     {ans}, %hi(_max_hart_id)
-                add     {ans}, {ans}, %lo(_max_hart_id)
-            ", ans = out(reg) ans)
-        };
-        ans
+        // 这个值将在初始化的时候加载,会从dtb_pa读取设备树,然后数里面有几个核
+        *crate::MAX_HART_ID.lock()
     }
 
     fn send_ipi_many(&mut self, hart_mask: HartMask) {

+ 58 - 0
platform/qemu/src/main.rs

@@ -46,6 +46,12 @@ fn oom(_layout: Layout) -> ! {
     loop {}
 }
 
+lazy_static::lazy_static! {
+    // 最大的硬件线程编号;只在启动时写入,跨核软中断发生时读取
+    pub static ref MAX_HART_ID: spin::Mutex<usize> = 
+        spin::Mutex::new(compiled_max_hartid());
+}
+
 // #[export_name = "_mp_hook"]
 pub extern "C" fn mp_hook() -> bool {
     let hartid = mhartid::read();
@@ -208,6 +214,9 @@ fn main() -> ! {
         }
         println!("[rustsbi] mideleg: {:#x}", mideleg::read().bits());
         println!("[rustsbi] medeleg: {:#x}", medeleg::read().bits());
+        let mut guard = MAX_HART_ID.lock();
+        *guard = unsafe { count_harts(dtb_pa) };
+        drop(guard);
         println!("[rustsbi] Kernel entry: 0x80200000");
     }
 
@@ -230,6 +239,55 @@ unsafe extern "C" fn s_mode_start() -> ! {
     ", options(noreturn))
 }
 
+unsafe fn count_harts(dtb_pa: usize) -> usize {
+    use device_tree::{DeviceTree, Node};
+    const DEVICE_TREE_MAGIC: u32 = 0xD00DFEED;
+    // 遍历“cpu_map”结构
+    // 这个结构的子结构是“处理核簇”(cluster)
+    // 每个“处理核簇”的子结构分别表示一个处理器核
+    fn enumerate_cpu_map(cpu_map_node: &Node) -> usize {
+        let mut tot = 0;
+        for cluster_node in cpu_map_node.children.iter() {
+            let name = &cluster_node.name;
+            let count = cluster_node.children.iter().count();
+            // 会输出:Hart count: cluster0 with 2 cores
+            // 在justfile的“threads := "2"”处更改
+            println!("[rustsbi] Hart count: {} with {} cores", name, count);
+            tot += count;
+        }
+        tot
+    }
+    #[repr(C)]
+    struct DtbHeader { magic: u32, size: u32 }
+    let header = &*(dtb_pa as *const DtbHeader);
+    // from_be 是大小端序的转换(from big endian)
+    let magic = u32::from_be(header.magic);
+    if magic == DEVICE_TREE_MAGIC {
+        let size = u32::from_be(header.size);
+        // 拷贝数据,加载并遍历
+        let data = core::slice::from_raw_parts(dtb_pa as *const u8, size as usize);
+        if let Ok(dt) = DeviceTree::load(data) {
+            if let Some(cpu_map) = dt.find("/cpus/cpu-map") {
+                return enumerate_cpu_map(cpu_map)
+            }
+        }
+    }
+    // 如果DTB的结构不对(读不到/cpus/cpu-map),返回默认的8个核
+    let ans = compiled_max_hartid();
+    println!("[rustsbi] Could not read '/cpus/cpu-map' from 'dtb_pa' device tree root; assuming {} cores", ans);
+    ans
+}
+
+#[inline]
+fn compiled_max_hartid() -> usize {
+    let ans;
+    unsafe { asm!("
+        lui     {ans}, %hi(_max_hart_id)
+        add     {ans}, {ans}, %lo(_max_hart_id)
+    ", ans = out(reg) ans) };
+    ans
+}
+
 global_asm!(
     "
     .equ REGBYTES, 8