Nothing to see here, move along
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}