1#[cfg(any(target_os = "android", target_os = "linux"))]
6use std::collections::BTreeMap;
7use std::fs::File;
8use std::fs::OpenOptions;
9use std::io::Write;
10use std::path::PathBuf;
11
12use arch::android::create_android_fdt;
13use arch::apply_device_tree_overlays;
14use arch::fdt::create_memory_node;
15use arch::fdt::create_reserved_memory_node;
16use arch::fdt::reserved_memory_regions_from_guest_mem;
17use arch::DtbOverlay;
18use base::open_file_or_duplicate;
19use cros_fdt::Error;
20use cros_fdt::Fdt;
21use resources::AddressRange;
22use vm_memory::GuestAddress;
23use vm_memory::GuestMemory;
24
25fn create_config_node(fdt: &mut Fdt, kernel_region: AddressRange) -> cros_fdt::Result<()> {
26 let addr: u32 = kernel_region
27 .start
28 .try_into()
29 .map_err(|_| Error::PropertyValueTooLarge)?;
30 let size: u32 = kernel_region
31 .len()
32 .expect("invalid kernel_region")
33 .try_into()
34 .map_err(|_| Error::PropertyValueTooLarge)?;
35
36 let config_node = fdt.root_mut().subnode_mut("config")?;
37 config_node.set_prop("kernel-address", addr)?;
38 config_node.set_prop("kernel-size", size)?;
39 Ok(())
40}
41
42fn create_chosen_node(fdt: &mut Fdt, initrd: Option<(GuestAddress, u32)>) -> cros_fdt::Result<()> {
43 let chosen_node = fdt.root_mut().subnode_mut("chosen")?;
44
45 if let Some((initrd_addr, initrd_size)) = initrd {
46 let initrd_start: u64 = initrd_addr.offset();
47 let initrd_end: u64 = initrd_start + initrd_size as u64;
48 chosen_node.set_prop("linux,initrd-start", initrd_start)?;
49 chosen_node.set_prop("linux,initrd-end", initrd_end)?;
50 }
51
52 Ok(())
53}
54
55pub fn create_fdt(
62 guest_mem: &GuestMemory,
63 android_fstab: Option<File>,
64 dump_device_tree_blob: Option<PathBuf>,
65 device_tree_overlays: Vec<DtbOverlay>,
66 kernel_region: AddressRange,
67 initrd: Option<(GuestAddress, u32)>,
68) -> Result<Vec<u8>, Error> {
69 let mut fdt = Fdt::new(&[]);
70 let reserved_memory_regions = reserved_memory_regions_from_guest_mem(guest_mem);
71
72 let root_node = fdt.root_mut();
74 root_node.set_prop("#address-cells", 0x2u32)?;
75 root_node.set_prop("#size-cells", 0x2u32)?;
76
77 if let Some(android_fstab) = android_fstab {
78 create_android_fdt(&mut fdt, android_fstab)?;
79 }
80
81 create_config_node(&mut fdt, kernel_region)?;
82 create_chosen_node(&mut fdt, initrd)?;
83 create_memory_node(&mut fdt, guest_mem)?;
84 create_reserved_memory_node(&mut fdt, &reserved_memory_regions)?;
85
86 apply_device_tree_overlays(
88 &mut fdt,
89 device_tree_overlays,
90 #[cfg(any(target_os = "android", target_os = "linux"))]
91 vec![],
92 #[cfg(any(target_os = "android", target_os = "linux"))]
93 &BTreeMap::new(),
94 )?;
95
96 let fdt_final = fdt.finish()?;
97
98 if let Some(file_path) = dump_device_tree_blob {
99 let mut fd = open_file_or_duplicate(
100 &file_path,
101 OpenOptions::new()
102 .read(true)
103 .create(true)
104 .truncate(true)
105 .write(true),
106 )
107 .map_err(|e| Error::FdtIoError(e.into()))?;
108 fd.write_all(&fdt_final)
109 .map_err(|e| Error::FdtDumpIoError(e, file_path.clone()))?;
110 }
111
112 Ok(fdt_final)
113}