diff --git a/.gitignore b/.gitignore index c994933..fa5fb3f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ Cargo.lock # Visual Studio Code configuration files .vscode/ -*.dts + +*.dtb +!examples/*.dtb diff --git a/Cargo.toml b/Cargo.toml index aa63f25..b73c02f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,14 +14,12 @@ 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" +serde = { version = "1.0", default-features = false, features = ["derive"] } +dyn_serde = { version = "1.0.2", default-features = false, optional = true } [features] -default = ["std"] +default = ["std", "ser"] +ser = ["dep:dyn_serde"] std = ["serde/std"] alloc = ["serde/alloc"] diff --git a/examples/hifive-unmatched-a00.rs b/examples/hifive-unmatched-a00.rs index 01fc38f..b975e47 100644 --- a/examples/hifive-unmatched-a00.rs +++ b/examples/hifive-unmatched-a00.rs @@ -1,7 +1,7 @@ extern crate alloc; use alloc::collections::BTreeMap; -use serde_derive::Deserialize; +use serde::Deserialize; use serde_device_tree::Compatible; #[derive(Debug, Deserialize)] diff --git a/examples/qemu-virt.rs b/examples/qemu-virt.rs index dbfcff1..0156142 100644 --- a/examples/qemu-virt.rs +++ b/examples/qemu-virt.rs @@ -1,8 +1,7 @@ //! 这是一个 `from_raw_mut` 反序列化设备树的示例。不需要 `alloc`。 // extern crate alloc; -// 在实际使用中,将这里的 `serde_derive::Deserialize` 改为 `serde::Deserialize`。 -use serde_derive::Deserialize; +use serde::Deserialize; // - `DtbPtr`: 验证设备树首部正确性,后续也可借助这个类型传递设备树,多次解析不必重复验证。 // - `Dtb`: 管理反序列化出的类型生命周期。 diff --git a/examples/serialize.rs b/examples/serialize.rs index d046307..ccf9352 100644 --- a/examples/serialize.rs +++ b/examples/serialize.rs @@ -1,4 +1,4 @@ -use serde_derive::Serialize; +use serde::Serialize; use std::io::prelude::*; const MAX_SIZE: usize = 256 + 32; diff --git a/src/de.rs b/src/de.rs index 3efd43d..2998e4b 100644 --- a/src/de.rs +++ b/src/de.rs @@ -42,7 +42,7 @@ use serde::de; /// # }); /// # aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); /// # let fdt_ptr = aligned_data.data.as_ptr(); -/// use serde_derive::Deserialize; +/// use serde::Deserialize; /// /// #[derive(Debug, Deserialize)] /// struct Tree<'a> { @@ -516,7 +516,7 @@ mod tests { #[cfg(feature = "alloc")] use alloc::format; #[cfg(any(feature = "std", feature = "alloc"))] - use serde_derive::Deserialize; + use serde::Deserialize; #[cfg(feature = "std")] use std::format; diff --git a/src/de_mut/matrix.rs b/src/de_mut/matrix.rs new file mode 100644 index 0000000..24e8b63 --- /dev/null +++ b/src/de_mut/matrix.rs @@ -0,0 +1,128 @@ +use crate::de_mut::ValueCursor; +use serde::{Deserialize, Serialize}; + +pub struct Matrix<'de, const T: usize> { + data: &'de [u32], +} + +pub struct MatrixItem<'de, const T: usize> { + offset: usize, + data: &'de [u32], +} + +impl<'de, const T: usize> Matrix<'de, T> { + #[inline(always)] + pub fn get_block_size() -> usize { + // Block size in bytes. + T * 4 + } + + #[inline(always)] + pub fn iter(&self) -> MatrixItem<'de, T> { + MatrixItem { + offset: 0, + data: self.data, + } + } + + #[inline(always)] + pub fn len(&self) -> usize { + self.data.len() / T + } + + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.data.len() != 0 + } + + #[inline(always)] + pub fn get(&self, i: usize) -> &'de [u32] { + &self.data[i * T..(i + 1) * T] + } +} + +impl<'de, const T: usize> Iterator for MatrixItem<'de, T> { + type Item = &'de [u32]; + + #[inline(always)] + fn next(&mut self) -> Option { + if self.data.len() <= self.offset { + return None; + } + let result = &self.data[self.offset..self.offset + T]; + self.offset += T; + Some(result) + } +} + +impl<'de, const T: usize> Deserialize<'de> for Matrix<'_, T> { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let value_deserialzer = super::ValueDeserializer::deserialize(deserializer)?; + let data = match value_deserialzer.cursor { + ValueCursor::Prop(_, cursor) => cursor.data_on(value_deserialzer.dtb), + _ => unreachable!(), + }; + if data.len() % Self::get_block_size() != 0 { + panic!("unaligned matrix"); + } + let (prefix, data, suffix) = unsafe { data.align_to::() }; + if !prefix.is_empty() || !suffix.is_empty() { + panic!("Not support unaligned data"); + } + + Ok(Self { data }) + } +} + +impl Serialize for Matrix<'_, T> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeSeq; + let mut seq = serializer.serialize_seq(Some(self.data.len()))?; + for x in self.data { + seq.serialize_element(x)?; + } + seq.end() + } +} + +#[cfg(test)] +mod tests { + use super::Matrix; + use crate::{Dtb, DtbPtr, buildin::Node, from_raw_mut}; + use serde::Serialize; + + const MAX_SIZE: usize = 256; + #[test] + fn base_ser_test() { + #[derive(Serialize)] + struct Base { + pub hello: [u32; 16], + } + let array: [u32; 16] = [0xdeadbeef; 16]; + let mut buf1 = [0u8; MAX_SIZE]; + + { + let base = Base { hello: array }; + crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); + } + + let ptr = DtbPtr::from_raw(buf1.as_mut_ptr()).unwrap(); + let dtb = Dtb::from(ptr).share(); + let node: Node = from_raw_mut(&dtb).unwrap(); + let matrix = node.get_prop("hello").unwrap().deserialize::>(); + let mut count = 0; + for x in matrix.iter() { + for y in x { + count += 1; + assert_eq!(u32::from_be(*y), 0xdeadbeef); + } + } + assert_eq!(count, 16); + } +} diff --git a/src/de_mut/mod.rs b/src/de_mut/mod.rs index e3c7641..3afaeb5 100644 --- a/src/de_mut/mod.rs +++ b/src/de_mut/mod.rs @@ -7,6 +7,7 @@ use serde::de; mod cursor; mod data; // mod group; +mod matrix; pub(crate) mod node; mod node_seq; mod reg; @@ -18,11 +19,11 @@ 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(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}; + pub use super::{matrix::Matrix, node::Node, node_seq::NodeSeq, reg::Reg, str_seq::StrSeq}; } use cursor::{BodyCursor, Cursor, MultiNodeCursor, PropCursor}; diff --git a/src/de_mut/node.rs b/src/de_mut/node.rs index 7ff6e48..0b1ee11 100644 --- a/src/de_mut/node.rs +++ b/src/de_mut/node.rs @@ -54,10 +54,18 @@ pub struct PropItem<'de> { impl<'de> Node<'de> { pub fn deserialize>(&self) -> T { use super::ValueCursor; + let result = match self.cursor.clone().move_on(self.dtb) { + Cursor::Title(c) => { + let (name, _) = c.split_on(self.dtb); + let take_result = c.take_node_on(self.dtb, name); + take_result + } + _ => unreachable!("Node's cursor should on its start"), + }; T::deserialize(&mut ValueDeserializer { dtb: self.dtb, reg: self.reg, - cursor: ValueCursor::Body(self.cursor), + cursor: ValueCursor::NodeIn(result), }) .unwrap() } @@ -302,7 +310,7 @@ impl<'de> PropItem<'de> { .unwrap() } } -impl<'se> Serialize for NodeItem<'se> { +impl Serialize for NodeItem<'_> { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -311,7 +319,7 @@ impl<'se> Serialize for NodeItem<'se> { } } -impl<'se> Serialize for PropItem<'se> { +impl Serialize for PropItem<'_> { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -320,7 +328,7 @@ impl<'se> Serialize for PropItem<'se> { } } -impl<'se> Serialize for Node<'se> { +impl Serialize for Node<'_> { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, diff --git a/src/de_mut/node_seq.rs b/src/de_mut/node_seq.rs index a7b2331..0e003a8 100644 --- a/src/de_mut/node_seq.rs +++ b/src/de_mut/node_seq.rs @@ -178,7 +178,7 @@ impl<'de> NodeSeqItem<'de> { mod tests { use crate::buildin::{NodeSeq, Reg}; use crate::{Dtb, DtbPtr, from_raw_mut}; - use serde_derive::Deserialize; + use serde::Deserialize; const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/bl808.dtb"); const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); diff --git a/src/de_mut/reg.rs b/src/de_mut/reg.rs index 2d1106a..eb5504d 100644 --- a/src/de_mut/reg.rs +++ b/src/de_mut/reg.rs @@ -117,7 +117,7 @@ impl Iterator for RegIter<'_> { } } -impl<'se> Serialize for Reg<'se> { +impl Serialize for Reg<'_> { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, diff --git a/src/de_mut/str_seq.rs b/src/de_mut/str_seq.rs index d0a4c48..9cc4f29 100644 --- a/src/de_mut/str_seq.rs +++ b/src/de_mut/str_seq.rs @@ -91,7 +91,7 @@ impl<'de> Iterator for StrSeqIter<'de> { } } -impl<'se> Serialize for StrSeq<'se> { +impl Serialize for StrSeq<'_> { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, diff --git a/src/lib.rs b/src/lib.rs index b7aeadc..c8d4452 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,13 +20,14 @@ extern crate alloc; pub mod de; pub mod error; +#[cfg(feature = "ser")] pub mod ser; pub mod utils; +pub mod value; mod common; mod de_mut; mod tag; -mod value; pub use value::compatible::Compatible; diff --git a/src/ser/mod.rs b/src/ser/mod.rs index e54bca3..6ba133e 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -39,7 +39,7 @@ where 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 struct_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)); @@ -47,7 +47,8 @@ where crate::ser::serializer::Serializer::new(&mut dst, &mut block, &mut patch_list); data.serialize(&mut ser)?; ser.dst.step_by_u32(FDT_END); - } + ser.dst.get_offset() + }; // Make header { let header = unsafe { &mut *(header.as_mut_ptr() as *mut Header) }; @@ -60,7 +61,7 @@ where 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? + header.size_dt_struct = u32::from_be(struct_len as u32); } Ok(()) } @@ -71,7 +72,7 @@ pub enum Error { } impl core::fmt::Display for Error { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(formatter, "{:?}", self) } } @@ -81,7 +82,7 @@ impl core::error::Error for Error {} impl serde::ser::Error for Error { fn custom(_msg: T) -> Self where - T: std::fmt::Display, + T: core::fmt::Display, { Self::Unknown } diff --git a/src/ser/patch.rs b/src/ser/patch.rs index 8210180..2a31881 100644 --- a/src/ser/patch.rs +++ b/src/ser/patch.rs @@ -4,7 +4,7 @@ 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, + pub data: &'se dyn dyn_serde::Serialize, name: &'se str, /// This patch match how many item between its path and serializer. @@ -15,7 +15,7 @@ pub struct Patch<'se> { impl<'se> Patch<'se> { #[inline(always)] - pub fn new(name: &'se str, data: &'se dyn erased_serde::Serialize) -> Patch<'se> { + pub fn new(name: &'se str, data: &'se dyn dyn_serde::Serialize) -> Patch<'se> { Patch { name, data, @@ -51,7 +51,7 @@ impl<'se> Patch<'se> { pub fn serialize(&self, serializer: &mut Serializer<'se>) { self.parsed.set(true); self.data - .erased_serialize(&mut ::erase(serializer)) + .serialize_dyn(&mut ::new(serializer)) .unwrap(); } } diff --git a/src/ser/serializer.rs b/src/ser/serializer.rs index 88bd22b..27c5da5 100644 --- a/src/ser/serializer.rs +++ b/src/ser/serializer.rs @@ -1,8 +1,8 @@ -use super::Error; use super::patch::PatchList; use super::pointer::Pointer; use super::string_block::StringBlock; use crate::common::*; +use crate::ser::Error; #[derive(Clone, Copy)] // The enum for current parsing type. @@ -446,11 +446,19 @@ impl<'se> serde::ser::Serializer for &mut Serializer<'se> { ) -> Result { todo!("struct variant"); } + + #[cfg(not(feature = "std"))] + fn collect_str(self, _value: &T) -> Result + where + T: ?Sized + core::fmt::Display, + { + todo!() + } } #[cfg(test)] mod tests { - use serde_derive::Serialize; + use serde::Serialize; const MAX_SIZE: usize = 256 + 32; #[test] fn base_ser_test() { @@ -530,7 +538,7 @@ mod tests { hello: 0xdeedbeef, base1: ["Hello", "World!", "Again"], }; - crate::ser::to_dtb(&base, &mut [], &mut buf1).unwrap(); + crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); } // TODO: check buf1 buf2 // println!("{:x?} {:x?}", buf1, buf2); @@ -560,7 +568,7 @@ mod tests { hello2: 0x11223344, base2: Base1 { hello: "Roger" }, }; - crate::ser::to_dtb(&base, &mut [], &mut buf1).unwrap(); + crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); } // TODO: check buf1 buf2 // println!("{:x?} {:x?}", buf1, buf2); diff --git a/src/value/mod.rs b/src/value/mod.rs index cc61a97..31699d4 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,3 +1,4 @@ pub mod compatible; pub mod cpu; +pub mod riscv_pmu; mod tree; diff --git a/src/value/riscv_pmu.rs b/src/value/riscv_pmu.rs new file mode 100644 index 0000000..6548acb --- /dev/null +++ b/src/value/riscv_pmu.rs @@ -0,0 +1,137 @@ +/// This module implement prop value described in +/// https://www.kernel.org/doc/Documentation/devicetree/bindings/perf/riscv%2Cpmu.yaml +use crate::buildin::*; + +use serde::{Deserialize, Serialize}; + +use core::ops::RangeInclusive; + +#[repr(transparent)] +#[derive(Deserialize, Serialize)] +#[serde(transparent)] +pub struct EventToMhpmevent<'a>(Matrix<'a, 3>); + +#[repr(transparent)] +#[derive(Deserialize, Serialize)] +#[serde(transparent)] +pub struct EventToMhpmcounters<'a>(Matrix<'a, 3>); + +#[repr(transparent)] +#[derive(Deserialize, Serialize)] +#[serde(transparent)] +pub struct RawEventToMhpcounters<'a>(Matrix<'a, 5>); + +impl EventToMhpmevent<'_> { + #[inline(always)] + pub fn len(&self) -> usize { + self.0.len() + } + + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + #[inline(always)] + pub fn get_event_id(&self, i: usize) -> u32 { + u32::from_be(self.0.get(i)[0]) + } + + #[inline(always)] + pub fn get_selector_value(&self, i: usize) -> u64 { + let current = self.0.get(i); + ((u32::from_be(current[1]) as u64) << 32) | (u32::from_be(current[2]) as u64) + } +} + +impl EventToMhpmcounters<'_> { + #[inline(always)] + pub fn len(&self) -> usize { + self.0.len() + } + + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + #[inline(always)] + pub fn get_event_idx_range(&self, i: usize) -> RangeInclusive { + let current = self.0.get(i); + u32::from_be(current[0])..=u32::from_be(current[1]) + } + + #[inline(always)] + pub fn get_counter_bitmap(&self, i: usize) -> u32 { + let current = self.0.get(i); + u32::from_be(current[2]) + } +} + +impl RawEventToMhpcounters<'_> { + #[inline(always)] + pub fn len(&self) -> usize { + self.0.len() + } + + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + #[inline(always)] + pub fn get_event_idx_base(&self, i: usize) -> u64 { + let current = self.0.get(i); + ((u32::from_be(current[0]) as u64) << 32) | (u32::from_be(current[1]) as u64) + } + + #[inline(always)] + pub fn get_event_idx_mask(&self, i: usize) -> u64 { + let current = self.0.get(i); + ((u32::from_be(current[2]) as u64) << 32) | (u32::from_be(current[3]) as u64) + } + + #[inline(always)] + pub fn get_counter_bitmap(&self, i: usize) -> u32 { + let current = self.0.get(i); + u32::from_be(current[4]) + } +} + +#[cfg(test)] +mod tests { + use super::EventToMhpmcounters; + use crate::{Dtb, DtbPtr, buildin::Node, from_raw_mut}; + + const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/qemu-virt.dtb"); + const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); + #[test] + fn test_chosen_stdout() { + #[repr(align(8))] + struct AlignedBuffer { + pub data: [u8; RAW_DEVICE_TREE.len()], + } + 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 result = node + .find("/pmu") + .unwrap() + .get_prop("riscv,event-to-mhpmcounters") + .unwrap() + .deserialize::(); + assert_eq!(result.len(), 5); + assert_eq!(result.get_event_idx_range(0), 1..=1); + assert_eq!(result.get_counter_bitmap(0), 0x7fff9); + assert_eq!(result.get_event_idx_range(1), 2..=2); + assert_eq!(result.get_counter_bitmap(1), 0x7fffc); + assert_eq!(result.get_event_idx_range(2), 0x10019..=0x10019); + assert_eq!(result.get_counter_bitmap(2), 0x7fff8); + } +} diff --git a/tests/bl808.rs b/tests/bl808.rs index 33afb63..0e016af 100644 --- a/tests/bl808.rs +++ b/tests/bl808.rs @@ -1,5 +1,4 @@ -// 在实际使用中,将这里的 `serde_derive::Deserialize` 改为 `serde::Deserialize`。 -use serde_derive::Deserialize; +use serde::Deserialize; use serde_device_tree::{Dtb, DtbPtr, buildin::NodeSeq, error::Error, from_raw_mut}; diff --git a/tests/hifive-unmatched-a00.rs b/tests/hifive-unmatched-a00.rs index e01238a..9c8ce51 100644 --- a/tests/hifive-unmatched-a00.rs +++ b/tests/hifive-unmatched-a00.rs @@ -1,4 +1,4 @@ -use serde_derive::Deserialize; +use serde::Deserialize; use serde_device_tree::Compatible; #[derive(Debug, Deserialize)] diff --git a/tests/qemu-virt.rs b/tests/qemu-virt.rs index 43c15b3..fa2e35b 100644 --- a/tests/qemu-virt.rs +++ b/tests/qemu-virt.rs @@ -1,5 +1,4 @@ -// 在实际使用中,将这里的 `serde_derive::Deserialize` 改为 `serde::Deserialize`。 -use serde_derive::Deserialize; +use serde::Deserialize; use serde_device_tree::{ Dtb, DtbPtr,