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