1002 lines
37 KiB
Diff
1002 lines
37 KiB
Diff
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 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<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 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<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 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<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 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::<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
|
||
|