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