use crate::types::Pid; pub use lancer_core::object_tag::ObjectTag; #[derive(Debug, Clone, Copy)] pub struct PidQueue { pub head: Option, pub tail: Option, len: u16, } impl PidQueue { pub const fn new() -> Self { Self { head: None, tail: None, len: 0, } } #[allow(dead_code)] pub const fn len(&self) -> u16 { self.len } #[allow(dead_code)] pub const fn is_empty(&self) -> bool { self.len == 0 } pub fn check_capacity(&self) -> Result<(), crate::error::KernelError> { if (self.len as usize) < crate::types::MAX_PIDS { Ok(()) } else { Err(crate::error::KernelError::ResourceExhausted) } } pub fn inc_len(&mut self) -> Result<(), crate::error::KernelError> { self.len = self .len .checked_add(1) .ok_or(crate::error::KernelError::ResourceExhausted)?; Ok(()) } pub fn dec_len(&mut self) { match self.len.checked_sub(1) { Some(n) => self.len = n, None => { crate::show!(ipc, error, "pidqueue dec_len underflow, clamping to 0"); self.len = 0; } } } pub fn validate(&self, next_link: impl Fn(Pid) -> Option) -> bool { let head_tail_ok = match self.len { 0 => self.head.is_none() && self.tail.is_none(), _ => self.head.is_some() && self.tail.is_some(), }; if !head_tail_ok { crate::show!( ipc, error, "pidqueue invariant violation len {} head {:?} tail {:?}", self.len, self.head, self.tail ); return false; } let max = crate::types::MAX_PIDS; let mut last = None; let chain_len = core::iter::successors(self.head, |&cur| { last = Some(cur); next_link(cur) }) .take(max + 1) .count(); if chain_len != self.len as usize { crate::show!( ipc, error, "pidqueue length mismatch chain {} stored {}", chain_len, self.len ); return false; } match (self.tail, last) { (Some(t), Some(l)) => { if t == l { true } else { crate::show!( ipc, error, "pidqueue tail mismatch stored {} walked {}", t.raw(), l.raw() ); false } } (None, None) => true, _ => { crate::show!( ipc, error, "pidqueue tail inconsistency stored {:?} walked {:?}", self.tail, last ); false } } } pub fn from_repr_c(head: u32, tail: u32, len: u16) -> Self { Self::from_parts(Pid::try_new(head), Pid::try_new(tail), len) } pub fn to_repr_c(self) -> (u32, u32, u16) { ( self.head .map_or(lancer_core::header::NONE_SENTINEL, |p| p.raw()), self.tail .map_or(lancer_core::header::NONE_SENTINEL, |p| p.raw()), self.len, ) } pub fn from_parts(head: Option, tail: Option, len: u16) -> Self { if len == 0 || head.is_none() || tail.is_none() { Self::new() } else { Self { head, tail, len } } } } #[derive(Debug, Clone, Copy)] pub struct CNodeData { pub slots_phys: x86_64::PhysAddr, pub size_bits: u8, pub frame_count: u8, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct IoPort(u16); impl IoPort { pub const fn new(port: u16) -> Self { Self(port) } pub(crate) const fn raw(self) -> u16 { self.0 } } impl core::fmt::Display for IoPort { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:#x}", self.0) } } #[derive(Debug, Clone, Copy)] pub struct PortRange { base: u16, count: u16, } impl PortRange { pub const fn new(base: u16, count: u16) -> Option { if count == 0 { return None; } let end = base as u32 + count as u32; if end > 0x10000 { return None; } Some(Self { base, count }) } #[allow(dead_code)] pub const fn base(self) -> u16 { self.base } #[allow(dead_code)] pub const fn count(self) -> u16 { self.count } pub fn contains(self, port: IoPort) -> bool { (port.0 as u32) >= (self.base as u32) && (port.0 as u32) < (self.base as u32) + (self.count as u32) } } #[derive(Debug, Clone, Copy)] pub enum IrqSource { Ioapic { gsi: crate::arch::ioapic::Gsi, }, Msix { device_table_idx: u8, entry_idx: u16, }, }