Next Generation WASM Microkernel Operating System
at main 605 lines 18 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8use core::ffi::CStr; 9use core::ptr::NonNull; 10use core::{fmt, iter, mem, slice}; 11 12use bumpalo::Bump; 13use fallible_iterator::FallibleIterator; 14use hashbrown::HashMap; 15use k23_fdt::{CellSizes, Error, Fdt, NodeName, StringList}; 16use smallvec::{SmallVec, smallvec}; 17 18type Link<T> = Option<NonNull<T>>; 19 20/// A device tree describing the hardware configuration of the system. 21#[ouroboros::self_referencing] // `root` and all other nodes & data borrows from `alloc` 22pub struct DeviceTree { 23 alloc: Bump, 24 #[borrows(alloc)] 25 #[covariant] 26 inner: DeviceTreeInner<'this>, 27} 28 29struct DeviceTreeInner<'devtree> { 30 phandle2ptr: HashMap<u32, NonNull<Device<'devtree>>>, 31 root: NonNull<Device<'devtree>>, 32} 33 34/// Tree of the following shape: 35/// 36/// 37/// root 38/// / 39/// / 40/// node - node - node 41/// / / 42/// / / 43/// node - node node 44/// 45/// where each node has a pointer to its first child, which in turn form a linked list of siblings. 46/// additionally each node has a pointer to back its parent. 47pub struct Device<'a> { 48 /// The name of the device 49 pub name: NodeName<'a>, 50 pub compatible: &'a str, 51 pub phandle: Option<u32>, 52 53 // linked list of device properties 54 properties: Link<Property<'a>>, 55 // links to other devices in the tree 56 parent: Link<Device<'a>>, 57 first_child: Link<Device<'a>>, 58 next_sibling: Link<Device<'a>>, 59} 60 61/// A property of a device. 62pub struct Property<'a> { 63 inner: k23_fdt::Property<'a>, 64 next: Link<Property<'a>>, 65} 66 67// Safety: `DeviceTree`s accessor methods allow non-mutable access. 68unsafe impl Send for DeviceTree {} 69// Safety: `DeviceTree`s accessor methods allow non-mutable access. 70unsafe impl Sync for DeviceTree {} 71 72impl fmt::Debug for DeviceTree { 73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 74 f.debug_struct("DeviceTree") 75 .field("root", &self.root()) 76 .finish() 77 } 78} 79 80impl DeviceTree { 81 pub fn parse(fdt: &[u8]) -> crate::Result<Self> { 82 // Safety: u32 has no invalid bit patterns 83 let (left, aligned, _) = unsafe { fdt.align_to::<u32>() }; 84 assert!(left.is_empty()); // TODO decide what to do with unaligned slices 85 let fdt = Fdt::new(aligned)?; 86 87 let alloc = Bump::new(); 88 89 DeviceTree::try_new(alloc, |alloc| { 90 let mut phandle2ptr = HashMap::new(); 91 92 let mut stack: [Link<Device>; 16] = [const { None }; 16]; 93 94 let root = unflatten_root(&fdt, alloc)?; 95 stack[0] = Some(root); 96 97 let mut iter = fdt.nodes()?; 98 while let Some((depth, node)) = iter.next()? { 99 let ptr = unflatten_node( 100 node, 101 &mut phandle2ptr, 102 stack[depth - 1].unwrap(), 103 stack[depth], 104 alloc, 105 )?; 106 107 // insert ourselves into the stack so we will become the new previous sibling in the next iteration 108 stack[depth] = Some(ptr); 109 } 110 111 Ok(DeviceTreeInner { phandle2ptr, root }) 112 }) 113 } 114 115 /// Matches the root device tree `compatible` string against the given list of strings. 116 #[inline] 117 pub fn is_compatible<'b>(&self, compats: impl IntoIterator<Item = &'b str>) -> bool { 118 self.root().is_compatible(compats) 119 } 120 121 /// Returns an iterator over all top-level devices in the tree. 122 #[inline] 123 pub fn children(&self) -> Children<'_> { 124 self.root().children() 125 } 126 127 /// Returns an iterator over all nodes in the tree in depth-first order. 128 #[inline] 129 pub fn descendants(&self) -> Descendants<'_> { 130 self.root().descendants() 131 } 132 133 /// Returns an iterator over all top-level properties in the tree. 134 #[inline] 135 pub fn properties(&self) -> Properties<'_> { 136 self.root().properties() 137 } 138 139 /// Returns the top-level property with the given name. 140 #[inline] 141 pub fn property(&self, name: &str) -> Option<&Property<'_>> { 142 self.root().property(name) 143 } 144 145 /// Returns the device with the given path. 146 #[inline] 147 pub fn find_by_path(&self, path: &str) -> Option<&Device<'_>> { 148 self.root().find_by_path(path) 149 } 150 151 pub fn find_by_phandle(&self, phandle: u32) -> Option<&Device<'_>> { 152 // Safety: we only inserted valid pointers into the map, so we should only get valid pointers out... 153 self.with_inner(|inner| unsafe { Some(inner.phandle2ptr.get(&phandle)?.as_ref()) }) 154 } 155 156 #[inline] 157 fn root(&self) -> &Device<'_> { 158 // Safety: `init` guarantees the root node always exists and is correctly initialized 159 unsafe { self.borrow_inner().root.as_ref() } 160 } 161} 162 163impl fmt::Debug for Device<'_> { 164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 165 let alternate = f.alternate(); 166 167 let mut s = f.debug_struct("Device"); 168 s.field("name", &self.name) 169 .field("compatible", &self.compatible) 170 .field("phandle", &self.phandle); 171 if alternate { 172 s.field_with("<properties>", |f| { 173 let mut f = f.debug_list(); 174 for prop in self.properties() { 175 f.entry(&prop); 176 } 177 f.finish() 178 }); 179 180 s.field_with("<children>", |f| { 181 let mut f = f.debug_list(); 182 for prop in self.children() { 183 f.entry(&prop); 184 } 185 f.finish() 186 }); 187 188 s.finish() 189 } else { 190 s.finish_non_exhaustive() 191 } 192 } 193} 194 195impl<'a> Device<'a> { 196 /// Returns `true` if this device is usable, i.e. its reported status property is "okay". 197 pub fn is_available(&self) -> bool { 198 self.properties() 199 .any(|prop| prop.inner.name == "status" && prop.inner.raw == b"okay") 200 } 201 202 /// Matches the device `compatible` string against the given list of strings. 203 pub fn is_compatible<'b>(&self, compats: impl IntoIterator<Item = &'b str>) -> bool { 204 compats.into_iter().any(|c| self.compatible.contains(c)) 205 } 206 207 pub fn parent(&self) -> Option<&Device<'a>> { 208 // Safety: tree construction guarantees that the pointer is valid 209 self.parent.map(|parent| unsafe { parent.as_ref() }) 210 } 211 212 /// Returns an iterator over all immediate children of this device. 213 pub fn children(&self) -> Children<'_> { 214 Children { 215 current: self.first_child, 216 } 217 } 218 219 /// Returns an iterator over all descendants of this device in depth-first order. 220 pub fn descendants(&self) -> Descendants<'_> { 221 Descendants { 222 stack: smallvec![], 223 current: self.children(), 224 } 225 } 226 227 /// Returns an iterator over all properties of this device. 228 pub fn properties(&self) -> Properties<'_> { 229 Properties { 230 current: self.properties, 231 } 232 } 233 234 /// Returns the property with the given name. 235 pub fn property(&self, name: &str) -> Option<&Property<'_>> { 236 self.properties().find(|prop| prop.inner.name == name) 237 } 238 239 /// Returns the device with the given path starting from this device. 240 pub fn find_by_path(&self, path: &str) -> Option<&Device<'_>> { 241 let mut node = self; 242 for component in path.trim_start_matches('/').split('/') { 243 node = node.children().find(|child| child.name.name == component)?; 244 } 245 Some(node) 246 } 247 248 pub fn cell_sizes(&self) -> CellSizes { 249 let address_cells = self 250 .property("#address-cells") 251 .and_then(|prop| prop.as_usize().ok()); 252 let size_cells = self 253 .property("#size-cells") 254 .and_then(|prop| prop.as_usize().ok()); 255 256 if let (Some(address_cells), Some(size_cells)) = (address_cells, size_cells) { 257 CellSizes { 258 address_cells, 259 size_cells, 260 } 261 } else if let Some(parent) = self.parent { 262 // Safety: tree construction ensures the parent ptr is always valid 263 unsafe { parent.as_ref() }.cell_sizes() 264 } else { 265 CellSizes::default() 266 } 267 } 268 269 pub fn regs(&self) -> Option<k23_fdt::Regs<'_>> { 270 self.properties() 271 .find(|p| p.name() == "reg") 272 .map(|prop| prop.inner.as_regs(self.cell_sizes())) 273 } 274 275 pub fn interrupt_cells(&self) -> Option<usize> { 276 self.property("#interrupt-cells")?.as_usize().ok() 277 } 278 279 pub fn interrupt_parent(&self, devtree: &'a DeviceTree) -> Option<&Device<'a>> { 280 self.properties() 281 .find(|p| p.name() == "interrupt-parent") 282 .and_then(|prop| devtree.find_by_phandle(prop.as_u32().ok()?)) 283 } 284 285 pub fn interrupts(&'a self, devtree: &'a DeviceTree) -> Option<Interrupts<'a>> { 286 let prop = self.property("interrupts")?; 287 let raw = prop.inner.raw.array_chunks::<4>(); 288 let parent = self.interrupt_parent(devtree)?; 289 Some(Interrupts { 290 parent, 291 parent_cells: parent.interrupt_cells()?, 292 raw: raw.map(|chunk| u32::from_be_bytes(*chunk)), 293 }) 294 } 295 296 pub fn interrupts_extended( 297 &'a self, 298 devtree: &'a DeviceTree, 299 ) -> Option<InterruptsExtended<'a>> { 300 let prop = self.property("interrupts-extended")?; 301 let raw = prop.inner.raw.array_chunks::<4>(); 302 Some(InterruptsExtended { 303 devtree, 304 raw: raw.map(|chunk| u32::from_be_bytes(*chunk)), 305 }) 306 } 307} 308 309impl fmt::Debug for Property<'_> { 310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 311 f.debug_struct("Property") 312 .field("name", &self.inner.name) 313 .field("raw", &self.inner.raw) 314 .finish() 315 } 316} 317 318impl<'a> Property<'a> { 319 pub fn name(&self) -> &'a str { 320 self.inner.name 321 } 322 323 pub fn raw(&self) -> &'a [u8] { 324 self.inner.raw 325 } 326 327 /// Returns the property as a `u32`. 328 /// 329 /// # Errors 330 /// 331 /// Returns an error if the property is not a u32. 332 pub fn as_u32(&self) -> Result<u32, Error> { 333 self.inner.as_u32() 334 } 335 336 /// Returns the property as a `u64`. 337 /// 338 /// # Errors 339 /// 340 /// Returns an error if the property is not a u64. 341 pub fn as_u64(&self) -> Result<u64, Error> { 342 self.inner.as_u64() 343 } 344 345 /// Returns the property as a `usize`. 346 /// 347 /// # Errors 348 /// 349 /// Returns an error if the property is not a usize. 350 pub fn as_usize(&self) -> Result<usize, Error> { 351 self.inner.as_usize() 352 } 353 354 /// Returns the property as a C string. 355 /// 356 /// # Errors 357 /// 358 /// Returns an error if the property is not a valid C string. 359 pub fn as_cstr(&self) -> Result<&'a CStr, Error> { 360 self.inner.as_cstr() 361 } 362 363 /// Returns the property as a string. 364 /// 365 /// # Errors 366 /// 367 /// Returns an error if the property is not a valid UTF-8 string. 368 pub fn as_str(&self) -> Result<&'a str, Error> { 369 self.inner.as_str() 370 } 371 372 /// Returns a fallible iterator over the strings in the property. 373 /// 374 /// # Errors 375 /// 376 /// Returns an error if the property is not a valid UTF-8 string. 377 pub fn as_strlist(&self) -> Result<StringList<'a>, Error> { 378 self.inner.as_strlist() 379 } 380} 381 382pub struct Children<'a> { 383 current: Link<Device<'a>>, 384} 385 386impl<'a> Iterator for Children<'a> { 387 type Item = &'a Device<'a>; 388 389 fn next(&mut self) -> Option<Self::Item> { 390 // Safety: tree construction guarantees that the pointer is valid 391 let dev = unsafe { self.current?.as_ref() }; 392 self.current = dev.next_sibling; 393 Some(dev) 394 } 395} 396 397pub struct Descendants<'a> { 398 stack: SmallVec<[Children<'a>; 6]>, 399 current: Children<'a>, 400} 401 402impl<'a> Iterator for Descendants<'a> { 403 type Item = (usize, &'a Device<'a>); 404 405 fn next(&mut self) -> Option<Self::Item> { 406 if let Some(next) = self.current.next() { 407 let depth = self.stack.len(); 408 if next.first_child.is_some() { 409 let parent = mem::replace(&mut self.current, next.children()); 410 self.stack.push(parent); 411 } 412 Some((depth, next)) 413 } else { 414 self.current = self.stack.pop()?; 415 self.next() 416 } 417 } 418} 419 420pub struct Properties<'a> { 421 current: Link<Property<'a>>, 422} 423 424impl<'a> Iterator for Properties<'a> { 425 type Item = &'a Property<'a>; 426 427 fn next(&mut self) -> Option<Self::Item> { 428 // Safety: list construction guarantees that the pointer is valid 429 let dev = unsafe { self.current?.as_ref() }; 430 self.current = dev.next; 431 Some(dev) 432 } 433} 434 435#[derive(Debug)] 436pub enum IrqSource { 437 C1(u32), 438 C3(u32, u32, u32), 439} 440 441#[expect(clippy::type_complexity, reason = "this is not thaaat complex")] 442pub struct Interrupts<'a> { 443 parent: &'a Device<'a>, 444 parent_cells: usize, 445 raw: iter::Map<slice::ArrayChunks<'a, u8, 4>, fn(&[u8; 4]) -> u32>, 446} 447impl<'a> Iterator for Interrupts<'a> { 448 type Item = (&'a Device<'a>, IrqSource); 449 450 fn next(&mut self) -> Option<Self::Item> { 451 Some(( 452 self.parent, 453 interrupt_address(&mut self.raw, self.parent_cells)?, 454 )) 455 } 456} 457 458#[expect(clippy::type_complexity, reason = "this is not thaaat complex")] 459pub struct InterruptsExtended<'a> { 460 devtree: &'a DeviceTree, 461 raw: iter::Map<slice::ArrayChunks<'a, u8, 4>, fn(&[u8; 4]) -> u32>, 462} 463impl<'a> Iterator for InterruptsExtended<'a> { 464 type Item = (&'a Device<'a>, IrqSource); 465 466 fn next(&mut self) -> Option<Self::Item> { 467 let parent_phandle = self.raw.next()?; 468 let parent = self.devtree.find_by_phandle(parent_phandle)?; 469 let parent_interrupt_cells = parent.interrupt_cells()?; 470 Some(( 471 parent, 472 interrupt_address(&mut self.raw, parent_interrupt_cells)?, 473 )) 474 } 475} 476 477fn interrupt_address( 478 iter: &mut impl Iterator<Item = u32>, 479 interrupt_cells: usize, 480) -> Option<IrqSource> { 481 match interrupt_cells { 482 1 => Some(IrqSource::C1(iter.next()?)), 483 3 if let Ok([a, b, c]) = iter.next_chunk() => Some(IrqSource::C3(a, b, c)), 484 _ => None, 485 } 486} 487 488fn unflatten_root<'a>(fdt: &Fdt, alloc: &'a Bump) -> crate::Result<NonNull<Device<'a>>> { 489 let mut compatible: Option<&str> = None; 490 491 let mut props_head: Link<Property> = None; 492 let mut props_tail: Link<Property> = None; 493 494 let mut props = fdt.properties(); 495 while let Some(prop) = props.next()? { 496 if prop.name == "compatible" { 497 compatible = Some(alloc.alloc_str(prop.as_str()?)); 498 } else { 499 unflatten_property(prop, &mut props_head, &mut props_tail, alloc); 500 } 501 } 502 503 let ptr = NonNull::from(alloc.alloc(Device { 504 name: NodeName { 505 name: "", 506 unit_address: None, 507 }, 508 compatible: compatible.unwrap_or_default(), 509 phandle: None, 510 properties: props_head, 511 parent: None, 512 first_child: None, 513 next_sibling: None, 514 })); 515 516 Ok(ptr) 517} 518 519fn unflatten_node<'a>( 520 node: k23_fdt::Node, 521 phandle2ptr: &mut HashMap<u32, NonNull<Device<'a>>>, 522 mut parent: NonNull<Device<'a>>, 523 prev_sibling: Link<Device<'a>>, 524 alloc: &'a Bump, 525) -> crate::Result<NonNull<Device<'a>>> { 526 let mut compatible: Option<&'a str> = None; 527 let mut phandle: Option<u32> = None; 528 529 let mut props_head: Link<Property> = None; 530 let mut props_tail: Link<Property> = None; 531 532 let mut props = node.properties(); 533 while let Some(prop) = props.next()? { 534 if prop.name == "compatible" { 535 compatible = Some(alloc.alloc_str(prop.as_str()?)); 536 } else if prop.name == "phandle" { 537 phandle = prop.as_u32().ok(); 538 } else { 539 unflatten_property(prop, &mut props_head, &mut props_tail, alloc); 540 } 541 } 542 543 let name = node.name()?; 544 let node = NonNull::from(alloc.alloc(Device { 545 name: NodeName { 546 name: alloc.alloc_str(name.name), 547 unit_address: name.unit_address.map(|addr| &*alloc.alloc_str(addr)), 548 }, 549 compatible: compatible.unwrap_or_default(), 550 phandle, 551 properties: props_head, 552 parent: Some(parent), 553 first_child: None, 554 next_sibling: None, 555 })); 556 557 if let Some(phandle) = phandle { 558 phandle2ptr.insert(phandle, node); 559 } 560 561 // update the parents `first_child` pointer if necessary 562 // Safety: callers responsibility to ensure that the parent pointer is valid 563 unsafe { 564 parent.as_mut().first_child.get_or_insert(node); 565 } 566 567 // update the previous sibling's `next_sibling` pointer if necessary 568 if let Some(mut sibling) = prev_sibling { 569 // Safety: callers responsibility to ensure that the parent pointer is valid 570 unsafe { 571 sibling.as_mut().next_sibling = Some(node); 572 } 573 } 574 575 Ok(node) 576} 577 578fn unflatten_property<'a>( 579 prop: k23_fdt::Property, 580 head: &mut Link<Property<'a>>, 581 tail: &mut Link<Property<'a>>, 582 alloc: &'a Bump, 583) { 584 let prop = NonNull::from(alloc.alloc(Property { 585 inner: k23_fdt::Property { 586 name: alloc.alloc_str(prop.name), 587 raw: alloc.alloc_slice_copy(prop.raw), 588 }, 589 next: None, 590 })); 591 592 // if there already is a tail node append the new node to it 593 if let &mut Some(mut tail) = tail { 594 // Safety: tail is either `None` or a valid pointer we allocated in a previous call below 595 let tail = unsafe { tail.as_mut() }; 596 tail.next = Some(prop); 597 } else { 598 // otherwise the list is empty, so update the head pointer 599 debug_assert!(head.is_none()); 600 *head = Some(prop); 601 } 602 603 // update the tail pointer so we will become the new tail in the next iteration 604 *tail = Some(prop); 605}