Nothing to see here, move along
at main 527 lines 13 kB view raw
1use lancer_core::untyped::UntypedState; 2use x86_64::PhysAddr; 3 4use crate::static_vec::StaticVec; 5use crate::types::{ObjectId, Pid, Priority}; 6 7pub use lancer_core::object_tag::ObjectTag; 8 9macro_rules! object_accessors { 10 ($( 11 $variant:ident => { 12 $( ref $ref_name:ident -> $ref_ty:ty; )* 13 $( mut $mut_name:ident -> $mut_ty:ty; )* 14 } 15 )*) => { 16 $( 17 $( 18 #[allow(dead_code)] 19 pub fn $ref_name(&self) -> Result<&$ref_ty, crate::error::KernelError> { 20 match self { 21 Self::$variant(inner) => Ok(inner), 22 _ => Err(crate::error::KernelError::InvalidType), 23 } 24 } 25 )* 26 $( 27 #[allow(dead_code)] 28 pub fn $mut_name(&mut self) -> Result<&mut $mut_ty, crate::error::KernelError> { 29 match self { 30 Self::$variant(inner) => Ok(inner), 31 _ => Err(crate::error::KernelError::InvalidType), 32 } 33 } 34 )* 35 )* 36 }; 37} 38 39#[derive(Debug)] 40#[allow(dead_code, clippy::large_enum_variant)] 41pub enum ObjectData { 42 Endpoint(EndpointData), 43 Notification(NotificationData), 44 Process(ProcessObjectData), 45 SchedContext(SchedContextData), 46 IrqHandler(IrqHandlerData), 47 Framebuffer(FramebufferData), 48 PciDevice(PciDeviceData), 49 CNode(CNodeData), 50 Untyped(UntypedObjectData), 51 Frame(FrameObjectData), 52} 53 54impl ObjectData { 55 pub const fn tag(&self) -> ObjectTag { 56 match self { 57 Self::Endpoint(_) => ObjectTag::Endpoint, 58 Self::Notification(_) => ObjectTag::Notification, 59 Self::Process(_) => ObjectTag::Process, 60 Self::SchedContext(_) => ObjectTag::SchedContext, 61 Self::IrqHandler(_) => ObjectTag::IrqHandler, 62 Self::Framebuffer(_) => ObjectTag::Framebuffer, 63 Self::PciDevice(_) => ObjectTag::PciDevice, 64 Self::CNode(_) => ObjectTag::CNode, 65 Self::Untyped(_) => ObjectTag::Untyped, 66 Self::Frame(_) => ObjectTag::Frame, 67 } 68 } 69 70 object_accessors! { 71 Endpoint => { 72 ref as_endpoint -> EndpointData; 73 mut as_endpoint_mut -> EndpointData; 74 } 75 Notification => { 76 ref as_notification -> NotificationData; 77 mut as_notification_mut -> NotificationData; 78 } 79 Process => { 80 ref as_process -> ProcessObjectData; 81 mut as_process_mut -> ProcessObjectData; 82 } 83 SchedContext => { 84 ref as_sched_context -> SchedContextData; 85 mut as_sched_context_mut -> SchedContextData; 86 } 87 IrqHandler => { 88 ref as_irq_handler -> IrqHandlerData; 89 mut as_irq_handler_mut -> IrqHandlerData; 90 } 91 Framebuffer => { 92 ref as_framebuffer -> FramebufferData; 93 mut as_framebuffer_mut -> FramebufferData; 94 } 95 PciDevice => { 96 ref as_pci_device -> PciDeviceData; 97 mut as_pci_device_mut -> PciDeviceData; 98 } 99 CNode => { 100 ref as_cnode -> CNodeData; 101 mut as_cnode_mut -> CNodeData; 102 } 103 Untyped => { 104 ref as_untyped -> UntypedObjectData; 105 mut as_untyped_mut -> UntypedObjectData; 106 } 107 Frame => { 108 ref as_frame -> FrameObjectData; 109 mut as_frame_mut -> FrameObjectData; 110 } 111 } 112} 113 114pub const MAX_NOTIFICATION_WAITERS: usize = 4; 115 116#[derive(Debug, Clone, Copy)] 117pub struct PidQueue { 118 pub head: Option<Pid>, 119 pub tail: Option<Pid>, 120 len: u16, 121} 122 123impl PidQueue { 124 pub const fn new() -> Self { 125 Self { 126 head: None, 127 tail: None, 128 len: 0, 129 } 130 } 131 132 #[allow(dead_code)] 133 pub const fn len(&self) -> u16 { 134 self.len 135 } 136 137 #[allow(dead_code)] 138 pub const fn is_empty(&self) -> bool { 139 self.len == 0 140 } 141 142 pub fn check_capacity(&self) -> Result<(), crate::error::KernelError> { 143 if (self.len as usize) < crate::types::MAX_PIDS { 144 Ok(()) 145 } else { 146 Err(crate::error::KernelError::ResourceExhausted) 147 } 148 } 149 150 pub fn inc_len(&mut self) -> Result<(), crate::error::KernelError> { 151 self.len = self 152 .len 153 .checked_add(1) 154 .ok_or(crate::error::KernelError::ResourceExhausted)?; 155 Ok(()) 156 } 157 158 pub fn dec_len(&mut self) { 159 match self.len.checked_sub(1) { 160 Some(n) => self.len = n, 161 None => { 162 crate::show!(ipc, error, "pidqueue dec_len underflow, clamping to 0"); 163 self.len = 0; 164 } 165 } 166 } 167 168 pub fn validate(&self, next_link: impl Fn(Pid) -> Option<Pid>) -> bool { 169 let head_tail_ok = match self.len { 170 0 => self.head.is_none() && self.tail.is_none(), 171 _ => self.head.is_some() && self.tail.is_some(), 172 }; 173 if !head_tail_ok { 174 crate::show!(ipc, error, 175 "pidqueue invariant violation len {} head {:?} tail {:?}", 176 self.len, 177 self.head, 178 self.tail 179 ); 180 return false; 181 } 182 183 let max = crate::types::MAX_PIDS; 184 let mut last = None; 185 let chain_len = core::iter::successors(self.head, |&cur| { 186 last = Some(cur); 187 next_link(cur) 188 }) 189 .take(max + 1) 190 .count(); 191 192 if chain_len != self.len as usize { 193 crate::show!(ipc, error, 194 "pidqueue length mismatch chain {} stored {}", 195 chain_len, 196 self.len 197 ); 198 return false; 199 } 200 201 match (self.tail, last) { 202 (Some(t), Some(l)) => { 203 if t == l { 204 true 205 } else { 206 crate::show!(ipc, error, 207 "pidqueue tail mismatch stored {} walked {}", 208 t.raw(), 209 l.raw() 210 ); 211 false 212 } 213 } 214 (None, None) => true, 215 _ => { 216 crate::show!(ipc, error, 217 "pidqueue tail inconsistency stored {:?} walked {:?}", 218 self.tail, 219 last 220 ); 221 false 222 } 223 } 224 } 225 226 pub fn from_parts(head: Option<Pid>, tail: Option<Pid>, len: u16) -> Self { 227 if len == 0 { 228 assert!( 229 head.is_none() && tail.is_none(), 230 "PidQueue invariant: len=0 requires head=None, tail=None" 231 ); 232 Self::new() 233 } else { 234 assert!( 235 head.is_some() && tail.is_some(), 236 "PidQueue invariant: len>0 requires head and tail" 237 ); 238 Self { head, tail, len } 239 } 240 } 241} 242 243#[derive(Debug, Clone)] 244pub struct EndpointData { 245 pub senders: PidQueue, 246 pub receivers: PidQueue, 247 pub holder: Option<Pid>, 248} 249 250impl EndpointData { 251 pub const fn new() -> Self { 252 Self { 253 senders: PidQueue::new(), 254 receivers: PidQueue::new(), 255 holder: None, 256 } 257 } 258} 259 260#[derive(Debug, Clone)] 261pub struct NotificationData { 262 pub word: u64, 263 pub waiters: StaticVec<Pid, MAX_NOTIFICATION_WAITERS>, 264} 265 266impl NotificationData { 267 pub const fn new() -> Self { 268 Self { 269 word: 0, 270 waiters: StaticVec::new(), 271 } 272 } 273} 274 275#[derive(Debug, Clone, Copy)] 276pub struct ProcessObjectData { 277 pub pid: Pid, 278} 279 280#[allow(dead_code)] 281#[derive(Debug, Clone, Copy)] 282pub struct SchedContextData { 283 pub budget_us: u64, 284 pub period_us: u64, 285 pub remaining_us: u64, 286 pub priority: Priority, 287 pub replenish_at: Option<u64>, 288 pub attached_pid: Option<Pid>, 289} 290 291impl SchedContextData { 292 pub const fn new(budget_us: u64, period_us: u64, priority: Priority) -> Self { 293 Self { 294 budget_us, 295 period_us, 296 remaining_us: budget_us, 297 priority, 298 replenish_at: None, 299 attached_pid: None, 300 } 301 } 302} 303 304#[derive(Debug, Clone, Copy, PartialEq, Eq)] 305pub struct IoPort(u16); 306 307impl IoPort { 308 pub const fn new(port: u16) -> Self { 309 Self(port) 310 } 311 312 pub(crate) const fn raw(self) -> u16 { 313 self.0 314 } 315} 316 317impl core::fmt::Display for IoPort { 318 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 319 write!(f, "{:#x}", self.0) 320 } 321} 322 323#[derive(Debug, Clone, Copy)] 324pub struct PortRange { 325 base: u16, 326 count: u16, 327} 328 329impl PortRange { 330 pub const fn new(base: u16, count: u16) -> Option<Self> { 331 if count == 0 { 332 return None; 333 } 334 let end = base as u32 + count as u32; 335 if end > 0x10000 { 336 return None; 337 } 338 Some(Self { base, count }) 339 } 340 341 pub const fn base(self) -> u16 { 342 self.base 343 } 344 345 pub const fn count(self) -> u16 { 346 self.count 347 } 348 349 pub fn contains(self, port: IoPort) -> bool { 350 (port.0 as u32) >= (self.base as u32) 351 && (port.0 as u32) < (self.base as u32) + (self.count as u32) 352 } 353} 354 355#[derive(Debug, Clone, Copy)] 356pub enum IrqSource { 357 Ioapic { 358 gsi: crate::arch::ioapic::Gsi, 359 }, 360 Msix { 361 device_table_idx: u8, 362 entry_idx: u16, 363 }, 364} 365 366#[allow(dead_code)] 367#[derive(Debug, Clone, Copy)] 368pub struct IrqHandlerData { 369 pub vector: crate::arch::idt::IrqVector, 370 pub source: IrqSource, 371 pub port_range: PortRange, 372} 373 374#[allow(dead_code)] 375#[derive(Debug, Clone, Copy)] 376pub struct FramebufferData { 377 phys_addr: u64, 378 width: u32, 379 height: u32, 380 pitch: u32, 381 bpp: u16, 382 byte_size: u64, 383} 384 385impl FramebufferData { 386 #[allow(dead_code)] 387 pub fn new( 388 phys_addr: u64, 389 width: u32, 390 height: u32, 391 pitch: u32, 392 bpp: u16, 393 byte_size: u64, 394 ) -> Option<Self> { 395 if width == 0 || height == 0 || bpp == 0 { 396 return None; 397 } 398 let bytes_per_pixel = (bpp as u32).checked_div(8)?; 399 let min_pitch = width.checked_mul(bytes_per_pixel)?; 400 if pitch < min_pitch { 401 return None; 402 } 403 let computed_size = (pitch as u64).checked_mul(height as u64)?; 404 if byte_size < computed_size { 405 return None; 406 } 407 Some(Self { 408 phys_addr, 409 width, 410 height, 411 pitch, 412 bpp, 413 byte_size, 414 }) 415 } 416 417 pub const fn phys_addr(&self) -> u64 { 418 self.phys_addr 419 } 420 #[allow(dead_code)] 421 pub const fn width(&self) -> u32 { 422 self.width 423 } 424 #[allow(dead_code)] 425 pub const fn height(&self) -> u32 { 426 self.height 427 } 428 #[allow(dead_code)] 429 pub const fn pitch(&self) -> u32 { 430 self.pitch 431 } 432 #[allow(dead_code)] 433 pub const fn bpp(&self) -> u16 { 434 self.bpp 435 } 436 pub const fn byte_size(&self) -> u64 { 437 self.byte_size 438 } 439} 440 441#[derive(Debug, Clone, Copy)] 442pub struct PciDeviceData { 443 pub device_table_idx: u8, 444} 445 446#[derive(Debug, Clone, Copy)] 447pub struct CNodeData { 448 pub slots_phys: x86_64::PhysAddr, 449 pub size_bits: u8, 450 pub frame_count: u8, 451} 452 453#[allow(dead_code)] 454#[derive(Debug)] 455pub struct UntypedObjectData { 456 pub phys_base: PhysAddr, 457 pub state: UntypedState, 458 pub first_child_id: Option<ObjectId>, 459} 460 461impl UntypedObjectData { 462 #[allow(dead_code)] 463 pub fn new(phys_base: PhysAddr, size_bits: u8, is_device: bool) -> Self { 464 Self { 465 phys_base, 466 state: UntypedState::new(size_bits, is_device), 467 first_child_id: None, 468 } 469 } 470} 471 472pub const MAX_FRAME_MAPPINGS: usize = 4; 473 474#[derive(Debug, Clone, Copy)] 475pub struct FrameMapping { 476 pub pid: Pid, 477 pub vaddr: x86_64::VirtAddr, 478} 479 480#[allow(dead_code)] 481#[derive(Debug)] 482pub struct FrameObjectData { 483 pub phys_addr: PhysAddr, 484 pub from_untyped: bool, 485 pub mappings: StaticVec<FrameMapping, MAX_FRAME_MAPPINGS>, 486} 487 488impl FrameObjectData { 489 #[allow(dead_code)] 490 pub fn new(phys_addr: PhysAddr) -> Self { 491 Self { 492 phys_addr, 493 from_untyped: false, 494 mappings: StaticVec::new(), 495 } 496 } 497 498 pub fn new_from_untyped(phys_addr: PhysAddr) -> Self { 499 Self { 500 phys_addr, 501 from_untyped: true, 502 mappings: StaticVec::new(), 503 } 504 } 505 506 pub fn add_mapping( 507 &mut self, 508 pid: Pid, 509 vaddr: x86_64::VirtAddr, 510 ) -> Result<(), crate::error::KernelError> { 511 self.mappings 512 .push(FrameMapping { pid, vaddr }) 513 .map_err(|_| crate::error::KernelError::ResourceExhausted) 514 } 515 516 pub fn remove_mapping(&mut self, pid: Pid, vaddr: x86_64::VirtAddr) -> bool { 517 let before = self.mappings.len(); 518 self.mappings 519 .retain(|m| !(m.pid == pid && m.vaddr == vaddr)); 520 self.mappings.len() < before 521 } 522 523 #[allow(dead_code)] 524 pub fn remove_all_for_pid(&mut self, pid: Pid) { 525 self.mappings.retain(|m| m.pid != pid); 526 } 527}