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
5use 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
54/// Creates a flattened device tree containing all of the parameters for the
55/// kernel and returns it as DTB.
56///
57/// # Arguments
58///
59/// * `android_fstab` - the File object for the android fstab
60pub 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    // The whole thing is put into one giant node with some top level properties
72    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    // Done writing base FDT, now apply DT overlays
86    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}