diff --git a/examples/qemu-virt.rs b/examples/qemu-virt.rs index 4f22fd3..dd3acd9 100644 --- a/examples/qemu-virt.rs +++ b/examples/qemu-virt.rs @@ -103,7 +103,8 @@ fn main() -> Result<(), Error> { { // 解析! - let t: Tree = from_raw_mut(&dtb).unwrap(); + let root: Node = from_raw_mut(&dtb).unwrap(); + let t: Tree = root.deserialize(); println!("model = {:?}", t.model); println!("compatible = {:?}", t.compatible); @@ -133,7 +134,7 @@ fn main() -> Result<(), Error> { } println!("{:?}", t.soc); - for current_node in t.soc.nodes().unwrap() { + for current_node in t.soc.nodes() { if current_node.get_parsed_name().0 == "virtio_mmio" { let mmio = current_node.deserialize::(); println!("{:?} {:?}", current_node.get_parsed_name(), mmio.reg); @@ -142,7 +143,7 @@ fn main() -> Result<(), Error> { // 解析过程中,设备树的内容被修改了。 // 因此若要以其他方式再次访问设备树,先将这次解析的结果释放。 - assert_ne!(slice, RAW_DEVICE_TREE); + // assert_ne!(slice, RAW_DEVICE_TREE); } // 释放后,内存会恢复原状。 assert_eq!(slice, RAW_DEVICE_TREE); diff --git a/src/de.rs b/src/de.rs index bd2629f..93b9c1a 100644 --- a/src/de.rs +++ b/src/de.rs @@ -31,7 +31,7 @@ use serde::de; /// # Example /// /// ``` -/// # static RAW_DEVICE_TREE: &'static [u8] = include_bytes!("../examples/hifive-unmatched-a00.dtb"); +/// # const RAW_DEVICE_TREE: &'static [u8] = include_bytes!("../examples/hifive-unmatched-a00.dtb"); /// # const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); /// # #[repr(align(4))] /// # struct AlignedBuffer { @@ -521,7 +521,7 @@ mod tests { #[cfg(any(feature = "std", feature = "alloc"))] #[test] fn error_invalid_magic() { - static DEVICE_TREE: &[u8] = &[0x11, 0x22, 0x33, 0x44]; // not device tree blob format + const DEVICE_TREE: &[u8] = &[0x11, 0x22, 0x33, 0x44]; // not device tree blob format const DEVICE_TREE_LEN: usize = DEVICE_TREE.len(); #[repr(align(8))] struct AlignedBuffer { diff --git a/src/de_mut/cursor.rs b/src/de_mut/cursor.rs index df27d65..dadb5cc 100644 --- a/src/de_mut/cursor.rs +++ b/src/de_mut/cursor.rs @@ -129,16 +129,18 @@ impl TitleCursor { /// 切分节点名。 pub fn split_on<'de>(&self, dtb: RefDtb<'de>) -> (&'de str, BodyCursor) { let mut index = self.0 + 1; + let mut len = 0; let structure = &dtb.borrow().structure; - let ptr = structure[index..].as_ptr() as *const u8; while let Some(block) = structure.get(index) { index += 1; if block.is_end_of_str() { let end = block.str_end(); - let s = unsafe { core::slice::from_raw_parts(ptr, end.offset_from(ptr) as _) }; - let s = unsafe { core::str::from_utf8_unchecked(s) }; + len += end; + let s = structure[self.0 + 1].lead_str(len); return (s, AnyCursor(index, PhantomData)); + } else { + len += 4; } } todo!() @@ -158,12 +160,7 @@ impl TitleCursor { body.skip_str_on(dtb); body.escape_from(dtb); if let Cursor::Title(c) = body.move_on(dtb) { - let s = unsafe { - core::slice::from_raw_parts( - structure[c.0 + 1..].as_ptr() as *const u8, - name_bytes.len() + 1, - ) - }; + let s = structure[c.0 + 1].lead_slice(name_bytes.len() + 1); if let [name @ .., b'@'] = s { if name == name_bytes { body.0 += 1 + name_skip; @@ -213,7 +210,7 @@ impl PropCursor { pub fn data_on<'a>(&self, dtb: RefDtb<'a>) -> &'a [u8] { if let [_, len_data, _, data @ ..] = &dtb.borrow().structure[self.0..] { - unsafe { core::slice::from_raw_parts(data.as_ptr() as _, len_data.as_usize()) } + data[0].lead_slice(len_data.as_usize()) } else { todo!() } @@ -221,7 +218,7 @@ impl PropCursor { pub fn map_on(&self, dtb: RefDtb<'_>, f: impl FnOnce(&[u8]) -> T) -> T { if let [_, len_data, _, data @ ..] = &dtb.borrow().structure[self.0..] { - f(unsafe { core::slice::from_raw_parts(data.as_ptr() as _, len_data.as_usize()) }) + f(data[0].lead_slice(len_data.as_usize())) } else { todo!() } @@ -246,16 +243,6 @@ impl PropCursor { )) } } - - pub fn operate_on(&self, dtb: RefDtb<'_>, f: impl FnOnce(&mut [u8])) { - if let [_, len_data, _, data @ ..] = &mut dtb.borrow_mut().structure[self.0..] { - f(unsafe { - core::slice::from_raw_parts_mut(data.as_mut_ptr() as _, len_data.as_usize()) - }); - } else { - todo!() - } - } } #[derive(Debug)] diff --git a/src/de_mut/data.rs b/src/de_mut/data.rs index 0074c1c..9145ccd 100644 --- a/src/de_mut/data.rs +++ b/src/de_mut/data.rs @@ -239,37 +239,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { if name == super::VALUE_DESERIALIZER_NAME { return visitor.visit_newtype_struct(self); } - match self.cursor { - ValueCursor::Prop(_, cursor) => match name { - "StrSeq" => { - let inner = super::str_seq::Inner { - dtb: self.dtb, - cursor, - }; - visitor.visit_borrowed_bytes(unsafe { - core::slice::from_raw_parts( - &inner as *const _ as *const u8, - core::mem::size_of_val(&inner), - ) - }) - } - "Reg" => { - let inner = super::reg::Inner { - dtb: self.dtb, - reg: self.reg, - cursor, - }; - visitor.visit_borrowed_bytes(unsafe { - core::slice::from_raw_parts( - &inner as *const _ as *const u8, - core::mem::size_of_val(&inner), - ) - }) - } - _ => visitor.visit_newtype_struct(self), - }, - ValueCursor::Body(_) => visitor.visit_newtype_struct(self), - } + unreachable!("unknown newtype struct"); } fn deserialize_seq(self, visitor: V) -> Result diff --git a/src/de_mut/node.rs b/src/de_mut/node.rs index 25b883d..60667b6 100644 --- a/src/de_mut/node.rs +++ b/src/de_mut/node.rs @@ -4,11 +4,14 @@ use core::marker::PhantomData; use serde::de::MapAccess; use serde::{de, Deserialize}; +// TODO: Spec 2.3.5 said that we should not inherited from ancestors and the size-cell & +// address-cells should only used for current node's children. #[allow(unused)] #[derive(Clone)] pub struct Node<'de> { dtb: RefDtb<'de>, reg: RegConfig, + cursor: BodyCursor, props_start: Option, nodes_start: Option, } @@ -16,7 +19,7 @@ pub struct Node<'de> { /// 节点迭代器。 pub struct NodeIter<'de, 'b> { node: &'b Node<'de>, - cursor: BodyCursor, + cursor: Option, i: usize, } @@ -31,7 +34,7 @@ pub struct NodeItem<'de> { /// 属性迭代器。 pub struct PropIter<'de, 'b> { node: &'b Node<'de>, - cursor: BodyCursor, + cursor: Option, i: usize, } @@ -46,23 +49,37 @@ pub struct PropItem<'de> { } impl<'de> Node<'de> { + pub fn deserialize>(&self) -> T { + use super::ValueCursor; + T::deserialize(&mut ValueDeserializer { + dtb: self.dtb, + reg: self.reg, + cursor: ValueCursor::Body(self.cursor), + }) + .unwrap() + } // TODO: Maybe use BTreeMap when have alloc /// 获得节点迭代器。 - pub fn nodes<'b>(&'b self) -> Option> { - self.nodes_start.map(|node_cursor| NodeIter { + pub fn nodes<'b>(&'b self) -> NodeIter<'de, 'b> { + NodeIter { node: self, - cursor: node_cursor, + cursor: self.nodes_start, i: 0, - }) + } } /// 获得属性迭代器。 - pub fn props<'b>(&'b self) -> Option> { - self.props_start.map(|node_cursor| PropIter { + pub fn props<'b>(&'b self) -> PropIter<'de, 'b> { + PropIter { node: self, - cursor: node_cursor, + cursor: self.props_start, i: 0, - }) + } + } + + /// 尝试获得指定属性 + pub fn get_prop<'b>(&'b self, name: &str) -> Option> { + self.props().find(|prop| prop.get_name() == name) } } @@ -70,30 +87,26 @@ impl Debug for Node<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let props = self.props(); write!(f, "Props: [")?; - if let Some(s) = props { - let mut first_written = true; - for prop in s { - if first_written { - write!(f, "\"{}\"", prop.get_name())?; - first_written = false; - } else { - write!(f, ",\"{}\"", prop.get_name())?; - } + let mut first_written = true; + for prop in props { + if first_written { + write!(f, "\"{}\"", prop.get_name())?; + first_written = false; + } else { + write!(f, ",\"{}\"", prop.get_name())?; } } writeln!(f, "]")?; let children = self.nodes(); write!(f, "Children: [")?; - if let Some(s) = children { - let mut first_written = true; - for child in s { - if first_written { - write!(f, "\"{}\"", child.get_full_name())?; - first_written = false; - } else { - write!(f, ",\"{}\"", child.get_full_name())?; - } + let mut first_written = true; + for child in children { + if first_written { + write!(f, "\"{}\"", child.get_full_name())?; + first_written = false; + } else { + write!(f, ",\"{}\"", child.get_full_name())?; } } writeln!(f, "]")?; @@ -106,19 +119,23 @@ impl<'de> Iterator for NodeIter<'de, '_> { type Item = NodeItem<'de>; fn next(&mut self) -> Option { - self.i += 1; - let dtb = self.node.dtb; - if let Cursor::Title(c) = self.cursor.move_on(dtb) { - let (name, _) = c.split_on(dtb); - let (node_cursor, next) = c.take_node_on(dtb, name); - let res = Some(Self::Item { - dtb, - reg: self.node.reg, - node: node_cursor, - name, - }); - self.cursor = next; - res + if let Some(ref mut cursor) = self.cursor { + self.i += 1; + let dtb = self.node.dtb; + if let Cursor::Title(c) = cursor.move_on(dtb) { + let (name, _) = c.split_on(dtb); + let (node_cursor, next) = c.take_node_on(dtb, name); + let res = Some(Self::Item { + dtb, + reg: self.node.reg, + node: node_cursor, + name, + }); + *cursor = next; + res + } else { + None + } } else { None } @@ -129,19 +146,23 @@ impl<'de> Iterator for PropIter<'de, '_> { type Item = PropItem<'de>; fn next(&mut self) -> Option { - self.i += 1; - let dtb = self.node.dtb; - if let Cursor::Prop(c) = self.cursor.move_on(dtb) { - let (name, next) = c.name_on(dtb); - let res = Some(Self::Item { - dtb, - body: self.cursor, - reg: self.node.reg, - prop: c, - name, - }); - self.cursor = next; - res + if let Some(ref mut cursor) = self.cursor { + self.i += 1; + let dtb = self.node.dtb; + if let Cursor::Prop(c) = cursor.move_on(dtb) { + let (name, next) = c.name_on(dtb); + let res = Some(Self::Item { + dtb, + body: *cursor, + reg: self.node.reg, + prop: c, + name, + }); + *cursor = next; + res + } else { + None + } } else { None } @@ -173,10 +194,17 @@ impl<'de> Deserialize<'de> for Node<'_> { let mut reg: Option = None; let mut props_start: Option = None; let mut nodes_start: Option = None; + let mut self_cursor: Option = None; while let Some((key, value)) = access.next_entry::<&str, ValueDeserializer<'b>>()? { dtb = Some(value.dtb); reg = Some(value.reg); if key == "/" { + self_cursor = match value.cursor { + ValueCursor::Body(cursor) => Some(cursor), + ValueCursor::Prop(_, _) => { + unreachable!("root of NodeSeq shouble be body cursor") + } + }; continue; } match value.cursor { @@ -196,6 +224,7 @@ impl<'de> Deserialize<'de> for Node<'_> { Ok(Node { dtb: dtb.unwrap(), reg: reg.unwrap(), + cursor: self_cursor.unwrap(), nodes_start, props_start, }) @@ -259,3 +288,28 @@ impl<'de> PropItem<'de> { .unwrap() } } + +#[cfg(test)] +mod tests { + use crate::{buildin::Node, from_raw_mut, Dtb, DtbPtr}; + const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/hifive-unmatched-a00.dtb"); + const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); + #[repr(align(8))] + struct AlignedBuffer { + pub data: [u8; RAW_DEVICE_TREE.len()], + } + #[test] + fn test_find_prop() { + let mut aligned_data: Box = Box::new(AlignedBuffer { + data: [0; BUFFER_SIZE], + }); + aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); + let mut slice = aligned_data.data.to_vec(); + let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); + let dtb = Dtb::from(ptr).share(); + + let node: Node = from_raw_mut(&dtb).unwrap(); + let prop = node.get_prop("compatible"); + assert!(prop.is_some()); + } +} diff --git a/src/de_mut/node_seq.rs b/src/de_mut/node_seq.rs index f3d1089..bcc4808 100644 --- a/src/de_mut/node_seq.rs +++ b/src/de_mut/node_seq.rs @@ -1,4 +1,4 @@ -use super::{BodyCursor, Cursor, RefDtb, RegConfig, ValueCursor, ValueDeserializer}; +use super::{BodyCursor, Cursor, RefDtb, RegConfig, ValueCursor, ValueDeserializer}; use core::{fmt::Debug, marker::PhantomData}; use serde::de::SeqAccess; use serde::{de, Deserialize}; @@ -63,9 +63,7 @@ impl<'de> Deserialize<'de> for NodeSeq<'_> { Cursor::Title(c) => { let (name, _) = c.split_on(starter.dtb); - let pre_len = name.as_bytes().iter().take_while(|b| **b != b'@').count(); - let name_bytes = &name.as_bytes()[..pre_len]; - let name = unsafe { core::str::from_utf8_unchecked(name_bytes) }; + let (name, _) = name.split_once('@').unwrap_or((name, "")); Ok(NodeSeq { name, count, @@ -137,14 +135,8 @@ impl<'de> Iterator for NodeSeqIter<'de, '_> { let (full_name, _) = c.split_on(self.de.dtb); let (node, next) = c.take_node_on(self.de.dtb, full_name); - let pre_len = full_name - .as_bytes() - .iter() - .take_while(|b| **b != b'@') - .count(); - let name_bytes = &full_name.as_bytes()[..pre_len]; - let name = unsafe { core::str::from_utf8_unchecked(name_bytes) }; - if self.seq.name != name { + let (pre_name, suf_name) = full_name.split_once('@').unwrap_or((full_name, "")); + if self.seq.name != pre_name { return None; } @@ -154,7 +146,7 @@ impl<'de> Iterator for NodeSeqIter<'de, '_> { dtb: self.de.dtb, reg: self.de.reg, body: node, - at: &full_name[pre_len + 1..], + at: suf_name, }) } _ => None, diff --git a/src/de_mut/reg.rs b/src/de_mut/reg.rs index cd2f4ac..b29cb93 100644 --- a/src/de_mut/reg.rs +++ b/src/de_mut/reg.rs @@ -1,6 +1,6 @@ -use super::{PropCursor, RefDtb, StructureBlock, BLOCK_LEN}; -use core::{fmt::Debug, marker::PhantomData, mem::MaybeUninit, ops::Range}; -use serde::{de, Deserialize}; +use super::{PropCursor, RefDtb, ValueCursor, BLOCK_LEN}; +use core::{fmt::Debug, ops::Range}; +use serde::Deserialize; /// 节点地址空间。 pub struct Reg<'de>(Inner<'de>); @@ -24,8 +24,8 @@ pub struct RegRegion(pub Range); #[derive(Clone, Copy, Debug)] #[repr(C)] pub(super) struct RegConfig { - pub address_cells: u32, - pub size_cells: u32, + pub address_cells: usize, + pub size_cells: usize, } impl RegConfig { @@ -40,58 +40,24 @@ impl<'de> Deserialize<'de> for Reg<'_> { where D: serde::Deserializer<'de>, { - struct Visitor<'de, 'b> { - marker: PhantomData>, - lifetime: PhantomData<&'de ()>, - } - impl<'de, 'b> de::Visitor<'de> for Visitor<'de, 'b> { - type Value = Reg<'b>; - - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(formatter, "struct Reg") - } + let value_deserialzer = super::ValueDeserializer::deserialize(deserializer)?; - fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result - where - E: de::Error, - { - // 结构体转为内存切片,然后拷贝过来 - if v.len() == core::mem::size_of::() { - Ok(Self::Value::from_raw_parts(v.as_ptr())) - } else { - Err(E::invalid_length( - v.len(), - &"`Reg` is copied with wrong size.", - )) + let inner = Inner { + dtb: value_deserialzer.dtb, + reg: value_deserialzer.reg, + cursor: match value_deserialzer.cursor { + ValueCursor::Prop(_, cursor) => cursor, + _ => { + unreachable!("Reg Deserialize should only be called by prop cursor") } - } - } - - serde::Deserializer::deserialize_newtype_struct( - deserializer, - "Reg", - Visitor { - marker: PhantomData, - lifetime: PhantomData, }, - ) + }; + + Ok(Self(inner)) } } impl Reg<'_> { - fn from_raw_parts(ptr: *const u8) -> Self { - // 直接从指针拷贝 - unsafe { - let mut res = MaybeUninit::::uninit(); - core::ptr::copy_nonoverlapping( - ptr, - res.as_mut_ptr() as *mut _, - core::mem::size_of::(), - ); - res.assume_init() - } - } - pub fn iter(&self) -> RegIter { RegIter { data: self.0.cursor.data_on(self.0.dtb), @@ -119,23 +85,30 @@ impl Iterator for RegIter<'_> { type Item = RegRegion; fn next(&mut self) -> Option { - let len = BLOCK_LEN * (self.config.address_cells + self.config.size_cells) as usize; + let len = BLOCK_LEN * (self.config.address_cells + self.config.size_cells); if self.data.len() >= len { - let mut block = self.data.as_ptr() as *const StructureBlock; - self.data = &self.data[len..]; + let (current_block, data) = self.data.split_at(len); + self.data = data; let mut base = 0; let mut len = 0; + let mut block_id = 0; for _ in 0..self.config.address_cells { - unsafe { - base = (base << 32) | (*block).as_usize(); - block = block.offset(1); - } + base = (base << 32) + | u32::from_be_bytes( + current_block[block_id * 4..(block_id + 1) * 4] + .try_into() + .unwrap(), + ) as usize; + block_id += 1; } for _ in 0..self.config.size_cells { - unsafe { - len = (len << 32) | (*block).as_usize(); - block = block.offset(1); - } + len = (len << 32) + | u32::from_be_bytes( + current_block[block_id * 4..(block_id + 1) * 4] + .try_into() + .unwrap(), + ) as usize; + block_id += 1; } Some(RegRegion(base..base + len)) } else { diff --git a/src/de_mut/str_seq.rs b/src/de_mut/str_seq.rs index 086d390..897d64e 100644 --- a/src/de_mut/str_seq.rs +++ b/src/de_mut/str_seq.rs @@ -1,6 +1,6 @@ -use super::{PropCursor, RefDtb}; -use core::{fmt::Debug, marker::PhantomData, mem::MaybeUninit}; -use serde::{de, Deserialize}; +use super::{PropCursor, RefDtb, ValueCursor}; +use core::fmt::Debug; +use serde::Deserialize; /// 一组 '\0' 分隔字符串的映射。 /// @@ -31,70 +31,23 @@ impl<'de> Deserialize<'de> for StrSeq<'_> { where D: serde::Deserializer<'de>, { - struct Visitor<'de, 'b> { - marker: PhantomData>, - lifetime: PhantomData<&'de ()>, - } - impl<'de, 'b> de::Visitor<'de> for Visitor<'de, 'b> { - type Value = StrSeq<'b>; - - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(formatter, "struct StrSeq") - } + let value_deserialzer = super::ValueDeserializer::deserialize(deserializer)?; - fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result - where - E: de::Error, - { - // 结构体转为内存切片,然后拷贝过来 - if v.len() == core::mem::size_of::() { - Ok(Self::Value::from_raw_parts(v.as_ptr())) - } else { - Err(E::invalid_length( - v.len(), - &"`StrSeq` is copied with wrong size.", - )) + let inner = Inner { + dtb: value_deserialzer.dtb, + cursor: match value_deserialzer.cursor { + ValueCursor::Prop(_, cursor) => cursor, + _ => { + unreachable!("StrSeq Deserialize should only be called by prop cursor") } - } - } - - serde::Deserializer::deserialize_newtype_struct( - deserializer, - "StrSeq", - Visitor { - marker: PhantomData, - lifetime: PhantomData, }, - ) + }; + + Ok(Self(inner)) } } impl StrSeq<'_> { - fn from_raw_parts(ptr: *const u8) -> Self { - // 直接从指针拷贝 - let res = unsafe { - let mut res = MaybeUninit::::uninit(); - core::ptr::copy_nonoverlapping( - ptr, - res.as_mut_ptr() as *mut _, - core::mem::size_of::(), - ); - res.assume_init() - }; - // 初始化 - res.0.cursor.operate_on(res.0.dtb, |data| { - let mut i = data.len() - 1; - for j in (0..data.len() - 1).rev() { - if data[j] == b'\0' { - data[i] = (i - j - 1) as _; - i = j; - } - } - data[i] = i as u8; - }); - res - } - /// 构造一个可访问每个字符串的迭代器。 pub fn iter(&self) -> StrSeqIter { StrSeqIter { @@ -125,27 +78,15 @@ impl<'de> Iterator for StrSeqIter<'de> { if self.data.is_empty() { None } else { - let len = *self.data.last().unwrap() as usize; - let (a, b) = self.data.split_at(self.data.len() - len - 1); - self.data = a; - Some(unsafe { core::str::from_utf8_unchecked(&b[..len]) }) + let pos = self + .data + .iter() + .position(|&x| x == b'\0') + .unwrap_or(self.data.len()); + let (a, b) = self.data.split_at(pos + 1); + self.data = b; + // Remove \0 at end + Some(unsafe { core::str::from_utf8_unchecked(&a[..a.len() - 1]) }) } } } - -impl Drop for StrSeq<'_> { - fn drop(&mut self) { - self.0.cursor.operate_on(self.0.dtb, |data| { - let mut idx = data.len() - 1; - loop { - let len = data[idx] as usize; - data[idx] = 0; - if idx > len { - idx -= len + 1; - } else { - break; - } - } - }) - } -} diff --git a/src/de_mut/struct_access.rs b/src/de_mut/struct_access.rs index 13e86ac..fdfcc82 100644 --- a/src/de_mut/struct_access.rs +++ b/src/de_mut/struct_access.rs @@ -56,9 +56,9 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { Cursor::Title(c) => { let (name, _) = c.split_on(self.de.dtb); - let pre_len = name.as_bytes().iter().take_while(|b| **b != b'@').count(); + let (pre_name, _) = name.split_once('@').unwrap_or((name, "")); // 子节点名字不带 @ 或正在解析 Node 类型 - if pre_len == name.as_bytes().len() || check_contains(name) { + if pre_name == name || check_contains(name) { let (node, next) = c.take_node_on(self.de.dtb, name); self.de.cursor = ValueCursor::Body(next); if check_contains(name) { @@ -68,13 +68,11 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { } // @ 之前的部分是真正的名字,用这个名字搜索连续的一组 else { - let name_bytes = &name.as_bytes()[..pre_len]; - let name = unsafe { core::str::from_utf8_unchecked(name_bytes) }; - let (group, _, next) = c.take_group_on(self.de.dtb, name); + let (group, _, next) = c.take_group_on(self.de.dtb, pre_name); self.de.cursor = ValueCursor::Body(next); - if check_contains(name) { + if check_contains(pre_name) { self.temp = Temp::Group(group); - break name; + break pre_name; } } } @@ -84,10 +82,10 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { self.de.cursor = ValueCursor::Body(next); match name { "#address-cells" => { - self.de.reg.address_cells = c.map_u32_on(self.de.dtb)?; + self.de.reg.address_cells = c.map_u32_on(self.de.dtb)? as usize; } "#size-cells" => { - self.de.reg.size_cells = c.map_u32_on(self.de.dtb)?; + self.de.reg.size_cells = c.map_u32_on(self.de.dtb)? as usize; } _ => {} } diff --git a/src/de_mut/structs.rs b/src/de_mut/structs.rs index 88b5481..b31d038 100644 --- a/src/de_mut/structs.rs +++ b/src/de_mut/structs.rs @@ -19,21 +19,23 @@ impl TryFrom for DtbPtr { } impl DtbPtr { + const fn get_header(ptr: &*mut u8) -> &Header { + unsafe { &*(*ptr as *const Header) } + } + /// 验证指针指向的设备树,并构造 `DtbPtr`。 pub fn from_raw(ptr: *mut u8) -> Result { - let ptr = ptr as usize; - if ptr & (ALIGN - 1) != 0 { - Err(DtError::unaligned(ptr)) + if (ptr as usize) & (ALIGN - 1) != 0 { + Err(DtError::unaligned(ptr as _)) } else { - unsafe { &*(ptr as *const Header) } - .verify() - .map(|_| Self(ptr)) + { Self::get_header(&ptr) }.verify().map(|_| Self(ptr as _)) } } /// 计算能容纳整个设备树的最小对齐。 pub const fn align(&self) -> usize { - let header = unsafe { &*(self.0 as *const Header) }; + let ptr = self.0 as *mut u8; + let header = Self::get_header(&ptr); let len = u32::from_be(header.total_size) as usize; let mut res = ALIGN; while res < len { @@ -76,14 +78,13 @@ impl StructureBlock { } /// '\0' 结尾字符串的实际结尾。 - pub fn str_end(&self) -> *const u8 { - let remnant = match self.0.to_ne_bytes() { + pub fn str_end(&self) -> usize { + match self.0.to_ne_bytes() { [0, _, _, _] => 0, [_, 0, _, _] => 1, [_, _, 0, _] => 2, [_, _, _, _] => 3, - }; - unsafe { (self as *const _ as *const u8).add(remnant) } + } } /// 转换为描述字节长度或偏移的数值。 @@ -93,11 +94,16 @@ impl StructureBlock { /// 构造字节切片。 /// - /// TODO - #[allow(unused)] + /// ### Safety + /// + /// 保证 当前位置 + 长度 不会超过文件大小。 pub fn lead_slice<'a>(&self, len: usize) -> &'a [u8] { unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, len) } } + pub fn lead_str<'a>(&self, len: usize) -> &'a str { + let slice = self.lead_slice(len); + unsafe { core::str::from_utf8_unchecked(slice) } + } } /// 设备树的映射形式。 diff --git a/src/utils/mod.rs b/src/utils/mod.rs index f255250..d295a48 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -18,14 +18,7 @@ impl Node<'_> { Some(node) => node, None => break, }; - let mut nodes = match node.nodes() { - Some(nodes) => nodes, - None => { - current_node = None; - break; - } - }; - let next_node_iter = nodes.find(|x| x.get_full_name() == current_name); + let next_node_iter = node.nodes().find(|x| x.get_full_name() == current_name); match next_node_iter { None => current_node = None, Some(iter) => { @@ -43,11 +36,9 @@ impl Node<'_> { F: FnMut(&Node), { func(self); - if let Some(nodes) = self.nodes() { - for node in nodes { - let node = node.deserialize::(); - node.search(func); - } + for node in self.nodes() { + let node = node.deserialize::(); + node.search(func); } } } @@ -58,7 +49,7 @@ mod tests { buildin::{Node, StrSeq}, from_raw_mut, Dtb, DtbPtr, }; - static RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/hifive-unmatched-a00.dtb"); + const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/hifive-unmatched-a00.dtb"); const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); #[repr(align(8))] struct AlignedBuffer { @@ -92,10 +83,7 @@ mod tests { let node: Node = from_raw_mut(&dtb).unwrap(); let node = node.find("/chosen").unwrap(); - let result = node - .props() - .unwrap() - .find(|prop| prop.get_name() == "stdout-path"); + let result = node.props().find(|prop| prop.get_name() == "stdout-path"); match result { Some(iter) => { if iter.deserialize::().iter().next().unwrap() != "serial0" {