Nothing to see here, move along
at main 579 lines 17 kB view raw
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}