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(
43 fdt: &mut Fdt,
44 initrd: Option<(GuestAddress, usize)>,
45) -> cros_fdt::Result<()> {
46 let chosen_node = fdt.root_mut().subnode_mut("chosen")?;
47
48 if let Some((initrd_addr, initrd_size)) = initrd {
49 let initrd_start = initrd_addr.offset() as u32;
50 let initrd_end = initrd_start + initrd_size as u32;
51 chosen_node.set_prop("linux,initrd-start", initrd_start)?;
52 chosen_node.set_prop("linux,initrd-end", initrd_end)?;
53 }
54
55 Ok(())
56}
57
58pub fn create_fdt(
65 guest_mem: &GuestMemory,
66 android_fstab: Option<File>,
67 dump_device_tree_blob: Option<PathBuf>,
68 device_tree_overlays: Vec<DtbOverlay>,
69 kernel_region: AddressRange,
70 initrd: Option<(GuestAddress, usize)>,
71) -> Result<Vec<u8>, Error> {
72 let mut fdt = Fdt::new(&[]);
73 let reserved_memory_regions = reserved_memory_regions_from_guest_mem(guest_mem);
74
75 let root_node = fdt.root_mut();
77 root_node.set_prop("#address-cells", 0x2u32)?;
78 root_node.set_prop("#size-cells", 0x2u32)?;
79
80 if let Some(android_fstab) = android_fstab {
81 create_android_fdt(&mut fdt, android_fstab)?;
82 }
83
84 create_config_node(&mut fdt, kernel_region)?;
85 create_chosen_node(&mut fdt, initrd)?;
86 create_memory_node(&mut fdt, guest_mem)?;
87 create_reserved_memory_node(&mut fdt, &reserved_memory_regions)?;
88
89 apply_device_tree_overlays(
91 &mut fdt,
92 device_tree_overlays,
93 #[cfg(any(target_os = "android", target_os = "linux"))]
94 vec![],
95 #[cfg(any(target_os = "android", target_os = "linux"))]
96 &BTreeMap::new(),
97 )?;
98
99 let fdt_final = fdt.finish()?;
100
101 if let Some(file_path) = dump_device_tree_blob {
102 let mut fd = open_file_or_duplicate(
103 &file_path,
104 OpenOptions::new()
105 .read(true)
106 .create(true)
107 .truncate(true)
108 .write(true),
109 )
110 .map_err(|e| Error::FdtIoError(e.into()))?;
111 fd.write_all(&fdt_final)
112 .map_err(|e| Error::FdtDumpIoError(e, file_path.clone()))?;
113 }
114
115 Ok(fdt_final)
116}