소스 검색

feat(arch): add fdt parse for riscv64

Heinz 8 달 전
부모
커밋
d6506ec044
7개의 변경된 파일135개의 추가작업 그리고 7개의 파일을 삭제
  1. 7 0
      Cargo.lock
  2. 1 0
      arch/Cargo.toml
  3. 11 1
      arch/src/riscv64/config.rs
  4. 109 0
      arch/src/riscv64/fdt.rs
  5. 4 5
      arch/src/riscv64/init.rs
  6. 1 1
      arch/src/riscv64/mm.rs
  7. 2 0
      arch/src/riscv64/mod.rs

+ 7 - 0
Cargo.lock

@@ -18,6 +18,7 @@ dependencies = [
  "buddy_allocator",
  "cfg-if",
  "eonix_mm",
+ "fdt",
  "intrusive_list",
  "percpu-macros",
  "riscv",
@@ -156,6 +157,12 @@ dependencies = [
  "intrusive-collections",
 ]
 
+[[package]]
+name = "fdt"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
+
 [[package]]
 name = "gbos-rust-part"
 version = "0.1.0"

+ 1 - 0
arch/Cargo.toml

@@ -14,3 +14,4 @@ cfg-if = "1.0"
 sbi = "0.3.0"
 riscv = { version = "0.13.0", features = ["s-mode"] }
 spin = "0.10.0"
+fdt = "0.1.5"

+ 11 - 1
arch/src/riscv64/config.rs

@@ -17,7 +17,17 @@ pub mod mm {
 
 /// smp
 pub mod smp {
-    pub const MAX_HART: usize = 4;
+    use spin::Once;
+
+    pub static NUM_HARTS: Once<usize> = Once::new();
+
+    pub fn set_num_harts(num: usize) {
+        NUM_HARTS.call_once(|| num);
+    }
+
+    pub fn get_num_harts() -> usize {
+        *NUM_HARTS.get().expect("NUM_HARTS should be initialized by now")
+    }
 }
 
 pub mod platform {

+ 109 - 0
arch/src/riscv64/fdt.rs

@@ -0,0 +1,109 @@
+extern crate alloc;
+
+use alloc::{string::String, vec::Vec};
+
+#[derive(Debug, Clone)]
+pub struct HartInfo {
+    pub hart_id: usize,
+    pub compatible: Option<String>,
+}
+
+#[derive(Debug)]
+pub struct CpuManager {
+    pub num_harts: usize,
+    pub harts: Vec<HartInfo>,
+    pub boot_hart_id: usize,
+}
+
+impl CpuManager {
+    pub fn from_fdt(dtb_addr: usize, boot_hart_id: usize) -> Self {
+        let fdt = unsafe {
+            fdt::Fdt::from_ptr(dtb_addr as *const u8)
+                .expect("Failed to parse device tree from dtb_addr")
+        };
+
+        let mut harts_info = Vec::new();
+        let mut num_harts = 0;
+
+        if let Some(cpus_node) = fdt.find_node("/cpus") {
+            for cpu_node in cpus_node.children() {
+                let mut is_riscv_cpu = false;
+                let compatible_string: Option<String> = 
+                    if let Some(compatible_prop) = cpu_node
+                        .properties()
+                        .find(|p| p.name == "compatible")
+                    {
+                        if let Some(s) = compatible_prop.as_str() {
+                            if s.starts_with("riscv,") {
+                                is_riscv_cpu = true;
+                            }
+                            Some(String::from(s))
+                        } else {
+                            None
+                        }
+                    } else {
+                        None
+                    };
+
+                if is_riscv_cpu {
+                    let hart_id = if let Some(hart_id_prop) = cpu_node
+                        .properties()
+                        .find(|p| p.name == "hartid")
+                    {
+                        hart_id_prop.as_usize()
+                            .expect("hartid property in CPU node is not a valid integer")
+                    } else if let Some(reg_prop) = cpu_node
+                        .properties()
+                        .find(|p| p.name == "reg")
+                    {
+                        reg_prop.as_usize()
+                            .expect("reg property in CPU node is not a valid integer for hartid")
+                    } else {
+                        panic!("CPU node {:?} does not have a 'hartid' or 'reg' property required for its ID", cpu_node.name);
+                    };
+
+                    let hart_info = HartInfo {
+                        hart_id,
+                        compatible: compatible_string,
+                    };
+                    harts_info.push(hart_info);
+                    num_harts += 1;
+                }
+            }
+        } else {
+            panic!("Device Tree does not contain a /cpus node!");
+        }
+
+        harts_info.sort_by_key(|h| h.hart_id);
+
+        Self {
+            num_harts,
+            harts: harts_info,
+            boot_hart_id,
+        }
+    }
+}
+
+pub fn get_num_harts(dtb_addr: usize) -> usize {
+    let fdt = unsafe {
+        fdt::Fdt::from_ptr(dtb_addr as *const u8)
+            .expect("Failed to parse device tree from dtb_addr")
+    };
+    let mut num_harts = 0;
+    if let Some(cpus_node) = fdt.find_node("/cpus") {
+        for cpu_node in cpus_node.children() {
+            if let Some(compatible_prop) = cpu_node
+                .properties()
+                .find(|p| p.name == "compatible")
+            {
+                if let Some(s) = compatible_prop.as_str() {
+                    if s.starts_with("riscv,") {
+                        // 找到一个 RISC-V CPU 节点,增加计数。
+                        num_harts += 1;
+                    }
+                }
+            }
+        }
+    }
+    num_harts
+}

+ 4 - 5
arch/src/riscv64/init.rs

@@ -5,10 +5,10 @@ use riscv::{asm::sfence_vma_all, register::{
 use sbi::PhysicalAddress;
 
 /// TODO:
-/// 解析设备树
+/// 中断handler
 /// 
 
-use super::{config::smp::MAX_HART, enable_sse, setup_kernel_page_table, InterruptControl};
+use super::{config::smp::get_num_harts, enable_sse, setup_kernel_satp, InterruptControl};
 
 /// RISC-V Hart
 pub struct CPU {
@@ -54,7 +54,7 @@ impl CPU {
         sstatus::write(current_sstatus);
 
         // setup kernel page table and flush tlb
-        setup_kernel_page_table();
+        setup_kernel_satp();
     }
 
     /// Boot all other hart.
@@ -62,8 +62,7 @@ impl CPU {
         extern "C" {
         fn ap_boot_entry();
         }
-        // TODO: 获取系统中的总 Hart 数量
-        let total_harts = MAX_HART;
+        let total_harts = get_num_harts();
 
         let ap_entry_point = PhysicalAddress::new(ap_boot_entry as usize);
 

+ 1 - 1
arch/src/riscv64/mm.rs

@@ -214,7 +214,7 @@ impl RawAttribute for PageAttribute64 {
 
 pub type DefaultPagingMode = PagingModeSv48;
 
-pub fn setup_kernel_page_table() {
+pub fn setup_kernel_satp() {
     unsafe {
         satp::set(satp::Mode::Sv48, 0, PFN::from(ROOT_PAGE_TABLE_PFN).into());
     }

+ 2 - 0
arch/src/riscv64/mod.rs

@@ -7,6 +7,7 @@ mod fence;
 mod config;
 mod init;
 mod interrupt;
+mod fdt;
 
 pub use self::mm::*;
 pub use self::entry::*;
@@ -17,3 +18,4 @@ pub use self::fence::*;
 pub use self::config::*;
 pub use self::init::*;
 pub use self::interrupt::*;
+pub use self::fdt::*;