Nothing to see here, move along meow
1use crate::cap::cnode;
2use crate::cap::frame_table::FRAME_TABLE;
3use crate::cap::object::ObjectTag;
4use crate::cap::ops;
5use crate::cap::pool::POOL;
6use crate::cap::table::Rights;
7use crate::error::KernelError;
8use crate::mem::phys::BitmapFrameAllocator;
9use crate::proc::PROCESSES;
10use crate::proc::address_space::{self, PageAccess};
11use crate::proc::context::CpuContext;
12use crate::syscall::{SyscallResult, try_syscall, validate_user_vaddr};
13use lancer_core::object_layout::FrameObject;
14use x86_64::addr::PhysAddr;
15
16pub fn sys_frame_map(ctx: &mut CpuContext) {
17 let frame_slot = ctx.rdi;
18 let vaddr_raw = ctx.rsi;
19 let flags = ctx.rdx;
20 let pid = crate::arch::syscall::current_pid();
21
22 let vaddr = try_syscall!(ctx, validate_user_vaddr(vaddr_raw));
23
24 let writable = flags & 1 != 0;
25 let executable = flags & 2 != 0;
26 let required_rights = match writable {
27 true => Rights::WRITE,
28 false => Rights::READ,
29 };
30
31 let access = match (writable, executable) {
32 (false, false) => PageAccess::ReadOnly,
33 (true, false) => PageAccess::ReadWrite,
34 (false, true) => PageAccess::ReadExecute,
35 (true, true) => PageAccess::ReadWriteExecute,
36 };
37
38 let ptable = PROCESSES.lock();
39 let cap = {
40 let pool = POOL.lock_after(&ptable);
41 try_syscall!(
42 ctx,
43 cnode::resolve_caller_validate(
44 pid,
45 frame_slot,
46 ObjectTag::Frame,
47 required_rights,
48 &ptable,
49 &pool,
50 )
51 )
52 };
53
54 let pml4_phys = match ptable.exec(pid).map(|e| e.pml4_phys) {
55 Some(p) => p,
56 None => {
57 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
58 return;
59 }
60 };
61
62 let (phys_addr, ft_idx) = {
63 let pool = POOL.lock_after(&ptable);
64 match pool.read_as::<FrameObject>(cap.phys(), cap.generation()) {
65 Ok(f) => (PhysAddr::new(f.phys_addr), f.frame_table_idx),
66 Err(e) => {
67 ctx.rax = SyscallResult::error(e).raw();
68 return;
69 }
70 }
71 };
72
73 if ft_idx == lancer_core::header::NONE_SENTINEL as u16 {
74 ctx.rax = SyscallResult::error(KernelError::ResourceExhausted).raw();
75 return;
76 }
77
78 let phys_frame = x86_64::structures::paging::PhysFrame::containing_address(phys_addr);
79 let mut allocator = BitmapFrameAllocator;
80
81 match address_space::map_user_page_inner(
82 pml4_phys,
83 vaddr.as_virt_addr(),
84 phys_frame,
85 access,
86 &mut allocator,
87 ) {
88 Ok(()) => {}
89 Err(e) => {
90 ctx.rax = SyscallResult::error(e).raw();
91 return;
92 }
93 }
94
95 match crate::mem::refcount::increment(phys_addr) {
96 Ok(_) => {}
97 Err(_) => {
98 let _ = address_space::unmap_user_page(pml4_phys, vaddr.as_virt_addr());
99 ctx.rax = SyscallResult::error(KernelError::ResourceExhausted).raw();
100 return;
101 }
102 }
103
104 match FRAME_TABLE
105 .lock()
106 .get_mut(ft_idx)
107 .add_mapping(pid, vaddr.as_virt_addr())
108 {
109 Ok(()) => {
110 ctx.rax = SyscallResult::ok().raw();
111 }
112 Err(e) => {
113 let _ = crate::mem::refcount::decrement(phys_addr);
114 let _ = address_space::unmap_user_page(pml4_phys, vaddr.as_virt_addr());
115 ctx.rax = SyscallResult::error(e).raw();
116 }
117 }
118}
119
120pub fn sys_frame_unmap(ctx: &mut CpuContext) {
121 let frame_slot = ctx.rdi;
122 let vaddr_raw = ctx.rsi;
123 let pid = crate::arch::syscall::current_pid();
124
125 let vaddr = try_syscall!(ctx, validate_user_vaddr(vaddr_raw));
126
127 let ptable = PROCESSES.lock();
128 let cap = {
129 let pool = POOL.lock_after(&ptable);
130 try_syscall!(
131 ctx,
132 cnode::resolve_caller_validate(
133 pid,
134 frame_slot,
135 ObjectTag::Frame,
136 Rights::WRITE,
137 &ptable,
138 &pool,
139 )
140 )
141 };
142
143 let pml4_phys = match ptable.exec(pid).map(|e| e.pml4_phys) {
144 Some(p) => p,
145 None => {
146 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
147 return;
148 }
149 };
150
151 let (phys_addr, ft_idx) = {
152 let pool = POOL.lock_after(&ptable);
153 match pool.read_as::<FrameObject>(cap.phys(), cap.generation()) {
154 Ok(f) => (PhysAddr::new(f.phys_addr), f.frame_table_idx),
155 Err(e) => {
156 ctx.rax = SyscallResult::error(e).raw();
157 return;
158 }
159 }
160 };
161
162 if ft_idx == lancer_core::header::NONE_SENTINEL as u16 {
163 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
164 return;
165 }
166
167 match FRAME_TABLE
168 .lock()
169 .get_mut(ft_idx)
170 .remove_mapping(pid, vaddr.as_virt_addr())
171 {
172 true => {}
173 false => {
174 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
175 return;
176 }
177 }
178
179 let _ = address_space::unmap_user_page(pml4_phys, vaddr.as_virt_addr());
180
181 match crate::mem::refcount::decrement(phys_addr) {
182 Ok(_) => {}
183 Err(e) => crate::kprintln!(
184 "[frame] refcount decrement failed: {:#x} {:?}",
185 phys_addr.as_u64(),
186 e
187 ),
188 }
189
190 ctx.rax = SyscallResult::ok().raw();
191}
192
193pub fn sys_frame_map_child(ctx: &mut CpuContext) {
194 let frame_slot = ctx.rdi;
195 let proc_slot = ctx.rsi;
196 let vaddr_raw = ctx.rdx;
197 let flags = ctx.r10;
198 let pid = crate::arch::syscall::current_pid();
199
200 let vaddr = try_syscall!(ctx, validate_user_vaddr(vaddr_raw));
201
202 let writable = flags & 1 != 0;
203 let executable = flags & 2 != 0;
204 let access = match (writable, executable) {
205 (false, false) => PageAccess::ReadOnly,
206 (true, false) => PageAccess::ReadWrite,
207 (false, true) => PageAccess::ReadExecute,
208 (true, true) => PageAccess::ReadWriteExecute,
209 };
210
211 let ptable = PROCESSES.lock();
212
213 let frame_cap = {
214 let pool = POOL.lock_after(&ptable);
215 try_syscall!(
216 ctx,
217 cnode::resolve_caller_validate(
218 pid,
219 frame_slot,
220 ObjectTag::Frame,
221 Rights::GRANT,
222 &ptable,
223 &pool,
224 )
225 )
226 };
227
228 let proc_cap = {
229 let pool = POOL.lock_after(&ptable);
230 try_syscall!(
231 ctx,
232 cnode::resolve_caller_validate(
233 pid,
234 proc_slot,
235 ObjectTag::Process,
236 Rights::WRITE,
237 &ptable,
238 &pool,
239 )
240 )
241 };
242
243 let child_pid = {
244 let pool = POOL.lock_after(&ptable);
245 try_syscall!(ctx, ops::resolve_process_cap(&proc_cap, &pool))
246 };
247
248 let child_pml4 = match ptable.exec(child_pid).map(|e| e.pml4_phys) {
249 Some(p) => p,
250 None => {
251 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
252 return;
253 }
254 };
255
256 let (phys_addr, ft_idx) = {
257 let pool = POOL.lock_after(&ptable);
258 match pool.read_as::<FrameObject>(frame_cap.phys(), frame_cap.generation()) {
259 Ok(f) => (PhysAddr::new(f.phys_addr), f.frame_table_idx),
260 Err(e) => {
261 ctx.rax = SyscallResult::error(e).raw();
262 return;
263 }
264 }
265 };
266
267 if ft_idx == lancer_core::header::NONE_SENTINEL as u16 {
268 ctx.rax = SyscallResult::error(KernelError::ResourceExhausted).raw();
269 return;
270 }
271
272 let phys_frame = x86_64::structures::paging::PhysFrame::containing_address(phys_addr);
273 let mut allocator = BitmapFrameAllocator;
274
275 match address_space::map_user_page_inner(
276 child_pml4,
277 vaddr.as_virt_addr(),
278 phys_frame,
279 access,
280 &mut allocator,
281 ) {
282 Ok(()) => {}
283 Err(e) => {
284 ctx.rax = SyscallResult::error(e).raw();
285 return;
286 }
287 }
288
289 match crate::mem::refcount::increment(phys_addr) {
290 Ok(_) => {}
291 Err(_) => {
292 let _ = address_space::unmap_user_page(child_pml4, vaddr.as_virt_addr());
293 ctx.rax = SyscallResult::error(KernelError::ResourceExhausted).raw();
294 return;
295 }
296 }
297
298 match FRAME_TABLE
299 .lock()
300 .get_mut(ft_idx)
301 .add_mapping(child_pid, vaddr.as_virt_addr())
302 {
303 Ok(()) => {
304 ctx.rax = SyscallResult::ok().raw();
305 }
306 Err(e) => {
307 let _ = crate::mem::refcount::decrement(phys_addr);
308 let _ = address_space::unmap_user_page(child_pml4, vaddr.as_virt_addr());
309 ctx.rax = SyscallResult::error(e).raw();
310 }
311 }
312}