Nothing to see here, move along
1use crate::arch::gdt;
2use crate::cap::cnode;
3use crate::cap::object::{ObjectData, ObjectTag, ProcessObjectData};
4use crate::cap::ops;
5use crate::cap::pool::POOL;
6use crate::cap::table::Rights;
7use crate::error::KernelError;
8use crate::mem::phys::BitmapFrameAllocator;
9use crate::proc::context::CpuContext;
10use crate::proc::{PROCESSES, ProcessState};
11use crate::syscall::{SyscallResult, try_syscall, validate_user_vaddr};
12use crate::types::Pid;
13
14const USER_RFLAGS_MASK: u64 = 0x0000_0000_0000_0CD5;
15const USER_RFLAGS_FORCE: u64 = 0x202;
16
17pub fn sys_proc_create(ctx: &mut CpuContext) {
18 let dest_addr = ctx.rdi;
19 let pid = crate::arch::syscall::current_pid();
20
21 let mut allocator = BitmapFrameAllocator;
22 let mut ptable = PROCESSES.lock();
23
24 let created = match ptable.allocate(&mut allocator) {
25 Some(c) => c,
26 None => {
27 ctx.rax = SyscallResult::error(KernelError::PoolExhausted).raw();
28 return;
29 }
30 };
31 let child_pid = created.pid();
32
33 let child_cnode_size = crate::proc::ROOT_CNODE_SIZE_BITS;
34 let child_cnode = match cnode::create_cnode(child_cnode_size, &allocator) {
35 Ok(cd) => cd,
36 Err(e) => {
37 ptable.destroy(child_pid, &mut allocator);
38 ctx.rax = SyscallResult::error(e).raw();
39 return;
40 }
41 };
42 let child_frame_count = child_cnode.frame_count;
43
44 let data = ObjectData::Process(ProcessObjectData { pid: child_pid });
45
46 let (cnode_id, cnode_gen, depth) = match cnode::cnode_coords(pid, &ptable) {
47 Ok(c) => c,
48 Err(_) => {
49 cnode::destroy_cnode(&child_cnode, &allocator);
50 ptable.destroy(child_pid, &mut allocator);
51 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
52 return;
53 }
54 };
55
56 let mut pool = POOL.lock_after(&ptable);
57
58 let (child_cnode_id, child_cnode_gen) =
59 match pool.allocate(ObjectData::CNode(child_cnode)) {
60 Ok(pair) => pair,
61 Err(e) => {
62 drop(pool);
63 ptable.destroy(child_pid, &mut allocator);
64 ctx.rax = SyscallResult::error(e).raw();
65 return;
66 }
67 };
68
69 if let Some(child) = ptable.get_mut(child_pid) {
70 child.root_cnode = Some((child_cnode_id, child_cnode_gen));
71 child.cnode_depth = child_cnode_size;
72 if child.charge_frames(child_frame_count as u16).is_err() {
73 let _ = pool.free(child_cnode_id, child_cnode_gen);
74 drop(pool);
75 ptable.destroy(child_pid, &mut allocator);
76 ctx.rax = SyscallResult::error(KernelError::ResourceExhausted).raw();
77 return;
78 }
79 }
80
81 let result = ops::insert_object_cap_via_cnode(
82 &mut pool,
83 cnode_id,
84 cnode_gen,
85 dest_addr,
86 depth,
87 data,
88 Rights::ALL,
89 );
90
91 ctx.rax = match result {
92 Ok(_) => SyscallResult::success(child_pid.raw() as u64).raw(),
93 Err(e) => {
94 drop(pool);
95 ptable.destroy(child_pid, &mut allocator);
96 SyscallResult::error(e).raw()
97 }
98 };
99}
100
101pub fn sys_proc_set_regs(ctx: &mut CpuContext) {
102 let proc_cap_addr = ctx.rdi;
103 let rip = ctx.rsi;
104 let rsp = ctx.rdx;
105 let rflags = ctx.r10;
106 let pid = crate::arch::syscall::current_pid();
107
108 try_syscall!(ctx, validate_user_vaddr(rip));
109 try_syscall!(ctx, validate_user_vaddr(rsp));
110 if !rsp.is_multiple_of(16) {
111 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
112 return;
113 }
114
115 let mut ptable = PROCESSES.lock();
116
117 let proc_cap = {
118 let pool = POOL.lock_after(&ptable);
119 try_syscall!(
120 ctx,
121 cnode::resolve_caller_validate(
122 pid,
123 proc_cap_addr,
124 ObjectTag::Process,
125 Rights::WRITE,
126 &ptable,
127 &pool,
128 )
129 )
130 };
131
132 let child_pid = try_syscall!(
133 ctx,
134 ops::resolve_process_cap(&proc_cap, &POOL.lock_after(&ptable))
135 );
136
137 let child = match ptable.get_mut(child_pid) {
138 Some(c) => c,
139 None => {
140 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
141 return;
142 }
143 };
144
145 match child.state() {
146 ProcessState::Created => {}
147 _ => {
148 ctx.rax = SyscallResult::error(KernelError::BadState).raw();
149 return;
150 }
151 }
152
153 let sels = gdt::selectors();
154 child.saved_context.rip = rip;
155 child.saved_context.rsp = rsp;
156 child.saved_context.rflags = (rflags & USER_RFLAGS_MASK) | USER_RFLAGS_FORCE;
157 child.saved_context.cs = sels.user_code.0 as u64;
158 child.saved_context.ss = sels.user_data.0 as u64;
159 child.seal_context();
160
161 ctx.rax = SyscallResult::ok().raw();
162}
163
164pub fn sys_proc_start(ctx: &mut CpuContext) {
165 let proc_cap_addr = ctx.rdi;
166 let bootstrap = ctx.rsi;
167 let pid = crate::arch::syscall::current_pid();
168
169 let mut ptable = PROCESSES.lock();
170
171 let proc_cap = {
172 let pool = POOL.lock_after(&ptable);
173 try_syscall!(
174 ctx,
175 cnode::resolve_caller_validate(
176 pid,
177 proc_cap_addr,
178 ObjectTag::Process,
179 Rights::WRITE,
180 &ptable,
181 &pool,
182 )
183 )
184 };
185
186 let child_pid = try_syscall!(
187 ctx,
188 ops::resolve_process_cap(&proc_cap, &POOL.lock_after(&ptable))
189 );
190
191 match ptable.get_mut(child_pid) {
192 Some(child) => {
193 child.saved_context.rdi = bootstrap;
194 child.seal_context();
195 }
196 None => {
197 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
198 return;
199 }
200 }
201
202 ctx.rax = match ptable.as_created(child_pid) {
203 Some(created) => match ptable.start(created) {
204 Ok(()) => SyscallResult::ok().raw(),
205 Err(e) => SyscallResult::error(e).raw(),
206 },
207 None => SyscallResult::error(KernelError::BadState).raw(),
208 };
209}
210
211pub fn sys_proc_destroy(ctx: &mut CpuContext) {
212 let proc_cap_addr = ctx.rdi;
213 let pid = crate::arch::syscall::current_pid();
214
215 let mut ptable = PROCESSES.lock();
216
217 let proc_cap = {
218 let pool = POOL.lock_after(&ptable);
219 try_syscall!(
220 ctx,
221 cnode::resolve_caller_validate(
222 pid,
223 proc_cap_addr,
224 ObjectTag::Process,
225 Rights::REVOKE,
226 &ptable,
227 &pool,
228 )
229 )
230 };
231
232 let child_pid = match ops::resolve_process_cap(&proc_cap, &POOL.lock_after(&ptable)) {
233 Ok(cp) => cp,
234 Err(KernelError::StaleGeneration) => {
235 let pool = POOL.lock_after(&ptable);
236 let _ = cnode::resolve_caller_clear(pid, proc_cap_addr, &ptable, &pool);
237 ctx.rax = SyscallResult::ok().raw();
238 return;
239 }
240 Err(e) => {
241 ctx.rax = SyscallResult::error(e).raw();
242 return;
243 }
244 };
245
246 if child_pid == pid || child_pid.raw() == 0 {
247 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
248 return;
249 }
250
251 let mut allocator = BitmapFrameAllocator;
252 if ptable.destroy(child_pid, &mut allocator) {
253 POOL.lock_after(&ptable)
254 .dec_ref(proc_cap.object_id(), proc_cap.generation());
255 {
256 let pool = POOL.lock_after(&ptable);
257 let _ = cnode::resolve_caller_clear(pid, proc_cap_addr, &ptable, &pool);
258 }
259
260 ctx.rax = SyscallResult::ok().raw();
261 } else {
262 ctx.rax = SyscallResult::error(KernelError::BadState).raw();
263 }
264}
265
266pub fn sys_proc_bind_death_notif(ctx: &mut CpuContext) {
267 let proc_cap_addr = ctx.rdi;
268 let notif_cap_addr = ctx.rsi;
269 let bits = ctx.rdx;
270 let pid = crate::arch::syscall::current_pid();
271
272 let mut ptable = PROCESSES.lock();
273
274 let (proc_cap, notif_cap) = {
275 let pool = POOL.lock_after(&ptable);
276 let pc = try_syscall!(
277 ctx,
278 cnode::resolve_caller_validate(
279 pid,
280 proc_cap_addr,
281 ObjectTag::Process,
282 Rights::WRITE,
283 &ptable,
284 &pool,
285 )
286 );
287 let nc = try_syscall!(
288 ctx,
289 cnode::resolve_caller_validate(
290 pid,
291 notif_cap_addr,
292 ObjectTag::Notification,
293 Rights::WRITE,
294 &ptable,
295 &pool,
296 )
297 );
298 (pc, nc)
299 };
300
301 let child_pid = try_syscall!(
302 ctx,
303 ops::resolve_process_cap(&proc_cap, &POOL.lock_after(&ptable))
304 );
305 let notif_id = notif_cap.object_id();
306 let notif_gen = notif_cap.generation();
307
308 match ptable.get_mut(child_pid) {
309 Some(child) => {
310 child.set_death_notification(notif_id, notif_gen, bits);
311 ctx.rax = SyscallResult::ok().raw();
312 }
313 None => {
314 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
315 }
316 }
317}
318
319pub fn sys_thread_create(ctx: &mut CpuContext) {
320 let dest_addr = ctx.rdi;
321 let entry_point = try_syscall!(ctx, validate_user_vaddr(ctx.rsi));
322 let user_stack_ptr = try_syscall!(ctx, validate_user_vaddr(ctx.rdx));
323 let arg = ctx.r10;
324
325 if !user_stack_ptr.as_u64().is_multiple_of(16) {
326 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
327 return;
328 }
329
330 let caller_pid = crate::arch::syscall::current_pid();
331 let mut allocator = BitmapFrameAllocator;
332 let mut ptable = PROCESSES.lock();
333
334 match ptable.get(caller_pid) {
335 Some(_) => {}
336 None => {
337 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
338 return;
339 }
340 }
341
342 let created = match ptable.allocate_thread(caller_pid, &mut allocator) {
343 Some(c) => c,
344 None => {
345 ctx.rax = SyscallResult::error(KernelError::PoolExhausted).raw();
346 return;
347 }
348 };
349 let child_pid = created.pid();
350
351 let sels = gdt::selectors();
352 match ptable.get_mut(child_pid) {
353 Some(child) => {
354 child.saved_context.rip = entry_point.as_u64();
355 child.saved_context.rsp = user_stack_ptr.as_u64();
356 child.saved_context.rdi = arg;
357 child.saved_context.rflags = USER_RFLAGS_FORCE;
358 child.saved_context.cs = sels.user_code.0 as u64;
359 child.saved_context.ss = sels.user_data.0 as u64;
360 child.seal_context();
361 }
362 None => {
363 ptable.destroy(child_pid, &mut allocator);
364 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
365 return;
366 }
367 }
368
369 let data = ObjectData::Process(ProcessObjectData { pid: child_pid });
370
371 let (cnode_id, cnode_gen, depth) = match cnode::cnode_coords(caller_pid, &ptable) {
372 Ok(c) => c,
373 Err(_) => {
374 ptable.destroy(child_pid, &mut allocator);
375 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
376 return;
377 }
378 };
379
380 let mut pool = POOL.lock_after(&ptable);
381
382 if pool.inc_ref(cnode_id, cnode_gen).is_err() {
383 drop(pool);
384 ptable.destroy(child_pid, &mut allocator);
385 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
386 return;
387 }
388
389 let result = ops::insert_object_cap_via_cnode(
390 &mut pool,
391 cnode_id,
392 cnode_gen,
393 dest_addr,
394 depth,
395 data,
396 Rights::ALL,
397 );
398
399 ctx.rax = match result {
400 Ok(_) => SyscallResult::success(child_pid.raw() as u64).raw(),
401 Err(e) => {
402 drop(pool);
403 ptable.destroy(child_pid, &mut allocator);
404 SyscallResult::error(e).raw()
405 }
406 };
407}
408
409pub fn sys_set_fsbase(ctx: &mut CpuContext) {
410 let fs_base = ctx.rdi;
411
412 let sign_bit = (fs_base >> 47) & 1;
413 let upper_bits = fs_base >> 48;
414 let canonical = match sign_bit {
415 0 => upper_bits == 0,
416 _ => upper_bits == 0xFFFF,
417 };
418 if !canonical {
419 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw();
420 return;
421 }
422
423 let caller_pid = crate::arch::syscall::current_pid();
424 let mut ptable = PROCESSES.lock();
425
426 match ptable.get_mut(caller_pid) {
427 Some(proc) => {
428 proc.fs_base = fs_base;
429 crate::sched::switch::write_fs_base(fs_base);
430 ctx.rax = SyscallResult::ok().raw();
431 }
432 None => {
433 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
434 }
435 }
436}
437
438pub fn sys_proc_load_module(ctx: &mut CpuContext) {
439 let proc_cap_addr = ctx.rdi;
440 let module_index = ctx.rsi;
441 let pid = crate::arch::syscall::current_pid();
442
443 let modules = match crate::arch::boot::modules() {
444 Some(m) => m,
445 None => {
446 ctx.rax = SyscallResult::error(KernelError::NotFound).raw();
447 return;
448 }
449 };
450
451 if module_index >= modules.len() as u64 {
452 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
453 return;
454 }
455 let idx = module_index as usize;
456
457 let child_pid: Pid = {
458 let ptable = PROCESSES.lock();
459 let pool = POOL.lock_after(&ptable);
460
461 let proc_cap = try_syscall!(
462 ctx,
463 cnode::resolve_caller_validate(
464 pid,
465 proc_cap_addr,
466 ObjectTag::Process,
467 Rights::WRITE,
468 &ptable,
469 &pool,
470 )
471 );
472
473 let child = try_syscall!(ctx, ops::resolve_process_cap(&proc_cap, &pool));
474
475 match ptable.get(child) {
476 Some(c) => match c.state() {
477 ProcessState::Created => {}
478 _ => {
479 ctx.rax = SyscallResult::error(KernelError::BadState).raw();
480 return;
481 }
482 },
483 None => {
484 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
485 return;
486 }
487 }
488
489 child
490 };
491
492 let file = modules[idx];
493 let data = unsafe { core::slice::from_raw_parts(file.addr(), file.size() as usize) };
494 let mut allocator = BitmapFrameAllocator;
495
496 ctx.rax = match crate::proc::loader::spawn_module(child_pid, data, &mut allocator) {
497 Ok(()) => {
498 let path_bytes = file.path().to_bytes();
499 let filename = {
500 let last_slash = (0..path_bytes.len()).rev().find(|&i| path_bytes[i] == b'/');
501 match last_slash {
502 Some(pos) => &path_bytes[pos + 1..],
503 None => path_bytes,
504 }
505 };
506 let mut ptable = PROCESSES.lock();
507 if let Some(child) = ptable.get_mut(child_pid) {
508 child.set_name(filename);
509 }
510 SyscallResult::ok().raw()
511 }
512 Err(e) => SyscallResult::error(e).raw(),
513 };
514}