Skip to content

Instantly share code, notes, and snippets.

@nihalpasham
Last active March 10, 2022 07:29
Show Gist options
  • Save nihalpasham/10fbf200c270bbde0fbd0bc7815a960e to your computer and use it in GitHub Desktop.
Save nihalpasham/10fbf200c270bbde0fbd0bc7815a960e to your computer and use it in GitHub Desktop.
Snippet to create flattened dtb nodes and properties
#[derive(Debug)]
#[repr(C)]
/// Constructs a device-tree `node`, given a name and buffer. The buffer must be adequately sized.
pub struct RawNodeConstructor<'a> {
fdt_begin_node: u32,
node_name: &'a [u8],
}
impl<'a> RawNodeConstructor<'a> {
pub fn make_raw_node(buf: &'a mut [u8], name: &'a str) -> Result<Self> {
// calculate `raw node size and count` in bytes. size includes null + padding bytes
let mut node_size_in_bytes;
let mut count;
let name_len = name.as_bytes().len();
match (TOKEN_SIZE + name_len) % 2 == 0 {
true => {
// if even
node_size_in_bytes =
(TOKEN_SIZE + name_len) + ((TOKEN_SIZE + name_len) % 4);
count = TOKEN_SIZE + name_len;
}
false => {
// if odd
node_size_in_bytes =
(TOKEN_SIZE + name_len) + ((TOKEN_SIZE + name_len + 2) % 4);
count = TOKEN_SIZE + name_len + 2;
}
}
if buf.len() < node_size_in_bytes {
return Err(Error::BufferTooSmall);
}
// construct raw node
let node_name = name.as_bytes();
println!("count: {}", count);
if count % 4 == 0 {
let padding = [0; 4]; // node names are always null terminated
buf[..name_len].copy_from_slice(node_name);
buf[name_len..name_len + 4].copy_from_slice(&padding[..]);
Ok(RawNodeConstructor {
fdt_begin_node: TOK_BEGIN_NODE,
node_name: &buf[..name_len + 4],
})
} else {
let padding = count % 4;
let max_padding_bytes = [0; 4]; // max padding is 3 bytes
buf[..name_len].copy_from_slice(node_name);
buf[name_len..name_len + padding]
.copy_from_slice(&max_padding_bytes[..padding]);
Ok(RawNodeConstructor {
fdt_begin_node: TOK_BEGIN_NODE,
node_name: &buf[..name_len + padding],
})
}
}
}
#[derive(Debug)]
#[repr(C)]
/// Constructs a device-tree `property`, given a buffer, a property value and an offset into the
/// device-tree `strings-block`. The buffer must be adequately sized.
pub struct RawPropertyConstructor<'a> {
fdt_prop: u32,
prop_len: u32,
name_off: u32,
prop_val: &'a [u8],
}
impl<'a> RawPropertyConstructor<'a> {
pub fn make_raw_property(
buf: &'a mut [u8],
prop_name_offset: usize,
prop_val: &'a str,
) -> Result<Self> {
// calculate `raw property size and count` in bytes. size includes null + padding bytes
let mut prop_size_in_bytes;
let mut count;
let prop_val_len = prop_val.as_bytes().len();
match (TOKEN_SIZE * 3 + prop_val_len) % 2 == 0 {
true => {
// if even
prop_size_in_bytes = (TOKEN_SIZE * 3 + prop_val_len)
+ ((TOKEN_SIZE * 3 + prop_val_len) % 4);
count = (TOKEN_SIZE * 3) + prop_val.len();
}
false => {
// if odd
prop_size_in_bytes = (TOKEN_SIZE * 3 + prop_val_len)
+ ((TOKEN_SIZE * 3 + prop_val_len + 2) % 4);
count = (TOKEN_SIZE * 3) + prop_val.len() + 2;
}
}
if buf.len() < prop_size_in_bytes {
return Err(Error::BufferTooSmall);
}
// construct raw property
if count % 4 == 0 {
let padding = [0; 4]; // property values are always null terminated
buf[..prop_val_len].copy_from_slice(prop_val.as_bytes());
buf[prop_val_len..prop_val_len + 4].copy_from_slice(&padding[..]);
Ok(RawPropertyConstructor {
fdt_prop: TOK_PROPERTY,
prop_len: prop_val.len() as u32,
name_off: prop_name_offset as u32,
prop_val: &buf[..prop_val_len + 4],
})
} else {
let padding = count % 4;
let max_padding_bytes = [0; 4]; // max padding is 3 bytes
buf[..prop_val_len].copy_from_slice(prop_val.as_bytes());
buf[prop_val_len..prop_val_len + padding]
.copy_from_slice(&max_padding_bytes[..padding]);
Ok(RawPropertyConstructor {
fdt_prop: TOK_PROPERTY,
prop_len: prop_val.len() as u32,
name_off: prop_name_offset as u32,
prop_val: &buf[..prop_val_len + padding],
})
}
}
}
@nihalpasham
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment