diff --git a/.gitignore b/.gitignore index b5f7d1d..c994933 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Cargo.lock # Visual Studio Code configuration files .vscode/ +*.dts diff --git a/Cargo.toml b/Cargo.toml index d772b15..aa63f25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,12 +9,13 @@ description = "A Device Tree blob serialization file format" readme = "README.md" keywords = ["serde", "serialization"] categories = ["no-std", "encoding"] -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] serde = { version = "1.0", default-features = false } +erased-serde = "0.4" [dev-dependencies] serde_derive = "1.0" diff --git a/examples/qemu-virt.rs b/examples/qemu-virt.rs index dd3acd9..dbfcff1 100644 --- a/examples/qemu-virt.rs +++ b/examples/qemu-virt.rs @@ -11,9 +11,10 @@ use serde_derive::Deserialize; // - `NodeSeq`: name@... 区分的一组同级同类的连续节点,这个类型要求可变的内存。 // - `StrSeq`: '\0' 分隔的一组字符串,设备树中一种常见的属性类型,这个类型要求可变的内存。 use serde_device_tree::{ + Dtb, DtbPtr, buildin::{Node, NodeSeq, Reg, StrSeq}, error::Error, - from_raw_mut, Dtb, DtbPtr, + from_raw_mut, }; const RAW_DEVICE_TREE: &[u8] = include_bytes!("qemu-virt.dtb"); diff --git a/examples/re_encode.rs b/examples/re_encode.rs new file mode 100644 index 0000000..eed52cd --- /dev/null +++ b/examples/re_encode.rs @@ -0,0 +1,30 @@ +use serde_device_tree::{Dtb, DtbPtr, buildin::Node, error::Error, from_raw_mut}; + +use std::io::prelude::*; + +const RAW_DEVICE_TREE: &[u8] = include_bytes!("qemu-virt.dtb"); +const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); + +#[repr(align(8))] +struct AlignedBuffer { + pub data: [u8; RAW_DEVICE_TREE.len()], +} + +fn main() -> Result<(), Error> { + 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 buf = [0u8; RAW_DEVICE_TREE.len() * 2]; + let mut slice = aligned_data.data.to_vec(); + let ptr = DtbPtr::from_raw(slice.as_mut_ptr())?; + let dtb = Dtb::from(ptr).share(); + + let root: Node = from_raw_mut(&dtb).unwrap(); + serde_device_tree::ser::to_dtb(&root, &[], &mut buf).unwrap(); + + let mut file = std::fs::File::create("gen.dtb").unwrap(); + file.write_all(&buf).unwrap(); + + Ok(()) +} diff --git a/examples/serialize.rs b/examples/serialize.rs new file mode 100644 index 0000000..d046307 --- /dev/null +++ b/examples/serialize.rs @@ -0,0 +1,36 @@ +use serde_derive::Serialize; +use std::io::prelude::*; + +const MAX_SIZE: usize = 256 + 32; + +fn main() { + #[derive(Serialize)] + struct Base { + pub hello: u32, + pub base1: Base1, + pub hello2: u32, + pub base2: Base1, + } + #[derive(Serialize)] + struct Base1 { + pub hello: &'static str, + } + let mut buf1 = [0u8; MAX_SIZE]; + + { + let new_base = Base1 { hello: "added" }; + let patch = serde_device_tree::ser::patch::Patch::new("/base3", &new_base as _); + let list = [patch]; + let base = Base { + hello: 0xdeedbeef, + base1: Base1 { + hello: "Hello, World!", + }, + hello2: 0x11223344, + base2: Base1 { hello: "Roger" }, + }; + serde_device_tree::ser::to_dtb(&base, &list, &mut buf1).unwrap(); + } + let mut file = std::fs::File::create("gen.dtb").unwrap(); + file.write_all(&buf1).unwrap(); +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..7a255b9 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,4 @@ +# Use rustfmt to format code + +edition = "2024" +# Empty file. diff --git a/src/common.rs b/src/common.rs index 2f99ff6..3086efd 100644 --- a/src/common.rs +++ b/src/common.rs @@ -15,7 +15,7 @@ pub(crate) struct Header { pub size_dt_struct: u32, } -const DEVICE_TREE_MAGIC: u32 = 0xD00DFEED; +pub const DEVICE_TREE_MAGIC: u32 = 0xD00DFEED; const U32_LEN: u32 = core::mem::size_of::() as _; pub(crate) const ALIGN: usize = core::mem::align_of::(); diff --git a/src/de.rs b/src/de.rs index 93b9c1a..3efd43d 100644 --- a/src/de.rs +++ b/src/de.rs @@ -68,23 +68,25 @@ pub unsafe fn from_raw<'de, T>(ptr: *const u8) -> Result where T: de::Deserialize<'de>, { - // read header - if (ptr as usize) & (ALIGN - 1) != 0 { - return Err(Error::unaligned(ptr as usize)); - } - let header = &*(ptr as *const Header); - header.verify()?; - - let total_size = u32::from_be(header.total_size); - let raw_data_len = (total_size - HEADER_LEN) as usize; - let ans_ptr = core::ptr::from_raw_parts(ptr, raw_data_len); - let device_tree: &DeviceTree = &*ans_ptr; - let tags = device_tree.tags(); - let mut d = Deserializer { - tags: tags.peekable(), - }; - let ret = T::deserialize(&mut d)?; - Ok(ret) + unsafe { + // read header + if (ptr as usize) & (ALIGN - 1) != 0 { + return Err(Error::unaligned(ptr as usize)); + } + let header = &*(ptr as *const Header); + header.verify()?; + + let total_size = u32::from_be(header.total_size); + let raw_data_len = (total_size - HEADER_LEN) as usize; + let ans_ptr = core::ptr::from_raw_parts(ptr, raw_data_len); + let device_tree: &DeviceTree = &*ans_ptr; + let tags = device_tree.tags(); + let mut d = Deserializer { + tags: tags.peekable(), + }; + let ret = T::deserialize(&mut d)?; + Ok(ret) + } } #[derive(Debug)] diff --git a/src/de_mut/cursor.rs b/src/de_mut/cursor.rs index d0dca23..5b52bb6 100644 --- a/src/de_mut/cursor.rs +++ b/src/de_mut/cursor.rs @@ -1,4 +1,4 @@ -use super::{DtError, RefDtb, StructureBlock, BLOCK_LEN}; +use super::{BLOCK_LEN, DtError, RefDtb, StructureBlock}; use core::marker::PhantomData; #[derive(Clone, Copy, Debug)] @@ -29,10 +29,10 @@ pub enum MoveResult { } #[derive(Clone, Copy, Debug)] -pub(super) struct MultiNodeCursor { +pub(crate) struct MultiNodeCursor { pub start_cursor: BodyCursor, - pub next_cursor: BodyCursor, pub skip_cursor: BodyCursor, + pub data_cursor: BodyCursor, #[allow(unused)] pub node_count: u32, } @@ -51,6 +51,7 @@ impl AnyCursor { impl BodyCursor { pub const ROOT: Self = Self(2, PhantomData); + pub const STARTER: Self = Self(0, PhantomData); /// 移动到下一个项目。 pub fn move_on(&mut self, dtb: RefDtb) -> Cursor { @@ -82,6 +83,7 @@ impl BodyCursor { } todo!() } + /// 移动指针至下一块 pub fn move_next(&mut self, dtb: RefDtb) -> MoveResult { use StructureBlock as B; @@ -183,8 +185,8 @@ impl TitleCursor { } MultiNodeCursor { start_cursor: group, - next_cursor: body, - skip_cursor: title_body, + skip_cursor: body, + data_cursor: title_body, node_count: len, } } @@ -201,8 +203,8 @@ impl TitleCursor { body.escape_from(dtb); MultiNodeCursor { start_cursor: origin, - next_cursor: body, - skip_cursor: node, + skip_cursor: body, + data_cursor: node, node_count: 1, } } diff --git a/src/de_mut/data.rs b/src/de_mut/data.rs index e4053ae..a85ccb6 100644 --- a/src/de_mut/data.rs +++ b/src/de_mut/data.rs @@ -1,15 +1,16 @@ -use super::cursor::MultiNodeCursor; +use super::cursor::MultiNodeCursor; use super::{BodyCursor, Cursor}; use super::{DtError, PropCursor, RefDtb, RegConfig}; use core::marker::PhantomData; -use serde::{de, Deserialize}; +use serde::{Deserialize, de}; #[derive(Clone, Copy, Debug)] pub(super) enum ValueCursor { Body(BodyCursor), Prop(BodyCursor, PropCursor), Node(MultiNodeCursor), + NodeIn(MultiNodeCursor), } #[derive(Clone, Copy)] @@ -208,8 +209,9 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { visitor.visit_some(self) } } - ValueCursor::Node(_) => visitor.visit_some(self), + ValueCursor::NodeIn(_) => visitor.visit_some(self), ValueCursor::Body(_) => visitor.visit_some(self), + ValueCursor::Node(_) => unreachable!("Node to option(NodeIn instead)"), } } @@ -251,7 +253,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { { use super::{StructAccess, StructAccessType, Temp}; match self.cursor { - ValueCursor::Node(result) => { + ValueCursor::NodeIn(result) => { let mut start_cursor = result.start_cursor; match start_cursor.move_on(self.dtb) { Cursor::Title(c) => { @@ -302,7 +304,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { { use super::{StructAccess, StructAccessType, Temp}; match self.cursor { - ValueCursor::Node(_) => visitor.visit_map(StructAccess { + ValueCursor::NodeIn(_) => visitor.visit_map(StructAccess { access_type: StructAccessType::Map(false), temp: Temp::Uninit, de: self, @@ -313,6 +315,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { de: self, }), ValueCursor::Prop(_, _) => unreachable!("Prop -> map"), + ValueCursor::Node(_) => unreachable!("Node -> map (Use NodeIn instead)"), } } @@ -327,7 +330,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { { use super::{StructAccess, StructAccessType, Temp}; match self.cursor { - ValueCursor::Node(_) => visitor.visit_map(StructAccess { + ValueCursor::NodeIn(_) => visitor.visit_map(StructAccess { access_type: StructAccessType::Struct(fields), temp: Temp::Uninit, de: self, @@ -338,6 +341,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { de: self, }), ValueCursor::Prop(_, _) => unreachable!("Prop -> struct {_name}"), + ValueCursor::Node(_) => unreachable!("Node -> struct {_name} (Use NodeIn instead)"), } } diff --git a/src/de_mut/mod.rs b/src/de_mut/mod.rs index 2e310a3..e3c7641 100644 --- a/src/de_mut/mod.rs +++ b/src/de_mut/mod.rs @@ -1,4 +1,4 @@ -//! Deserialize device tree data to a Rust data structure, +//! Deserialize device tree data to a Rust data structure, //! the memory region contains dtb file should be mutable. use crate::error::Error as DtError; @@ -7,7 +7,7 @@ use serde::de; mod cursor; mod data; // mod group; -mod node; +pub(crate) mod node; mod node_seq; mod reg; mod str_seq; @@ -16,17 +16,20 @@ mod struct_access; mod structs; const VALUE_DESERIALIZER_NAME: &str = "$serde_device_tree$de_mut$ValueDeserializer"; +pub(crate) const NODE_NAME: &str = "$serde_device_tree$de_mut$Node"; +pub(crate) const NODE_NODE_ITEM_NAME: &str = "$serde_device_tree$de_mut$Node$NodeItem"; +pub(crate) const NODE_PROP_ITEM_NAME: &str = "$serde_device_tree$de_mut$Node$PropItem"; pub use structs::{Dtb, DtbPtr}; pub mod buildin { pub use super::{node::Node, node_seq::NodeSeq, reg::Reg, str_seq::StrSeq}; } -use cursor::{BodyCursor, Cursor, PropCursor}; +use cursor::{BodyCursor, Cursor, MultiNodeCursor, PropCursor}; use data::{ValueCursor, ValueDeserializer}; use reg::RegConfig; use struct_access::{StructAccess, StructAccessType, Temp}; -use structs::{RefDtb, StructureBlock, BLOCK_LEN}; +use structs::{BLOCK_LEN, RefDtb, StructureBlock}; /// 从 [`RefDtb`] 反序列化一个描述设备树的 `T` 类型实例。 /// @@ -41,7 +44,12 @@ where let mut d = ValueDeserializer { dtb, reg: RegConfig::DEFAULT, - cursor: ValueCursor::Body(BodyCursor::ROOT), + cursor: ValueCursor::NodeIn(MultiNodeCursor { + start_cursor: BodyCursor::STARTER, + skip_cursor: BodyCursor::ROOT, // This item will never be used. + data_cursor: BodyCursor::ROOT, + node_count: 1, + }), }; T::deserialize(&mut d).and_then(|t| { // 解析必须完成 diff --git a/src/de_mut/node.rs b/src/de_mut/node.rs index 2ff632f..7ff6e48 100644 --- a/src/de_mut/node.rs +++ b/src/de_mut/node.rs @@ -1,8 +1,11 @@ -use super::{BodyCursor, Cursor, PropCursor, RefDtb, RegConfig, ValueCursor, ValueDeserializer}; +use super::{ + BodyCursor, Cursor, MultiNodeCursor, PropCursor, RefDtb, RegConfig, ValueCursor, + ValueDeserializer, +}; use core::fmt::Debug; use core::marker::PhantomData; use serde::de::MapAccess; -use serde::{de, Deserialize}; +use serde::{Deserialize, Serialize, de}; // 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. @@ -27,7 +30,7 @@ pub struct NodeIter<'de, 'b> { pub struct NodeItem<'de> { dtb: RefDtb<'de>, reg: RegConfig, - node: BodyCursor, + node: MultiNodeCursor, name: &'de str, } @@ -81,6 +84,16 @@ impl<'de> Node<'de> { pub fn get_prop<'b>(&'b self, name: &str) -> Option> { self.props().find(|prop| prop.get_name() == name) } + + pub fn name(&self) -> &'de str { + let cursor = self.cursor.clone().move_on(self.dtb); + if let Cursor::Title(c) = cursor { + let (name, _) = c.split_on(self.dtb); + name + } else { + todo!(); + } + } } impl Debug for Node<'_> { @@ -128,10 +141,10 @@ impl<'de> Iterator for NodeIter<'de, '_> { let res = Some(Self::Item { dtb, reg: self.node.reg, - node: node_cursor.skip_cursor, + node: node_cursor, name, }); - *cursor = node_cursor.next_cursor; + *cursor = node_cursor.skip_cursor; res } else { None @@ -200,10 +213,9 @@ impl<'de> Deserialize<'de> for Node<'_> { reg = Some(value.reg); if key == "/" { self_cursor = match value.cursor { - ValueCursor::Body(cursor) => Some(cursor), - ValueCursor::Node(result) => Some(result.next_cursor), + ValueCursor::NodeIn(result) => Some(result.start_cursor), _ => { - unreachable!("root of NodeSeq shouble be body cursor") + unreachable!("root of NodeSeq shouble be NodeIn cursor") } }; continue; @@ -214,7 +226,7 @@ impl<'de> Deserialize<'de> for Node<'_> { props_start = Some(cursor); } } - ValueCursor::Node(cursor) => { + ValueCursor::NodeIn(cursor) => { if nodes_start.is_none() { nodes_start = Some(cursor.start_cursor); } @@ -249,7 +261,7 @@ impl<'de> NodeItem<'de> { T::deserialize(&mut ValueDeserializer { dtb: self.dtb, reg: self.reg, - cursor: ValueCursor::Body(self.node), + cursor: ValueCursor::NodeIn(self.node), }) .unwrap() } @@ -271,13 +283,13 @@ impl<'de> NodeItem<'de> { } } - pub fn get_full_name(&self) -> &str { + pub fn get_full_name(&self) -> &'de str { self.name } } impl<'de> PropItem<'de> { - pub fn get_name(&self) -> &str { + pub fn get_name(&self) -> &'de str { self.name } pub fn deserialize>(&self) -> T { @@ -290,10 +302,36 @@ impl<'de> PropItem<'de> { .unwrap() } } +impl<'se> Serialize for NodeItem<'se> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_newtype_struct(crate::de_mut::NODE_NODE_ITEM_NAME, self) + } +} + +impl<'se> Serialize for PropItem<'se> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_bytes(self.prop.data_on(self.dtb)) + } +} + +impl<'se> Serialize for Node<'se> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_newtype_struct(crate::de_mut::NODE_NAME, self) + } +} #[cfg(test)] mod tests { - use crate::{buildin::Node, from_raw_mut, Dtb, DtbPtr}; + use crate::{Dtb, DtbPtr, buildin::Node, from_raw_mut}; const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/hifive-unmatched-a00.dtb"); const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); #[repr(align(8))] diff --git a/src/de_mut/node_seq.rs b/src/de_mut/node_seq.rs index 1247803..a7b2331 100644 --- a/src/de_mut/node_seq.rs +++ b/src/de_mut/node_seq.rs @@ -1,7 +1,7 @@ use super::{BodyCursor, Cursor, RefDtb, RegConfig, ValueCursor, ValueDeserializer}; use core::{fmt::Debug, marker::PhantomData}; use serde::de::SeqAccess; -use serde::{de, Deserialize}; +use serde::{Deserialize, de}; /// 一组名字以 `@...` 区分,同类、同级且连续的节点的映射。 /// @@ -140,12 +140,12 @@ impl<'de> Iterator for NodeSeqIter<'de, '_> { return None; } - self.de.cursor = ValueCursor::Body(node_reuslt.next_cursor); + self.de.cursor = ValueCursor::Body(node_reuslt.skip_cursor); Some(Self::Item { dtb: self.de.dtb, reg: self.de.reg, - body: node_reuslt.skip_cursor, + body: node_reuslt.data_cursor, at: suf_name, }) } @@ -177,7 +177,7 @@ impl<'de> NodeSeqItem<'de> { #[cfg(test)] mod tests { use crate::buildin::{NodeSeq, Reg}; - use crate::{from_raw_mut, Dtb, DtbPtr}; + use crate::{Dtb, DtbPtr, from_raw_mut}; use serde_derive::Deserialize; const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/bl808.dtb"); diff --git a/src/de_mut/reg.rs b/src/de_mut/reg.rs index b29cb93..2d1106a 100644 --- a/src/de_mut/reg.rs +++ b/src/de_mut/reg.rs @@ -1,6 +1,6 @@ -use super::{PropCursor, RefDtb, ValueCursor, BLOCK_LEN}; +use super::{BLOCK_LEN, PropCursor, RefDtb, ValueCursor}; use core::{fmt::Debug, ops::Range}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; /// 节点地址空间。 pub struct Reg<'de>(Inner<'de>); @@ -116,3 +116,13 @@ impl Iterator for RegIter<'_> { } } } + +impl<'se> Serialize for Reg<'se> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + // Pass bytes directly for Reg. + serializer.serialize_bytes(self.0.cursor.data_on(self.0.dtb)) + } +} diff --git a/src/de_mut/str_seq.rs b/src/de_mut/str_seq.rs index 7af38a3..d0a4c48 100644 --- a/src/de_mut/str_seq.rs +++ b/src/de_mut/str_seq.rs @@ -1,6 +1,6 @@ use super::{PropCursor, RefDtb, ValueCursor}; use core::fmt::Debug; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; /// 一组 '\0' 分隔字符串的映射。 /// @@ -90,3 +90,13 @@ impl<'de> Iterator for StrSeqIter<'de> { } } } + +impl<'se> Serialize for StrSeq<'se> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + // Pass bytes directly for StrSeq. + serializer.serialize_bytes(self.0.cursor.data_on(self.0.dtb)) + } +} diff --git a/src/de_mut/struct_access.rs b/src/de_mut/struct_access.rs index ce2d928..640f3fe 100644 --- a/src/de_mut/struct_access.rs +++ b/src/de_mut/struct_access.rs @@ -50,14 +50,17 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { let origin_cursor = match self.de.cursor { ValueCursor::Body(cursor) => cursor, ValueCursor::Node(result) => result.skip_cursor, + ValueCursor::NodeIn(result) => result.data_cursor, _ => unreachable!("map access's cursor should always be body cursor"), }; self.de.cursor = ValueCursor::Body(origin_cursor); let name = loop { let origin_cursor = match self.de.cursor { ValueCursor::Body(cursor) => cursor, + ValueCursor::Node(result) => result.skip_cursor, _ => unreachable!("map access's cursor should always be body cursor"), }; + self.de.cursor = ValueCursor::Body(origin_cursor); match self.de.move_on() { // 子节点名字 Cursor::Title(c) => { @@ -67,7 +70,7 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { // 子节点名字不带 @ 或正在解析 Node 类型 if pre_name == name || check_contains(name) { let take_result = c.take_node_on(self.de.dtb, name); - self.de.cursor = ValueCursor::Body(take_result.next_cursor); + self.de.cursor = ValueCursor::Node(take_result); if check_contains(name) { self.temp = Temp::Nodes(take_result); break name; @@ -76,7 +79,7 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { // @ 之前的部分是真正的名字,用这个名字搜索连续的一组 else { let take_result = c.take_group_on(self.de.dtb, pre_name); - self.de.cursor = ValueCursor::Body(take_result.next_cursor); + self.de.cursor = ValueCursor::Node(take_result); if check_contains(pre_name) { self.temp = Temp::Nodes(take_result); break pre_name; @@ -133,12 +136,12 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { StructAccessType::Map(_) => seed.deserialize(&mut ValueDeserializer { dtb: self.de.dtb, reg: self.de.reg, - cursor: ValueCursor::Node(*result), + cursor: ValueCursor::NodeIn(*result), }), StructAccessType::Struct(_) => seed.deserialize(&mut ValueDeserializer { dtb: self.de.dtb, reg: self.de.reg, - cursor: ValueCursor::Node(*result), + cursor: ValueCursor::NodeIn(*result), }), _ => unreachable!(), } @@ -170,7 +173,7 @@ impl<'de> de::SeqAccess<'de> for StructAccess<'de, '_> { // 子节点名字 Cursor::Title(c) => { let (name, _) = c.split_on(self.de.dtb); - let next = c.take_node_on(self.de.dtb, name).next_cursor; + let next = c.take_node_on(self.de.dtb, name).skip_cursor; let prev_cursor = match self.de.cursor { ValueCursor::Body(cursor) => cursor, _ => unreachable!(), diff --git a/src/de_mut/structs.rs b/src/de_mut/structs.rs index b31d038..48b3e3f 100644 --- a/src/de_mut/structs.rs +++ b/src/de_mut/structs.rs @@ -1,5 +1,5 @@ -use crate::{ - common::{Header, ALIGN}, +use crate::{ + common::{ALIGN, Header}, error::Error as DtError, }; use core::{cell::RefCell, fmt::Display}; diff --git a/src/lib.rs b/src/lib.rs index c5333c3..b7aeadc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ extern crate alloc; pub mod de; pub mod error; +pub mod ser; pub mod utils; mod common; @@ -33,7 +34,7 @@ pub use value::compatible::Compatible; pub use de::from_raw; #[doc(inline)] -pub use de_mut::{buildin, from_raw_mut, Dtb, DtbPtr}; +pub use de_mut::{Dtb, DtbPtr, buildin, from_raw_mut}; #[doc(inline)] pub use error::Result; diff --git a/src/ser/mod.rs b/src/ser/mod.rs new file mode 100644 index 0000000..e54bca3 --- /dev/null +++ b/src/ser/mod.rs @@ -0,0 +1,88 @@ +pub mod patch; +pub mod pointer; +pub mod serializer; +pub mod string_block; + +use crate::common::*; +use crate::ser::patch::Patch; + +// TODO: set reverse map +const RSVMAP_LEN: usize = 16; + +/// Serialize the data to dtb, with a list fof Patch, write to the `writer`. +/// +/// We do run-twice on convert, first time to generate string block, second time todo real +/// structure. +pub fn to_dtb<'se, T>(data: &T, list: &'se [Patch<'se>], writer: &'se mut [u8]) -> Result<(), Error> +where + T: serde::ser::Serialize, +{ + writer.iter_mut().for_each(|x| *x = 0); + + let mut offset: usize = 0; + { + let mut dst = crate::ser::pointer::Pointer::new(None); + let mut patch_list = crate::ser::patch::PatchList::new(list); + let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset); + let mut ser = + crate::ser::serializer::Serializer::new(&mut dst, &mut block, &mut patch_list); + data.serialize(&mut ser)?; + }; + list.iter().for_each(|patch| patch.init()); + // Write from bottom to top, to avoid overlap. + for i in (0..offset).rev() { + writer[writer.len() - offset + i] = writer[i]; + writer[i] = 0; + } + // TODO: make sure no out of bound. + + let writer_len = writer.len(); + let (data_block, string_block) = writer.split_at_mut(writer.len() - offset); + let (header, data_block) = data_block.split_at_mut(HEADER_LEN as usize + RSVMAP_LEN); + { + let mut patch_list = crate::ser::patch::PatchList::new(list); + let mut block = crate::ser::string_block::StringBlock::new(string_block, &mut offset); + let mut dst = crate::ser::pointer::Pointer::new(Some(data_block)); + let mut ser = + crate::ser::serializer::Serializer::new(&mut dst, &mut block, &mut patch_list); + data.serialize(&mut ser)?; + ser.dst.step_by_u32(FDT_END); + } + // Make header + { + let header = unsafe { &mut *(header.as_mut_ptr() as *mut Header) }; + header.magic = u32::from_be(DEVICE_TREE_MAGIC); + header.total_size = u32::from_be(writer_len as u32); + header.off_dt_struct = u32::from_be(HEADER_LEN + RSVMAP_LEN as u32); + header.off_dt_strings = u32::from_be((writer_len - offset) as u32); + header.off_mem_rsvmap = u32::from_be(HEADER_LEN); + header.version = u32::from_be(SUPPORTED_VERSION); + header.last_comp_version = u32::from_be(SUPPORTED_VERSION); // TODO: maybe 16 + header.boot_cpuid_phys = 0; // TODO: wtf is this prop + header.size_dt_strings = u32::from_be(offset as u32); + header.size_dt_struct = u32::from_be(data_block.len() as u32); // TODO: correct? + } + Ok(()) +} + +#[derive(Debug)] +pub enum Error { + Unknown, +} + +impl core::fmt::Display for Error { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "{:?}", self) + } +} + +impl core::error::Error for Error {} + +impl serde::ser::Error for Error { + fn custom(_msg: T) -> Self + where + T: std::fmt::Display, + { + Self::Unknown + } +} diff --git a/src/ser/patch.rs b/src/ser/patch.rs new file mode 100644 index 0000000..8210180 --- /dev/null +++ b/src/ser/patch.rs @@ -0,0 +1,104 @@ +use super::serializer::Serializer; +use core::cell::Cell; + +/// Since this crate is mostly work with `noalloc`, we use `Patch` and `PatchList` for change or +/// add on a dtb. +pub struct Patch<'se> { + pub data: &'se dyn erased_serde::Serialize, + name: &'se str, + + /// This patch match how many item between its path and serializer. + matched_depth: Cell, + /// Show this patch have been parsed. + parsed: Cell, +} + +impl<'se> Patch<'se> { + #[inline(always)] + pub fn new(name: &'se str, data: &'se dyn erased_serde::Serialize) -> Patch<'se> { + Patch { + name, + data, + matched_depth: Cell::new(0), + parsed: Cell::new(false), + } + } + + #[inline(always)] + /// Reset the status of patch. + pub fn init(&self) { + self.matched_depth.set(0); + self.parsed.set(false); + } + + #[inline(always)] + pub fn get_depth(&self) -> usize { + self.name.split('/').count() - 1 + } + + #[inline(always)] + pub fn get_depth_path(&self, x: usize) -> &'se str { + if x == 0 { + return ""; + } + self.name.split('/').nth(x).unwrap_or_default() + } + + // I hope to impl serde::ser::Serializer, but erase_serialize's return value is different from + // normal serialize, so we do this. + /// Serialize this patch with serializer. + #[inline(always)] + pub fn serialize(&self, serializer: &mut Serializer<'se>) { + self.parsed.set(true); + self.data + .erased_serialize(&mut ::erase(serializer)) + .unwrap(); + } +} + +/// Here is a list of `Patch`, and have some methods for update `Patch` status. +pub struct PatchList<'se> { + list: &'se [Patch<'se>], +} + +impl<'se> PatchList<'se> { + #[inline(always)] + pub fn new(list: &'se [Patch<'se>]) -> PatchList<'se> { + PatchList { list } + } + + #[inline(always)] + pub fn step_forward(&self, name: &'se str, depth: usize) -> Option<&'se Patch<'se>> { + let mut matched_patch = None; + self.list.iter().for_each(|patch| { + if patch.matched_depth.get() == depth - 1 && patch.get_depth_path(depth) == name { + patch.matched_depth.set(patch.matched_depth.get() + 1); + if patch.get_depth() == depth { + if matched_patch.is_some() { + panic!("More than one replace data on a same path"); + } + matched_patch = Some(patch); + } + } + }); + matched_patch + } + + #[inline(always)] + pub fn step_back(&self, depth: usize) { + self.list.iter().for_each(|patch| { + if patch.matched_depth.get() == depth { + patch.matched_depth.set(patch.matched_depth.get() - 1); + } + }); + } + + #[inline(always)] + /// Return a list which is on this level, but haven't been parsed, which usually means this + /// patch is for adding. + pub fn add_list(&self, depth: usize) -> impl Iterator> + use<'se> { + self.list.iter().filter(move |x| { + x.matched_depth.get() == depth && x.get_depth() == depth + 1 && !x.parsed.get() + }) + } +} diff --git a/src/ser/pointer.rs b/src/ser/pointer.rs new file mode 100644 index 0000000..45871e6 --- /dev/null +++ b/src/ser/pointer.rs @@ -0,0 +1,82 @@ +use crate::common::*; + +pub struct Pointer<'se> { + offset: usize, + data: Option<&'se mut [u8]>, +} + +impl<'se> Pointer<'se> { + #[inline(always)] + pub fn new(dst: Option<&'se mut [u8]>) -> Pointer<'se> { + Pointer { + offset: 0, + data: dst, + } + } + + #[inline(always)] + pub fn update_data(&mut self, data: Option<&'se mut [u8]>) { + self.data = data; + } + + #[inline(always)] + pub fn get_offset(&self) -> usize { + self.offset + } + + #[inline(always)] + pub fn write_to_offset_u32(&mut self, offset: usize, value: u32) { + if let Some(ref mut data) = self.data { + data[offset..offset + 4].copy_from_slice(&u32::to_be_bytes(value)) + } + } + + #[inline(always)] + pub fn step_by_prop(&mut self) -> usize { + self.step_by_u32(FDT_PROP); + let offset = self.offset; + self.step_by_u32(FDT_NOP); // When create prop header, we do not know how long of the prop value. + self.step_by_u32(FDT_NOP); // We can not assume this is a prop, so nop for default. + offset + } + + #[inline(always)] + pub fn step_by_len(&mut self, len: usize) { + self.offset += len + } + + #[inline(always)] + pub fn step_by_u32(&mut self, value: u32) { + if let Some(ref mut data) = self.data { + data[self.offset..self.offset + 4].copy_from_slice(&u32::to_be_bytes(value)) + } + self.step_by_len(4); + } + + #[inline(always)] + pub fn step_by_u8(&mut self, value: u8) { + if let Some(ref mut data) = self.data { + data[self.offset] = value + } + self.step_by_len(1); + } + + #[inline(always)] + pub fn step_align(&mut self) { + while self.offset % 4 != 0 { + if let Some(ref mut data) = self.data { + data[self.offset] = 0 + } + self.offset += 1; + } + } + + #[inline(always)] + pub fn step_by_name(&mut self, name: &str) { + name.bytes().for_each(|x| { + self.step_by_u8(x); + }); + self.step_by_u8(0); + self.step_align(); + } +} diff --git a/src/ser/serializer.rs b/src/ser/serializer.rs new file mode 100644 index 0000000..88bd22b --- /dev/null +++ b/src/ser/serializer.rs @@ -0,0 +1,670 @@ +use super::Error; +use super::patch::PatchList; +use super::pointer::Pointer; +use super::string_block::StringBlock; +use crate::common::*; + +#[derive(Clone, Copy)] +// The enum for current parsing type. +enum ValueType { + Node, + Prop, +} + +/// Serializer +/// - `dst`: Pointer of distance &[u8] and the ref of &[u8]. +/// - `current_value_type`, `current_name`, `current_dep`: For recursive. +pub struct Serializer<'se> { + pub dst: &'se mut Pointer<'se>, + string_block: &'se mut StringBlock<'se>, + patch_list: &'se mut PatchList<'se>, + + current_value_type: ValueType, + current_name: &'se str, + current_dep: usize, +} + +impl<'se> Serializer<'se> { + #[inline(always)] + pub fn new( + dst: &'se mut Pointer<'se>, + cache: &'se mut StringBlock<'se>, + patch_list: &'se mut PatchList<'se>, + ) -> Serializer<'se> { + Serializer { + dst, + string_block: cache, + current_dep: 0, + current_name: "", + current_value_type: ValueType::Node, + patch_list, + } + } +} + +trait SerializeDynamicField<'se> { + fn serialize_dynamic_field(&mut self, key: &'se str, value: &T) -> Result<(), Error> + where + T: serde::ser::Serialize + ?Sized; +} + +impl<'se> SerializeDynamicField<'se> for &mut Serializer<'se> { + fn serialize_dynamic_field(&mut self, key: &'se str, value: &T) -> Result<(), Error> + where + T: serde::ser::Serialize + ?Sized, + { + let prop_header_offset = self.dst.step_by_prop(); + + // Save prev + let prev_type = self.current_value_type; + let prev_name = self.current_name; + self.current_dep += 1; + self.current_name = key; + let matched_patch = self.patch_list.step_forward(key, self.current_dep); + + match matched_patch { + Some(data) => { + data.serialize(self); + } + None => { + value.serialize(&mut **self)?; + } + } + + // We now know how long the prop value. + // TODO: make we have some better way than put nop, like move this block ahead. + if let ValueType::Node = self.current_value_type { + self.dst + .write_to_offset_u32(prop_header_offset - 4, FDT_NOP); + } else { + self.dst.write_to_offset_u32( + prop_header_offset, + (self.dst.get_offset() - prop_header_offset - 8) as u32, + ); + self.dst.write_to_offset_u32( + prop_header_offset + 4, + self.string_block.find_or_insert(key) as u32, + ); + } + + self.dst.step_align(); + + // Load prev + self.patch_list.step_back(self.current_dep); + self.current_value_type = prev_type; + self.current_name = prev_name; + self.current_dep -= 1; + + Ok(()) + } +} + +impl serde::ser::SerializeMap for &mut Serializer<'_> { + type Ok = (); + type Error = Error; + + fn serialize_key(&mut self, _input: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize + ?Sized, + { + todo!("map_key"); + } + + fn serialize_value(&mut self, _value: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize + ?Sized, + { + todo!("map_value"); + } + + fn end(self) -> Result { + todo!("map_end"); + } +} + +impl serde::ser::SerializeStruct for &mut Serializer<'_> { + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize + ?Sized, + { + self.serialize_dynamic_field(key, value)?; + + Ok(()) + } + + fn end(mut self) -> Result { + for patch in self.patch_list.add_list(self.current_dep) { + let key = patch.get_depth_path(self.current_dep + 1); + self.serialize_dynamic_field(key, patch.data)?; + } + self.dst.step_by_u32(FDT_END_NODE); + Ok(()) + } +} + +impl serde::ser::SerializeStructVariant for &mut Serializer<'_> { + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, _key: &'static str, _value: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize + ?Sized, + { + todo!("struct_field"); + } + + fn end(self) -> Result { + todo!("struct_end"); + } +} + +impl serde::ser::SerializeSeq for &mut Serializer<'_> { + type Ok = (); + type Error = Error; + // TODO: make sure there are no node seq serialize over this function. + fn serialize_element(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + serde::ser::Serialize, + { + value.serialize(&mut **self) + } + + // Close the sequence. + fn end(self) -> Result<(), Error> { + Ok(()) + } +} + +impl serde::ser::SerializeTuple for &mut Serializer<'_> { + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + serde::ser::Serialize, + { + value.serialize(&mut **self) + } + + // Close the sequence. + fn end(self) -> Result<(), Error> { + Ok(()) + } +} + +impl serde::ser::SerializeTupleVariant for &mut Serializer<'_> { + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, _value: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize + ?Sized, + { + todo!("tuple_variant_field"); + } + + fn end(self) -> Result<(), Error> { + todo!("tuple_variant_end"); + } +} + +impl serde::ser::SerializeTupleStruct for &mut Serializer<'_> { + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, _value: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize + ?Sized, + { + todo!("tuple_struct_field"); + } + + fn end(self) -> Result<(), Error> { + todo!("tuple_struct_end"); + } +} + +impl<'se> serde::ser::Serializer for &mut Serializer<'se> { + type Ok = (); + type Error = Error; + type SerializeSeq = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeStructVariant = Self; + + fn serialize_bool(self, _v: bool) -> Result { + todo!("bool"); + } + + fn serialize_i8(self, _v: i8) -> Result { + todo!("i8"); + } + + fn serialize_i16(self, _v: i16) -> Result { + todo!("i16"); + } + + fn serialize_i32(self, _v: i32) -> Result { + todo!("i32"); + } + + fn serialize_i64(self, _v: i64) -> Result { + todo!("i64"); + } + + fn serialize_u8(self, _v: u8) -> Result { + todo!("u8"); + } + + fn serialize_u16(self, _v: u16) -> Result { + todo!("u16"); + } + + fn serialize_u32(self, v: u32) -> Result { + self.current_value_type = ValueType::Prop; + self.dst.step_by_u32(v); + Ok(()) + } + + fn serialize_u64(self, _v: u64) -> Result { + todo!("u64"); + } + + fn serialize_f32(self, _v: f32) -> Result { + todo!("f32"); + } + + fn serialize_f64(self, _v: f64) -> Result { + todo!("f64"); + } + + fn serialize_char(self, _v: char) -> Result { + todo!("char"); + } + + fn serialize_str(self, v: &str) -> Result { + self.current_value_type = ValueType::Prop; + v.bytes().for_each(|x| { + self.dst.step_by_u8(x); + }); + self.dst.step_by_u8(0); + Ok(()) + } + + fn serialize_bytes(self, v: &[u8]) -> Result { + self.current_value_type = ValueType::Prop; + v.iter().for_each(|x| self.dst.step_by_u8(*x)); + Ok(()) + } + + fn serialize_none(self) -> Result { + todo!("none"); + } + + fn serialize_some(self, _v: &T) -> Result + where + T: serde::ser::Serialize + ?Sized, + { + todo!("some"); + } + + fn serialize_unit(self) -> Result { + todo!("unit"); + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + todo!("unit struct"); + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result { + todo!("unit struct variant"); + } + + fn serialize_newtype_struct( + mut self, + name: &'static str, + v: &T, + ) -> Result + where + T: serde::ser::Serialize + ?Sized, + { + use crate::de_mut::node::{Node, NodeItem}; + use crate::de_mut::{NODE_NAME, NODE_NODE_ITEM_NAME}; + use core::ptr::addr_of; + match name { + NODE_NAME => { + // TODO: match level + self.current_value_type = ValueType::Node; + let v = unsafe { &*(addr_of!(v) as *const &Node<'se>) }; + self.dst.step_by_u32(FDT_BEGIN_NODE); + if self.current_dep == 0 { + // The name of root node should be empty. + self.dst.step_by_u32(0); + } else { + self.dst.step_by_name(v.name()); + self.dst.step_align(); + } + for prop in v.props() { + self.serialize_dynamic_field(prop.get_name(), &prop)?; + } + for node in v.nodes() { + self.serialize_dynamic_field( + node.get_full_name(), + &node.deserialize::(), + )?; + } + self.dst.step_by_u32(FDT_END_NODE); + Ok(()) + } + NODE_NODE_ITEM_NAME => { + self.current_value_type = ValueType::Node; + let v = unsafe { &*(addr_of!(v) as *const &NodeItem<'se>) }; + self.serialize_newtype_struct(NODE_NAME, &v.deserialize::()) + } + _ => todo!(), + } + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result + where + T: serde::ser::Serialize + ?Sized, + { + todo!("newtype struct variant"); + } + + fn serialize_seq(self, _len: Option) -> Result { + self.current_value_type = ValueType::Prop; + Ok(self) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + todo!("tuple struct"); + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + todo!("tuple variant"); + } + + fn serialize_map(self, _len: Option) -> Result { + todo!("map"); + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + self.dst.step_by_u32(FDT_BEGIN_NODE); + if self.current_dep == 0 { + // The name of root node should be empty. + self.dst.step_by_u32(0); + } else { + self.dst.step_by_name(self.current_name); + } + self.dst.step_align(); + self.current_value_type = ValueType::Node; + Ok(self) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + todo!("struct variant"); + } +} + +#[cfg(test)] +mod tests { + use serde_derive::Serialize; + const MAX_SIZE: usize = 256 + 32; + #[test] + fn base_ser_test() { + #[derive(Serialize)] + struct Base { + pub hello: u32, + } + let mut buf1 = [0u8; MAX_SIZE]; + + { + let base = Base { hello: 0xdeedbeef }; + crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); + } + // TODO: check buf1 buf2 + } + #[test] + fn rev_ser_test() { + #[derive(Serialize)] + struct Base { + pub hello: u32, + pub base1: Base1, + } + #[derive(Serialize)] + struct Base1 { + pub hello: u32, + } + let mut buf1 = [0u8; MAX_SIZE]; + + { + let base = Base { + hello: 0xdeedbeef, + base1: Base1 { hello: 0x10000001 }, + }; + crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); + } + // TODO: check buf1 buf2 + // println!("{:x?} {:x?}", buf1, buf2); + // assert!(false); + } + #[test] + fn rev_str_ser_test() { + #[derive(Serialize)] + struct Base { + pub hello: u32, + pub base1: Base1, + } + #[derive(Serialize)] + struct Base1 { + pub hello: &'static str, + } + let mut buf1 = [0u8; MAX_SIZE]; + + { + let base = Base { + hello: 0xdeedbeef, + base1: Base1 { + hello: "Hello, World!", + }, + }; + crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); + } + // TODO: check buf1 buf2 + // println!("{:x?} {:x?}", buf1, buf2); + // assert!(false); + } + #[test] + fn seq_str_ser_test() { + #[derive(Serialize)] + struct Base { + pub hello: u32, + pub base1: [&'static str; 3], + } + let mut buf1 = [0u8; MAX_SIZE]; + + { + let base = Base { + hello: 0xdeedbeef, + base1: ["Hello", "World!", "Again"], + }; + crate::ser::to_dtb(&base, &mut [], &mut buf1).unwrap(); + } + // TODO: check buf1 buf2 + // println!("{:x?} {:x?}", buf1, buf2); + // assert!(false); + } + #[test] + fn node_prop_ser_test() { + #[derive(Serialize)] + struct Base { + pub hello: u32, + pub base1: Base1, + pub hello2: u32, + pub base2: Base1, + } + #[derive(Serialize)] + struct Base1 { + pub hello: &'static str, + } + let mut buf1 = [0u8; MAX_SIZE]; + + { + let base = Base { + hello: 0xdeedbeef, + base1: Base1 { + hello: "Hello, World!", + }, + hello2: 0x11223344, + base2: Base1 { hello: "Roger" }, + }; + crate::ser::to_dtb(&base, &mut [], &mut buf1).unwrap(); + } + // TODO: check buf1 buf2 + // println!("{:x?} {:x?}", buf1, buf2); + // assert!(false); + } + #[test] + fn replace_prop_ser_test() { + #[derive(Serialize)] + struct Base { + pub hello: u32, + pub base1: Base1, + pub hello2: u32, + pub base2: Base1, + } + #[derive(Serialize)] + struct Base1 { + pub hello: &'static str, + } + let mut buf1 = [0u8; MAX_SIZE]; + + { + let number = 0x55667788u32; + let patch = crate::ser::patch::Patch::new("/hello", &number as _); + let list = [patch]; + let base = Base { + hello: 0xdeedbeef, + base1: Base1 { + hello: "Hello, World!", + }, + hello2: 0x11223344, + base2: Base1 { hello: "Roger" }, + }; + crate::ser::to_dtb(&base, &list, &mut buf1).unwrap(); + } + // TODO: check buf1 buf2 + // println!("{:x?} {:x?}", buf1, buf2); + // assert!(false); + } + #[test] + fn replace_node_ser_test() { + #[derive(Serialize)] + struct Base { + pub hello: u32, + pub base1: Base1, + pub hello2: u32, + pub base2: Base1, + } + #[derive(Serialize)] + struct Base1 { + pub hello: &'static str, + } + let mut buf1 = [0u8; MAX_SIZE]; + + { + let new_base = Base1 { + hello: "replacement", + }; + let patch = crate::ser::patch::Patch::new("/hello", &new_base as _); + let list = [patch]; + let base = Base { + hello: 0xdeedbeef, + base1: Base1 { + hello: "Hello, World!", + }, + hello2: 0x11223344, + base2: Base1 { hello: "Roger" }, + }; + crate::ser::to_dtb(&base, &list, &mut buf1).unwrap(); + } + // TODO: check buf1 buf2 + // println!("{:x?} {:x?}", buf1, buf2); + // assert!(false); + } + #[test] + fn add_node_ser_test() { + #[derive(Serialize)] + struct Base { + pub hello: u32, + pub base1: Base1, + pub hello2: u32, + pub base2: Base1, + } + #[derive(Serialize)] + struct Base1 { + pub hello: &'static str, + } + let mut buf1 = [0u8; MAX_SIZE]; + + { + let new_base = Base1 { hello: "added" }; + let patch = crate::ser::patch::Patch::new("/base3", &new_base as _); + let list = [patch]; + let base = Base { + hello: 0xdeedbeef, + base1: Base1 { + hello: "Hello, World!", + }, + hello2: 0x11223344, + base2: Base1 { hello: "Roger" }, + }; + crate::ser::to_dtb(&base, &list, &mut buf1).unwrap(); + } + // TODO: check buf1 buf2 + // println!("{:x?}", buf1); + // assert!(false); + } +} diff --git a/src/ser/string_block.rs b/src/ser/string_block.rs new file mode 100644 index 0000000..af86434 --- /dev/null +++ b/src/ser/string_block.rs @@ -0,0 +1,68 @@ +/// StringBlock +/// As spec said, dtb have a block called string block for saving prop names. +pub struct StringBlock<'se> { + end: &'se mut usize, + data: &'se mut [u8], +} + +impl<'se> StringBlock<'se> { + /// Make a new string block. + /// + /// For get how long is string block, we make `end` as a mut ref. + #[inline(always)] + pub fn new(dst: &'se mut [u8], end: &'se mut usize) -> StringBlock<'se> { + StringBlock { data: dst, end } + } + + // TODO: show as error + /// Assume the passing `offset` is the start of a string, and return this string. + /// Return (Result String, End Offset). + /// + /// Will panic when len > end. + #[inline(always)] + pub fn get_str_by_offset(&self, offset: usize) -> (&str, usize) { + if offset > *self.end { + panic!("invalid read"); + } + let current_slice = &self.data[offset..]; + let pos = current_slice + .iter() + .position(|&x| x == b'\0') + .unwrap_or(self.data.len()); + let (a, _) = current_slice.split_at(pos + 1); + let result = unsafe { core::str::from_utf8_unchecked(&a[..a.len() - 1]) }; + (result, pos + offset + 1) + } + + #[inline(always)] + fn insert_u8(&mut self, data: u8) { + self.data[*self.end] = data; + *self.end += 1; + } + + /// Return the start offset of inserted string. + #[inline(always)] + pub fn insert_str(&mut self, name: &str) -> usize { + let result = *self.end; + name.bytes().for_each(|x| { + self.insert_u8(x); + }); + self.insert_u8(0); + result + } + + /// Find a string. If not found, insert it. + #[inline(always)] + pub fn find_or_insert(&mut self, name: &str) -> usize { + let mut current_pos = 0; + while current_pos < *self.end { + let (result, new_pos) = self.get_str_by_offset(current_pos); + if result == name { + return current_pos; + } + current_pos = new_pos; + } + + self.insert_str(name) + } +} diff --git a/src/utils/chosen.rs b/src/utils/chosen.rs index 52170bb..5afd6e6 100644 --- a/src/utils/chosen.rs +++ b/src/utils/chosen.rs @@ -38,7 +38,7 @@ impl<'de> Node<'de> { #[cfg(test)] mod tests { - use crate::{buildin::Node, from_raw_mut, Dtb, DtbPtr}; + use crate::{Dtb, DtbPtr, buildin::Node, from_raw_mut}; const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/bl808.dtb"); const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); diff --git a/src/utils/mod.rs b/src/utils/mod.rs index c71c673..beaf1c1 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -70,8 +70,9 @@ impl<'de> Node<'de> { #[cfg(test)] mod tests { use crate::{ + Dtb, DtbPtr, buildin::{Node, StrSeq}, - from_raw_mut, Dtb, DtbPtr, + from_raw_mut, }; const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/hifive-unmatched-a00.dtb"); const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); diff --git a/src/value/compatible.rs b/src/value/compatible.rs index 3102e45..a9de660 100644 --- a/src/value/compatible.rs +++ b/src/value/compatible.rs @@ -1,5 +1,5 @@ use core::{fmt, marker::PhantomData}; -use serde::{de::Visitor, Deserialize}; +use serde::{Deserialize, de::Visitor}; /// Field representing compatability of a certain device in the tree. /// diff --git a/tests/bl808.rs b/tests/bl808.rs index 3eaac1d..33afb63 100644 --- a/tests/bl808.rs +++ b/tests/bl808.rs @@ -1,7 +1,7 @@ // 在实际使用中,将这里的 `serde_derive::Deserialize` 改为 `serde::Deserialize`。 use serde_derive::Deserialize; -use serde_device_tree::{buildin::NodeSeq, error::Error, from_raw_mut, Dtb, DtbPtr}; +use serde_device_tree::{Dtb, DtbPtr, buildin::NodeSeq, error::Error, from_raw_mut}; const RAW_DEVICE_TREE: &[u8] = include_bytes!("../examples/bl808.dtb"); const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); diff --git a/tests/qemu-virt.rs b/tests/qemu-virt.rs index 0fdc5ad..43c15b3 100644 --- a/tests/qemu-virt.rs +++ b/tests/qemu-virt.rs @@ -2,9 +2,10 @@ use serde_derive::Deserialize; use serde_device_tree::{ + Dtb, DtbPtr, buildin::{NodeSeq, Reg}, error::Error, - from_raw_mut, Dtb, DtbPtr, + from_raw_mut, }; const RAW_DEVICE_TREE: &[u8] = include_bytes!("../examples/qemu-virt.dtb");