stratovirt/0014-Replace-mod-device_tree-with-mod-fdt.patch

1002 lines
37 KiB
Diff
Raw Normal View History

From e1d0d0ef1d7de4454653a907e7f27e0c7f0185db Mon Sep 17 00:00:00 2001
From: Jiajie Li <lijiajie11@huawei.com>
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 <lijiajie11@huawei.com>
---
.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<u8>) -> 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<u32> = 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<u8>,
+ /// 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<u8>,
+ /// The structure block of flattened device tree.
+ /// It describes the structure and contents of the tree.
+ structure_blk: Vec<u8>,
+ /// The strings block of flattened device tree.
+ /// It contains strings representing all the property names used in the tree.
+ strings_blk: Vec<u8>,
+ /// The physical ID of the systems 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<u8>) -> 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<Vec<u8>> {
+ 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<u32> {
+ if !check_string_legality(node_name) {
+ return Err(ErrorKind::IllegalString(node_name.to_string()).into());
+ }
-pub fn add_sub_node(fdt: &mut Vec<u8>, 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 nodes 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<u8>,
- 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::<c_void>(), 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<u8>,
- 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::<u32>());
+ 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<u8>, 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::<u64>());
+ 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<u8>, 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<u8>,
- node_path: &str,
- prop: &str,
- array: &[u32],
-) -> Result<()> {
- let mut bytes: Vec<u8> = 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<u8>,
- node_path: &str,
- prop: &str,
- array: &[u64],
-) -> Result<()> {
- let mut bytes: Vec<u8> = 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<u8>) -> 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<u8>,
- /// 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<u8>,
- /// The structure block of flattened device tree.
- /// It describes the structure and contents of the tree.
- structure_blk: Vec<u8>,
- /// The strings block of flattened device tree.
- /// It contains strings representing all the property names used in the tree.
- strings_blk: Vec<u8>,
- /// The physical ID of the systems 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<Vec<u8>> {
- 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<u32> {
- 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 nodes 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::<u32>());
- 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::<u64>());
- 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