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