Nothing to see here, move along
at main 462 lines 14 kB view raw
1use super::object::{CNodeData, ObjectTag}; 2use super::pool::ObjectPool; 3use super::table::{CapRef, CapSlot, Rights}; 4use crate::error::KernelError; 5use crate::mem::addr; 6use crate::mem::phys::BitmapFrameAllocator; 7use crate::proc::ProcessManager; 8use crate::types::{Generation, ObjectId, Pid}; 9use x86_64::PhysAddr; 10 11pub use lancer_core::cnode::{MAX_CNODE_BITS, MIN_CNODE_BITS}; 12use lancer_core::cnode::{MAX_RESOLVE_DEPTH, PAGE_SIZE, extract_index, frames_for_cnode}; 13 14pub fn create_cnode( 15 size_bits: u8, 16 allocator: &BitmapFrameAllocator, 17) -> Result<CNodeData, KernelError> { 18 if !(MIN_CNODE_BITS..=MAX_CNODE_BITS).contains(&size_bits) { 19 return Err(KernelError::InvalidParameter); 20 } 21 let frame_count = frames_for_cnode(size_bits); 22 let slots_phys = allocator 23 .allocate_contiguous(frame_count as usize) 24 .ok_or(KernelError::ResourceExhausted)?; 25 26 let slot_count = 1usize << size_bits; 27 let base_ptr = addr::phys_to_virt(slots_phys).as_mut_ptr::<CapSlot>(); 28 (0..slot_count).for_each(|i| unsafe { 29 base_ptr.add(i).write(CapSlot::Empty); 30 }); 31 32 Ok(CNodeData { 33 slots_phys, 34 size_bits, 35 frame_count, 36 }) 37} 38 39pub fn destroy_cnode(cnode: &CNodeData, allocator: &BitmapFrameAllocator) { 40 let base_frame_idx = (cnode.slots_phys.as_u64() / PAGE_SIZE as u64) as usize; 41 (0..cnode.frame_count as usize).for_each(|i| { 42 let frame_phys = PhysAddr::new((base_frame_idx + i) as u64 * PAGE_SIZE as u64); 43 crate::mem::addr::zero_frame(frame_phys); 44 let frame = unsafe { 45 x86_64::structures::paging::PhysFrame::from_start_address_unchecked(frame_phys) 46 }; 47 allocator.deallocate_frame(frame); 48 }); 49} 50 51unsafe fn read_slot(slots_phys: PhysAddr, index: usize) -> CapSlot { 52 let base = addr::phys_to_virt(slots_phys).as_ptr::<CapSlot>(); 53 unsafe { base.add(index).read() } 54} 55 56unsafe fn slot_ptr(slots_phys: PhysAddr, index: usize) -> *mut CapSlot { 57 let base = addr::phys_to_virt(slots_phys).as_mut_ptr::<CapSlot>(); 58 unsafe { base.add(index) } 59} 60 61pub fn resolve( 62 pool: &ObjectPool, 63 cnode_id: ObjectId, 64 cnode_gen: Generation, 65 address: u64, 66 depth: u8, 67) -> Result<CapSlot, KernelError> { 68 resolve_inner(pool, cnode_id, cnode_gen, address, depth, 0) 69} 70 71fn resolve_inner( 72 pool: &ObjectPool, 73 cnode_id: ObjectId, 74 cnode_gen: Generation, 75 address: u64, 76 depth: u8, 77 recursion: u8, 78) -> Result<CapSlot, KernelError> { 79 if recursion >= MAX_RESOLVE_DEPTH { 80 return Err(KernelError::InvalidSlot); 81 } 82 83 let (slots_phys, size_bits) = { 84 let data = pool.get(cnode_id, cnode_gen)?; 85 let cnode = data.as_cnode()?; 86 (cnode.slots_phys, cnode.size_bits) 87 }; 88 89 if depth < size_bits { 90 return Err(KernelError::InvalidSlot); 91 } 92 93 let index = extract_index(address, depth, size_bits) as usize; 94 let remaining = depth - size_bits; 95 let slot = unsafe { read_slot(slots_phys, index) }; 96 97 match remaining { 98 0 => Ok(slot), 99 _ => match slot { 100 CapSlot::Active(cap) if cap.tag() == ObjectTag::CNode => resolve_inner( 101 pool, 102 cap.object_id(), 103 cap.generation(), 104 address, 105 remaining, 106 recursion + 1, 107 ), 108 _ => Err(KernelError::InvalidSlot), 109 }, 110 } 111} 112 113fn resolve_slot_ptr( 114 pool: &ObjectPool, 115 cnode_id: ObjectId, 116 cnode_gen: Generation, 117 address: u64, 118 depth: u8, 119) -> Result<*mut CapSlot, KernelError> { 120 resolve_slot_ptr_inner(pool, cnode_id, cnode_gen, address, depth, 0) 121} 122 123fn resolve_slot_ptr_inner( 124 pool: &ObjectPool, 125 cnode_id: ObjectId, 126 cnode_gen: Generation, 127 address: u64, 128 depth: u8, 129 recursion: u8, 130) -> Result<*mut CapSlot, KernelError> { 131 if recursion >= MAX_RESOLVE_DEPTH { 132 return Err(KernelError::InvalidSlot); 133 } 134 135 let (slots_phys, size_bits) = { 136 let data = pool.get(cnode_id, cnode_gen)?; 137 let cnode = data.as_cnode()?; 138 (cnode.slots_phys, cnode.size_bits) 139 }; 140 141 if depth < size_bits { 142 return Err(KernelError::InvalidSlot); 143 } 144 145 let index = extract_index(address, depth, size_bits) as usize; 146 let remaining = depth - size_bits; 147 148 match remaining { 149 0 => Ok(unsafe { slot_ptr(slots_phys, index) }), 150 _ => { 151 let slot = unsafe { read_slot(slots_phys, index) }; 152 match slot { 153 CapSlot::Active(cap) if cap.tag() == ObjectTag::CNode => { 154 resolve_slot_ptr_inner( 155 pool, 156 cap.object_id(), 157 cap.generation(), 158 address, 159 remaining, 160 recursion + 1, 161 ) 162 } 163 _ => Err(KernelError::InvalidSlot), 164 } 165 } 166 } 167} 168 169pub fn resolve_and_insert( 170 pool: &ObjectPool, 171 cnode_id: ObjectId, 172 cnode_gen: Generation, 173 address: u64, 174 depth: u8, 175 cap: CapRef, 176) -> Result<(), KernelError> { 177 let ptr = resolve_slot_ptr(pool, cnode_id, cnode_gen, address, depth)?; 178 let slot = unsafe { &mut *ptr }; 179 match slot { 180 CapSlot::Active(_) => Err(KernelError::SlotOccupied), 181 CapSlot::Empty => { 182 *slot = CapSlot::Active(cap); 183 Ok(()) 184 } 185 } 186} 187 188pub fn resolve_and_validate( 189 pool: &ObjectPool, 190 cnode_id: ObjectId, 191 cnode_gen: Generation, 192 address: u64, 193 depth: u8, 194 expected_tag: ObjectTag, 195 required_rights: Rights, 196) -> Result<CapRef, KernelError> { 197 match resolve(pool, cnode_id, cnode_gen, address, depth)? { 198 CapSlot::Empty => Err(KernelError::SlotEmpty), 199 CapSlot::Active(cap) => { 200 if cap.tag() != expected_tag { 201 return Err(KernelError::InvalidType); 202 } 203 if !cap.rights().contains(required_rights) { 204 return Err(KernelError::InsufficientRights); 205 } 206 Ok(cap) 207 } 208 } 209} 210 211pub fn resolve_and_read( 212 pool: &ObjectPool, 213 cnode_id: ObjectId, 214 cnode_gen: Generation, 215 address: u64, 216 depth: u8, 217) -> Result<CapRef, KernelError> { 218 match resolve(pool, cnode_id, cnode_gen, address, depth)? { 219 CapSlot::Empty => Err(KernelError::SlotEmpty), 220 CapSlot::Active(cap) => Ok(cap), 221 } 222} 223 224pub fn resolve_and_clear( 225 pool: &ObjectPool, 226 cnode_id: ObjectId, 227 cnode_gen: Generation, 228 address: u64, 229 depth: u8, 230) -> Result<CapRef, KernelError> { 231 let ptr = resolve_slot_ptr(pool, cnode_id, cnode_gen, address, depth)?; 232 let slot = unsafe { &mut *ptr }; 233 match slot { 234 CapSlot::Empty => Err(KernelError::SlotEmpty), 235 CapSlot::Active(cap) => { 236 let cap = *cap; 237 *slot = CapSlot::Empty; 238 Ok(cap) 239 } 240 } 241} 242 243pub fn walk_cnode_slots( 244 pool: &ObjectPool, 245 cnode_id: ObjectId, 246 cnode_gen: Generation, 247 mut f: impl FnMut(&mut CapSlot), 248) -> Result<(), KernelError> { 249 let (slots_phys, size_bits) = { 250 let data = pool.get(cnode_id, cnode_gen)?; 251 let cnode = data.as_cnode()?; 252 (cnode.slots_phys, cnode.size_bits) 253 }; 254 255 let slot_count = 1usize << size_bits; 256 (0..slot_count).for_each(|i| { 257 let slot = unsafe { &mut *slot_ptr(slots_phys, i) }; 258 f(slot); 259 }); 260 Ok(()) 261} 262 263pub fn cnode_coords( 264 pid: Pid, 265 ptable: &ProcessManager, 266) -> Result<(ObjectId, Generation, u8), KernelError> { 267 let proc = ptable.get(pid).ok_or(KernelError::InvalidObject)?; 268 let (cnode_id, cnode_gen) = proc.root_cnode().ok_or(KernelError::InvalidObject)?; 269 Ok((cnode_id, cnode_gen, proc.cnode_depth())) 270} 271 272pub fn resolve_caller_validate( 273 pid: Pid, 274 address: u64, 275 expected_tag: ObjectTag, 276 required_rights: Rights, 277 ptable: &ProcessManager, 278 pool: &ObjectPool, 279) -> Result<CapRef, KernelError> { 280 let (cnode_id, cnode_gen, depth) = cnode_coords(pid, ptable)?; 281 resolve_and_validate(pool, cnode_id, cnode_gen, address, depth, expected_tag, required_rights) 282} 283 284pub fn resolve_caller_read( 285 pid: Pid, 286 address: u64, 287 ptable: &ProcessManager, 288 pool: &ObjectPool, 289) -> Result<CapRef, KernelError> { 290 let (cnode_id, cnode_gen, depth) = cnode_coords(pid, ptable)?; 291 resolve_and_read(pool, cnode_id, cnode_gen, address, depth) 292} 293 294pub fn resolve_caller_insert( 295 pid: Pid, 296 address: u64, 297 cap: CapRef, 298 ptable: &ProcessManager, 299 pool: &ObjectPool, 300) -> Result<(), KernelError> { 301 let (cnode_id, cnode_gen, depth) = cnode_coords(pid, ptable)?; 302 resolve_and_insert(pool, cnode_id, cnode_gen, address, depth, cap) 303} 304 305pub fn resolve_caller_clear( 306 pid: Pid, 307 address: u64, 308 ptable: &ProcessManager, 309 pool: &ObjectPool, 310) -> Result<CapRef, KernelError> { 311 let (cnode_id, cnode_gen, depth) = cnode_coords(pid, ptable)?; 312 resolve_and_clear(pool, cnode_id, cnode_gen, address, depth) 313} 314 315#[cfg(lancer_test)] 316pub fn drain_cnode_tree( 317 pool: &mut ObjectPool, 318 cnode_id: ObjectId, 319 cnode_gen: Generation, 320 callback: &mut impl FnMut(CapRef, &mut ObjectPool), 321) -> Result<(), KernelError> { 322 drain_cnode_tree_inner(pool, cnode_id, cnode_gen, callback, 0) 323} 324 325#[cfg(lancer_test)] 326fn drain_cnode_tree_inner( 327 pool: &mut ObjectPool, 328 cnode_id: ObjectId, 329 cnode_gen: Generation, 330 callback: &mut impl FnMut(CapRef, &mut ObjectPool), 331 recursion: u8, 332) -> Result<(), KernelError> { 333 if recursion >= MAX_RESOLVE_DEPTH { 334 return Err(KernelError::InvalidSlot); 335 } 336 337 let (slots_phys, size_bits) = { 338 let data = pool.get(cnode_id, cnode_gen)?; 339 let cnode = data.as_cnode()?; 340 (cnode.slots_phys, cnode.size_bits) 341 }; 342 343 let slot_count = 1usize << size_bits; 344 (0..slot_count).for_each(|i| { 345 let slot = unsafe { &mut *slot_ptr(slots_phys, i) }; 346 match slot { 347 CapSlot::Active(cap) => { 348 let cap = *cap; 349 *slot = CapSlot::Empty; 350 if cap.tag() == ObjectTag::CNode { 351 let _ = drain_cnode_tree_inner( 352 pool, 353 cap.object_id(), 354 cap.generation(), 355 callback, 356 recursion + 1, 357 ); 358 } 359 callback(cap, pool); 360 } 361 CapSlot::Empty => {} 362 } 363 }); 364 Ok(()) 365} 366 367pub fn drain_cnode_data( 368 cnode: &super::object::CNodeData, 369 pool: &mut ObjectPool, 370 callback: &mut impl FnMut(CapRef, &mut ObjectPool), 371) { 372 drain_cnode_data_inner(cnode, pool, callback, 0); 373} 374 375fn drain_cnode_data_inner( 376 cnode: &super::object::CNodeData, 377 pool: &mut ObjectPool, 378 callback: &mut impl FnMut(CapRef, &mut ObjectPool), 379 recursion: u8, 380) { 381 if recursion >= MAX_RESOLVE_DEPTH { 382 return; 383 } 384 385 let slot_count = 1usize << cnode.size_bits; 386 (0..slot_count).for_each(|i| { 387 let slot = unsafe { &mut *slot_ptr(cnode.slots_phys, i) }; 388 match slot { 389 CapSlot::Active(cap) => { 390 let cap = *cap; 391 *slot = CapSlot::Empty; 392 match cap.tag() == ObjectTag::CNode { 393 true => match pool.dec_ref(cap.object_id(), cap.generation()) { 394 Some(super::object::ObjectData::CNode(ref nested)) => { 395 drain_cnode_data_inner(nested, pool, callback, recursion + 1); 396 destroy_cnode(nested, &BitmapFrameAllocator); 397 } 398 Some(ref data) => { 399 super::ops::cleanup_object_data(data); 400 } 401 None => {} 402 }, 403 false => callback(cap, pool), 404 } 405 } 406 CapSlot::Empty => {} 407 } 408 }); 409} 410 411pub fn invalidate_stale_in_cnode( 412 pool: &ObjectPool, 413 cnode_id: ObjectId, 414 cnode_gen: Generation, 415 target_oid: ObjectId, 416 target_gen: Generation, 417) -> Result<(), KernelError> { 418 invalidate_stale_inner(pool, cnode_id, cnode_gen, target_oid, target_gen, 0) 419} 420 421fn invalidate_stale_inner( 422 pool: &ObjectPool, 423 cnode_id: ObjectId, 424 cnode_gen: Generation, 425 target_oid: ObjectId, 426 target_gen: Generation, 427 recursion: u8, 428) -> Result<(), KernelError> { 429 if recursion >= MAX_RESOLVE_DEPTH { 430 return Err(KernelError::InvalidSlot); 431 } 432 433 let (slots_phys, size_bits) = { 434 let data = pool.get(cnode_id, cnode_gen)?; 435 let cnode = data.as_cnode()?; 436 (cnode.slots_phys, cnode.size_bits) 437 }; 438 439 let slot_count = 1usize << size_bits; 440 (0..slot_count).for_each(|i| { 441 let slot = unsafe { &mut *slot_ptr(slots_phys, i) }; 442 match slot { 443 CapSlot::Active(cap) => { 444 if cap.tag() == ObjectTag::CNode { 445 let _ = invalidate_stale_inner( 446 pool, 447 cap.object_id(), 448 cap.generation(), 449 target_oid, 450 target_gen, 451 recursion + 1, 452 ); 453 } 454 if cap.object_id() == target_oid && cap.generation() == target_gen { 455 *slot = CapSlot::Empty; 456 } 457 } 458 CapSlot::Empty => {} 459 } 460 }); 461 Ok(()) 462}