Nothing to see here, move along
1pub mod address_space;
2#[cfg(not(lancer_test))]
3pub mod bootstrap;
4pub mod context;
5pub mod elf;
6pub mod loader;
7pub mod manager;
8pub mod pid_table;
9
10use crate::mem::typed_addr::Pml4Phys;
11use crate::ring::RingIndex;
12use crate::types::{BlockedPid, Generation, ObjPhys, Pid, Priority};
13
14pub(crate) const ROOT_CNODE_SIZE_BITS: u8 = 10;
15use context::{CpuContext, FpuState, IpcMessage};
16
17pub use lancer_core::process_state::ProcessState;
18pub use manager::{PROCESSES, ProcessManager};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum BlockedReason {
22 Sending(ObjPhys, Generation),
23 Receiving(ObjPhys, Generation),
24 Calling(ObjPhys, Generation),
25 WaitingNotification(ObjPhys, Generation),
26}
27
28pub(crate) const PROC_NAME_LEN: usize = 32;
29
30#[repr(C, align(64))]
31pub struct SchedEntity {
32 pub(crate) pid: Pid,
33 pub(crate) generation: Generation,
34 pub(crate) state: ProcessState,
35 pub(crate) priority: Priority,
36 pub(crate) effective_priority: Priority,
37 pub(crate) sched_context: Option<(ObjPhys, Generation)>,
38 pub(crate) next_ipc: Option<Pid>,
39 pub(crate) blocked_reason: Option<BlockedReason>,
40 pub(crate) run_cpu: Option<u16>,
41 pub(crate) death_notification: Option<(ObjPhys, Generation, u64)>,
42 pub(crate) bound_notification: Option<(ObjPhys, Generation)>,
43 pub(crate) exec_phys: u64,
44 pub(crate) next_free: u32,
45 pub(crate) run_prev: u32,
46 pub(crate) run_next: u32,
47 pub(crate) run_priority: u8,
48 pub(crate) timer_prev: u32,
49 pub(crate) timer_next: u32,
50 pub(crate) timer_slot: u16,
51 pub(crate) timer_deadline: u64,
52}
53
54#[repr(C, align(64))]
55pub struct ExecContext {
56 pub(crate) saved_context: CpuContext,
57 pub(crate) fpu_state: FpuState,
58 pub(crate) pml4_phys: Pml4Phys,
59 pub(crate) fs_base: u64,
60 pub(crate) context_checksum: u64,
61 pub(crate) ipc_message: IpcMessage,
62 pub(crate) ipc_badge: u64,
63 pub(crate) reply_target: Option<Pid>,
64 pub(crate) ring_region_id: Option<(ObjPhys, Generation)>,
65 pub(crate) ring_sq_head: RingIndex,
66 pub(crate) ring_cq_tail: RingIndex,
67 pub(crate) allocated_frames: u16,
68 pub(crate) name: [u8; PROC_NAME_LEN],
69 pub(crate) name_len: u8,
70 pub(crate) root_cnode: Option<(ObjPhys, Generation)>,
71 pub(crate) cnode_depth: u8,
72 pub(crate) root_guard_value: u64,
73 pub(crate) root_guard_bits: u8,
74 pub(crate) from_untyped: bool,
75}
76
77pub const MAX_FRAMES_PER_PROCESS: u16 = 16384;
78
79const _: () = assert!(core::mem::size_of::<SchedEntity>() <= 256);
80const _: () = assert!(core::mem::size_of::<ExecContext>() <= 1536);
81
82use lancer_core::header::NONE_SENTINEL;
83
84impl SchedEntity {
85 pub const EMPTY: Self = Self {
86 pid: Pid::new(0),
87 generation: Generation::new(0),
88 state: ProcessState::Free,
89 priority: Priority::IDLE,
90 effective_priority: Priority::IDLE,
91 sched_context: None,
92 next_ipc: None,
93 blocked_reason: None,
94 run_cpu: None,
95 death_notification: None,
96 bound_notification: None,
97 exec_phys: 0,
98 next_free: NONE_SENTINEL,
99 run_prev: NONE_SENTINEL,
100 run_next: NONE_SENTINEL,
101 run_priority: 0,
102 timer_prev: NONE_SENTINEL,
103 timer_next: NONE_SENTINEL,
104 timer_slot: 0,
105 timer_deadline: 0,
106 };
107
108 pub fn state(&self) -> ProcessState {
109 self.state
110 }
111
112 pub fn transition_to(&mut self, to: ProcessState) -> Result<(), crate::error::KernelError> {
113 match to {
114 ProcessState::Dead => Err(crate::error::KernelError::BadState),
115 _ => self.state.transition(to),
116 }
117 }
118
119 pub fn zombify_state(&mut self) -> Result<(), crate::error::KernelError> {
120 self.state.transition(ProcessState::Zombie)
121 }
122
123 pub fn is_runnable(&self) -> bool {
124 matches!(self.state, ProcessState::Ready | ProcessState::Running)
125 }
126
127 pub fn blocked_reason(&self) -> Option<BlockedReason> {
128 self.blocked_reason
129 }
130
131 pub fn blocked_proof(&self) -> BlockedPid {
132 assert!(
133 self.state == ProcessState::Blocked,
134 "blocked_proof called on non-blocked process (pid={}, state={:?})",
135 self.pid.raw(),
136 self.state
137 );
138 BlockedPid::from_blocked(self.pid, self.generation)
139 }
140
141 pub fn block_on(
142 &mut self,
143 reason: BlockedReason,
144 ) -> Result<BlockedPid, crate::error::KernelError> {
145 self.state.transition(ProcessState::Blocked)?;
146 self.blocked_reason = Some(reason);
147 Ok(BlockedPid::from_blocked(self.pid, self.generation))
148 }
149
150 pub fn unblock(&mut self, _proof: BlockedPid) -> Result<(), crate::error::KernelError> {
151 self.state.transition(ProcessState::Ready)?;
152 self.blocked_reason = None;
153 Ok(())
154 }
155
156 pub fn effective_priority(&self) -> Priority {
157 self.effective_priority
158 }
159
160 pub fn boost_effective_priority(&mut self, donor: Priority) {
161 if donor > self.effective_priority {
162 self.effective_priority = donor;
163 }
164 }
165
166 pub fn reset_effective_priority(&mut self) {
167 self.effective_priority = self.priority;
168 }
169
170 pub fn sched_context(&self) -> Option<(ObjPhys, Generation)> {
171 self.sched_context
172 }
173
174 pub fn attach_sched_context(
175 &mut self,
176 id: ObjPhys,
177 generation: Generation,
178 priority: Priority,
179 ) {
180 self.sched_context = Some((id, generation));
181 self.priority = priority;
182 self.effective_priority = priority;
183 }
184
185 pub fn detach_sched_context(&mut self) {
186 self.sched_context = None;
187 }
188
189 pub fn death_notification(&self) -> Option<(ObjPhys, Generation, u64)> {
190 self.death_notification
191 }
192
193 pub fn set_death_notification(
194 &mut self,
195 notif_id: ObjPhys,
196 generation: Generation,
197 bits: u64,
198 ) {
199 self.death_notification = Some((notif_id, generation, bits));
200 }
201
202 pub fn bound_notification(&self) -> Option<(ObjPhys, Generation)> {
203 self.bound_notification
204 }
205
206 pub fn bind_notification(&mut self, notif_id: ObjPhys, generation: Generation) {
207 self.bound_notification = Some((notif_id, generation));
208 }
209
210 pub fn unbind_notification(&mut self) {
211 self.bound_notification = None;
212 }
213}
214
215impl ExecContext {
216 pub fn seal_context(&mut self) {
217 self.context_checksum = self.saved_context.checksum();
218 }
219
220 pub fn verify_context(&self, pid: Pid) {
221 let computed = self.saved_context.checksum();
222 assert!(
223 self.context_checksum == computed,
224 "context checksum mismatch for pid {} (stored={:#x}, computed={:#x})",
225 pid.raw(),
226 self.context_checksum,
227 computed
228 );
229 }
230
231 pub fn set_name(&mut self, src: &[u8]) {
232 let copy_len = src.len().min(PROC_NAME_LEN);
233 self.name[..copy_len].copy_from_slice(&src[..copy_len]);
234 (copy_len..PROC_NAME_LEN).for_each(|i| self.name[i] = 0);
235 self.name_len = copy_len as u8;
236 }
237
238 pub fn name_str(&self) -> &str {
239 let len = self.name_len as usize;
240 match len {
241 0 => "?",
242 _ => core::str::from_utf8(&self.name[..len]).unwrap_or("?"),
243 }
244 }
245
246 pub fn charge_frames(&mut self, count: u16) -> Result<(), crate::error::KernelError> {
247 let new_total = self
248 .allocated_frames
249 .checked_add(count)
250 .filter(|&t| t <= MAX_FRAMES_PER_PROCESS)
251 .ok_or(crate::error::KernelError::ResourceExhausted)?;
252 self.allocated_frames = new_total;
253 Ok(())
254 }
255
256 pub fn root_cnode(&self) -> Option<(ObjPhys, Generation)> {
257 self.root_cnode
258 }
259
260 pub fn cnode_depth(&self) -> u8 {
261 self.cnode_depth
262 }
263
264 pub fn root_guard_value(&self) -> u64 {
265 self.root_guard_value
266 }
267
268 pub fn root_guard_bits(&self) -> u8 {
269 self.root_guard_bits
270 }
271}
272
273#[cfg(lancer_test)]
274pub fn report_refcount_audit() {
275 let ptable = PROCESSES.lock();
276 let cap = ptable.capacity();
277 let (total, violations) = (0..cap as u32)
278 .filter_map(crate::types::Pid::try_new)
279 .filter_map(|pid| ptable.exec(pid).map(|e| e.pml4_phys.raw()))
280 .fold((0usize, 0usize), |(t, v), pml4| {
281 let (pt, pv) = address_space::audit_user_pages(pml4);
282 (t + pt, v + pv)
283 });
284 crate::klog!(
285 "test",
286 "refcount audit {} PTEs checked, {} violations",
287 total,
288 violations
289 );
290}