Слияние кода завершено, страница обновится автоматически
// 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");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_all_properties() {
let mut fdt_builder = FdtBuilder::new();
let root_node = fdt_builder.begin_node("").unwrap();
fdt_builder.set_property("null", &[]).unwrap();
fdt_builder.set_property_u32("u32", 0x01234567).unwrap();
fdt_builder
.set_property_u64("u64", 0x0123456789abcdef)
.unwrap();
fdt_builder
.set_property_array_u32(
"u32_array",
&vec![0x11223344, 0x55667788, 0x99aabbcc, 0xddeeff00],
)
.unwrap();
fdt_builder
.set_property_array_u64("u64_array", &vec![0x0011223344556677, 0x8899aabbccddeeff])
.unwrap();
fdt_builder
.set_property_string("string", "hello fdt")
.unwrap();
fdt_builder.end_node(root_node).unwrap();
let right_fdt: Vec<u8> = vec![
0xd0, 0x0d, 0xfe, 0xed, // 00: magic (0xd00dfeed)
0x00, 0x00, 0x00, 0xf0, // 04: totalsize (0xf0)
0x00, 0x00, 0x00, 0x38, // 08: off_dt_struct (0x38)
0x00, 0x00, 0x00, 0xc8, // 0c: off_dt_strings (0xc8)
0x00, 0x00, 0x00, 0x28, // 10: off_mem_rsvmap (0x28)
0x00, 0x00, 0x00, 0x11, // 14: version (17)
0x00, 0x00, 0x00, 0x10, // 18: last_comp_version (16)
0x00, 0x00, 0x00, 0x00, // 1c: boot_cpuid_phys (0)
0x00, 0x00, 0x00, 0x28, // 20: size_dt_strings (0x28)
0x00, 0x00, 0x00, 0x90, // 24: size_dt_struct (0x90)
0x00, 0x00, 0x00, 0x00, // 28: high address of memory reservation block terminator
0x00, 0x00, 0x00, 0x00, // 2c: low address of memory reservation block terminator
0x00, 0x00, 0x00, 0x00, // 30: high size of memory reservation block terminator
0x00, 0x00, 0x00, 0x00, // 34: low size of memory reservation block terminator
0x00, 0x00, 0x00, 0x01, // 38: FDT_BEGIN_NODE
0x00, 0x00, 0x00, 0x00, // 3c: node name ("") with 4-byte alignment
0x00, 0x00, 0x00, 0x03, // 40: FDT_PROP ("null")
0x00, 0x00, 0x00, 0x00, // 44: property len (0)
0x00, 0x00, 0x00, 0x00, // 48: property nameoff (0x00)
0x00, 0x00, 0x00, 0x03, // 4c: FDT_PROP ("u32")
0x00, 0x00, 0x00, 0x04, // 50: property len (4)
0x00, 0x00, 0x00, 0x05, // 54: property nameoff (0x05)
0x01, 0x23, 0x45, 0x67, // 58: property’s value (0x01234567)
0x00, 0x00, 0x00, 0x03, // 5c: FDT_PROP ("u64")
0x00, 0x00, 0x00, 0x08, // 60: property len (8)
0x00, 0x00, 0x00, 0x09, // 64: property nameoff (0x09)
0x01, 0x23, 0x45, 0x67, // 68: property’s value (0x01234567)
0x89, 0xab, 0xcd, 0xef, // 6c: property’s value (0x89abcdef)
0x00, 0x00, 0x00, 0x03, // 70: FDT_PROP ("u32_array")
0x00, 0x00, 0x00, 0x10, // 74: property len (16)
0x00, 0x00, 0x00, 0x0d, // 78: property nameoff (0x0d)
0x11, 0x22, 0x33, 0x44, // 7c: property’s value (0x11223344)
0x55, 0x66, 0x77, 0x88, // 80: property’s value (0x55667788)
0x99, 0xaa, 0xbb, 0xcc, // 84: property’s value (0x99aabbcc)
0xdd, 0xee, 0xff, 0x00, // 88: property’s value (0xddeeff00)
0x00, 0x00, 0x00, 0x03, // 8c: FDT_PROP ("u64_array")
0x00, 0x00, 0x00, 0x10, // 90: property len (16)
0x00, 0x00, 0x00, 0x17, // 94: property nameoff (0x17)
0x00, 0x11, 0x22, 0x33, // 98: property’s value (0x00112233)
0x44, 0x55, 0x66, 0x77, // 9c: property’s value (0x44556677)
0x88, 0x99, 0xaa, 0xbb, // a0: property’s value (0x8899aabb)
0xcc, 0xdd, 0xee, 0xff, // a4: property’s value (0xccddeeff)
0x00, 0x00, 0x00, 0x03, // a8: FDT_PROP ("string")
0x00, 0x00, 0x00, 0x0a, // ac: property len (10)
0x00, 0x00, 0x00, 0x21, // b0: property nameoff (0x21)
b'h', b'e', b'l', b'l', // b4: property’s value ("hell")
b'o', b' ', b'f', b'd', // b8: property’s value ("o fd")
b't', b'\0', 0x00, 0x00, // bc: property’s value ("t\0" with padding)
0x00, 0x00, 0x00, 0x02, // c0: FDT_END_NODE
0x00, 0x00, 0x00, 0x09, // c4: FDT_END
b'n', b'u', b'l', b'l', b'\0', // c8: "null" with offset 0x00
b'u', b'3', b'2', b'\0', // cd: "u32" with offset 0x05
b'u', b'6', b'4', b'\0', // d1: "u64" with offset 0x09
b'u', b'3', b'2', b'_', b'a', b'r', b'r', b'a', b'y',
b'\0', // d5: "u32_array" with offset 0x0d
b'u', b'6', b'4', b'_', b'a', b'r', b'r', b'a', b'y',
b'\0', // df: "u64_array" with offset 0x17
b's', b't', b'r', b'i', b'n', b'g', b'\0', // e9: "string" with offset 0x21
];
let sample_fdt = fdt_builder.finish().unwrap();
assert_eq!(right_fdt, sample_fdt);
}
#[test]
fn test_nested_node() {
let mut fdt_builder = FdtBuilder::new();
let root_node = fdt_builder.begin_node("").unwrap();
let cpus_node = fdt_builder.begin_node("cpus").unwrap();
fdt_builder.set_property_u32("addrcells", 0x02).unwrap();
fdt_builder.set_property_u32("sizecells", 0x0).unwrap();
let cpu_map_node = fdt_builder.begin_node("cpu-map").unwrap();
fdt_builder.set_property_u32("cpu", 10).unwrap();
fdt_builder.end_node(cpu_map_node).unwrap();
fdt_builder.end_node(cpus_node).unwrap();
fdt_builder.end_node(root_node).unwrap();
fdt_builder.set_boot_cpuid_phys(1);
let right_fdt: Vec<u8> = vec![
0xd0, 0x0d, 0xfe, 0xed, // 00: magic (0xd00dfeed)
0x00, 0x00, 0x00, 0xb0, // 04: totalsize (0xb0)
0x00, 0x00, 0x00, 0x38, // 08: off_dt_struct (0x38)
0x00, 0x00, 0x00, 0x98, // 0c: off_dt_strings (0x98)
0x00, 0x00, 0x00, 0x28, // 10: off_mem_rsvmap (0x28)
0x00, 0x00, 0x00, 0x11, // 14: version (17)
0x00, 0x00, 0x00, 0x10, // 18: last_comp_version (16)
0x00, 0x00, 0x00, 0x01, // 1c: boot_cpuid_phys (1)
0x00, 0x00, 0x00, 0x18, // 20: size_dt_strings (0x18)
0x00, 0x00, 0x00, 0x60, // 24: size_dt_struct (0x60)
0x00, 0x00, 0x00, 0x00, // 28: high address of memory reservation block terminator
0x00, 0x00, 0x00, 0x00, // 2c: low address of memory reservation block terminator
0x00, 0x00, 0x00, 0x00, // 30: high size of memory reservation block terminator
0x00, 0x00, 0x00, 0x00, // 34: low size of memory reservation block terminator
0x00, 0x00, 0x00, 0x01, // 38: FDT_BEGIN_NODE
0x00, 0x00, 0x00, 0x00, // 3c: node name ("")
0x00, 0x00, 0x00, 0x01, // 40: FDT_BEGIN_NODE
b'c', b'p', b'u', b's', // 44: node name ("cpus") with 4-byte alignment
b'\0', 0x00, 0x00, 0x00, // 48: padding
0x00, 0x00, 0x00, 0x03, // 4c: FDT_PROP ("addrcells")
0x00, 0x00, 0x00, 0x04, // 50: property len (4)
0x00, 0x00, 0x00, 0x00, // 54: property nameoff (0x00)
0x00, 0x00, 0x00, 0x02, // 58: property’s value (0x02)
0x00, 0x00, 0x00, 0x03, // 5c: FDT_PROP ("sizecells")
0x00, 0x00, 0x00, 0x04, // 60: property len (4)
0x00, 0x00, 0x00, 0x0a, // 64: property nameoff (0xa)
0x00, 0x00, 0x00, 0x00, // 68: property’s value (0x0)
0x00, 0x00, 0x00, 0x01, // 6c: FDT_BEGIN_NODE
b'c', b'p', b'u', b'-', // 70: node name ("cpu-map")
b'm', b'a', b'p', b'\0', // 74: node name ("cpu-map")
0x00, 0x00, 0x00, 0x03, // 78: FDT_PROP ("cpu")
0x00, 0x00, 0x00, 0x04, // 7c: property len (4)
0x00, 0x00, 0x00, 0x14, // 80: property nameoff (0x14)
0x00, 0x00, 0x00, 0x0a, // 84: property’s value (10)
0x00, 0x00, 0x00, 0x02, // 88: FDT_END_NODE
0x00, 0x00, 0x00, 0x02, // 8c: FDT_END_NODE
0x00, 0x00, 0x00, 0x02, // 90: FDT_END_NODE
0x00, 0x00, 0x00, 0x09, // 94: FDT_END
b'a', b'd', b'd', b'r', b'c', b'e', b'l', b'l', b's',
b'\0', // 98: "addrcells" with offset 0x00
b's', b'i', b'z', b'e', b'c', b'e', b'l', b'l', b's',
b'\0', // a2: "sizecells" with offset 0x0a
b'c', b'p', b'u', b'\0', // ac: "cpu" with offset 0x14
];
let sample_fdt = fdt_builder.finish().unwrap();
assert_eq!(right_fdt, sample_fdt);
}
#[test]
fn test_illegeal_string() {
let mut fdt_builder = FdtBuilder::new();
assert!(fdt_builder.begin_node("bad\0string").is_err());
fdt_builder.begin_node("good string").unwrap();
assert!(fdt_builder.set_property("bad property\0name", &[]).is_err());
assert!(fdt_builder
.set_property_string("good property name", "test\0val")
.is_ok());
}
#[test]
fn test_unclose_nested_node() {
let mut fdt_builder = FdtBuilder::new();
let root_node = fdt_builder.begin_node("").unwrap();
fdt_builder.begin_node("nested node").unwrap();
assert!(fdt_builder.end_node(root_node).is_err());
assert!(fdt_builder.finish().is_err());
}
#[test]
fn test_mem_reserve_overlap() {
let mut fdt_builder = FdtBuilder::new();
let mem_reservations = [
FdtReserveEntry {
address: 0x100,
size: 0x100,
},
FdtReserveEntry {
address: 0x150,
size: 0x100,
},
];
assert!(fdt_builder.add_mem_reserve(&mem_reservations).is_err());
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарий ( 0 )