@@ -11,7 +11,7 @@ cfg_if::cfg_if! {
1111 }
1212}
1313
14- use alloc:: format;
14+ use alloc:: { format, vec } ;
1515#[ allow( unused) ]
1616use core:: arch:: { asm, naked_asm} ;
1717use core:: ops:: Range ;
@@ -38,9 +38,6 @@ pub struct BootHart {
3838pub extern "C" fn raw_fdt ( ) {
3939 naked_asm ! ( concat!( ".incbin \" " , env!( "PROTOTYPER_FDT_PATH" ) , "\" " ) , )
4040}
41- const DEVICE_TREE_BUFFER_LENGTH : usize = 0x10000 ;
42- #[ unsafe( link_section = ".patched_fdt" ) ]
43- static mut DEVICE_TREE_BUFFER : [ u8 ; DEVICE_TREE_BUFFER_LENGTH ] = [ 0u8 ; DEVICE_TREE_BUFFER_LENGTH ] ;
4441
4542#[ inline]
4643#[ cfg( feature = "fdt" ) ]
@@ -71,16 +68,12 @@ pub fn get_boot_hart(opaque: usize, nonstandard_a2: usize) -> BootHart {
7168pub fn patch_device_tree ( device_tree_ptr : usize ) -> usize {
7269 use serde_device_tree:: buildin:: Node ;
7370 use serde_device_tree:: ser:: serializer:: ValueType ;
74- use serde_device_tree:: * ;
71+ use serde_device_tree:: { Dtb , DtbPtr } ;
7572 let Ok ( ptr) = DtbPtr :: from_raw ( device_tree_ptr as * mut _ ) else {
7673 panic ! ( "Can not parse device tree!" ) ;
7774 } ;
78- let origin_size = ptr. align ( ) ;
75+ let original_length = ptr. align ( ) ;
7976 let dtb = Dtb :: from ( ptr) ;
80- // TODO: use probe length instead of a magic const number.
81- if origin_size + 2048 > DEVICE_TREE_BUFFER_LENGTH {
82- panic ! ( "dtb file is too big!" ) ;
83- }
8477
8578 // Update const
8679 unsafe {
@@ -91,7 +84,7 @@ pub fn patch_device_tree(device_tree_ptr: usize) -> usize {
9184 let sbi_end = unsafe { SBI_END_ADDRESS } ;
9285
9386 let dtb = dtb. share ( ) ;
94- let root: serde_device_tree :: buildin :: Node =
87+ let root: Node =
9588 serde_device_tree:: from_raw_mut ( & dtb) . unwrap_or_else ( fail:: device_tree_deserialize_root) ;
9689 let tree: Node = root. deserialize ( ) ;
9790
@@ -129,17 +122,38 @@ pub fn patch_device_tree(device_tree_ptr: usize) -> usize {
129122 let patch2 =
130123 serde_device_tree:: ser:: patch:: Patch :: new ( & path_name, & new_base_2 as _ , ValueType :: Node ) ;
131124 let raw_list = [ patch1, patch2] ;
132- // Only patch `reserved-memory` when it not exists.
125+ // Only add `reserved-memory` section when it not exists.
133126 let list = if tree. find ( "/reserved-memory" ) . is_some ( ) {
134127 & raw_list[ 1 ..]
135128 } else {
136129 & raw_list[ ..]
137130 } ;
138131
139- unsafe {
140- serde_device_tree:: ser:: to_dtb ( & tree, & list, & mut DEVICE_TREE_BUFFER ) . unwrap ( ) ;
141- DEVICE_TREE_BUFFER . as_ptr ( ) as _
142- }
132+ // Firstly, allocate a temporary buffer to store the fdt and get the real total size of the patched fdt.
133+ // TODO: The serde_device_tree can provide a function to calculate the accuracy size of patched fdt.
134+ debug ! (
135+ "Allocate temporary DTB buffer with length 0x{:x}." ,
136+ original_length + 2048
137+ ) ;
138+ let mut temporary_buffer = vec ! [ 0u8 ; original_length + 2048 ] ;
139+ serde_device_tree:: ser:: to_dtb ( & tree, & list, & mut temporary_buffer) . unwrap ( ) ;
140+ let Ok ( patched_dtb_ptr) = DtbPtr :: from_raw ( temporary_buffer. as_mut_ptr ( ) ) else {
141+ panic ! ( "Failed to parse the patched dtb." )
142+ } ;
143+ let patched_length = patched_dtb_ptr. align ( ) ;
144+
145+ // Secondly, allocate the exactly buffer to store the fdt.
146+ let mut patched_dtb_buffer = vec ! [ 0u8 ; patched_length] ;
147+ serde_device_tree:: ser:: to_dtb ( & tree, & list, & mut patched_dtb_buffer) . unwrap ( ) ;
148+ // Intentionally leak the buffer so that the patched DTB remains valid for the lifetime of the firmware.
149+ // This is required because the returned pointer is used elsewhere and must not be deallocated.
150+ let patched_dtb = patched_dtb_buffer. leak ( ) ;
151+ info ! (
152+ "The patched dtb is located at 0x{:x} with length 0x{:x}." ,
153+ patched_dtb. as_ptr( ) as usize ,
154+ patched_length
155+ ) ;
156+ patched_dtb. as_ptr ( ) as usize
143157}
144158
145159static mut SBI_START_ADDRESS : usize = 0 ;
0 commit comments