mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 20:48:55 +00:00
crosvm: Apply device tree overlays
This change propagates the overlay files to the `fdt::create_fdt` function, load the file contents, and applies a series of device tree overlays to the base device tree after it has been constructed. Test: tools/run_tests Bug: b/296796644 Change-Id: I01f4db604fba5b8ecd756f93d092432145357977 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4855968 Commit-Queue: Jakob Vukalović <jakobvukalovic@google.com> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
d9bc6e99ff
commit
d31b856040
9 changed files with 86 additions and 4 deletions
|
@ -6,7 +6,9 @@ use std::collections::BTreeMap;
|
|||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use arch::apply_device_tree_overlays;
|
||||
use arch::CpuSet;
|
||||
use arch::DtbOverlay;
|
||||
use arch::SERIAL_ADDR;
|
||||
use cros_fdt::Error;
|
||||
use cros_fdt::Fdt;
|
||||
|
@ -207,6 +209,7 @@ fn create_gic_node(fdt: &mut Fdt, is_gicv3: bool, num_cpus: u64) -> Result<()> {
|
|||
intc_node.set_prop("phandle", PHANDLE_GIC)?;
|
||||
intc_node.set_prop("#address-cells", 2u32)?;
|
||||
intc_node.set_prop("#size-cells", 2u32)?;
|
||||
add_symbols_entry(fdt, "intc", "/intc")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -549,6 +552,22 @@ fn create_vmwdt_node(fdt: &mut Fdt, vmwdt_cfg: VmWdtConfig) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// Add a node path to __symbols__ node of the FDT, so it can be referenced by an overlay.
|
||||
fn add_symbols_entry(fdt: &mut Fdt, symbol: &str, path: &str) -> Result<()> {
|
||||
// Ensure the path points to a valid node with a defined phandle
|
||||
let Some(target_node) = fdt.get_node(path) else {
|
||||
return Err(Error::InvalidPath(format!("{path} does not exist")));
|
||||
};
|
||||
target_node
|
||||
.get_prop::<u32>("phandle")
|
||||
.or_else(|| target_node.get_prop("linux,phandle"))
|
||||
.ok_or_else(|| Error::InvalidPath(format!("{path} must have a phandle")))?;
|
||||
// Add the label -> path mapping.
|
||||
let symbols_node = fdt.root_mut().subnode_mut("__symbols__")?;
|
||||
symbols_node.set_prop(symbol, path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a flattened device tree containing all of the parameters for the
|
||||
/// kernel and loads it into the guest memory at the specified offset.
|
||||
///
|
||||
|
@ -595,6 +614,7 @@ pub fn create_fdt(
|
|||
dump_device_tree_blob: Option<PathBuf>,
|
||||
vm_generator: &impl Fn(&mut Fdt, &BTreeMap<&str, u32>) -> cros_fdt::Result<()>,
|
||||
dynamic_power_coefficient: BTreeMap<usize, u32>,
|
||||
device_tree_overlays: Vec<DtbOverlay>,
|
||||
) -> Result<()> {
|
||||
let mut fdt = Fdt::new(&[]);
|
||||
let mut phandles = BTreeMap::new();
|
||||
|
@ -647,6 +667,9 @@ pub fn create_fdt(
|
|||
create_virt_cpufreq_node(&mut fdt, num_cpus as u64)?;
|
||||
}
|
||||
|
||||
// Done writing base FDT, now apply DT overlays
|
||||
apply_device_tree_overlays(&mut fdt, device_tree_overlays)?;
|
||||
|
||||
let fdt_final = fdt.finish()?;
|
||||
|
||||
if let Some(file_path) = dump_device_tree_blob {
|
||||
|
@ -714,4 +737,23 @@ mod tests {
|
|||
vec!["arm,psci-1.0", "arm,psci-0.2"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbols_entries() {
|
||||
const TEST_SYMBOL: &str = "dev";
|
||||
const TEST_PATH: &str = "/dev";
|
||||
|
||||
let mut fdt = Fdt::new(&[]);
|
||||
add_symbols_entry(&mut fdt, TEST_SYMBOL, TEST_PATH).expect_err("missing node");
|
||||
|
||||
fdt.root_mut().subnode_mut(TEST_SYMBOL).unwrap();
|
||||
add_symbols_entry(&mut fdt, TEST_SYMBOL, TEST_PATH).expect_err("missing phandle");
|
||||
|
||||
let intc_node = fdt.get_node_mut(TEST_PATH).unwrap();
|
||||
intc_node.set_prop("phandle", 1u32).unwrap();
|
||||
add_symbols_entry(&mut fdt, TEST_SYMBOL, TEST_PATH).expect("valid path");
|
||||
|
||||
let symbols = fdt.get_node("/__symbols__").unwrap();
|
||||
assert_eq!(symbols.get_prop::<String>(TEST_SYMBOL).unwrap(), TEST_PATH);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -397,7 +397,7 @@ impl arch::LinuxArch for AArch64 {
|
|||
#[cfg(any(target_os = "android", target_os = "linux"))] _guest_suspended_cvar: Option<
|
||||
Arc<(Mutex<bool>, Condvar)>,
|
||||
>,
|
||||
_device_tree_overlays: Vec<DtbOverlay>,
|
||||
device_tree_overlays: Vec<DtbOverlay>,
|
||||
) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error>
|
||||
where
|
||||
V: VmAArch64,
|
||||
|
@ -751,6 +751,7 @@ impl arch::LinuxArch for AArch64 {
|
|||
dump_device_tree_blob,
|
||||
&|writer, phandles| vm.create_fdt(writer, phandles),
|
||||
components.dynamic_power_coefficient,
|
||||
device_tree_overlays,
|
||||
)
|
||||
.map_err(Error::CreateFdt)?;
|
||||
|
||||
|
|
|
@ -3,6 +3,25 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
use cros_fdt::apply_overlay;
|
||||
use cros_fdt::Error;
|
||||
use cros_fdt::Fdt;
|
||||
use cros_fdt::Result;
|
||||
|
||||
/// Device tree overlay file
|
||||
pub struct DtbOverlay(pub File);
|
||||
|
||||
/// Apply multiple device tree overlays to the base FDT.
|
||||
pub fn apply_device_tree_overlays(fdt: &mut Fdt, overlays: Vec<DtbOverlay>) -> Result<()> {
|
||||
for DtbOverlay(mut overlay_file) in overlays {
|
||||
let mut buffer = Vec::new();
|
||||
overlay_file
|
||||
.read_to_end(&mut buffer)
|
||||
.map_err(Error::FdtIoError)?;
|
||||
let overlay = Fdt::from_blob(buffer.as_slice())?;
|
||||
apply_overlay::<&str>(fdt, overlay, [])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ use devices::ProxyDevice;
|
|||
use devices::SerialHardware;
|
||||
use devices::SerialParameters;
|
||||
use devices::VirtioMmioDevice;
|
||||
pub use fdt::apply_device_tree_overlays;
|
||||
pub use fdt::DtbOverlay;
|
||||
#[cfg(feature = "gdb")]
|
||||
use gdbstub::arch::Arch;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use arch::apply_device_tree_overlays;
|
||||
use arch::DtbOverlay;
|
||||
use cros_fdt::Error;
|
||||
use cros_fdt::Fdt;
|
||||
use cros_fdt::Result;
|
||||
|
@ -302,6 +304,7 @@ pub fn create_fdt(
|
|||
cmdline: &str,
|
||||
initrd: Option<(GuestAddress, usize)>,
|
||||
timebase_frequency: u32,
|
||||
device_tree_overlays: Vec<DtbOverlay>,
|
||||
) -> Result<()> {
|
||||
let mut fdt = Fdt::new(&[]);
|
||||
|
||||
|
@ -316,6 +319,9 @@ pub fn create_fdt(
|
|||
create_aia_node(&mut fdt, num_cpus as usize, aia_num_ids, aia_num_sources)?;
|
||||
create_pci_nodes(&mut fdt, pci_irqs, pci_cfg, pci_ranges)?;
|
||||
|
||||
// Done writing base FDT, now apply DT overlays
|
||||
apply_device_tree_overlays(&mut fdt, device_tree_overlays)?;
|
||||
|
||||
let fdt_final = fdt.finish()?;
|
||||
if fdt_final.len() > fdt_max_size {
|
||||
return Err(Error::TotalSizeTooLarge);
|
||||
|
@ -328,5 +334,6 @@ pub fn create_fdt(
|
|||
if written < fdt_final.len() {
|
||||
return Err(Error::FdtGuestMemoryWriteError);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ impl arch::LinuxArch for Riscv64 {
|
|||
#[cfg(any(target_os = "android", target_os = "linux"))] _guest_suspended_cvar: Option<
|
||||
Arc<(Mutex<bool>, Condvar)>,
|
||||
>,
|
||||
_device_tree_overlays: Vec<DtbOverlay>,
|
||||
device_tree_overlays: Vec<DtbOverlay>,
|
||||
) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error>
|
||||
where
|
||||
V: VmRiscv64,
|
||||
|
@ -383,6 +383,7 @@ impl arch::LinuxArch for Riscv64 {
|
|||
cmdline.as_str(),
|
||||
initrd,
|
||||
timebase_freq,
|
||||
device_tree_overlays,
|
||||
)
|
||||
.map_err(Error::CreateFdt)?;
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ use std::fs::File;
|
|||
use std::path::PathBuf;
|
||||
|
||||
use arch::android::create_android_fdt;
|
||||
use arch::apply_device_tree_overlays;
|
||||
use arch::DtbOverlay;
|
||||
use cros_fdt::Error;
|
||||
use cros_fdt::Fdt;
|
||||
|
||||
|
@ -21,10 +23,15 @@ use crate::SetupDataType;
|
|||
pub fn create_fdt(
|
||||
android_fstab: File,
|
||||
dump_device_tree_blob: Option<PathBuf>,
|
||||
device_tree_overlays: Vec<DtbOverlay>,
|
||||
) -> Result<SetupData, Error> {
|
||||
let mut fdt = Fdt::new(&[]);
|
||||
// The whole thing is put into one giant node with some top level properties
|
||||
create_android_fdt(&mut fdt, android_fstab)?;
|
||||
|
||||
// Done writing base FDT, now apply DT overlays
|
||||
apply_device_tree_overlays(&mut fdt, device_tree_overlays)?;
|
||||
|
||||
let fdt_final = fdt.finish()?;
|
||||
|
||||
if let Some(file_path) = dump_device_tree_blob {
|
||||
|
|
|
@ -692,7 +692,7 @@ impl arch::LinuxArch for X8664arch {
|
|||
#[cfg(any(target_os = "android", target_os = "linux"))] guest_suspended_cvar: Option<
|
||||
Arc<(Mutex<bool>, Condvar)>,
|
||||
>,
|
||||
_device_tree_overlays: Vec<DtbOverlay>,
|
||||
device_tree_overlays: Vec<DtbOverlay>,
|
||||
) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error>
|
||||
where
|
||||
V: VmX86_64,
|
||||
|
@ -996,6 +996,7 @@ impl arch::LinuxArch for X8664arch {
|
|||
kernel_end,
|
||||
params,
|
||||
dump_device_tree_blob,
|
||||
device_tree_overlays,
|
||||
)?;
|
||||
|
||||
// Configure the bootstrap VCPU for the Linux/x86 64-bit boot protocol.
|
||||
|
@ -1615,6 +1616,7 @@ impl X8664arch {
|
|||
kernel_end: u64,
|
||||
params: boot_params,
|
||||
dump_device_tree_blob: Option<PathBuf>,
|
||||
device_tree_overlays: Vec<DtbOverlay>,
|
||||
) -> Result<()> {
|
||||
kernel_loader::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline)
|
||||
.map_err(Error::LoadCmdline)?;
|
||||
|
@ -1622,7 +1624,8 @@ impl X8664arch {
|
|||
let mut setup_data = Vec::<SetupData>::new();
|
||||
if let Some(android_fstab) = android_fstab {
|
||||
setup_data.push(
|
||||
fdt::create_fdt(android_fstab, dump_device_tree_blob).map_err(Error::CreateFdt)?,
|
||||
fdt::create_fdt(android_fstab, dump_device_tree_blob, device_tree_overlays)
|
||||
.map_err(Error::CreateFdt)?,
|
||||
);
|
||||
}
|
||||
setup_data.push(setup_data_rng_seed());
|
||||
|
|
|
@ -234,6 +234,7 @@ where
|
|||
kernel_end,
|
||||
params,
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.expect("failed to setup system_memory");
|
||||
|
||||
|
|
Loading…
Reference in a new issue