|
1 | 1 | //! DTB (Device Tree Blob) related functionality. |
2 | | -use fdt_parser::{Fdt, FdtHeader}; |
3 | | - |
4 | 2 | use core::fmt::Write; |
| 3 | +use fdt_parser::{Fdt, FdtHeader}; |
5 | 4 | use lazyinit::LazyInit; |
6 | 5 |
|
7 | | -static BOOTARGS_STR: LazyInit<heapless::String<256>> = LazyInit::new(); |
| 6 | +/// Record address of the boot argument (DTB address). |
| 7 | +pub static BOOT_ARG: LazyInit<usize> = LazyInit::new(); |
| 8 | +static CACHED_FDT: LazyInit<Fdt<'static>> = LazyInit::new(); |
| 9 | +static BOOTARGS_STR: LazyInit<heapless::String<1024>> = LazyInit::new(); |
| 10 | + |
| 11 | +/// Returns the boot argument. |
| 12 | +/// This is typically the device tree blob address passed from the bootloader. |
| 13 | +pub fn get_bootarg() -> usize { |
| 14 | + *BOOT_ARG |
| 15 | +} |
8 | 16 |
|
9 | | -/// Get the bootargs from the device tree. |
10 | | -pub fn bootargs_message() -> Option<&'static str> { |
11 | | - let fdt_addr = crate::get_bootarg(); |
| 17 | +/// Get the cached FDT or initialize it if not already done. |
| 18 | +fn get_fdt() -> Option<&'static Fdt<'static>> { |
| 19 | + // Return cached FDT if available |
| 20 | + if let Some(fdt) = CACHED_FDT.get() { |
| 21 | + return Some(fdt); |
| 22 | + } |
12 | 23 |
|
| 24 | + // Parse and cache the FDT |
| 25 | + let fdt_addr = get_bootarg(); |
13 | 26 | if fdt_addr == 0 { |
14 | 27 | return None; |
15 | 28 | } |
16 | 29 |
|
17 | 30 | let virt_addr = crate::mem::phys_to_virt(crate::mem::PhysAddr::from(fdt_addr)).as_usize(); |
18 | 31 |
|
19 | | - let fdt_header = unsafe { |
| 32 | + let fdt = unsafe { |
| 33 | + // First read the header to get the size |
20 | 34 | let header_size = core::mem::size_of::<FdtHeader>(); |
21 | | - let ptr = virt_addr as *const u8; |
22 | | - core::slice::from_raw_parts(ptr, header_size) |
23 | | - }; |
| 35 | + let header_ptr = virt_addr as *const u8; |
| 36 | + let header_slice = core::slice::from_raw_parts(header_ptr, header_size); |
24 | 37 |
|
25 | | - let fdt_header = match FdtHeader::from_bytes(fdt_header) { |
26 | | - Ok(header) => header, |
27 | | - Err(_) => return None, |
28 | | - }; |
| 38 | + let fdt_header = match FdtHeader::from_bytes(header_slice) { |
| 39 | + Ok(header) => header, |
| 40 | + Err(_) => return None, |
| 41 | + }; |
29 | 42 |
|
30 | | - let fdt_bytes = unsafe { |
31 | | - let ptr = virt_addr as *const u8; |
32 | 43 | let size = fdt_header.total_size() as usize; |
33 | | - core::slice::from_raw_parts(ptr, size) |
34 | | - }; |
| 44 | + let fdt_ptr = virt_addr as *const u8; |
| 45 | + let fdt_slice = core::slice::from_raw_parts(fdt_ptr, size); |
| 46 | + |
| 47 | + let fdt_slice_static = core::mem::transmute::<&[u8], &'static [u8]>(fdt_slice); |
35 | 48 |
|
36 | | - let fdt = match Fdt::from_bytes(fdt_bytes) { |
37 | | - Ok(fdt) => fdt, |
38 | | - Err(_) => return None, |
| 49 | + match Fdt::from_bytes(fdt_slice_static) { |
| 50 | + Ok(fdt) => fdt, |
| 51 | + Err(_) => return None, |
| 52 | + } |
39 | 53 | }; |
40 | 54 |
|
| 55 | + // Store the FDT in the cache |
| 56 | + CACHED_FDT.init_once(fdt); |
| 57 | + CACHED_FDT.get() |
| 58 | +} |
| 59 | + |
| 60 | +/// Get the bootargs chosen from the device tree. |
| 61 | +pub fn get_chosen() -> Option<&'static str> { |
| 62 | + // If bootargs are already cached, return them |
| 63 | + if let Some(bootargs) = BOOTARGS_STR.get() { |
| 64 | + return Some(bootargs.as_str()); |
| 65 | + } |
| 66 | + |
| 67 | + // Get or initialize the cached FDT |
| 68 | + let fdt = get_fdt()?; |
| 69 | + |
41 | 70 | if let Some(chosen) = fdt.chosen() { |
42 | 71 | if let Some(bootargs) = chosen.bootargs() { |
43 | 72 | // Store bootargs in static variable |
44 | | - let mut bootargs_str = heapless::String::<256>::new(); |
| 73 | + let mut bootargs_str = heapless::String::<1024>::new(); |
45 | 74 | if write!(bootargs_str, "{}", bootargs).is_ok() { |
46 | 75 | BOOTARGS_STR.init_once(bootargs_str); |
47 | 76 | return Some(BOOTARGS_STR.as_str()); |
| 77 | + } else { |
| 78 | + warn!("Failed to write bootargs"); |
48 | 79 | } |
49 | 80 | } |
50 | 81 | } |
|
0 commit comments