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