Skip to content

Commit 9d48da6

Browse files
authored
Add probe length for serializer (#19)
* refactor(ser): split to_dtb Signed-off-by: Woshiluo Luo <[email protected]> * feat(ser): add probe length feat(ser): now to dtb will return total size Signed-off-by: Woshiluo Luo <[email protected]> --------- Signed-off-by: Woshiluo Luo <[email protected]>
1 parent f051687 commit 9d48da6

File tree

5 files changed

+169
-72
lines changed

5 files changed

+169
-72
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ serde = { version = "1.0", default-features = false, features = ["derive"] }
1818
dyn_serde = { version = "=1.1.2", default-features = false, optional = true }
1919

2020
[features]
21-
default = ["std", "ser"]
21+
default = ["std", "ser", "alloc"]
2222

2323
ser = ["dep:dyn_serde"]
2424
std = ["serde/std"]

src/de.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,6 @@ mod tests {
518518
use alloc::format;
519519
#[cfg(any(feature = "std", feature = "alloc"))]
520520
use serde::Deserialize;
521-
#[cfg(feature = "std")]
522-
use std::format;
523521

524522
#[cfg(any(feature = "std", feature = "alloc"))]
525523
#[test]

src/ser/mod.rs

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod patch;
22
pub mod pointer;
33
pub mod serializer;
4+
45
pub mod string_block;
56

67
use crate::common::*;
@@ -9,83 +10,112 @@ use crate::ser::patch::Patch;
910
// TODO: set reverse map
1011
const RSVMAP_LEN: usize = 16;
1112

13+
#[inline(always)]
14+
fn get_structure_padding(length: usize) -> usize {
15+
let rem = length & (ALIGN - 1);
16+
ALIGN - rem
17+
}
18+
19+
/// Make dtb header with structure block and string block length.
20+
fn make_header<'se>(
21+
writer: &'se mut [u8],
22+
structure_length: u32,
23+
string_block_length: u32,
24+
) -> usize {
25+
let (header, _) = writer.split_at_mut(HEADER_LEN as usize);
26+
let header = unsafe { &mut *(header.as_mut_ptr() as *mut Header) };
27+
let total_size =
28+
HEADER_PADDING_LEN + RSVMAP_LEN as u32 + structure_length + string_block_length;
29+
let padding = get_structure_padding(total_size as usize);
30+
let total_size = total_size + padding as u32;
31+
header.magic = u32::from_be(DEVICE_TREE_MAGIC);
32+
header.total_size = u32::from_be(total_size);
33+
assert_eq!(header.total_size % 8, 0);
34+
header.off_dt_struct = u32::from_be(HEADER_PADDING_LEN + RSVMAP_LEN as u32);
35+
header.off_dt_strings = u32::from_be(HEADER_PADDING_LEN + RSVMAP_LEN as u32 + structure_length);
36+
header.off_mem_rsvmap = u32::from_be(HEADER_PADDING_LEN);
37+
header.version = u32::from_be(SUPPORTED_VERSION);
38+
header.last_comp_version = u32::from_be(SUPPORTED_VERSION); // TODO: maybe 16
39+
header.boot_cpuid_phys = 0; // TODO
40+
header.size_dt_strings = u32::from_be(string_block_length as u32);
41+
header.size_dt_struct = u32::from_be(structure_length as u32);
42+
43+
total_size as usize
44+
}
45+
1246
/// Serialize the data to dtb, with a list fof Patch, write to the `writer`.
1347
///
1448
/// We do run-twice on convert, first time to generate string block, second time todo real
1549
/// structure.
16-
pub fn to_dtb<'se, T>(data: &T, list: &'se [Patch<'se>], writer: &'se mut [u8]) -> Result<(), Error>
50+
pub fn to_dtb<'se, T>(
51+
data: &T,
52+
list: &'se [Patch<'se>],
53+
writer: &'se mut [u8],
54+
) -> Result<usize, Error>
1755
where
1856
T: serde::ser::Serialize,
1957
{
20-
writer.iter_mut().for_each(|x| *x = 0);
58+
writer.fill(0);
2159

22-
let string_block_length = {
60+
let (string_block_length, structure_length) = {
2361
let mut offset: usize = 0;
24-
{
25-
let mut dst = crate::ser::pointer::Pointer::new(None);
26-
let mut patch_list = crate::ser::patch::PatchList::new(list);
27-
let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset);
28-
let mut ser =
29-
crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list);
30-
let ser = crate::ser::serializer::Serializer::new(&mut ser);
31-
data.serialize(ser)?;
32-
offset
33-
};
34-
{
35-
let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset);
36-
block.align();
37-
};
38-
offset
62+
let mut block = crate::ser::string_block::StringBlock::new(Some(writer), &mut offset);
63+
let mut dst = crate::ser::pointer::Pointer::new(None);
64+
let mut patch_list = crate::ser::patch::PatchList::new(list);
65+
let mut ser =
66+
crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list);
67+
let ser = crate::ser::serializer::Serializer::new(&mut ser);
68+
let structure_length = data.serialize(ser)?.1;
69+
(offset, structure_length)
3970
};
71+
72+
// Clear string block
73+
writer[0..string_block_length].fill(0);
4074
list.iter().for_each(|patch| patch.init());
41-
// Write from bottom to top, to avoid overlap.
42-
for i in (0..string_block_length).rev() {
43-
writer[writer.len() - string_block_length + i] = writer[i];
44-
writer[i] = 0;
45-
}
75+
let string_block_start = HEADER_PADDING_LEN as usize + RSVMAP_LEN + structure_length;
4676

47-
let struct_len = {
48-
let (data_block, string_block) = writer.split_at_mut(writer.len() - string_block_length);
77+
{
78+
let (data_block, string_block) = writer.split_at_mut(string_block_start);
4979
let (_, data_block) = data_block.split_at_mut(HEADER_PADDING_LEN as usize + RSVMAP_LEN);
80+
5081
let mut patch_list = crate::ser::patch::PatchList::new(list);
51-
let mut temp_length = string_block_length;
52-
let mut block = crate::ser::string_block::StringBlock::new(string_block, &mut temp_length);
82+
let mut temp_length = 0;
83+
let mut block =
84+
crate::ser::string_block::StringBlock::new(Some(string_block), &mut temp_length);
5385
let mut dst = crate::ser::pointer::Pointer::new(Some(data_block));
5486
let mut ser =
5587
crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list);
5688
let ser = crate::ser::serializer::Serializer::new(&mut ser);
5789
let struct_len = data.serialize(ser)?.1;
58-
assert_eq!(struct_len % 4, 0); // As spec, structure block align with 4 bytes.
5990
assert_eq!(temp_length, string_block_length); // StringBlock should be same with first run.
6091
struct_len
6192
};
6293

63-
// Align to 8-bytes.
64-
for i in 0..string_block_length {
65-
writer[HEADER_PADDING_LEN as usize + RSVMAP_LEN + struct_len + i] =
66-
writer[writer.len() - string_block_length + i];
67-
writer[writer.len() - string_block_length + i] = 0;
68-
}
94+
let result = make_header(writer, structure_length as u32, string_block_length as u32);
6995

70-
// Make header
71-
{
72-
let (header, _) = writer.split_at_mut(HEADER_LEN as usize);
73-
let header = unsafe { &mut *(header.as_mut_ptr() as *mut Header) };
74-
header.magic = u32::from_be(DEVICE_TREE_MAGIC);
75-
header.total_size = u32::from_be(
76-
HEADER_PADDING_LEN + (RSVMAP_LEN + struct_len + string_block_length) as u32,
77-
);
78-
assert_eq!(header.total_size % 8, 0);
79-
header.off_dt_struct = u32::from_be(HEADER_PADDING_LEN + RSVMAP_LEN as u32);
80-
header.off_dt_strings = u32::from_be(HEADER_PADDING_LEN + (RSVMAP_LEN + struct_len) as u32);
81-
header.off_mem_rsvmap = u32::from_be(HEADER_PADDING_LEN);
82-
header.version = u32::from_be(SUPPORTED_VERSION);
83-
header.last_comp_version = u32::from_be(SUPPORTED_VERSION); // TODO: maybe 16
84-
header.boot_cpuid_phys = 0; // TODO
85-
header.size_dt_strings = u32::from_be(string_block_length as u32);
86-
header.size_dt_struct = u32::from_be(struct_len as u32);
87-
}
88-
Ok(())
96+
Ok(result)
97+
}
98+
99+
#[cfg(feature = "alloc")]
100+
pub fn probe_dtb_length<'se, T>(data: &T, list: &'se [Patch<'se>]) -> Result<usize, Error>
101+
where
102+
T: serde::ser::Serialize,
103+
{
104+
let mut offset: usize = 0;
105+
let structure_length = {
106+
let mut dst = crate::ser::pointer::Pointer::new(None);
107+
let mut patch_list = crate::ser::patch::PatchList::new(list);
108+
let mut block = crate::ser::string_block::StringBlock::new(None, &mut offset);
109+
let mut ser =
110+
crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list);
111+
let ser = crate::ser::serializer::Serializer::new(&mut ser);
112+
data.serialize(ser)?.1
113+
};
114+
115+
let total_size = HEADER_PADDING_LEN as usize + RSVMAP_LEN + structure_length + offset;
116+
let padding = get_structure_padding(total_size);
117+
let total_size = total_size + padding;
118+
Ok(total_size)
89119
}
90120

91121
#[derive(Debug)]

src/ser/serializer.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,4 +763,39 @@ mod tests {
763763
// println!("{:x?}", buf1);
764764
// assert!(false);
765765
}
766+
#[test]
767+
#[cfg(feature = "alloc")]
768+
fn probe_length() {
769+
#[derive(Serialize)]
770+
struct Base {
771+
pub hello: u32,
772+
pub base1: Base1,
773+
pub hello2: u32,
774+
pub base2: Base1,
775+
}
776+
#[derive(Serialize)]
777+
struct Base1 {
778+
pub hello: &'static str,
779+
}
780+
let mut buf1 = [0u8; MAX_SIZE];
781+
782+
let new_base = Base1 { hello: "added" };
783+
let patch = crate::ser::patch::Patch::new(
784+
"/base3",
785+
&new_base as _,
786+
crate::ser::serializer::ValueType::Node,
787+
);
788+
let list = [patch];
789+
let base = Base {
790+
hello: 0xdeedbeef,
791+
base1: Base1 {
792+
hello: "Hello, World!",
793+
},
794+
hello2: 0x11223344,
795+
base2: Base1 { hello: "Roger" },
796+
};
797+
let probe_legnth = crate::ser::probe_dtb_length(&base, &list).unwrap();
798+
let result = crate::ser::to_dtb(&base, &list, &mut buf1).unwrap();
799+
assert_eq!(probe_legnth, result);
800+
}
766801
}

src/ser/string_block.rs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
1+
#[cfg(feature = "alloc")]
2+
use alloc::collections::BTreeMap;
3+
14
/// StringBlock
25
/// As spec said, dtb have a block called string block for saving prop names.
36
pub struct StringBlock<'se> {
47
end: &'se mut usize,
5-
data: &'se mut [u8],
8+
data: Option<&'se mut [u8]>,
9+
#[cfg(feature = "alloc")]
10+
tree: BTreeMap<&'se str, usize>,
611
}
712

813
impl<'se> StringBlock<'se> {
914
/// Make a new string block.
1015
///
1116
/// For get how long is string block, we make `end` as a mut ref.
1217
#[inline(always)]
13-
pub fn new(dst: &'se mut [u8], end: &'se mut usize) -> StringBlock<'se> {
14-
StringBlock { data: dst, end }
18+
pub fn new(dst: Option<&'se mut [u8]>, end: &'se mut usize) -> StringBlock<'se> {
19+
StringBlock {
20+
data: dst,
21+
#[cfg(feature = "alloc")]
22+
tree: BTreeMap::new(),
23+
end,
24+
}
1525
}
1626

1727
// TODO: show as error
@@ -24,26 +34,39 @@ impl<'se> StringBlock<'se> {
2434
if offset > *self.end {
2535
panic!("invalid read");
2636
}
27-
let current_slice = &self.data[offset..];
28-
let pos = current_slice
29-
.iter()
30-
.position(|&x| x == b'\0')
31-
.unwrap_or(self.data.len());
32-
let (a, _) = current_slice.split_at(pos + 1);
33-
let result = unsafe { core::str::from_utf8_unchecked(&a[..a.len() - 1]) };
34-
(result, pos + offset + 1)
37+
if let Some(data) = &self.data {
38+
let current_slice = &data[offset..];
39+
let pos = current_slice
40+
.iter()
41+
.position(|&x| x == b'\0')
42+
.unwrap_or(data.len());
43+
let (a, _) = current_slice.split_at(pos + 1);
44+
let result = unsafe { core::str::from_utf8_unchecked(&a[..a.len() - 1]) };
45+
(result, pos + offset + 1)
46+
} else {
47+
panic!("must have writer when no alloc");
48+
}
49+
}
50+
51+
#[inline(always)]
52+
fn write_u8(&mut self, index: usize, data: u8) {
53+
if let Some(buffer) = &mut self.data {
54+
buffer[index] = data;
55+
}
3556
}
3657

3758
#[inline(always)]
3859
fn insert_u8(&mut self, data: u8) {
39-
self.data[*self.end] = data;
60+
self.write_u8(*self.end, data);
4061
*self.end += 1;
4162
}
4263

4364
/// Return the start offset of inserted string.
4465
#[inline(always)]
45-
pub fn insert_str(&mut self, name: &str) -> usize {
66+
pub fn insert_str(&mut self, name: &'se str) -> usize {
4667
let result = *self.end;
68+
#[cfg(feature = "alloc")]
69+
self.tree.insert(name, result);
4770
name.bytes().for_each(|x| {
4871
self.insert_u8(x);
4972
});
@@ -55,14 +78,14 @@ impl<'se> StringBlock<'se> {
5578
#[inline(always)]
5679
pub fn align(&mut self) {
5780
while (*self.end & 0b111) != 0 {
58-
self.data[*self.end] = 0;
59-
*self.end += 1;
81+
self.insert_u8(0);
6082
}
6183
}
6284

6385
/// Find a string. If not found, insert it.
6486
#[inline(always)]
65-
pub fn find_or_insert(&mut self, name: &str) -> usize {
87+
#[cfg(not(feature = "alloc"))]
88+
pub fn find_or_insert(&mut self, name: &'se str) -> usize {
6689
let mut current_pos = 0;
6790
while current_pos < *self.end {
6891
let (result, new_pos) = self.get_str_by_offset(current_pos);
@@ -74,4 +97,15 @@ impl<'se> StringBlock<'se> {
7497

7598
self.insert_str(name)
7699
}
100+
101+
#[inline(always)]
102+
#[cfg(feature = "alloc")]
103+
pub fn find_or_insert(&mut self, name: &'se str) -> usize {
104+
let result = self.tree.get(name);
105+
if result.is_some() {
106+
*result.unwrap()
107+
} else {
108+
self.insert_str(name)
109+
}
110+
}
77111
}

0 commit comments

Comments
 (0)