@@ -11,7 +11,7 @@ use alloc::collections::btree_map::BTreeMap;
1111use alloc:: string:: String ;
1212use alloc:: vec:: Vec ;
1313
14- use zerocopy:: IntoBytes ;
14+ use zerocopy:: { FromZeros , IntoBytes } ;
1515
1616use crate :: fdt:: { FDT_BEGIN_NODE , FDT_END , FDT_END_NODE , FDT_MAGIC , FDT_PROP , Fdt , FdtHeader } ;
1717use crate :: memreserve:: MemoryReservation ;
@@ -22,17 +22,26 @@ const LAST_VERSION: u32 = 17;
2222const LAST_COMP_VERSION : u32 = 16 ;
2323
2424pub ( crate ) fn to_bytes ( tree : & DeviceTree ) -> Vec < u8 > {
25- let memory_reservations = write_memory_reservations ( & tree. memory_reservations ) ;
26- let ( struct_block, strings_block) = write_root ( & tree. root ) ;
25+ let mut dtb = Vec :: new ( ) ;
2726
28- let off_mem_rsvmap = size_of :: < FdtHeader > ( ) ;
29- let off_dt_struct = off_mem_rsvmap + memory_reservations. len ( ) ;
30- let off_dt_strings = off_dt_struct + struct_block. len ( ) ;
31- let totalsize = off_dt_strings + strings_block. len ( ) ;
27+ // reserve space for header
28+ dtb. extend_from_slice ( FdtHeader :: new_zeroed ( ) . as_bytes ( ) ) ;
3229
33- let mut dtb = Vec :: new ( ) ;
30+ let off_mem_rsvmap = dtb. len ( ) ;
31+ write_memory_reservations ( & mut dtb, & tree. memory_reservations ) ;
32+
33+ let off_dt_struct = dtb. len ( ) ;
34+ let mut string_map = StringMap :: new ( ) ;
35+ write_root ( & mut dtb, & mut string_map, & tree. root ) ;
3436
35- // Header
37+ let off_dt_strings = dtb. len ( ) ;
38+ string_map. write_string_block ( & mut dtb) ;
39+
40+ let totalsize = dtb. len ( ) ;
41+ let size_dt_strings = totalsize - off_dt_strings;
42+ let size_dt_struct = off_dt_strings - off_dt_struct;
43+
44+ // write header
3645 let header = FdtHeader {
3746 magic : FDT_MAGIC . into ( ) ,
3847 totalsize : u32:: try_from ( totalsize)
@@ -50,110 +59,104 @@ pub(crate) fn to_bytes(tree: &DeviceTree) -> Vec<u8> {
5059 version : LAST_VERSION . into ( ) ,
5160 last_comp_version : LAST_COMP_VERSION . into ( ) ,
5261 boot_cpuid_phys : 0u32 . into ( ) ,
53- size_dt_strings : u32:: try_from ( strings_block . len ( ) )
62+ size_dt_strings : u32:: try_from ( size_dt_strings )
5463 . expect ( "size_dt_strings exceeds u32" )
5564 . into ( ) ,
56- size_dt_struct : u32:: try_from ( struct_block . len ( ) )
65+ size_dt_struct : u32:: try_from ( size_dt_struct )
5766 . expect ( "size_dt_struct exceeds u32" )
5867 . into ( ) ,
5968 } ;
60- dtb. extend_from_slice ( header. as_bytes ( ) ) ;
61- assert_eq ! (
62- dtb. len( ) ,
63- size_of:: <FdtHeader >( ) ,
64- "invalid header size after writing"
65- ) ;
6669
67- // Memory reservations block
68- dtb. extend_from_slice ( & memory_reservations) ;
69-
70- // Struct block
71- dtb. extend_from_slice ( & struct_block) ;
72-
73- // Strings block
74- dtb. extend_from_slice ( & strings_block) ;
70+ dtb[ ..size_of :: < FdtHeader > ( ) ] . copy_from_slice ( header. as_bytes ( ) ) ;
7571
7672 dtb
7773}
7874
79- fn write_memory_reservations ( reservations : & [ MemoryReservation ] ) -> Vec < u8 > {
80- let mut memory_reservations = Vec :: new ( ) ;
75+ fn write_memory_reservations ( dtb : & mut Vec < u8 > , reservations : & [ MemoryReservation ] ) {
8176 for reservation in reservations {
82- memory_reservations . extend_from_slice ( & reservation. address ( ) . to_be_bytes ( ) ) ;
83- memory_reservations . extend_from_slice ( & reservation. size ( ) . to_be_bytes ( ) ) ;
77+ dtb . extend_from_slice ( & reservation. address ( ) . to_be_bytes ( ) ) ;
78+ dtb . extend_from_slice ( & reservation. size ( ) . to_be_bytes ( ) ) ;
8479 }
85- memory_reservations. extend_from_slice ( & 0u64 . to_be_bytes ( ) ) ;
86- memory_reservations. extend_from_slice ( & 0u64 . to_be_bytes ( ) ) ;
87- memory_reservations
80+ dtb. extend_from_slice ( & 0u64 . to_be_bytes ( ) ) ;
81+ dtb. extend_from_slice ( & 0u64 . to_be_bytes ( ) ) ;
8882}
8983
90- fn write_root ( root_node : & DeviceTreeNode ) -> ( Vec < u8 > , Vec < u8 > ) {
91- let mut struct_block = Vec :: new ( ) ;
92- let mut strings_block = Vec :: new ( ) ;
93- let mut string_map = BTreeMap :: new ( ) ;
94-
95- write_node (
96- & mut struct_block,
97- & mut strings_block,
98- & mut string_map,
99- root_node,
100- ) ;
101- struct_block. extend_from_slice ( & FDT_END . to_be_bytes ( ) ) ;
102-
103- ( struct_block, strings_block)
84+ fn write_root ( dtb : & mut Vec < u8 > , string_map : & mut StringMap , root_node : & DeviceTreeNode ) {
85+ write_node ( dtb, string_map, root_node) ;
86+ dtb. extend_from_slice ( & FDT_END . to_be_bytes ( ) ) ;
10487}
10588
106- fn write_node (
107- struct_block : & mut Vec < u8 > ,
108- strings_block : & mut Vec < u8 > ,
109- string_map : & mut BTreeMap < String , u32 > ,
110- node : & DeviceTreeNode ,
111- ) {
112- struct_block. extend_from_slice ( & FDT_BEGIN_NODE . to_be_bytes ( ) ) ;
113- struct_block. extend_from_slice ( node. name ( ) . as_bytes ( ) ) ;
114- struct_block. push ( 0 ) ;
115- align ( struct_block) ;
89+ fn write_node ( dtb : & mut Vec < u8 > , string_map : & mut StringMap , node : & DeviceTreeNode ) {
90+ dtb. extend_from_slice ( & FDT_BEGIN_NODE . to_be_bytes ( ) ) ;
91+ dtb. extend_from_slice ( node. name ( ) . as_bytes ( ) ) ;
92+ dtb. push ( 0 ) ;
93+ align ( dtb) ;
11694
11795 for prop in node. properties ( ) {
118- write_prop ( struct_block , strings_block , string_map, prop) ;
96+ write_prop ( dtb , string_map, prop) ;
11997 }
12098
12199 for child in node. children ( ) {
122- write_node ( struct_block , strings_block , string_map, child) ;
100+ write_node ( dtb , string_map, child) ;
123101 }
124102
125- struct_block . extend_from_slice ( & FDT_END_NODE . to_be_bytes ( ) ) ;
103+ dtb . extend_from_slice ( & FDT_END_NODE . to_be_bytes ( ) ) ;
126104}
127105
128- fn write_prop (
129- struct_block : & mut Vec < u8 > ,
130- strings_block : & mut Vec < u8 > ,
131- string_map : & mut BTreeMap < String , u32 > ,
132- prop : & DeviceTreeProperty ,
133- ) {
134- let name_offset = if let Some ( offset) = string_map. get ( prop. name ( ) ) {
135- * offset
136- } else {
137- let offset = u32:: try_from ( strings_block. len ( ) ) . expect ( "string block length exceeds u32" ) ;
138- strings_block. extend_from_slice ( prop. name ( ) . as_bytes ( ) ) ;
139- strings_block. push ( 0 ) ;
140- string_map. insert ( prop. name ( ) . to_owned ( ) , offset) ;
141- offset
142- } ;
106+ fn write_prop ( dtb : & mut Vec < u8 > , string_map : & mut StringMap , prop : & DeviceTreeProperty ) {
107+ let name_offset = string_map. get_offset ( prop. name ( ) ) ;
143108
144- struct_block . extend_from_slice ( & FDT_PROP . to_be_bytes ( ) ) ;
145- struct_block . extend_from_slice (
109+ dtb . extend_from_slice ( & FDT_PROP . to_be_bytes ( ) ) ;
110+ dtb . extend_from_slice (
146111 & u32:: try_from ( prop. value ( ) . len ( ) )
147112 . expect ( "property value length exceeds u32" )
148113 . to_be_bytes ( ) ,
149114 ) ;
150- struct_block . extend_from_slice ( & name_offset. to_be_bytes ( ) ) ;
151- struct_block . extend_from_slice ( prop. value ( ) ) ;
152- align ( struct_block ) ;
115+ dtb . extend_from_slice ( & name_offset. to_be_bytes ( ) ) ;
116+ dtb . extend_from_slice ( prop. value ( ) ) ;
117+ align ( dtb ) ;
153118}
154119
155120fn align ( vec : & mut Vec < u8 > ) {
156121 let len = vec. len ( ) ;
157122 let new_len = Fdt :: align_tag_offset ( len) ;
158123 vec. resize ( new_len, 0 ) ;
159124}
125+
126+ struct StringMap {
127+ string_map : BTreeMap < String , u32 > ,
128+ next_offset : u32 ,
129+ }
130+
131+ impl StringMap {
132+ fn new ( ) -> Self {
133+ Self {
134+ string_map : BTreeMap :: new ( ) ,
135+ next_offset : 0 ,
136+ }
137+ }
138+
139+ fn get_offset ( & mut self , key : & str ) -> u32 {
140+ if let Some ( & offset) = self . string_map . get ( key) {
141+ offset
142+ } else {
143+ let offset = self . next_offset ;
144+ self . string_map . insert ( key. to_owned ( ) , offset) ;
145+ self . next_offset = u32:: try_from ( self . next_offset as usize + key. len ( ) + 1 )
146+ . expect ( "string block length exceeds u32" ) ;
147+ offset
148+ }
149+ }
150+
151+ fn write_string_block ( self , dtb : & mut Vec < u8 > ) {
152+ // write the strings in the order when they appear, mimicking the behavior
153+ // of `dtc` (Device Tree Compiler)
154+ let mut items: Vec < _ > = self . string_map . into_iter ( ) . collect ( ) ;
155+ items. sort_unstable_by_key ( |( _s, offset) | * offset) ;
156+
157+ for ( s, _offset) in items {
158+ dtb. extend_from_slice ( s. as_bytes ( ) ) ;
159+ dtb. push ( 0 ) ;
160+ }
161+ }
162+ }
0 commit comments