Browse Source

feat: add get_compatible_and_range for serde_device_tree::Node

feat: find clint and reset device in a better way

Signed-off-by: Woshiluo Luo <woshiluo.luo@outlook.com>
Woshiluo Luo 4 months ago
parent
commit
74f1205c44
3 changed files with 79 additions and 64 deletions
  1. 5 0
      prototyper/src/board.rs
  2. 38 12
      prototyper/src/dt.rs
  3. 36 52
      prototyper/src/main.rs

+ 5 - 0
prototyper/src/board.rs

@@ -14,6 +14,11 @@ use crate::sbi::ipi::IpiDevice;
 use crate::sbi::reset::ResetDevice;
 use crate::sbi::Sbi;
 
+pub(crate) const UART16650_COMPATIBLE: &str = "ns16550a";
+pub(crate) const UARTAXILITE_COMPATIBLE: &str = "xlnx,xps-uartlite-1.00.a";
+pub(crate) const SIFIVETEST_COMPATIBLE: &str = "sifive,test0";
+pub(crate) const SIFIVECLINT_COMPATIBLE: &str = "riscv,clint0";
+
 pub struct Device {
     pub memory_range: Option<Range<usize>>,
     pub uart: Option<Mutex<MachineConsole>>,

+ 38 - 12
prototyper/src/dt.rs

@@ -1,9 +1,11 @@
 use serde::Deserialize;
 use serde_device_tree::{
-    buildin::{NodeSeq, Reg, StrSeq},
+    buildin::{Node, NodeSeq, Reg, StrSeq},
     Dtb, DtbPtr,
 };
 
+use core::ops::Range;
+
 /// Root device tree structure containing system information.
 #[derive(Deserialize)]
 pub struct Tree<'a> {
@@ -15,8 +17,6 @@ pub struct Tree<'a> {
     pub memory: NodeSeq<'a>,
     /// CPU information.
     pub cpus: Cpus<'a>,
-    /// System-on-chip components.
-    pub soc: Soc<'a>,
 }
 
 /// Chosen node containing boot parameters.
@@ -45,15 +45,6 @@ pub struct Cpu<'a> {
     pub reg: Reg<'a>,
 }
 
-/// System-on-chip components.
-#[derive(Deserialize, Debug)]
-pub struct Soc<'a> {
-    /// Test device nodes.
-    pub test: Option<NodeSeq<'a>>,
-    /// CLINT (Core Local Interruptor) nodes.
-    pub clint: Option<NodeSeq<'a>>,
-}
-
 /// Generic device node information.
 #[allow(unused)]
 #[derive(Deserialize, Debug)]
@@ -82,3 +73,38 @@ pub fn parse_device_tree(opaque: usize) -> Result<Dtb, ParseDeviceTreeError> {
     let dtb = Dtb::from(ptr);
     Ok(dtb)
 }
+
+pub fn get_compatible_and_range<'de>(node: &Node) -> Option<(StrSeq<'de>, Range<usize>)> {
+    let compatible = node
+        .props()
+        .map(|mut prop_iter| {
+            prop_iter
+                .find(|prop_item| prop_item.get_name() == "compatible")
+                .map(|prop_item| prop_item.deserialize::<serde_device_tree::buildin::StrSeq>())
+        })
+        .map_or_else(|| None, |v| v);
+    let regs = node
+        .props()
+        .map(|mut prop_iter| {
+            prop_iter
+                .find(|prop_item| prop_item.get_name() == "reg")
+                .map(|prop_item| {
+                    let reg = prop_item.deserialize::<serde_device_tree::buildin::Reg>();
+                    if let Some(range) = reg.iter().next() {
+                        return Some(range);
+                    }
+                    None
+                })
+                .map_or_else(|| None, |v| v)
+        })
+        .map_or_else(|| None, |v| v);
+    if let Some(compatible) = compatible {
+        if let Some(regs) = regs {
+            Some((compatible, regs.0))
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}

+ 36 - 52
prototyper/src/main.rs

@@ -58,68 +58,52 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
             serde_device_tree::from_raw_mut(&dtb).unwrap_or_else(fail::device_tree_deserialize);
         // 2. Init device
         // TODO: The device base address should be find in a better way.
-        'console_finder: for console_path in tree.chosen.stdout_path.iter() {
+        for console_path in tree.chosen.stdout_path.iter() {
             if let Some(node) = root.find(console_path) {
-                let compatible = node
-                    .props()
-                    .map(|mut prop_iter| {
-                        prop_iter
-                            .find(|prop_item| prop_item.get_name() == "compatible")
-                            .map(|prop_item| {
-                                prop_item.deserialize::<serde_device_tree::buildin::StrSeq>()
-                            })
-                    })
-                    .map_or_else(|| None, |v| v);
-                let regs = node
-                    .props()
-                    .map(|mut prop_iter| {
-                        prop_iter
-                            .find(|prop_item| prop_item.get_name() == "reg")
-                            .map(|prop_item| {
-                                let reg =
-                                    prop_item.deserialize::<serde_device_tree::buildin::Reg>();
-                                if let Some(range) = reg.iter().next() {
-                                    return Some(range);
-                                }
-                                None
-                            })
-                            .map_or_else(|| None, |v| v)
-                    })
-                    .map_or_else(|| None, |v| v);
-                if compatible.is_some() && regs.is_some() {
-                    for device_id in compatible.unwrap().iter() {
-                        if device_id == "ns16550a" {
-                            board::console_dev_init(
-                                MachineConsoleType::Uart16550,
-                                regs.unwrap().0.start,
-                            );
-                            break 'console_finder;
+                let info = dt::get_compatible_and_range(&node);
+                let result = info.is_some_and(|info| {
+                    let (compatible, regs) = info;
+                    for device_id in compatible.iter() {
+                        if device_id == board::UART16650_COMPATIBLE {
+                            board::console_dev_init(MachineConsoleType::Uart16550, regs.start);
+                            return true;
                         }
-                        if device_id == "xlnx,xps-uartlite-1.00.a" {
-                            board::console_dev_init(
-                                MachineConsoleType::UartAxiLite,
-                                regs.unwrap().0.start,
-                            );
-                            break 'console_finder;
+                        if device_id == board::UARTAXILITE_COMPATIBLE {
+                            board::console_dev_init(MachineConsoleType::UartAxiLite, regs.start);
+                            return true;
                         }
                     }
+                    false
+                });
+                if result {
+                    break;
                 }
             }
         }
 
-        let clint_device = tree.soc.clint.unwrap().iter().next().unwrap();
+        let mut clint_device_address: Option<usize> = None;
+        let mut find_device = |node: &serde_device_tree::buildin::Node| {
+            let info = dt::get_compatible_and_range(node);
+            if let Some(info) = info {
+                let (compatible, regs) = info;
+                let base_address = regs.start;
+                for device_id in compatible.iter() {
+                    // Initialize clint device.
+                    if device_id == board::SIFIVECLINT_COMPATIBLE {
+                        clint_device_address = Some(base_address);
+                        board::ipi_dev_init(base_address);
+                    }
+                    // Initialize reset device.
+                    if device_id == board::SIFIVETEST_COMPATIBLE {
+                        board::reset_dev_init(base_address);
+                    }
+                }
+            }
+        };
+        root.search(&mut find_device);
         let cpu_num = tree.cpus.cpu.len();
-        let ipi_base_address = clint_device.at();
-
-        // Initialize reset device if present.
-        if let Some(test) = tree.soc.test {
-            let reset_device = test.iter().next().unwrap();
-            let reset_base_address = reset_device.at();
-            board::reset_dev_init(usize::from_str_radix(reset_base_address, 16).unwrap());
-        }
 
         // Initialize console and IPI devices.
-        board::ipi_dev_init(usize::from_str_radix(ipi_base_address, 16).unwrap());
 
         // 3. Init the SBI implementation
         // TODO: More than one memory node or range?
@@ -160,7 +144,7 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
         if let Some(model) = tree.model {
             info!("Model: {}", model.iter().next().unwrap_or("<unspecified>"));
         }
-        info!("Clint device: {}", ipi_base_address);
+        info!("Clint device: {:x?}", clint_device_address);
         info!(
             "Chosen stdout item: {}",
             tree.chosen