x86_64/
fdt.rs

1// Copyright 2018 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#[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
55/// Creates a flattened device tree containing all of the parameters for the
56/// kernel and returns it as DTB.
57///
58/// # Arguments
59///
60/// * `android_fstab` - the File object for the android fstab
61pub 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    // The whole thing is put into one giant node with some top level properties
73    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    // Done writing base FDT, now apply DT overlays
87    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}