From e1d0d0ef1d7de4454653a907e7f27e0c7f0185db Mon Sep 17 00:00:00 2001 From: Jiajie Li Date: Wed, 23 Jun 2021 15:24:37 +0800 Subject: [PATCH 4/5] Replace mod device_tree with mod fdt Delete mod device_tree and replace the dependency on the mod device_tree with mod fdt. What's more, remove the compile parameter "link-arg=-lfdt" in config to get rid of libfdt. Signed-off-by: Jiajie Li --- .cargo/config | 1 - .../src/interrupt_controller/aarch64/gicv3.rs | 12 +- .../src/interrupt_controller/aarch64/mod.rs | 4 +- machine_manager/src/config/mod.rs | 4 +- micro_vm/src/lib.rs | 37 +- util/src/device_tree.rs | 386 +++++++++++------- util/src/fdt.rs | 300 -------------- util/src/lib.rs | 2 - 8 files changed, 264 insertions(+), 482 deletions(-) delete mode 100644 util/src/fdt.rs diff --git a/.cargo/config b/.cargo/config index 0b1372f..2105adb 100644 --- a/.cargo/config +++ b/.cargo/config @@ -15,5 +15,4 @@ [target.'cfg(any(target_arch="aarch64"))'] rustflags = [ "-C", "link-arg=-lgcc", - "-C", "link-arg=-lfdt", ] diff --git a/devices/src/interrupt_controller/aarch64/gicv3.rs b/devices/src/interrupt_controller/aarch64/gicv3.rs index a39a3d5..08f2fd5 100644 --- a/devices/src/interrupt_controller/aarch64/gicv3.rs +++ b/devices/src/interrupt_controller/aarch64/gicv3.rs @@ -14,7 +14,7 @@ use std::sync::{Arc, Mutex}; use kvm_ioctls::{DeviceFd, VmFd}; use machine_manager::machine::{KvmVmState, MachineLifecycle}; -use util::fdt::{self, FdtBuilder}; +use util::device_tree::{self, FdtBuilder}; use super::{GICConfig, GICDevice, UtilResult}; use crate::errors::{ErrorKind, Result, ResultExt}; @@ -393,13 +393,17 @@ impl GICDevice for GICv3 { fdt.set_property_string("compatible", "arm,gic-v3")?; fdt.set_property("interrupt-controller", &Vec::new())?; fdt.set_property_u32("#interrupt-cells", 0x3)?; - fdt.set_property_u32("phandle", fdt::GIC_PHANDLE)?; + fdt.set_property_u32("phandle", device_tree::GIC_PHANDLE)?; fdt.set_property_u32("#address-cells", 0x2)?; fdt.set_property_u32("#size-cells", 0x2)?; fdt.set_property_u32("#redistributor-regions", redist_count)?; fdt.set_property_array_u64("reg", &gic_reg)?; - let gic_intr = [fdt::GIC_FDT_IRQ_TYPE_PPI, 0x9, fdt::IRQ_TYPE_LEVEL_HIGH]; + let gic_intr = [ + device_tree::GIC_FDT_IRQ_TYPE_PPI, + 0x9, + device_tree::IRQ_TYPE_LEVEL_HIGH, + ]; fdt.set_property_array_u32("interrupts", &gic_intr)?; if let Some(its) = &self.its_dev { @@ -409,7 +413,7 @@ impl GICDevice for GICv3 { let its_node_dep = fdt.begin_node(node)?; fdt.set_property_string("compatible", "arm,gic-v3-its")?; fdt.set_property("msi-controller", &Vec::new())?; - fdt.set_property_u32("phandle", fdt::GIC_ITS_PHANDLE)?; + fdt.set_property_u32("phandle", device_tree::GIC_ITS_PHANDLE)?; fdt.set_property_array_u64("reg", &its_reg)?; fdt.end_node(its_node_dep)?; } diff --git a/devices/src/interrupt_controller/aarch64/mod.rs b/devices/src/interrupt_controller/aarch64/mod.rs index f1b40cf..ba44eb5 100644 --- a/devices/src/interrupt_controller/aarch64/mod.rs +++ b/devices/src/interrupt_controller/aarch64/mod.rs @@ -19,8 +19,8 @@ use std::sync::Arc; use kvm_ioctls::VmFd; use machine_manager::machine::{KvmVmState, MachineLifecycle}; use util::{ + device_tree::{self, FdtBuilder}, errors::Result as UtilResult, - fdt::{self, FdtBuilder}, }; use crate::errors::{ErrorKind, Result, ResultExt}; @@ -124,7 +124,7 @@ impl InterruptController { } } -impl fdt::CompileFDT for InterruptController { +impl device_tree::CompileFDT for InterruptController { fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> UtilResult<()> { self.gic.generate_fdt(fdt)?; Ok(()) diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 0922943..b83b9b4 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -29,7 +29,7 @@ use std::str::FromStr; use serde::{Deserialize, Serialize}; #[cfg(target_arch = "aarch64")] -use util::device_tree; +use util::device_tree::{self, FdtBuilder}; pub use self::errors::{ErrorKind, Result}; pub use balloon::*; @@ -238,7 +238,7 @@ impl VmConfig { #[cfg(target_arch = "aarch64")] impl device_tree::CompileFDT for VmConfig { - fn generate_fdt_node(&self, _fdt: &mut Vec) -> util::errors::Result<()> { + fn generate_fdt_node(&self, _fdt: &mut FdtBuilder) -> util::errors::Result<()> { Ok(()) } } diff --git a/micro_vm/src/lib.rs b/micro_vm/src/lib.rs index dd6cf97..5cf7226 100644 --- a/micro_vm/src/lib.rs +++ b/micro_vm/src/lib.rs @@ -109,9 +109,7 @@ use sysbus::SysBus; #[cfg(target_arch = "aarch64")] use sysbus::{SysBusDevType, SysRes}; #[cfg(target_arch = "aarch64")] -use util::device_tree; -#[cfg(target_arch = "aarch64")] -use util::fdt::{self, CompileFDT, FdtBuilder}; +use util::device_tree::{self, CompileFDT, FdtBuilder}; use util::loop_context::{ EventLoopManager, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; @@ -1483,14 +1481,14 @@ fn generate_serial_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::erro 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_u32("clocks", device_tree::CLK_PHANDLE)?; fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; fdt.set_property_array_u32( "interrupts", &[ - fdt::GIC_FDT_IRQ_TYPE_SPI, + device_tree::GIC_FDT_IRQ_TYPE_SPI, res.irq as u32, - fdt::IRQ_TYPE_EDGE_RISING, + device_tree::IRQ_TYPE_EDGE_RISING, ], )?; fdt.end_node(serial_node_dep)?; @@ -1510,14 +1508,14 @@ fn generate_rtc_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::errors: 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_u32("clocks", device_tree::CLK_PHANDLE)?; fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; fdt.set_property_array_u32( "interrupts", &[ - fdt::GIC_FDT_IRQ_TYPE_SPI, + device_tree::GIC_FDT_IRQ_TYPE_SPI, res.irq as u32, - fdt::IRQ_TYPE_LEVEL_HIGH, + device_tree::IRQ_TYPE_LEVEL_HIGH, ], )?; fdt.end_node(rtc_node_dep)?; @@ -1536,14 +1534,14 @@ fn generate_virtio_devices_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::err 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_u32("interrupt-parent", device_tree::GIC_PHANDLE)?; fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; fdt.set_property_array_u32( "interrupts", &[ - fdt::GIC_FDT_IRQ_TYPE_SPI, + device_tree::GIC_FDT_IRQ_TYPE_SPI, res.irq as u32, - fdt::IRQ_TYPE_EDGE_RISING, + device_tree::IRQ_TYPE_EDGE_RISING, ], )?; fdt.end_node(virtio_node_dep)?; @@ -1633,7 +1631,10 @@ impl CompileFDTHelper for LightMachine { 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_u32( + "phandle", + u32::from(cpu_index) + device_tree::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 { @@ -1665,9 +1666,9 @@ impl CompileFDTHelper for LightMachine { // timer let mut cells: Vec = Vec::new(); for &irq in [13, 14, 11, 10].iter() { - cells.push(fdt::GIC_FDT_IRQ_TYPE_PPI); + cells.push(device_tree::GIC_FDT_IRQ_TYPE_PPI); cells.push(irq); - cells.push(fdt::IRQ_TYPE_LEVEL_HIGH); + cells.push(device_tree::IRQ_TYPE_LEVEL_HIGH); } let node = "timer"; let timer_node_dep = fdt.begin_node(node)?; @@ -1683,7 +1684,7 @@ impl CompileFDTHelper for LightMachine { 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.set_property_u32("phandle", device_tree::CLK_PHANDLE)?; fdt.end_node(clock_node_dep)?; // psci @@ -1732,14 +1733,14 @@ impl CompileFDTHelper for LightMachine { } #[cfg(target_arch = "aarch64")] -impl fdt::CompileFDT for LightMachine { +impl device_tree::CompileFDT for LightMachine { fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { let node_dep = fdt.begin_node("")?; 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)?; + fdt.set_property_u32("interrupt-parent", device_tree::GIC_PHANDLE)?; self.generate_cpu_nodes(fdt)?; self.generate_memory_node(fdt)?; diff --git a/util/src/device_tree.rs b/util/src/device_tree.rs index 120fd7c..2fdab44 100644 --- a/util/src/device_tree.rs +++ b/util/src/device_tree.rs @@ -10,9 +10,10 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use super::errors::Result; -use libc::{c_char, c_int, c_void}; -use std::ffi::CString; +use std::mem::size_of; + +use crate::errors::{ErrorKind, Result, ResultExt}; +use byteorder::{BigEndian, ByteOrder}; pub const CLK_PHANDLE: u32 = 1; pub const GIC_PHANDLE: u32 = 2; @@ -26,185 +27,257 @@ pub const IRQ_TYPE_LEVEL_HIGH: u32 = 4; pub const FDT_MAX_SIZE: u32 = 0x1_0000; -extern "C" { - fn fdt_create(buf: *mut c_void, bufsize: c_int) -> c_int; - fn fdt_finish_reservemap(fdt: *mut c_void) -> c_int; - fn fdt_begin_node(fdt: *mut c_void, name: *const c_char) -> c_int; - fn fdt_end_node(fdt: *mut c_void) -> c_int; - fn fdt_finish(fdt: *const c_void) -> c_int; - fn fdt_open_into(fdt: *const c_void, buf: *mut c_void, size: c_int) -> c_int; - - fn fdt_path_offset(fdt: *const c_void, path: *const c_char) -> c_int; - fn fdt_add_subnode(fdt: *mut c_void, offset: c_int, name: *const c_char) -> c_int; - fn fdt_setprop( - fdt: *mut c_void, - offset: c_int, - name: *const c_char, - val: *const c_void, - len: c_int, - ) -> c_int; +// Magic number in fdt header(big-endian). +const FDT_MAGIC: u32 = 0xd00dfeed; +// Fdt Header default information. +const FDT_HEADER_SIZE: usize = 40; +const FDT_VERSION: u32 = 17; +const FDT_LAST_COMP_VERSION: u32 = 16; +// Beginning token type of structure block. +const FDT_BEGIN_NODE: u32 = 0x00000001; +const FDT_END_NODE: u32 = 0x00000002; +const FDT_PROP: u32 = 0x00000003; +const FDT_END: u32 = 0x00000009; +// Memory reservation block alignment. +const MEM_RESERVE_ALIGNMENT: usize = 8; +// Structure block alignment. +const STRUCTURE_BLOCK_ALIGNMENT: usize = 4; + +/// FdtBuilder structure. +pub struct FdtBuilder { + /// The header of flattened device tree. + fdt_header: Vec, + /// The memory reservation block of flattened device tree. + /// It provides the client program with a list of areas + /// in physical memory which are reserved. + mem_reserve: Vec, + /// The structure block of flattened device tree. + /// It describes the structure and contents of the tree. + structure_blk: Vec, + /// The strings block of flattened device tree. + /// It contains strings representing all the property names used in the tree. + strings_blk: Vec, + /// The physical ID of the system’s boot CPU. + boot_cpuid_phys: u32, + /// The depth of nested node. + subnode_depth: u32, + /// Is there a open node or not. + begin_node: bool, } -pub fn create_device_tree(fdt: &mut Vec) -> Result<()> { - let mut ret = unsafe { fdt_create(fdt.as_mut_ptr() as *mut c_void, FDT_MAX_SIZE as c_int) }; - if ret < 0 { - bail!("Failed to fdt_create, return {}.", ret); +/// FdtReserveEntry structure. +#[derive(Clone, Debug)] +pub struct FdtReserveEntry { + /// The address of reserved memory. + /// On 32-bit CPUs the upper 32-bits of the value are ignored. + address: u64, + /// The size of reserved memory. + size: u64, +} + +fn check_mem_reserve_overlap(mem_reservations: &[FdtReserveEntry]) -> bool { + if mem_reservations.len() <= 1 { + return true; } - ret = unsafe { fdt_finish_reservemap(fdt.as_mut_ptr() as *mut c_void) }; - if ret < 0 { - bail!("Failed to fdt_finish_reservemap, return {}.", ret); + let mut mem_reser = mem_reservations.to_vec(); + mem_reser.sort_by_key(|m| m.address); + + for i in 0..(mem_reser.len() - 1) { + if mem_reser[i].address + mem_reser[i].size > mem_reser[i + 1].address { + return false; + } } + true +} + +// If there is null character in string, return false. +fn check_string_legality(s: &str) -> bool { + !s.contains('\0') +} - let c_str = CString::new("").unwrap(); - ret = unsafe { fdt_begin_node(fdt.as_mut_ptr() as *mut c_void, c_str.as_ptr()) }; - if ret < 0 { - bail!("Failed to fdt_begin_node, return {}.", ret); +impl Default for FdtBuilder { + fn default() -> Self { + Self { + fdt_header: vec![0_u8; FDT_HEADER_SIZE], + mem_reserve: Vec::new(), + structure_blk: Vec::new(), + strings_blk: Vec::new(), + boot_cpuid_phys: 0, + subnode_depth: 0, + begin_node: false, + } } +} - ret = unsafe { fdt_end_node(fdt.as_mut_ptr() as *mut c_void) }; - if ret < 0 { - bail!("Failed to fdt_end_node, return {}.", ret); +impl FdtBuilder { + pub fn new() -> Self { + FdtBuilder::default() } - ret = unsafe { fdt_finish(fdt.as_mut_ptr() as *mut c_void) }; - if ret < 0 { - bail!("Failed to fdt_finish, return {}.", ret); + pub fn finish(mut self) -> Result> { + if self.subnode_depth > 0 { + return Err(ErrorKind::NodeUnclosed(self.subnode_depth).into()); + } + self.structure_blk + .extend_from_slice(&FDT_END.to_be_bytes()[..]); + + // According to the spec, mem_reserve blocks shall be ended + // with an entry where both address and size are equal to 0. + self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); + self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); + + // Fill fdt header. + let total_size = FDT_HEADER_SIZE + + self.mem_reserve.len() + + self.structure_blk.len() + + self.strings_blk.len(); + let off_dt_struct = FDT_HEADER_SIZE + self.mem_reserve.len(); + let off_dt_strings = FDT_HEADER_SIZE + self.mem_reserve.len() + self.structure_blk.len(); + let off_mem_rsvmap = FDT_HEADER_SIZE; + + BigEndian::write_u32(&mut self.fdt_header[0..4], FDT_MAGIC); + BigEndian::write_u32(&mut self.fdt_header[4..8], total_size as u32); + BigEndian::write_u32(&mut self.fdt_header[8..12], off_dt_struct as u32); + BigEndian::write_u32(&mut self.fdt_header[12..16], off_dt_strings as u32); + BigEndian::write_u32(&mut self.fdt_header[16..20], off_mem_rsvmap as u32); + BigEndian::write_u32(&mut self.fdt_header[20..24], FDT_VERSION); + BigEndian::write_u32(&mut self.fdt_header[24..28], FDT_LAST_COMP_VERSION); + BigEndian::write_u32(&mut self.fdt_header[28..32], self.boot_cpuid_phys); + BigEndian::write_u32(&mut self.fdt_header[32..36], self.strings_blk.len() as u32); + BigEndian::write_u32( + &mut self.fdt_header[36..40], + self.structure_blk.len() as u32, + ); + + self.fdt_header.extend_from_slice(&self.mem_reserve); + self.fdt_header.extend_from_slice(&self.structure_blk); + self.fdt_header.extend_from_slice(&self.strings_blk); + Ok(self.fdt_header) } - ret = unsafe { - fdt_open_into( - fdt.as_ptr() as *mut c_void, - fdt.as_mut_ptr() as *mut c_void, - FDT_MAX_SIZE as c_int, - ) - }; - if ret < 0 { - bail!("Failed to fdt_open_into, return {}.", ret); + pub fn add_mem_reserve(&mut self, mem_reservations: &[FdtReserveEntry]) -> Result<()> { + if !check_mem_reserve_overlap(mem_reservations) { + return Err(ErrorKind::MemReserveOverlap.into()); + } + + for mem_reser in mem_reservations { + self.mem_reserve + .extend_from_slice(&mem_reser.address.to_be_bytes()); + self.mem_reserve + .extend_from_slice(&mem_reser.size.to_be_bytes()); + } + self.align_structure_blk(MEM_RESERVE_ALIGNMENT); + + Ok(()) } - Ok(()) -} + pub fn begin_node(&mut self, node_name: &str) -> Result { + if !check_string_legality(node_name) { + return Err(ErrorKind::IllegalString(node_name.to_string()).into()); + } -pub fn add_sub_node(fdt: &mut Vec, node_path: &str) -> Result<()> { - let names: Vec<&str> = node_path.split('/').collect(); - if names.len() < 2 { - bail!("Failed to add sub node, node_path: {} invalid.", node_path); + self.structure_blk + .extend_from_slice(&FDT_BEGIN_NODE.to_be_bytes()[..]); + if node_name.is_empty() { + self.structure_blk + .extend_from_slice(&0_u32.to_be_bytes()[..]); + } else { + let mut val_array = node_name.as_bytes().to_vec(); + // The node’s name string should end with null('\0'). + val_array.push(0x0_u8); + self.structure_blk.extend_from_slice(&val_array); + } + self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); + self.subnode_depth += 1; + self.begin_node = true; + Ok(self.subnode_depth) } - let node_name = names[names.len() - 1]; - let pare_name = names[0..names.len() - 1].join("/"); + pub fn end_node(&mut self, begin_node_depth: u32) -> Result<()> { + if begin_node_depth != self.subnode_depth { + return Err(ErrorKind::NodeDepthMismatch(begin_node_depth, self.subnode_depth).into()); + } - let c_str = if pare_name.is_empty() { - CString::new("/").unwrap() - } else { - CString::new(pare_name).unwrap() - }; + self.structure_blk + .extend_from_slice(&FDT_END_NODE.to_be_bytes()[..]); + self.subnode_depth -= 1; + self.begin_node = false; + Ok(()) + } - let offset = unsafe { fdt_path_offset(fdt.as_ptr() as *const c_void, c_str.as_ptr()) }; - if offset < 0 { - bail!("Failed to fdt_path_offset, return {}.", offset); + pub fn set_boot_cpuid_phys(&mut self, boot_cpuid: u32) { + self.boot_cpuid_phys = boot_cpuid; } - let c_str = CString::new(node_name).unwrap(); - let ret = unsafe { fdt_add_subnode(fdt.as_mut_ptr() as *mut c_void, offset, c_str.as_ptr()) }; - if ret < 0 { - bail!("Failed to fdt_add_subnode, return {}.", ret); + pub fn set_property_string(&mut self, prop: &str, val: &str) -> Result<()> { + let mut val_array = val.as_bytes().to_vec(); + // The string property should end with null('\0'). + val_array.push(0x0_u8); + self.set_property(prop, &val_array) + .chain_err(|| ErrorKind::SetPropertyErr("string".to_string())) } - Ok(()) -} + pub fn set_property_u32(&mut self, prop: &str, val: u32) -> Result<()> { + self.set_property(prop, &val.to_be_bytes()[..]) + .chain_err(|| ErrorKind::SetPropertyErr("u32".to_string())) + } -pub fn set_property( - fdt: &mut Vec, - node_path: &str, - prop: &str, - val: Option<&[u8]>, -) -> Result<()> { - let c_str = CString::new(node_path).unwrap(); - let offset = unsafe { fdt_path_offset(fdt.as_ptr() as *const c_void, c_str.as_ptr()) }; - if offset < 0 { - bail!("Failed to fdt_path_offset, return {}.", offset); - } - - let (ptr, len) = if let Some(val) = val { - (val.as_ptr() as *const c_void, val.len() as i32) - } else { - (std::ptr::null::(), 0) - }; - - let c_str = CString::new(prop).unwrap(); - let ret = unsafe { - fdt_setprop( - fdt.as_mut_ptr() as *mut c_void, - offset, - c_str.as_ptr(), - ptr, - len, - ) - }; - if ret < 0 { - bail!("Failed to fdt_setprop, return {}.", ret); - } - - Ok(()) -} + pub fn set_property_u64(&mut self, prop: &str, val: u64) -> Result<()> { + self.set_property(prop, &val.to_be_bytes()[..]) + .chain_err(|| ErrorKind::SetPropertyErr("u64".to_string())) + } -pub fn set_property_string( - fdt: &mut Vec, - node_path: &str, - prop: &str, - val: &str, -) -> Result<()> { - set_property( - fdt, - node_path, - prop, - Some(&([val.as_bytes(), &[0_u8]].concat())), - ) -} + pub fn set_property_array_u32(&mut self, prop: &str, array: &[u32]) -> Result<()> { + let mut prop_array = Vec::with_capacity(array.len() * size_of::()); + for element in array { + prop_array.extend_from_slice(&element.to_be_bytes()[..]); + } + self.set_property(prop, &prop_array) + .chain_err(|| ErrorKind::SetPropertyErr("u32 array".to_string())) + } -pub fn set_property_u32(fdt: &mut Vec, node_path: &str, prop: &str, val: u32) -> Result<()> { - set_property(fdt, node_path, prop, Some(&val.to_be_bytes())) -} + pub fn set_property_array_u64(&mut self, prop: &str, array: &[u64]) -> Result<()> { + let mut prop_array = Vec::with_capacity(array.len() * size_of::()); + for element in array { + prop_array.extend_from_slice(&element.to_be_bytes()[..]); + } + self.set_property(prop, &prop_array) + .chain_err(|| ErrorKind::SetPropertyErr("u64 array".to_string())) + } -pub fn set_property_u64(fdt: &mut Vec, node_path: &str, prop: &str, val: u64) -> Result<()> { - set_property(fdt, node_path, prop, Some(&val.to_be_bytes())) -} + pub fn set_property(&mut self, property_name: &str, property_val: &[u8]) -> Result<()> { + if !check_string_legality(property_name) { + return Err(ErrorKind::IllegalString(property_name.to_string()).into()); + } -pub fn set_property_array_u32( - fdt: &mut Vec, - node_path: &str, - prop: &str, - array: &[u32], -) -> Result<()> { - let mut bytes: Vec = Vec::new(); - for &val in array { - bytes.append(&mut val.to_be_bytes().to_vec()); - } - set_property(fdt, node_path, prop, Some(&bytes)) -} + if !self.begin_node { + return Err(ErrorKind::IllegelPropertyPos.into()); + } -pub fn set_property_array_u64( - fdt: &mut Vec, - node_path: &str, - prop: &str, - array: &[u64], -) -> Result<()> { - let mut bytes: Vec = Vec::new(); - for &val in array { - bytes.append(&mut val.to_be_bytes().to_vec()); - } - set_property(fdt, node_path, prop, Some(&bytes)) -} + let len = property_val.len() as u32; + let nameoff = self.strings_blk.len() as u32; + self.structure_blk + .extend_from_slice(&FDT_PROP.to_be_bytes()[..]); + self.structure_blk.extend_from_slice(&len.to_be_bytes()[..]); + self.structure_blk + .extend_from_slice(&nameoff.to_be_bytes()[..]); + self.structure_blk.extend_from_slice(property_val); + self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); -pub fn dump_dtb(fdt: &[u8], file_path: &str) { - use std::fs::File; - use std::io::Write; + self.strings_blk.extend_from_slice(property_name.as_bytes()); + // These strings in strings block should end with null('\0'). + self.strings_blk.extend_from_slice("\0".as_bytes()); - let mut f = File::create(file_path).unwrap(); - for i in fdt.iter() { - f.write_all(&[*i]).expect("Unable to write data"); + Ok(()) + } + + fn align_structure_blk(&mut self, alignment: usize) { + let remainder = self.structure_blk.len() % alignment; + if remainder != 0 { + self.structure_blk + .extend(vec![0_u8; (alignment - remainder) as usize]); + } } } @@ -215,6 +288,13 @@ pub trait CompileFDT { /// /// # Arguments /// - /// * `fdt` - the fdt slice to be expended. - fn generate_fdt_node(&self, fdt: &mut Vec) -> Result<()>; + /// * `fdt` - the FdtBuilder to be filled. + fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> Result<()>; +} + +pub fn dump_dtb(fdt: &[u8], file_path: &str) { + use std::fs::File; + use std::io::Write; + let mut f = File::create(file_path).unwrap(); + f.write_all(fdt).expect("Unable to write data"); } diff --git a/util/src/fdt.rs b/util/src/fdt.rs deleted file mode 100644 index 2fdab44..0000000 --- a/util/src/fdt.rs +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) 2020 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use std::mem::size_of; - -use crate::errors::{ErrorKind, Result, ResultExt}; -use byteorder::{BigEndian, ByteOrder}; - -pub const CLK_PHANDLE: u32 = 1; -pub const GIC_PHANDLE: u32 = 2; -pub const GIC_ITS_PHANDLE: u32 = 3; -pub const CPU_PHANDLE_START: u32 = 10; - -pub const GIC_FDT_IRQ_TYPE_SPI: u32 = 0; -pub const GIC_FDT_IRQ_TYPE_PPI: u32 = 1; -pub const IRQ_TYPE_EDGE_RISING: u32 = 1; -pub const IRQ_TYPE_LEVEL_HIGH: u32 = 4; - -pub const FDT_MAX_SIZE: u32 = 0x1_0000; - -// Magic number in fdt header(big-endian). -const FDT_MAGIC: u32 = 0xd00dfeed; -// Fdt Header default information. -const FDT_HEADER_SIZE: usize = 40; -const FDT_VERSION: u32 = 17; -const FDT_LAST_COMP_VERSION: u32 = 16; -// Beginning token type of structure block. -const FDT_BEGIN_NODE: u32 = 0x00000001; -const FDT_END_NODE: u32 = 0x00000002; -const FDT_PROP: u32 = 0x00000003; -const FDT_END: u32 = 0x00000009; -// Memory reservation block alignment. -const MEM_RESERVE_ALIGNMENT: usize = 8; -// Structure block alignment. -const STRUCTURE_BLOCK_ALIGNMENT: usize = 4; - -/// FdtBuilder structure. -pub struct FdtBuilder { - /// The header of flattened device tree. - fdt_header: Vec, - /// The memory reservation block of flattened device tree. - /// It provides the client program with a list of areas - /// in physical memory which are reserved. - mem_reserve: Vec, - /// The structure block of flattened device tree. - /// It describes the structure and contents of the tree. - structure_blk: Vec, - /// The strings block of flattened device tree. - /// It contains strings representing all the property names used in the tree. - strings_blk: Vec, - /// The physical ID of the system’s boot CPU. - boot_cpuid_phys: u32, - /// The depth of nested node. - subnode_depth: u32, - /// Is there a open node or not. - begin_node: bool, -} - -/// FdtReserveEntry structure. -#[derive(Clone, Debug)] -pub struct FdtReserveEntry { - /// The address of reserved memory. - /// On 32-bit CPUs the upper 32-bits of the value are ignored. - address: u64, - /// The size of reserved memory. - size: u64, -} - -fn check_mem_reserve_overlap(mem_reservations: &[FdtReserveEntry]) -> bool { - if mem_reservations.len() <= 1 { - return true; - } - - let mut mem_reser = mem_reservations.to_vec(); - mem_reser.sort_by_key(|m| m.address); - - for i in 0..(mem_reser.len() - 1) { - if mem_reser[i].address + mem_reser[i].size > mem_reser[i + 1].address { - return false; - } - } - true -} - -// If there is null character in string, return false. -fn check_string_legality(s: &str) -> bool { - !s.contains('\0') -} - -impl Default for FdtBuilder { - fn default() -> Self { - Self { - fdt_header: vec![0_u8; FDT_HEADER_SIZE], - mem_reserve: Vec::new(), - structure_blk: Vec::new(), - strings_blk: Vec::new(), - boot_cpuid_phys: 0, - subnode_depth: 0, - begin_node: false, - } - } -} - -impl FdtBuilder { - pub fn new() -> Self { - FdtBuilder::default() - } - - pub fn finish(mut self) -> Result> { - if self.subnode_depth > 0 { - return Err(ErrorKind::NodeUnclosed(self.subnode_depth).into()); - } - self.structure_blk - .extend_from_slice(&FDT_END.to_be_bytes()[..]); - - // According to the spec, mem_reserve blocks shall be ended - // with an entry where both address and size are equal to 0. - self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); - self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); - - // Fill fdt header. - let total_size = FDT_HEADER_SIZE - + self.mem_reserve.len() - + self.structure_blk.len() - + self.strings_blk.len(); - let off_dt_struct = FDT_HEADER_SIZE + self.mem_reserve.len(); - let off_dt_strings = FDT_HEADER_SIZE + self.mem_reserve.len() + self.structure_blk.len(); - let off_mem_rsvmap = FDT_HEADER_SIZE; - - BigEndian::write_u32(&mut self.fdt_header[0..4], FDT_MAGIC); - BigEndian::write_u32(&mut self.fdt_header[4..8], total_size as u32); - BigEndian::write_u32(&mut self.fdt_header[8..12], off_dt_struct as u32); - BigEndian::write_u32(&mut self.fdt_header[12..16], off_dt_strings as u32); - BigEndian::write_u32(&mut self.fdt_header[16..20], off_mem_rsvmap as u32); - BigEndian::write_u32(&mut self.fdt_header[20..24], FDT_VERSION); - BigEndian::write_u32(&mut self.fdt_header[24..28], FDT_LAST_COMP_VERSION); - BigEndian::write_u32(&mut self.fdt_header[28..32], self.boot_cpuid_phys); - BigEndian::write_u32(&mut self.fdt_header[32..36], self.strings_blk.len() as u32); - BigEndian::write_u32( - &mut self.fdt_header[36..40], - self.structure_blk.len() as u32, - ); - - self.fdt_header.extend_from_slice(&self.mem_reserve); - self.fdt_header.extend_from_slice(&self.structure_blk); - self.fdt_header.extend_from_slice(&self.strings_blk); - Ok(self.fdt_header) - } - - pub fn add_mem_reserve(&mut self, mem_reservations: &[FdtReserveEntry]) -> Result<()> { - if !check_mem_reserve_overlap(mem_reservations) { - return Err(ErrorKind::MemReserveOverlap.into()); - } - - for mem_reser in mem_reservations { - self.mem_reserve - .extend_from_slice(&mem_reser.address.to_be_bytes()); - self.mem_reserve - .extend_from_slice(&mem_reser.size.to_be_bytes()); - } - self.align_structure_blk(MEM_RESERVE_ALIGNMENT); - - Ok(()) - } - - pub fn begin_node(&mut self, node_name: &str) -> Result { - if !check_string_legality(node_name) { - return Err(ErrorKind::IllegalString(node_name.to_string()).into()); - } - - self.structure_blk - .extend_from_slice(&FDT_BEGIN_NODE.to_be_bytes()[..]); - if node_name.is_empty() { - self.structure_blk - .extend_from_slice(&0_u32.to_be_bytes()[..]); - } else { - let mut val_array = node_name.as_bytes().to_vec(); - // The node’s name string should end with null('\0'). - val_array.push(0x0_u8); - self.structure_blk.extend_from_slice(&val_array); - } - self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); - self.subnode_depth += 1; - self.begin_node = true; - Ok(self.subnode_depth) - } - - pub fn end_node(&mut self, begin_node_depth: u32) -> Result<()> { - if begin_node_depth != self.subnode_depth { - return Err(ErrorKind::NodeDepthMismatch(begin_node_depth, self.subnode_depth).into()); - } - - self.structure_blk - .extend_from_slice(&FDT_END_NODE.to_be_bytes()[..]); - self.subnode_depth -= 1; - self.begin_node = false; - Ok(()) - } - - pub fn set_boot_cpuid_phys(&mut self, boot_cpuid: u32) { - self.boot_cpuid_phys = boot_cpuid; - } - - pub fn set_property_string(&mut self, prop: &str, val: &str) -> Result<()> { - let mut val_array = val.as_bytes().to_vec(); - // The string property should end with null('\0'). - val_array.push(0x0_u8); - self.set_property(prop, &val_array) - .chain_err(|| ErrorKind::SetPropertyErr("string".to_string())) - } - - pub fn set_property_u32(&mut self, prop: &str, val: u32) -> Result<()> { - self.set_property(prop, &val.to_be_bytes()[..]) - .chain_err(|| ErrorKind::SetPropertyErr("u32".to_string())) - } - - pub fn set_property_u64(&mut self, prop: &str, val: u64) -> Result<()> { - self.set_property(prop, &val.to_be_bytes()[..]) - .chain_err(|| ErrorKind::SetPropertyErr("u64".to_string())) - } - - pub fn set_property_array_u32(&mut self, prop: &str, array: &[u32]) -> Result<()> { - let mut prop_array = Vec::with_capacity(array.len() * size_of::()); - for element in array { - prop_array.extend_from_slice(&element.to_be_bytes()[..]); - } - self.set_property(prop, &prop_array) - .chain_err(|| ErrorKind::SetPropertyErr("u32 array".to_string())) - } - - pub fn set_property_array_u64(&mut self, prop: &str, array: &[u64]) -> Result<()> { - let mut prop_array = Vec::with_capacity(array.len() * size_of::()); - for element in array { - prop_array.extend_from_slice(&element.to_be_bytes()[..]); - } - self.set_property(prop, &prop_array) - .chain_err(|| ErrorKind::SetPropertyErr("u64 array".to_string())) - } - - pub fn set_property(&mut self, property_name: &str, property_val: &[u8]) -> Result<()> { - if !check_string_legality(property_name) { - return Err(ErrorKind::IllegalString(property_name.to_string()).into()); - } - - if !self.begin_node { - return Err(ErrorKind::IllegelPropertyPos.into()); - } - - let len = property_val.len() as u32; - let nameoff = self.strings_blk.len() as u32; - self.structure_blk - .extend_from_slice(&FDT_PROP.to_be_bytes()[..]); - self.structure_blk.extend_from_slice(&len.to_be_bytes()[..]); - self.structure_blk - .extend_from_slice(&nameoff.to_be_bytes()[..]); - self.structure_blk.extend_from_slice(property_val); - self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); - - self.strings_blk.extend_from_slice(property_name.as_bytes()); - // These strings in strings block should end with null('\0'). - self.strings_blk.extend_from_slice("\0".as_bytes()); - - Ok(()) - } - - fn align_structure_blk(&mut self, alignment: usize) { - let remainder = self.structure_blk.len() % alignment; - if remainder != 0 { - self.structure_blk - .extend(vec![0_u8; (alignment - remainder) as usize]); - } - } -} - -/// Trait for devices to be added to the Flattened Device Tree. -#[allow(clippy::upper_case_acronyms)] -pub trait CompileFDT { - /// function to generate fdt node - /// - /// # Arguments - /// - /// * `fdt` - the FdtBuilder to be filled. - fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> Result<()>; -} - -pub fn dump_dtb(fdt: &[u8], file_path: &str) { - use std::fs::File; - use std::io::Write; - let mut f = File::create(file_path).unwrap(); - f.write_all(fdt).expect("Unable to write data"); -} diff --git a/util/src/lib.rs b/util/src/lib.rs index d135c74..2c59065 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -28,8 +28,6 @@ pub mod checksum; pub mod daemonize; #[cfg(target_arch = "aarch64")] pub mod device_tree; -#[cfg(target_arch = "aarch64")] -pub mod fdt; pub mod leak_bucket; mod link_list; pub mod loop_context; -- 2.31.1