stratovirt/0014-Replace-mod-device_tree-with-mod-fdt.patch
Fei Xu a4a59d2b07 StratoVirt: Add fdt patches for musl compilation
Signed-off-by: Fei Xu <xufei30@huawei.com>
2021-07-27 14:38:08 +08:00

1002 lines
37 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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