From 999b6194eff54881f3ce4181f2355113fc72435b Mon Sep 17 00:00:00 2001 From: Jiajie Li Date: Wed, 23 Jun 2021 15:20:54 +0800 Subject: [PATCH 3/5] machine/micro_vm: use fdt API of mod fdt instead of device_tree Use fdt API provided by mod fdt, instead of mod device_tree which is a wrapper around libfdt. Signed-off-by: Jiajie Li --- micro_vm/src/lib.rs | 291 ++++++++++++++++++++++---------------------- 1 file changed, 143 insertions(+), 148 deletions(-) diff --git a/micro_vm/src/lib.rs b/micro_vm/src/lib.rs index 7188f21..dd6cf97 100644 --- a/micro_vm/src/lib.rs +++ b/micro_vm/src/lib.rs @@ -111,7 +111,7 @@ use sysbus::{SysBusDevType, SysRes}; #[cfg(target_arch = "aarch64")] use util::device_tree; #[cfg(target_arch = "aarch64")] -use util::device_tree::CompileFDT; +use util::fdt::{self, CompileFDT, FdtBuilder}; use util::loop_context::{ EventLoopManager, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; @@ -628,12 +628,13 @@ impl LightMachine { drop(boot_source); #[cfg(target_arch = "aarch64")] { - let mut fdt = vec![0; device_tree::FDT_MAX_SIZE as usize]; - vm.generate_fdt_node(&mut fdt)?; + let mut fdt_helper = FdtBuilder::new(); + vm.generate_fdt_node(&mut fdt_helper)?; + let fdt_vec = fdt_helper.finish()?; vm.sys_mem.write( - &mut fdt.as_slice(), + &mut fdt_vec.as_slice(), GuestAddress(boot_config.fdt_addr as u64), - fdt.len() as u64, + fdt_vec.len() as u64, )?; } vm.register_power_event()?; @@ -1477,23 +1478,23 @@ impl EventLoopManager for LightMachine { // * `dev_info` - Device resource info of serial device. // * `fdt` - Flatted device-tree blob where serial node will be filled into. #[cfg(target_arch = "aarch64")] -fn generate_serial_device_node(fdt: &mut Vec, res: &SysRes) -> util::errors::Result<()> { - let node = format!("/uart@{:x}", res.region_base); - device_tree::add_sub_node(fdt, &node)?; - device_tree::set_property_string(fdt, &node, "compatible", "ns16550a")?; - device_tree::set_property_string(fdt, &node, "clock-names", "apb_pclk")?; - device_tree::set_property_u32(fdt, &node, "clocks", device_tree::CLK_PHANDLE)?; - device_tree::set_property_array_u64(fdt, &node, "reg", &[res.region_base, res.region_size])?; - device_tree::set_property_array_u32( - fdt, - &node, +fn generate_serial_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::errors::Result<()> { + let node = format!("uart@{:x}", res.region_base); + let serial_node_dep = fdt.begin_node(&node)?; + fdt.set_property_string("compatible", "ns16550a")?; + fdt.set_property_string("clock-names", "apb_pclk")?; + fdt.set_property_u32("clocks", fdt::CLK_PHANDLE)?; + fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; + fdt.set_property_array_u32( "interrupts", &[ - device_tree::GIC_FDT_IRQ_TYPE_SPI, + fdt::GIC_FDT_IRQ_TYPE_SPI, res.irq as u32, - device_tree::IRQ_TYPE_EDGE_RISING, + fdt::IRQ_TYPE_EDGE_RISING, ], )?; + fdt.end_node(serial_node_dep)?; + Ok(()) } @@ -1504,23 +1505,23 @@ fn generate_serial_device_node(fdt: &mut Vec, res: &SysRes) -> util::errors: // * `dev_info` - Device resource info of RTC device. // * `fdt` - Flatted device-tree blob where RTC node will be filled into. #[cfg(target_arch = "aarch64")] -fn generate_rtc_device_node(fdt: &mut Vec, res: &SysRes) -> util::errors::Result<()> { - let node = format!("/pl031@{:x}", res.region_base); - device_tree::add_sub_node(fdt, &node)?; - device_tree::set_property_string(fdt, &node, "compatible", "arm,pl031\0arm,primecell\0")?; - device_tree::set_property_string(fdt, &node, "clock-names", "apb_pclk")?; - device_tree::set_property_u32(fdt, &node, "clocks", device_tree::CLK_PHANDLE)?; - device_tree::set_property_array_u64(fdt, &node, "reg", &[res.region_base, res.region_size])?; - device_tree::set_property_array_u32( - fdt, - &node, +fn generate_rtc_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::errors::Result<()> { + let node = format!("pl031@{:x}", res.region_base); + let rtc_node_dep = fdt.begin_node(&node)?; + fdt.set_property_string("compatible", "arm,pl031\0arm,primecell\0")?; + fdt.set_property_string("clock-names", "apb_pclk")?; + fdt.set_property_u32("clocks", fdt::CLK_PHANDLE)?; + fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; + fdt.set_property_array_u32( "interrupts", &[ - device_tree::GIC_FDT_IRQ_TYPE_SPI, + fdt::GIC_FDT_IRQ_TYPE_SPI, res.irq as u32, - device_tree::IRQ_TYPE_LEVEL_HIGH, + fdt::IRQ_TYPE_LEVEL_HIGH, ], )?; + fdt.end_node(rtc_node_dep)?; + Ok(()) } @@ -1531,22 +1532,21 @@ fn generate_rtc_device_node(fdt: &mut Vec, res: &SysRes) -> util::errors::Re // * `dev_info` - Device resource info of Virtio-Mmio device. // * `fdt` - Flatted device-tree blob where node will be filled into. #[cfg(target_arch = "aarch64")] -fn generate_virtio_devices_node(fdt: &mut Vec, res: &SysRes) -> util::errors::Result<()> { - let node = format!("/virtio_mmio@{:x}", res.region_base); - device_tree::add_sub_node(fdt, &node)?; - device_tree::set_property_string(fdt, &node, "compatible", "virtio,mmio")?; - device_tree::set_property_u32(fdt, &node, "interrupt-parent", device_tree::GIC_PHANDLE)?; - device_tree::set_property_array_u64(fdt, &node, "reg", &[res.region_base, res.region_size])?; - device_tree::set_property_array_u32( - fdt, - &node, +fn generate_virtio_devices_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::errors::Result<()> { + let node = format!("virtio_mmio@{:x}", res.region_base); + let virtio_node_dep = fdt.begin_node(&node)?; + fdt.set_property_string("compatible", "virtio,mmio")?; + fdt.set_property_u32("interrupt-parent", fdt::GIC_PHANDLE)?; + fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; + fdt.set_property_array_u32( "interrupts", &[ - device_tree::GIC_FDT_IRQ_TYPE_SPI, + fdt::GIC_FDT_IRQ_TYPE_SPI, res.irq as u32, - device_tree::IRQ_TYPE_EDGE_RISING, + fdt::IRQ_TYPE_EDGE_RISING, ], )?; + fdt.end_node(virtio_node_dep)?; Ok(()) } @@ -1555,73 +1555,72 @@ fn generate_virtio_devices_node(fdt: &mut Vec, res: &SysRes) -> util::errors #[cfg(target_arch = "aarch64")] trait CompileFDTHelper { /// Function that helps to generate cpu nodes. - fn generate_cpu_nodes(&self, fdt: &mut Vec) -> util::errors::Result<()>; + fn generate_cpu_nodes(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()>; /// Function that helps to generate memory nodes. - fn generate_memory_node(&self, fdt: &mut Vec) -> util::errors::Result<()>; + fn generate_memory_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()>; /// Function that helps to generate Virtio-mmio devices' nodes. - fn generate_devices_node(&self, fdt: &mut Vec) -> util::errors::Result<()>; + fn generate_devices_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()>; /// Function that helps to generate the chosen node. - fn generate_chosen_node(&self, fdt: &mut Vec) -> util::errors::Result<()>; + fn generate_chosen_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()>; } #[cfg(target_arch = "aarch64")] impl CompileFDTHelper for LightMachine { - fn generate_cpu_nodes(&self, fdt: &mut Vec) -> util::errors::Result<()> { - let node = "/cpus"; + fn generate_cpu_nodes(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { + let node = "cpus"; - device_tree::add_sub_node(fdt, node)?; - device_tree::set_property_u32(fdt, node, "#address-cells", 0x02)?; - device_tree::set_property_u32(fdt, node, "#size-cells", 0x0)?; + let cpus_node_dep = fdt.begin_node(node)?; + fdt.set_property_u32("#address-cells", 0x02)?; + fdt.set_property_u32("#size-cells", 0x0)?; // Generate CPU topology if self.cpu_topo.max_cpus > 0 && self.cpu_topo.max_cpus % 8 == 0 { - device_tree::add_sub_node(fdt, "/cpus/cpu-map")?; + let cpu_map_node_dep = fdt.begin_node("cpu-map")?; let sockets = self.cpu_topo.max_cpus / 8; for cluster in 0..u32::from(sockets) { - let clster = format!("/cpus/cpu-map/cluster{}", cluster); - device_tree::add_sub_node(fdt, &clster)?; + let clster = format!("cluster{}", cluster); + let cluster_node_dep = fdt.begin_node(&clster)?; for i in 0..2_u32 { - let sub_cluster = format!("{}/cluster{}", clster, i); - device_tree::add_sub_node(fdt, &sub_cluster)?; - - let core0 = format!("{}/core0", sub_cluster); - device_tree::add_sub_node(fdt, &core0)?; - let thread0 = format!("{}/thread0", core0); - device_tree::add_sub_node(fdt, &thread0)?; - device_tree::set_property_u32(fdt, &thread0, "cpu", cluster * 8 + i * 4 + 10)?; - - let thread1 = format!("{}/thread1", core0); - device_tree::add_sub_node(fdt, &thread1)?; - device_tree::set_property_u32( - fdt, - &thread1, - "cpu", - cluster * 8 + i * 4 + 10 + 1, - )?; - - let core1 = format!("{}/core1", sub_cluster); - device_tree::add_sub_node(fdt, &core1)?; - let thread0 = format!("{}/thread0", core1); - device_tree::add_sub_node(fdt, &thread0)?; - device_tree::set_property_u32( - fdt, - &thread0, - "cpu", - cluster * 8 + i * 4 + 10 + 2, - )?; - - let thread1 = format!("{}/thread1", core1); - device_tree::add_sub_node(fdt, &thread1)?; - device_tree::set_property_u32( - fdt, - &thread1, - "cpu", - cluster * 8 + i * 4 + 10 + 3, - )?; + let sub_cluster = format!("cluster{}", i); + let sub_cluster_node_dep = fdt.begin_node(&sub_cluster)?; + + let core0 = "core0".to_string(); + let core0_node_dep = fdt.begin_node(&core0)?; + + let thread0 = "thread0".to_string(); + let thread0_node_dep = fdt.begin_node(&thread0)?; + fdt.set_property_u32("cpu", cluster * 8 + i * 4 + 10)?; + fdt.end_node(thread0_node_dep)?; + + let thread1 = "thread1".to_string(); + let thread1_node_dep = fdt.begin_node(&thread1)?; + fdt.set_property_u32("cpu", cluster * 8 + i * 4 + 10 + 1)?; + fdt.end_node(thread1_node_dep)?; + + fdt.end_node(core0_node_dep)?; + + let core1 = "core1".to_string(); + let core1_node_dep = fdt.begin_node(&core1)?; + + let thread0 = "thread0".to_string(); + let thread0_node_dep = fdt.begin_node(&thread0)?; + fdt.set_property_u32("cpu", cluster * 8 + i * 4 + 10 + 2)?; + fdt.end_node(thread0_node_dep)?; + + let thread1 = "thread1".to_string(); + let thread1_node_dep = fdt.begin_node(&thread1)?; + fdt.set_property_u32("cpu", cluster * 8 + i * 4 + 10 + 3)?; + fdt.end_node(thread1_node_dep)?; + + fdt.end_node(core1_node_dep)?; + + fdt.end_node(sub_cluster_node_dep)?; } + fdt.end_node(cluster_node_dep)?; } + fdt.end_node(cpu_map_node_dep)?; } let cpu_list = self.cpus.lock().unwrap(); @@ -1632,68 +1631,69 @@ impl CompileFDTHelper for LightMachine { .unwrap() .get_mpidr(cpu_list[cpu_index as usize].fd()); - let node = format!("/cpus/cpu@{:x}", mpidr); - device_tree::add_sub_node(fdt, &node)?; - device_tree::set_property_u32( - fdt, - &node, - "phandle", - u32::from(cpu_index) + device_tree::CPU_PHANDLE_START, - )?; - device_tree::set_property_string(fdt, &node, "device_type", "cpu")?; - device_tree::set_property_string(fdt, &node, "compatible", "arm,arm-v8")?; + let node = format!("cpu@{:x}", mpidr); + let mpidr_node_dep = fdt.begin_node(&node)?; + fdt.set_property_u32("phandle", u32::from(cpu_index) + fdt::CPU_PHANDLE_START)?; + fdt.set_property_string("device_type", "cpu")?; + fdt.set_property_string("compatible", "arm,arm-v8")?; if self.cpu_topo.max_cpus > 1 { - device_tree::set_property_string(fdt, &node, "enable-method", "psci")?; + fdt.set_property_string("enable-method", "psci")?; } - device_tree::set_property_u64(fdt, &node, "reg", mpidr & 0x007F_FFFF)?; + fdt.set_property_u64("reg", mpidr & 0x007F_FFFF)?; + fdt.end_node(mpidr_node_dep)?; } + fdt.end_node(cpus_node_dep)?; + Ok(()) } - fn generate_memory_node(&self, fdt: &mut Vec) -> util::errors::Result<()> { + fn generate_memory_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { let mem_base = MEM_LAYOUT[LayoutEntryType::Mem as usize].0; let mem_size = self.sys_mem.memory_end_address().raw_value() - MEM_LAYOUT[LayoutEntryType::Mem as usize].0; - let node = "/memory"; - device_tree::add_sub_node(fdt, node)?; - device_tree::set_property_string(fdt, node, "device_type", "memory")?; - device_tree::set_property_array_u64(fdt, node, "reg", &[mem_base, mem_size as u64])?; + let node = "memory"; + let memory_node_dep = fdt.begin_node(node)?; + fdt.set_property_string("device_type", "memory")?; + fdt.set_property_array_u64("reg", &[mem_base, mem_size as u64])?; + fdt.end_node(memory_node_dep)?; Ok(()) } - fn generate_devices_node(&self, fdt: &mut Vec) -> util::errors::Result<()> { + fn generate_devices_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { // timer let mut cells: Vec = Vec::new(); for &irq in [13, 14, 11, 10].iter() { - cells.push(device_tree::GIC_FDT_IRQ_TYPE_PPI); + cells.push(fdt::GIC_FDT_IRQ_TYPE_PPI); cells.push(irq); - cells.push(device_tree::IRQ_TYPE_LEVEL_HIGH); + cells.push(fdt::IRQ_TYPE_LEVEL_HIGH); } - let node = "/timer"; - device_tree::add_sub_node(fdt, node)?; - device_tree::set_property_string(fdt, node, "compatible", "arm,armv8-timer")?; - device_tree::set_property(fdt, node, "always-on", None)?; - device_tree::set_property_array_u32(fdt, node, "interrupts", &cells)?; + let node = "timer"; + let timer_node_dep = fdt.begin_node(node)?; + fdt.set_property_string("compatible", "arm,armv8-timer")?; + fdt.set_property("always-on", &Vec::new())?; + fdt.set_property_array_u32("interrupts", &cells)?; + fdt.end_node(timer_node_dep)?; // clock - let node = "/apb-pclk"; - device_tree::add_sub_node(fdt, node)?; - device_tree::set_property_string(fdt, node, "compatible", "fixed-clock")?; - device_tree::set_property_string(fdt, node, "clock-output-names", "clk24mhz")?; - device_tree::set_property_u32(fdt, node, "#clock-cells", 0x0)?; - device_tree::set_property_u32(fdt, node, "clock-frequency", 24_000_000)?; - device_tree::set_property_u32(fdt, node, "phandle", device_tree::CLK_PHANDLE)?; + let node = "apb-pclk"; + let clock_node_dep = fdt.begin_node(node)?; + fdt.set_property_string("compatible", "fixed-clock")?; + fdt.set_property_string("clock-output-names", "clk24mhz")?; + fdt.set_property_u32("#clock-cells", 0x0)?; + fdt.set_property_u32("clock-frequency", 24_000_000)?; + fdt.set_property_u32("phandle", fdt::CLK_PHANDLE)?; + fdt.end_node(clock_node_dep)?; // psci - let node = "/psci"; - device_tree::add_sub_node(fdt, node)?; - device_tree::set_property_string(fdt, node, "compatible", "arm,psci-0.2")?; - device_tree::set_property_string(fdt, node, "method", "hvc")?; + let node = "psci"; + let psci_node_dep = fdt.begin_node(node)?; + fdt.set_property_string("compatible", "arm,psci-0.2")?; + fdt.set_property_string("method", "hvc")?; + fdt.end_node(psci_node_dep)?; - // Reversing vector is needed because FDT node is added in reverse. - for dev in self.sysbus.devices.iter().rev() { + for dev in self.sysbus.devices.iter() { let mut locked_dev = dev.lock().unwrap(); let dev_type = locked_dev.get_type(); let sys_res = locked_dev.get_sys_resource(); @@ -1707,46 +1707,39 @@ impl CompileFDTHelper for LightMachine { Ok(()) } - fn generate_chosen_node(&self, fdt: &mut Vec) -> util::errors::Result<()> { - let node = "/chosen"; - + fn generate_chosen_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { + let node = "chosen"; let boot_source = self.boot_source.lock().unwrap(); - device_tree::add_sub_node(fdt, node)?; + let chosen_node_dep = fdt.begin_node(node)?; let cmdline = &boot_source.kernel_cmdline.to_string(); - device_tree::set_property_string(fdt, node, "bootargs", cmdline.as_str())?; + fdt.set_property_string("bootargs", cmdline.as_str())?; match &boot_source.initrd { Some(initrd) => { - device_tree::set_property_u64( - fdt, - node, - "linux,initrd-start", - *initrd.initrd_addr.lock().unwrap(), - )?; - device_tree::set_property_u64( - fdt, - node, + fdt.set_property_u64("linux,initrd-start", *initrd.initrd_addr.lock().unwrap())?; + fdt.set_property_u64( "linux,initrd-end", *initrd.initrd_addr.lock().unwrap() + initrd.initrd_size, )?; } None => {} } + fdt.end_node(chosen_node_dep)?; Ok(()) } } #[cfg(target_arch = "aarch64")] -impl device_tree::CompileFDT for LightMachine { - fn generate_fdt_node(&self, fdt: &mut Vec) -> util::errors::Result<()> { - device_tree::create_device_tree(fdt)?; +impl fdt::CompileFDT for LightMachine { + fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { + let node_dep = fdt.begin_node("")?; - device_tree::set_property_string(fdt, "/", "compatible", "linux,dummy-virt")?; - device_tree::set_property_u32(fdt, "/", "#address-cells", 0x2)?; - device_tree::set_property_u32(fdt, "/", "#size-cells", 0x2)?; - device_tree::set_property_u32(fdt, "/", "interrupt-parent", device_tree::GIC_PHANDLE)?; + fdt.set_property_string("compatible", "linux,dummy-virt")?; + fdt.set_property_u32("#address-cells", 0x2)?; + fdt.set_property_u32("#size-cells", 0x2)?; + fdt.set_property_u32("interrupt-parent", fdt::GIC_PHANDLE)?; self.generate_cpu_nodes(fdt)?; self.generate_memory_node(fdt)?; @@ -1754,6 +1747,8 @@ impl device_tree::CompileFDT for LightMachine { self.generate_chosen_node(fdt)?; self.irq_chip.as_ref().unwrap().generate_fdt_node(fdt)?; + fdt.end_node(node_dep)?; + Ok(()) } } -- 2.31.1