Nothing to see here, move along
at main 268 lines 9.3 kB view raw
1use super::object::{EndpointData, NotificationData, ObjectData, ObjectTag}; 2use super::pool::POOL; 3use super::table::{CapRef, Rights}; 4use crate::error::KernelError; 5use crate::types::{Generation, ObjectId}; 6 7pub fn cleanup_object_data(data: &ObjectData) { 8 match data { 9 ObjectData::IrqHandler(irq) => { 10 crate::irq::unbind_by_vector(irq.vector); 11 } 12 ObjectData::CNode(cnode) => { 13 super::cnode::destroy_cnode(cnode, &crate::mem::phys::BitmapFrameAllocator); 14 } 15 ObjectData::Endpoint(_) 16 | ObjectData::Notification(_) 17 | ObjectData::Process(_) 18 | ObjectData::SchedContext(_) 19 | ObjectData::Framebuffer(_) 20 | ObjectData::PciDevice(_) 21 | ObjectData::Untyped(_) 22 | ObjectData::Frame(_) => {} 23 } 24} 25 26pub fn cleanup_object_data_with_ptable(data: &ObjectData, ptable: &mut crate::proc::ProcessManager) { 27 cleanup_object_data(data); 28 match data { 29 ObjectData::Endpoint(ep) => { 30 unblock_queue(&ep.senders, ptable); 31 unblock_queue(&ep.receivers, ptable); 32 } 33 ObjectData::Notification(notif) => { 34 notif.waiters.iter().for_each(|&pid| { 35 let proof = ptable[pid].blocked_proof(); 36 let proc = &mut ptable[pid]; 37 match proc.unblock(proof) { 38 Ok(()) => { 39 proc.saved_context.rax = 40 crate::error::KernelError::InvalidObject.to_errno() as u64; 41 proc.seal_context(); 42 } 43 Err(e) => { 44 crate::kprintln!( 45 "[cap] BUG: notification cleanup failed to unblock pid {}: {:?}", 46 pid.raw(), 47 e 48 ); 49 } 50 } 51 }); 52 } 53 ObjectData::SchedContext(sc) => { 54 sc.attached_pid.inspect(|&pid| { 55 if let Some(proc) = ptable.get_mut(pid) { 56 proc.detach_sched_context(); 57 } 58 }); 59 } 60 ObjectData::Frame(frame) => { 61 let phys = frame.phys_addr; 62 let owned_by_untyped = frame.from_untyped; 63 frame.mappings.iter().for_each(|mapping| { 64 if let Some(proc) = ptable.get(mapping.pid) { 65 let _ = 66 crate::proc::address_space::unmap_user_page(proc.pml4_phys, mapping.vaddr); 67 match crate::mem::refcount::decrement(phys) { 68 Ok(0) if !owned_by_untyped => { 69 crate::mem::phys::BitmapFrameAllocator::free_frame_by_addr(phys) 70 } 71 Ok(_) => {} 72 Err(e) => crate::kprintln!( 73 "[cap] frame refcount decrement failed: {:#x} {:?}", 74 phys.as_u64(), 75 e 76 ), 77 } 78 } 79 }); 80 } 81 ObjectData::Process(_) 82 | ObjectData::Framebuffer(_) 83 | ObjectData::PciDevice(_) 84 | ObjectData::Untyped(_) => {} 85 ObjectData::CNode(_) | ObjectData::IrqHandler(_) => {} 86 } 87} 88 89fn unblock_queue(queue: &super::object::PidQueue, ptable: &mut crate::proc::ProcessManager) { 90 let mut cursor = queue.head; 91 let mut steps = 0u16; 92 let max = crate::types::MAX_PIDS as u16; 93 core::iter::from_fn(|| { 94 cursor.filter(|_| steps < max).inspect(|&pid| { 95 steps += 1; 96 cursor = ptable[pid].next_ipc; 97 ptable[pid].next_ipc = None; 98 let proof = ptable[pid].blocked_proof(); 99 match ptable[pid].unblock(proof) { 100 Ok(()) => { 101 ptable[pid].saved_context.rax = 102 crate::error::KernelError::InvalidObject.to_errno() as u64; 103 ptable[pid].seal_context(); 104 } 105 Err(e) => { 106 crate::kprintln!( 107 "[cap] BUG: unblock_queue failed to unblock pid {}: {:?}", 108 pid.raw(), 109 e 110 ); 111 } 112 } 113 ptable.clear_reply_targets_for(pid); 114 }) 115 }) 116 .count(); 117} 118 119pub fn resolve_process_cap( 120 cap: &CapRef, 121 pool: &super::pool::ObjectPool, 122) -> Result<crate::types::Pid, KernelError> { 123 pool.get(cap.object_id(), cap.generation())? 124 .as_process() 125 .map(|p| p.pid) 126} 127 128pub fn create_via_cnode( 129 pool: &mut super::pool::ObjectPool, 130 cnode_id: ObjectId, 131 cnode_gen: Generation, 132 address: u64, 133 depth: u8, 134 tag: ObjectTag, 135) -> Result<ObjectId, KernelError> { 136 let data = match tag { 137 ObjectTag::Endpoint => ObjectData::Endpoint(EndpointData::new()), 138 ObjectTag::Notification => ObjectData::Notification(NotificationData::new()), 139 ObjectTag::Process 140 | ObjectTag::SchedContext 141 | ObjectTag::IrqHandler 142 | ObjectTag::Framebuffer 143 | ObjectTag::PciDevice 144 | ObjectTag::CNode 145 | ObjectTag::Untyped 146 | ObjectTag::Frame 147 | ObjectTag::MemoryRegion => { 148 return Err(KernelError::InvalidType); 149 } 150 }; 151 152 let (object_id, obj_gen) = pool.allocate(data)?; 153 let cap = CapRef::new(tag, object_id, Rights::ALL, obj_gen); 154 match super::cnode::resolve_and_insert(pool, cnode_id, cnode_gen, address, depth, cap) { 155 Ok(()) => Ok(object_id), 156 Err(e) => { 157 let r = pool.free(object_id, obj_gen); 158 debug_assert!(r.is_ok()); 159 Err(e) 160 } 161 } 162} 163 164pub fn derive_via_cnode( 165 pool: &mut super::pool::ObjectPool, 166 cnode_id: ObjectId, 167 cnode_gen: Generation, 168 src_addr: u64, 169 dest_addr: u64, 170 depth: u8, 171 rights_mask: Rights, 172) -> Result<(), KernelError> { 173 let src = super::cnode::resolve_and_read(pool, cnode_id, cnode_gen, src_addr, depth)?; 174 if !src.rights().contains(Rights::GRANT) { 175 return Err(KernelError::InsufficientRights); 176 } 177 pool.inc_ref(src.object_id(), src.generation())?; 178 let derived = src.with_rights(src.rights() & rights_mask); 179 match super::cnode::resolve_and_insert(pool, cnode_id, cnode_gen, dest_addr, depth, derived) { 180 Ok(()) => Ok(()), 181 Err(e) => { 182 pool.dec_ref(src.object_id(), src.generation()); 183 Err(e) 184 } 185 } 186} 187 188pub fn identify_via_cnode( 189 pool: &super::pool::ObjectPool, 190 cnode_id: ObjectId, 191 cnode_gen: Generation, 192 address: u64, 193 depth: u8, 194) -> Result<(ObjectTag, Rights), KernelError> { 195 let cap = super::cnode::resolve_and_read(pool, cnode_id, cnode_gen, address, depth)?; 196 match pool.get(cap.object_id(), cap.generation()) { 197 Ok(_) => Ok((cap.tag(), cap.rights())), 198 Err(KernelError::StaleGeneration) => { 199 let _ = super::cnode::resolve_and_clear(pool, cnode_id, cnode_gen, address, depth); 200 Err(KernelError::StaleGeneration) 201 } 202 Err(e) => Err(e), 203 } 204} 205 206pub fn insert_object_cap_via_cnode( 207 pool: &mut super::pool::ObjectPool, 208 cnode_id: ObjectId, 209 cnode_gen: Generation, 210 address: u64, 211 depth: u8, 212 data: ObjectData, 213 rights: Rights, 214) -> Result<ObjectId, KernelError> { 215 let tag = data.tag(); 216 let (object_id, obj_gen) = pool.allocate(data)?; 217 let cap = CapRef::new(tag, object_id, rights, obj_gen); 218 match super::cnode::resolve_and_insert(pool, cnode_id, cnode_gen, address, depth, cap) { 219 Ok(()) => Ok(object_id), 220 Err(e) => { 221 let r = pool.free(object_id, obj_gen); 222 debug_assert!(r.is_ok()); 223 Err(e) 224 } 225 } 226} 227 228pub fn revoke_via_cnode( 229 pid: crate::types::Pid, 230 address: u64, 231 ptable: &mut crate::proc::ProcessManager, 232) -> Result<(), KernelError> { 233 let (cnode_id, cnode_gen, depth) = super::cnode::cnode_coords(pid, ptable)?; 234 let cap_snapshot = { 235 let pool = POOL.lock(); 236 super::cnode::resolve_and_read(&pool, cnode_id, cnode_gen, address, depth)? 237 }; 238 if !cap_snapshot.rights().contains(Rights::REVOKE) { 239 return Err(KernelError::InsufficientRights); 240 } 241 let stale_oid = cap_snapshot.object_id(); 242 let stale_gen = cap_snapshot.generation(); 243 let (_new_gen, old_data) = POOL.lock().revoke(stale_oid, stale_gen)?; 244 { 245 let pool = POOL.lock(); 246 let _ = super::cnode::resolve_and_clear(&pool, cnode_id, cnode_gen, address, depth); 247 invalidate_stale_caps_via_cnode(ptable, &pool, stale_oid, stale_gen); 248 } 249 old_data.inspect(|data| cleanup_object_data_with_ptable(data, ptable)); 250 Ok(()) 251} 252 253pub fn invalidate_stale_caps_via_cnode( 254 ptable: &crate::proc::ProcessManager, 255 pool: &super::pool::ObjectPool, 256 object_id: ObjectId, 257 stale_gen: Generation, 258) { 259 let cap = ptable.capacity(); 260 (0..cap as u16) 261 .filter_map(crate::types::Pid::try_new) 262 .filter_map(|pid| { 263 ptable.get(pid).and_then(|p| p.root_cnode()) 264 }) 265 .for_each(|(cid, cgen)| { 266 let _ = super::cnode::invalidate_stale_in_cnode(pool, cid, cgen, object_id, stale_gen); 267 }); 268}