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