| // Copyright 2018 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #[cfg(any(target_os = "android", target_os = "linux"))] |
| use std::collections::BTreeMap; |
| use std::fs::File; |
| use std::fs::OpenOptions; |
| use std::io::Write; |
| use std::path::PathBuf; |
| |
| use arch::android::create_android_fdt; |
| use arch::apply_device_tree_overlays; |
| use arch::fdt::create_memory_node; |
| use arch::fdt::create_reserved_memory_node; |
| use arch::fdt::reserved_memory_regions_from_guest_mem; |
| use arch::DtbOverlay; |
| use base::open_file_or_duplicate; |
| use cros_fdt::Error; |
| use cros_fdt::Fdt; |
| use resources::AddressRange; |
| use vm_memory::GuestAddress; |
| use vm_memory::GuestMemory; |
| |
| fn create_config_node(fdt: &mut Fdt, kernel_region: AddressRange) -> cros_fdt::Result<()> { |
| let addr: u32 = kernel_region |
| .start |
| .try_into() |
| .map_err(|_| Error::PropertyValueTooLarge)?; |
| let size: u32 = kernel_region |
| .len() |
| .expect("invalid kernel_region") |
| .try_into() |
| .map_err(|_| Error::PropertyValueTooLarge)?; |
| |
| let config_node = fdt.root_mut().subnode_mut("config")?; |
| config_node.set_prop("kernel-address", addr)?; |
| config_node.set_prop("kernel-size", size)?; |
| Ok(()) |
| } |
| |
| fn create_chosen_node(fdt: &mut Fdt, initrd: Option<(GuestAddress, u32)>) -> cros_fdt::Result<()> { |
| let chosen_node = fdt.root_mut().subnode_mut("chosen")?; |
| |
| if let Some((initrd_addr, initrd_size)) = initrd { |
| let initrd_start: u64 = initrd_addr.offset(); |
| let initrd_end: u64 = initrd_start + initrd_size as u64; |
| chosen_node.set_prop("linux,initrd-start", initrd_start)?; |
| chosen_node.set_prop("linux,initrd-end", initrd_end)?; |
| } |
| |
| Ok(()) |
| } |
| |
| /// Creates a flattened device tree containing all of the parameters for the |
| /// kernel and returns it as DTB. |
| /// |
| /// # Arguments |
| /// |
| /// * `android_fstab` - the File object for the android fstab |
| pub fn create_fdt( |
| guest_mem: &GuestMemory, |
| android_fstab: Option<File>, |
| dump_device_tree_blob: Option<PathBuf>, |
| device_tree_overlays: Vec<DtbOverlay>, |
| kernel_region: AddressRange, |
| initrd: Option<(GuestAddress, u32)>, |
| ) -> Result<Vec<u8>, Error> { |
| let mut fdt = Fdt::new(&[]); |
| let reserved_memory_regions = reserved_memory_regions_from_guest_mem(guest_mem); |
| |
| // The whole thing is put into one giant node with some top level properties |
| let root_node = fdt.root_mut(); |
| root_node.set_prop("#address-cells", 0x2u32)?; |
| root_node.set_prop("#size-cells", 0x2u32)?; |
| |
| if let Some(android_fstab) = android_fstab { |
| create_android_fdt(&mut fdt, android_fstab)?; |
| } |
| |
| create_config_node(&mut fdt, kernel_region)?; |
| create_chosen_node(&mut fdt, initrd)?; |
| create_memory_node(&mut fdt, guest_mem)?; |
| create_reserved_memory_node(&mut fdt, &reserved_memory_regions)?; |
| |
| // Done writing base FDT, now apply DT overlays |
| apply_device_tree_overlays( |
| &mut fdt, |
| device_tree_overlays, |
| #[cfg(any(target_os = "android", target_os = "linux"))] |
| vec![], |
| #[cfg(any(target_os = "android", target_os = "linux"))] |
| &BTreeMap::new(), |
| )?; |
| |
| let fdt_final = fdt.finish()?; |
| |
| if let Some(file_path) = dump_device_tree_blob { |
| let mut fd = open_file_or_duplicate( |
| &file_path, |
| OpenOptions::new() |
| .read(true) |
| .create(true) |
| .truncate(true) |
| .write(true), |
| ) |
| .map_err(|e| Error::FdtIoError(e.into()))?; |
| fd.write_all(&fdt_final) |
| .map_err(|e| Error::FdtDumpIoError(e, file_path.clone()))?; |
| } |
| |
| Ok(fdt_final) |
| } |