Nothing to see here, move along meow
1use crate::cap::cnode;
2use crate::cap::pool::POOL;
3use crate::cap::table::Rights;
4use crate::mem::phys::BitmapFrameAllocator;
5use crate::proc::PROCESSES;
6use crate::proc::address_space::{self, PageAccess};
7use crate::proc::context::CpuContext;
8use crate::syscall::{SyscallResult, try_syscall, validate_user_vaddr};
9use lancer_core::object_layout::VRegionObject;
10use lancer_core::object_tag::ObjectTag;
11use lancer_core::types::{MAX_VREGION_PAGES, VRegionFlags};
12use x86_64::PhysAddr;
13use x86_64::structures::paging::PhysFrame;
14
15use super::USER_ADDR_LIMIT;
16
17fn flags_to_access(flags: VRegionFlags) -> PageAccess {
18 match (flags.writable(), flags.executable()) {
19 (false, false) => PageAccess::ReadOnly,
20 (true, false) => PageAccess::ReadWrite,
21 (false, true) => PageAccess::ReadExecute,
22 (true, true) => PageAccess::ReadWriteExecute,
23 }
24}
25
26pub fn sys_vregion_create(ctx: &mut CpuContext) {
27 let untyped_slot = ctx.rdi;
28 let dest_slot = ctx.rsi;
29 let vaddr_raw = ctx.rdx;
30 let page_count_raw = ctx.r10;
31 let flags_raw = ctx.r8;
32 let pid = crate::arch::syscall::current_pid();
33
34 let page_count = try_syscall!(ctx, super::u16_from_reg(page_count_raw));
35 match page_count {
36 1..=MAX_VREGION_PAGES => {}
37 _ => {
38 ctx.rax = SyscallResult::error(crate::error::KernelError::InvalidParameter).raw();
39 return;
40 }
41 }
42
43 let vaddr = try_syscall!(ctx, validate_user_vaddr(vaddr_raw));
44 let vaddr_u64 = vaddr.as_u64();
45 if vaddr_u64 % 4096 != 0 {
46 ctx.rax = SyscallResult::error(crate::error::KernelError::InvalidAddress).raw();
47 return;
48 }
49
50 let region_size = page_count as u64 * 4096;
51 match vaddr_u64.checked_add(region_size) {
52 Some(e) if e <= USER_ADDR_LIMIT => {}
53 _ => {
54 ctx.rax = SyscallResult::error(crate::error::KernelError::InvalidAddress).raw();
55 return;
56 }
57 }
58
59 let flags_u16 = try_syscall!(ctx, super::u16_from_reg(flags_raw));
60 let flags = match VRegionFlags::try_new(flags_u16) {
61 Some(f) => f,
62 None => {
63 ctx.rax = SyscallResult::error(crate::error::KernelError::InvalidParameter).raw();
64 return;
65 }
66 };
67
68 let access = flags_to_access(flags);
69
70 let ptable = PROCESSES.lock();
71 let (cnode_phys, cnode_gen, depth, gv, gb) =
72 try_syscall!(ctx, cnode::cnode_coords(pid, &ptable));
73
74 let mut pool = POOL.lock_after(&ptable);
75
76 let untyped_cap = try_syscall!(
77 ctx,
78 cnode::resolve_and_validate(
79 &pool,
80 cnode_phys,
81 cnode_gen,
82 untyped_slot,
83 depth,
84 gv,
85 gb,
86 ObjectTag::Untyped,
87 Rights::REVOKE,
88 )
89 );
90
91 let untyped_phys = untyped_cap.phys();
92 let untyped_gen = untyped_cap.generation();
93
94 match crate::cap::retype::retype_vregion_from_untyped(
95 &mut pool,
96 untyped_phys,
97 untyped_gen,
98 page_count,
99 cnode_phys,
100 cnode_gen,
101 dest_slot,
102 depth,
103 gv,
104 gb,
105 ) {
106 Ok(()) => {}
107 Err(e) => {
108 ctx.rax = SyscallResult::error(e).raw();
109 return;
110 }
111 }
112
113 let vr_cap = match cnode::resolve_and_validate(
114 &pool,
115 cnode_phys,
116 cnode_gen,
117 dest_slot,
118 depth,
119 gv,
120 gb,
121 ObjectTag::VRegion,
122 Rights::WRITE,
123 ) {
124 Ok(c) => c,
125 Err(_) => {
126 panic!("just-inserted VRegion cap unreadable: kernel invariant violated");
127 }
128 };
129
130 let vr_phys = vr_cap.phys();
131 let vr_gen = vr_cap.generation();
132
133 let teardown_cap = |pool: &mut crate::cap::pool::ObjectPool| {
134 crate::cap::derivation::unlink_child(pool, vr_phys);
135 let _ = cnode::resolve_and_clear(
136 pool,
137 cnode_phys,
138 cnode_gen,
139 dest_slot,
140 depth,
141 gv,
142 gb,
143 );
144 let _ = pool.free_phys(vr_phys, vr_gen);
145 crate::cap::kernel_objects::free_slot(vr_phys.raw());
146 };
147
148 let backing_phys = match pool.read_as::<VRegionObject>(vr_phys, vr_gen) {
149 Ok(obj) => obj.phys_base,
150 Err(e) => {
151 teardown_cap(&mut pool);
152 ctx.rax = SyscallResult::error(e).raw();
153 return;
154 }
155 };
156
157 let pml4_phys = match ptable.exec(pid).map(|e| e.pml4_phys) {
158 Some(p) => p,
159 None => {
160 teardown_cap(&mut pool);
161 ctx.rax =
162 SyscallResult::error(crate::error::KernelError::InvalidObject).raw();
163 return;
164 }
165 };
166
167 let mut allocator = BitmapFrameAllocator;
168
169 let map_result = (0..page_count as u64).try_fold((), |(), i| {
170 let page_phys = PhysAddr::new(backing_phys + i * 4096);
171 crate::mem::addr::zero_frame(page_phys);
172 let phys_frame = PhysFrame::containing_address(page_phys);
173 let page_vaddr = x86_64::VirtAddr::new(vaddr_u64 + i * 4096);
174 address_space::map_user_page_inner(
175 pml4_phys,
176 page_vaddr,
177 phys_frame,
178 access,
179 &mut allocator,
180 )
181 });
182
183 match map_result {
184 Ok(()) => {}
185 Err(map_err) => {
186 crate::cap::ops::unmap_region(pml4_phys, vaddr_u64, page_count);
187 teardown_cap(&mut pool);
188 ctx.rax = SyscallResult::error(map_err).raw();
189 return;
190 }
191 }
192
193 match pool.write_as::<VRegionObject>(vr_phys, vr_gen) {
194 Ok(vr) => {
195 vr.owner_pid = pid.raw();
196 vr.owner_vaddr = vaddr_u64;
197 vr.flags = flags;
198 }
199 Err(e) => {
200 crate::cap::ops::unmap_region(pml4_phys, vaddr_u64, page_count);
201 teardown_cap(&mut pool);
202 ctx.rax = SyscallResult::error(e).raw();
203 return;
204 }
205 }
206
207 ctx.rax = SyscallResult::ok().raw();
208}
209
210pub fn sys_vregion_destroy(ctx: &mut CpuContext) {
211 let vregion_slot = ctx.rdi;
212 let pid = crate::arch::syscall::current_pid();
213
214 let mut ptable = PROCESSES.lock();
215 let (cnode_phys, cnode_gen, depth, gv, gb) =
216 try_syscall!(ctx, cnode::cnode_coords(pid, &ptable));
217
218 let mut pool = POOL.lock_after(&ptable);
219
220 let cap = try_syscall!(
221 ctx,
222 cnode::resolve_and_validate(
223 &pool,
224 cnode_phys,
225 cnode_gen,
226 vregion_slot,
227 depth,
228 gv,
229 gb,
230 ObjectTag::VRegion,
231 Rights::WRITE,
232 )
233 );
234
235 let _ = cnode::resolve_and_clear(
236 &pool,
237 cnode_phys,
238 cnode_gen,
239 vregion_slot,
240 depth,
241 gv,
242 gb,
243 );
244
245 let freed_phys = cap.phys();
246 match pool.dec_ref_phys(cap.phys(), cap.generation()) {
247 Some((phys, tag)) => {
248 crate::cap::derivation::unlink_child(&mut pool, freed_phys);
249 drop(pool);
250 crate::cap::ops::cleanup_by_tag_with_ptable(tag, phys, &mut ptable);
251 }
252 None => {}
253 }
254
255 ctx.rax = SyscallResult::ok().raw();
256}