Nothing to see here, move along
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}