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