Nothing to see here, move along
at main 431 lines 13 kB view raw
1use crate::cap::cnode; 2use crate::cap::object::ObjectTag; 3use crate::cap::pool::POOL; 4use crate::cap::table::{CapRef, CapSlot, Rights}; 5use crate::error::KernelError; 6use crate::mem::phys::BitmapFrameAllocator; 7use crate::proc::PROCESSES; 8use crate::proc::context::CpuContext; 9use crate::syscall::{SyscallResult, try_syscall}; 10use lancer_core::header::KernelObjectHeader; 11use lancer_core::object_layout::{CNodeObject, KernelObject}; 12 13pub fn sys_cnode_create(ctx: &mut CpuContext) { 14 let size_bits = try_syscall!(ctx, super::u8_from_reg(ctx.rdi)); 15 let dest_addr = ctx.rsi; 16 let pid = crate::arch::syscall::current_pid(); 17 18 if !(cnode::MIN_CNODE_BITS..=cnode::MAX_CNODE_BITS).contains(&size_bits) { 19 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 20 return; 21 } 22 23 let allocator = &BitmapFrameAllocator; 24 let cnode_data = match cnode::create_cnode(size_bits, allocator) { 25 Ok(cd) => cd, 26 Err(e) => { 27 ctx.rax = SyscallResult::error(e).raw(); 28 return; 29 } 30 }; 31 let frame_count = cnode_data.frame_count; 32 33 let obj_phys = match crate::cap::kernel_objects::alloc_slot() { 34 Some(p) => p, 35 None => { 36 cnode::destroy_cnode(&cnode_data, allocator); 37 ctx.rax = SyscallResult::error(KernelError::PoolExhausted).raw(); 38 return; 39 } 40 }; 41 42 let header = KernelObjectHeader::new(ObjectTag::CNode, 0, 64); 43 let mut obj = CNodeObject::init_default(header); 44 obj.slots_phys = cnode_data.slots_phys.as_u64(); 45 obj.size_bits = cnode_data.size_bits; 46 obj.frame_count = cnode_data.frame_count; 47 crate::cap::kernel_objects::write_at(obj_phys, obj); 48 49 let mut ptable = PROCESSES.lock(); 50 let mut pool = POOL.lock_after(&ptable); 51 52 let (cnode_id, cnode_gen) = match pool.register_object(obj_phys, ObjectTag::CNode) { 53 Ok(pair) => pair, 54 Err(e) => { 55 crate::cap::kernel_objects::free_slot(obj_phys); 56 cnode::destroy_cnode(&cnode_data, allocator); 57 ctx.rax = SyscallResult::error(e).raw(); 58 return; 59 } 60 }; 61 62 let cap = CapRef::new(ObjectTag::CNode, cnode_id, Rights::ALL, cnode_gen); 63 64 let (caller_cnode_id, caller_cnode_gen, depth, guard_value, guard_bits) = 65 match cnode::cnode_coords(pid, &ptable) { 66 Ok(c) => c, 67 Err(e) => { 68 let _ = pool.free_phys(cnode_id, cnode_gen); 69 ctx.rax = SyscallResult::error(e).raw(); 70 return; 71 } 72 }; 73 74 if let Err(e) = cnode::resolve_and_insert( 75 &pool, 76 caller_cnode_id, 77 caller_cnode_gen, 78 dest_addr, 79 depth, 80 guard_value, 81 guard_bits, 82 cap, 83 ) { 84 let _ = pool.free_phys(cnode_id, cnode_gen); 85 ctx.rax = SyscallResult::error(e).raw(); 86 return; 87 } 88 89 match ptable.exec_mut(pid) { 90 Some(exec) => { 91 if let Err(e) = exec.charge_frames(frame_count as u16) { 92 let _ = cnode::resolve_and_clear( 93 &pool, 94 caller_cnode_id, 95 caller_cnode_gen, 96 dest_addr, 97 depth, 98 guard_value, 99 guard_bits, 100 ); 101 let _ = pool.free_phys(cnode_id, cnode_gen); 102 ctx.rax = SyscallResult::error(e).raw(); 103 return; 104 } 105 } 106 None => { 107 let _ = cnode::resolve_and_clear( 108 &pool, 109 caller_cnode_id, 110 caller_cnode_gen, 111 dest_addr, 112 depth, 113 guard_value, 114 guard_bits, 115 ); 116 let _ = pool.free_phys(cnode_id, cnode_gen); 117 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 118 return; 119 } 120 } 121 122 ctx.rax = SyscallResult::ok().raw(); 123} 124 125pub fn sys_cnode_copy(ctx: &mut CpuContext) { 126 let src_addr = ctx.rdi; 127 let dest_addr = ctx.rsi; 128 let rights_raw = try_syscall!(ctx, super::u16_from_reg(ctx.rdx)); 129 let rights_mask = Rights::from_bits(rights_raw); 130 let pid = crate::arch::syscall::current_pid(); 131 132 let ptable = PROCESSES.lock(); 133 let (cnode_id, cnode_gen, depth, guard_value, guard_bits) = 134 try_syscall!(ctx, cnode::cnode_coords(pid, &ptable)); 135 let mut pool = POOL.lock_after(&ptable); 136 137 let src_cap = match cnode::resolve_and_read( 138 &pool, 139 cnode_id, 140 cnode_gen, 141 src_addr, 142 depth, 143 guard_value, 144 guard_bits, 145 ) { 146 Ok(cap) => cap, 147 Err(e) => { 148 ctx.rax = SyscallResult::error(e).raw(); 149 return; 150 } 151 }; 152 153 if let Err(e) = pool.inc_ref(src_cap.phys(), src_cap.generation()) { 154 ctx.rax = SyscallResult::error(e).raw(); 155 return; 156 } 157 158 let copied = src_cap.with_rights(src_cap.rights() & rights_mask); 159 160 ctx.rax = match cnode::resolve_and_insert( 161 &pool, 162 cnode_id, 163 cnode_gen, 164 dest_addr, 165 depth, 166 guard_value, 167 guard_bits, 168 copied, 169 ) { 170 Ok(()) => SyscallResult::ok().raw(), 171 Err(e) => { 172 pool.dec_ref_phys(src_cap.phys(), src_cap.generation()); 173 SyscallResult::error(e).raw() 174 } 175 }; 176} 177 178pub fn sys_cnode_delete(ctx: &mut CpuContext) { 179 let address = ctx.rdi; 180 let pid = crate::arch::syscall::current_pid(); 181 182 let mut ptable = PROCESSES.lock(); 183 let (cnode_id, cnode_gen, depth, guard_value, guard_bits) = 184 try_syscall!(ctx, cnode::cnode_coords(pid, &ptable)); 185 let mut pool = POOL.lock_after(&ptable); 186 187 let cap = match cnode::resolve_and_clear( 188 &pool, 189 cnode_id, 190 cnode_gen, 191 address, 192 depth, 193 guard_value, 194 guard_bits, 195 ) { 196 Ok(cap) => cap, 197 Err(e) => { 198 ctx.rax = SyscallResult::error(e).raw(); 199 return; 200 } 201 }; 202 203 let freed_phys = cap.phys(); 204 match pool.dec_ref_phys(cap.phys(), cap.generation()) { 205 Some((phys, lancer_core::object_tag::ObjectTag::CNode)) => { 206 crate::cap::derivation::unlink_child(&mut pool, freed_phys); 207 let obj = unsafe { 208 &*(crate::mem::addr::phys_to_virt(x86_64::PhysAddr::new(phys)) 209 .as_ptr::<CNodeObject>()) 210 }; 211 cnode::drain_cnode_phys( 212 x86_64::PhysAddr::new(obj.slots_phys), 213 obj.size_bits, 214 obj.frame_count, 215 &mut pool, 216 &mut ptable, 217 ); 218 } 219 Some((phys, tag)) => { 220 crate::cap::derivation::unlink_child(&mut pool, freed_phys); 221 crate::cap::ops::cleanup_by_tag_with_ptable(tag, phys, &mut ptable); 222 } 223 None => {} 224 } 225 226 ctx.rax = SyscallResult::ok().raw(); 227} 228 229#[allow(clippy::too_many_arguments)] 230pub fn sys_cnode_mint(ctx: &mut CpuContext) { 231 let src_addr = ctx.rdi; 232 let dest_addr = ctx.rsi; 233 let rights_raw = try_syscall!(ctx, super::u16_from_reg(ctx.rdx)); 234 let rights_mask = Rights::from_bits(rights_raw); 235 let new_guard_value = ctx.r10; 236 let new_guard_bits = try_syscall!(ctx, super::u8_from_reg(ctx.r8)); 237 let pid = crate::arch::syscall::current_pid(); 238 239 if new_guard_bits > 64 { 240 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 241 return; 242 } 243 match new_guard_bits { 244 64 => {} 245 b => { 246 if new_guard_value >= (1u64 << b) { 247 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 248 return; 249 } 250 } 251 } 252 253 let ptable = PROCESSES.lock(); 254 let (cnode_id, cnode_gen, depth, gv, gb) = try_syscall!(ctx, cnode::cnode_coords(pid, &ptable)); 255 let mut pool = POOL.lock_after(&ptable); 256 257 let src_cap = match cnode::resolve_and_read(&pool, cnode_id, cnode_gen, src_addr, depth, gv, gb) 258 { 259 Ok(cap) => cap, 260 Err(e) => { 261 ctx.rax = SyscallResult::error(e).raw(); 262 return; 263 } 264 }; 265 266 if new_guard_bits > 0 && src_cap.tag() != ObjectTag::CNode { 267 ctx.rax = SyscallResult::error(KernelError::InvalidType).raw(); 268 return; 269 } 270 271 if src_cap.tag() == ObjectTag::CNode { 272 let cnode_obj = match pool.read_as::<CNodeObject>(src_cap.phys(), src_cap.generation()) 273 { 274 Ok(c) => c, 275 Err(e) => { 276 ctx.rax = SyscallResult::error(e).raw(); 277 return; 278 } 279 }; 280 let total = (new_guard_bits as u16) + (cnode_obj.size_bits as u16); 281 if total > 64 { 282 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 283 return; 284 } 285 } 286 287 if let Err(e) = pool.inc_ref(src_cap.phys(), src_cap.generation()) { 288 ctx.rax = SyscallResult::error(e).raw(); 289 return; 290 } 291 292 let minted = src_cap 293 .with_rights(src_cap.rights() & rights_mask) 294 .with_guard(new_guard_value, new_guard_bits); 295 296 ctx.rax = match cnode::resolve_and_insert( 297 &pool, cnode_id, cnode_gen, dest_addr, depth, gv, gb, minted, 298 ) { 299 Ok(()) => SyscallResult::ok().raw(), 300 Err(e) => { 301 pool.dec_ref_phys(src_cap.phys(), src_cap.generation()); 302 SyscallResult::error(e).raw() 303 } 304 }; 305} 306 307pub fn sys_cnode_copy_to(ctx: &mut CpuContext) { 308 let src_addr = ctx.rdi; 309 let dest_cnode_addr = ctx.rsi; 310 let dest_index = ctx.rdx; 311 let rights_raw = try_syscall!(ctx, super::u16_from_reg(ctx.r10)); 312 let rights_mask = Rights::from_bits(rights_raw); 313 let pid = crate::arch::syscall::current_pid(); 314 315 let ptable = PROCESSES.lock(); 316 let (cnode_id, cnode_gen, depth, gv, gb) = try_syscall!(ctx, cnode::cnode_coords(pid, &ptable)); 317 let mut pool = POOL.lock_after(&ptable); 318 319 let src_cap = match cnode::resolve_and_read(&pool, cnode_id, cnode_gen, src_addr, depth, gv, gb) 320 { 321 Ok(cap) => cap, 322 Err(e) => { 323 ctx.rax = SyscallResult::error(e).raw(); 324 return; 325 } 326 }; 327 328 let dest_cnode_cap = match cnode::resolve_and_validate( 329 &pool, 330 cnode_id, 331 cnode_gen, 332 dest_cnode_addr, 333 depth, 334 gv, 335 gb, 336 ObjectTag::CNode, 337 Rights::ALL, 338 ) { 339 Ok(cap) => cap, 340 Err(e) => { 341 ctx.rax = SyscallResult::error(e).raw(); 342 return; 343 } 344 }; 345 346 let dest_cnode_obj = match pool 347 .read_as::<CNodeObject>(dest_cnode_cap.phys(), dest_cnode_cap.generation()) 348 { 349 Ok(c) => c, 350 Err(e) => { 351 ctx.rax = SyscallResult::error(e).raw(); 352 return; 353 } 354 }; 355 356 let slot_count = 1u64 << dest_cnode_obj.size_bits; 357 if dest_index >= slot_count { 358 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 359 return; 360 } 361 362 let slots_phys = x86_64::PhysAddr::new(dest_cnode_obj.slots_phys); 363 let slot_ptr = unsafe { 364 let base = crate::mem::addr::phys_to_virt(slots_phys).as_mut_ptr::<CapSlot>(); 365 &mut *base.add(dest_index as usize) 366 }; 367 368 match slot_ptr { 369 CapSlot::Active(_) => { 370 ctx.rax = SyscallResult::error(KernelError::SlotOccupied).raw(); 371 return; 372 } 373 CapSlot::Empty => {} 374 } 375 376 if let Err(e) = pool.inc_ref(src_cap.phys(), src_cap.generation()) { 377 ctx.rax = SyscallResult::error(e).raw(); 378 return; 379 } 380 381 *slot_ptr = CapSlot::Active(src_cap.with_rights(src_cap.rights() & rights_mask)); 382 ctx.rax = SyscallResult::ok().raw(); 383} 384 385pub fn sys_cspace_set_guard(ctx: &mut CpuContext) { 386 let new_guard_bits = try_syscall!(ctx, super::u8_from_reg(ctx.rdi)); 387 let pid = crate::arch::syscall::current_pid(); 388 389 let mut ptable = PROCESSES.lock(); 390 let pool = POOL.lock_after(&ptable); 391 392 let exec = match ptable.exec(pid) { 393 Some(e) => e, 394 None => { 395 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 396 return; 397 } 398 }; 399 400 let (cnode_id, cnode_gen) = match exec.root_cnode() { 401 Some(pair) => pair, 402 None => { 403 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 404 return; 405 } 406 }; 407 408 let root_size_bits = match pool.read_as::<CNodeObject>(cnode_id, cnode_gen) { 409 Ok(c) => c.size_bits, 410 Err(e) => { 411 ctx.rax = SyscallResult::error(e).raw(); 412 return; 413 } 414 }; 415 416 if (new_guard_bits as u16) + (root_size_bits as u16) > 64 { 417 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 418 return; 419 } 420 421 let exec_mut = match ptable.exec_mut(pid) { 422 Some(e) => e, 423 None => { 424 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 425 return; 426 } 427 }; 428 429 exec_mut.root_guard_bits = new_guard_bits; 430 ctx.rax = SyscallResult::ok().raw(); 431}