Skip to content

Commit fc3b264

Browse files
committed
dt: Iterate through structure block
1 parent 5c002b5 commit fc3b264

File tree

9 files changed

+198
-17
lines changed

9 files changed

+198
-17
lines changed

src/common/src/big_endian.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use core::fmt::{Debug, Display};
22

3-
use crate::numbers::Number;
3+
use crate::{consumable_buffer::FromU8Buffer, numbers::Number};
44

5-
#[derive(PartialEq, Eq)]
5+
#[derive(PartialEq, Eq, Clone, Copy)]
66
#[repr(transparent)]
77
pub struct BigEndian<T: Number>(pub T);
88

@@ -12,6 +12,12 @@ impl<T: Number> BigEndian<T> {
1212
}
1313
}
1414

15+
impl<T: Number> FromU8Buffer for BigEndian<T> {
16+
fn from_u8_buffer(buffer: &[u8]) -> Self {
17+
BigEndian(T::from_le_bytes(buffer))
18+
}
19+
}
20+
1521
impl<T: Number> Debug for BigEndian<T> {
1622
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1723
write!(f, "{}", self.get())

src/common/src/consumable_buffer.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use core::slice;
2+
3+
use crate::util::align_up;
4+
5+
pub struct ConsumableBuffer<'a> {
6+
buffer: &'a [u8],
7+
position: usize,
8+
}
9+
10+
impl<'a> ConsumableBuffer<'a> {
11+
pub fn new(buffer: &'a [u8]) -> ConsumableBuffer<'a> {
12+
ConsumableBuffer {
13+
buffer,
14+
position: 0,
15+
}
16+
}
17+
18+
pub fn consume_slice(&mut self, size: usize) -> Option<&'a [u8]> {
19+
if self.position + size > self.buffer.len() {
20+
return None;
21+
}
22+
23+
if size == 0 {
24+
return Some(&[]);
25+
}
26+
27+
let result = &self.buffer[self.position..self.position + size];
28+
self.position += size;
29+
Some(result)
30+
}
31+
32+
pub fn consume_sized_type<T: FromU8Buffer>(&mut self) -> Option<T> {
33+
let size = core::mem::size_of::<T>();
34+
let result = self.consume_slice(size)?;
35+
Some(T::from_u8_buffer(result))
36+
}
37+
38+
pub fn consume_alignment(&mut self, alignment: usize) -> Option<()> {
39+
let aligned_value = align_up(self.position, alignment);
40+
let diff = aligned_value - self.position;
41+
self.consume_slice(diff)?;
42+
Some(())
43+
}
44+
45+
pub fn consume_str(&mut self) -> Option<&'a str> {
46+
let mut length = 0;
47+
while self.position + length < self.buffer.len() && self.buffer[self.position + length] != 0
48+
{
49+
length += 1;
50+
}
51+
// Check if we really found a null-terminated string
52+
if self.buffer[self.position + length] != 0 {
53+
return None;
54+
}
55+
56+
let string = unsafe {
57+
core::str::from_utf8(slice::from_raw_parts(&self.buffer[self.position], length)).ok()?
58+
};
59+
60+
// Consume null byte
61+
length += 1;
62+
63+
self.position += length;
64+
65+
Some(string)
66+
}
67+
68+
pub fn empty(&self) -> bool {
69+
self.position >= self.buffer.len()
70+
}
71+
72+
pub fn size_left(&self) -> usize {
73+
if self.position >= self.buffer.len() {
74+
0
75+
} else {
76+
self.buffer.len() - self.position
77+
}
78+
}
79+
}
80+
81+
pub trait FromU8Buffer: Copy {
82+
fn from_u8_buffer(buffer: &[u8]) -> Self;
83+
}

src/common/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
#![reexport_test_harness_main = "test_main"]
77

88
pub mod big_endian;
9+
pub mod consumable_buffer;
910
pub mod mutex;
1011
pub mod numbers;
1112
pub mod syscalls;
13+
pub mod util;
1214

1315
// Inspired by https://os.phil-opp.com/testing/
1416

src/common/src/numbers.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use core::fmt::{Debug, Display};
22

33
pub trait Number: Debug + Display + Copy + Clone {
44
fn from_be(value: Self) -> Self;
5+
fn from_le_bytes(bytes: &[u8]) -> Self;
56
}
67

78
macro_rules! impl_number {
@@ -10,6 +11,9 @@ macro_rules! impl_number {
1011
fn from_be(value: Self) -> Self {
1112
<$T>::from_be(value)
1213
}
14+
fn from_le_bytes(bytes: &[u8]) -> Self {
15+
<$T>::from_le_bytes(bytes.try_into().unwrap())
16+
}
1317
}
1418
};
1519
}

src/common/src/util.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
pub const fn align_up(value: usize, alignment: usize) -> usize {
2+
let remainder = value % alignment;
3+
if remainder == 0 {
4+
value
5+
} else {
6+
value + alignment - remainder
7+
}
8+
}

src/kernel/src/device_tree.rs

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
use common::big_endian::BigEndian;
1+
use common::{big_endian::BigEndian, consumable_buffer::ConsumableBuffer};
22
use core::{
33
fmt::{Debug, Display},
4+
mem::size_of,
45
slice,
56
};
67

8+
use crate::info;
9+
710
const FDT_MAGIC: u32 = 0xd00dfeed;
811
const FDT_VERSION: u32 = 17;
912

@@ -42,6 +45,29 @@ impl Header {
4245
slice::from_raw_parts(start, len)
4346
}
4447
}
48+
49+
pub fn get_structure_block(&self) -> StructureBlockIterator {
50+
let offset = self.off_dt_struct.get();
51+
let start = self.offset_from_header(offset as usize);
52+
info!("Structure Block Start: {:p}", start);
53+
StructureBlockIterator {
54+
buffer: ConsumableBuffer::new(unsafe {
55+
slice::from_raw_parts(start, self.size_dt_struct.get() as usize)
56+
}),
57+
header: self,
58+
}
59+
}
60+
61+
fn get_string(&self, offset: usize) -> Option<&str> {
62+
let start: *const u8 = self.offset_from_header(self.off_dt_strings.get() as usize);
63+
let size = self.size_dt_strings.get() as usize;
64+
if offset >= size {
65+
return None;
66+
}
67+
let strings_data = unsafe { slice::from_raw_parts(start, size) };
68+
let mut consumable_buffer = ConsumableBuffer::new(&strings_data[offset..]);
69+
consumable_buffer.consume_str()
70+
}
4571
}
4672

4773
impl Debug for Header {
@@ -109,6 +135,63 @@ impl Display for ReserveEntry {
109135
}
110136
}
111137

138+
const FDT_BEGIN_NODE: u32 = 0x1;
139+
const FDT_END_NODE: u32 = 0x2;
140+
const FDT_PROP: u32 = 0x3;
141+
const FDT_NOP: u32 = 0x4;
142+
const FDT_END: u32 = 0x9;
143+
144+
#[derive(Debug)]
145+
pub enum FdtToken<'a> {
146+
BeginNode(&'a str),
147+
EndNode,
148+
Prop(&'a str, &'a [u8]),
149+
Nop,
150+
End,
151+
}
152+
153+
pub struct StructureBlockIterator<'a> {
154+
header: &'a Header,
155+
buffer: ConsumableBuffer<'a>,
156+
}
157+
158+
impl<'a> Iterator for StructureBlockIterator<'a> {
159+
type Item = FdtToken<'a>;
160+
161+
fn next(&mut self) -> Option<Self::Item> {
162+
if self.buffer.empty() {
163+
return None;
164+
}
165+
166+
let numeric_token_value = self.buffer.consume_sized_type::<BigEndian<u32>>()?;
167+
let token = match numeric_token_value.get() {
168+
FDT_BEGIN_NODE => {
169+
let name = self.buffer.consume_str()?;
170+
self.buffer.consume_alignment(size_of::<u32>());
171+
FdtToken::BeginNode(name)
172+
}
173+
FDT_END_NODE => FdtToken::EndNode,
174+
FDT_PROP => {
175+
let len = self.buffer.consume_sized_type::<BigEndian<u32>>()?.get() as usize;
176+
let string_offset =
177+
self.buffer.consume_sized_type::<BigEndian<u32>>()?.get() as usize;
178+
let data = self.buffer.consume_slice(len)?;
179+
self.buffer.consume_alignment(size_of::<u32>());
180+
let string = self.header.get_string(string_offset)?;
181+
FdtToken::Prop(string, data)
182+
}
183+
FDT_NOP => FdtToken::Nop,
184+
FDT_END => {
185+
assert!(self.buffer.empty());
186+
FdtToken::End
187+
}
188+
_ => panic!("Unknown token: {:#x}", numeric_token_value.get()),
189+
};
190+
191+
Some(token)
192+
}
193+
}
194+
112195
pub fn parse(device_tree_pointer: *const ()) -> &'static Header {
113196
let header = unsafe { &*(device_tree_pointer as *const Header) };
114197

src/kernel/src/klibc/util.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
use core::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Shl, Shr};
22

3-
use crate::memory::PAGE_SIZE;
3+
use common::util::align_up;
44

5-
pub const fn align_up(value: usize, alignment: usize) -> usize {
6-
let remainder = value % alignment;
7-
if remainder == 0 {
8-
value
9-
} else {
10-
value + alignment - remainder
11-
}
12-
}
5+
use crate::memory::PAGE_SIZE;
136

147
pub const fn minimum_amount_of_pages(value: usize) -> usize {
158
align_up(value, PAGE_SIZE) / PAGE_SIZE

src/kernel/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ extern "C" fn kernel_init(hart_id: usize, device_tree_pointer: *const ()) {
7070
"There should be no reserved memory regions"
7171
);
7272

73+
let structured_block = dtb.get_structure_block();
74+
for node in structured_block {
75+
debug!("{:?}", node);
76+
}
77+
7378
unsafe {
7479
info!("Initializing page allocator");
7580
info!(

src/kernel/src/memory/heap.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@ use core::{
55
ptr::{null_mut, NonNull},
66
};
77

8-
use common::mutex::Mutex;
8+
use common::{mutex::Mutex, util::align_up};
99

10-
use crate::{
11-
assert::static_assert_size,
12-
klibc::util::{align_up, minimum_amount_of_pages},
13-
};
10+
use crate::{assert::static_assert_size, klibc::util::minimum_amount_of_pages};
1411

1512
use super::{page_allocator::PageAllocator, PAGE_SIZE};
1613

0 commit comments

Comments
 (0)