Nothing to see here, move along
1use crate::cap::cnode;
2use crate::cap::object::ObjectTag;
3use crate::cap::ops;
4use crate::cap::pool::POOL;
5use crate::cap::table::Rights;
6use crate::error::KernelError;
7use crate::proc::PROCESSES;
8use crate::proc::address_space::map_fb_page_inner;
9use crate::proc::context::CpuContext;
10use crate::syscall::{SyscallResult, try_syscall, validate_user_vaddr};
11use lancer_core::header::KernelObjectHeader;
12use lancer_core::object_layout::{FrameObject, FramebufferObject, KernelObject};
13
14use x86_64::PhysAddr;
15use x86_64::structures::paging::{PhysFrame, Size4KiB};
16
17pub fn sys_fb_info(ctx: &mut CpuContext) {
18 let cap_addr = ctx.rdi;
19 let pid = crate::arch::syscall::current_pid();
20
21 let cap = {
22 let ptable = PROCESSES.lock();
23 let pool = POOL.lock_after(&ptable);
24 try_syscall!(
25 ctx,
26 cnode::resolve_caller_validate(
27 pid,
28 cap_addr,
29 ObjectTag::Framebuffer,
30 Rights::READ,
31 &ptable,
32 &pool
33 )
34 )
35 };
36
37 let pool = POOL.lock();
38 let fb = match pool.read_as::<FramebufferObject>(cap.phys(), cap.generation()) {
39 Ok(f) => *f,
40 Err(e) => {
41 ctx.rax = SyscallResult::error(e).raw();
42 return;
43 }
44 };
45
46 ctx.rax = ((fb.height as u64) << 32) | (fb.width as u64);
47 ctx.rsi = fb.pitch as u64;
48 ctx.rdx = fb.bpp as u64;
49 ctx.r8 = fb.byte_size;
50}
51
52pub fn sys_fb_map(ctx: &mut CpuContext) {
53 let cap_addr = ctx.rdi;
54 let dest_vaddr = ctx.rsi;
55 let pid = crate::arch::syscall::current_pid();
56
57 let _ = try_syscall!(ctx, validate_user_vaddr(dest_vaddr));
58
59 match dest_vaddr & 0xFFF {
60 0 => {}
61 _ => {
62 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw();
63 return;
64 }
65 }
66
67 let ptable = PROCESSES.lock();
68 let (cap, pml4_phys) = {
69 let pool = POOL.lock_after(&ptable);
70 match cnode::resolve_caller_validate(
71 pid,
72 cap_addr,
73 ObjectTag::Framebuffer,
74 Rights::WRITE,
75 &ptable,
76 &pool,
77 ) {
78 Ok(c) => {
79 let pml4 = ptable
80 .exec(pid)
81 .map(|e| e.pml4_phys)
82 .ok_or(KernelError::InvalidObject);
83 match pml4 {
84 Ok(pml4_phys) => (c, pml4_phys),
85 Err(e) => {
86 ctx.rax = SyscallResult::error(e).raw();
87 return;
88 }
89 }
90 }
91 Err(e) => {
92 ctx.rax = SyscallResult::error(e).raw();
93 return;
94 }
95 }
96 };
97
98 let fb = {
99 let pool = POOL.lock_after(&ptable);
100 match pool.read_as::<FramebufferObject>(cap.phys(), cap.generation()) {
101 Ok(f) => *f,
102 Err(e) => {
103 ctx.rax = SyscallResult::error(e).raw();
104 return;
105 }
106 }
107 };
108
109 let page_count = fb.byte_size.div_ceil(4096) as usize;
110
111 match dest_vaddr.checked_add((page_count as u64) * 4096) {
112 Some(end) if end <= super::USER_ADDR_LIMIT => {}
113 _ => {
114 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw();
115 return;
116 }
117 }
118
119 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
120
121 let result = (0..page_count).try_fold(0usize, |count, i| {
122 let phys = PhysAddr::new(fb.phys_addr + (i as u64) * 4096);
123 let virt = x86_64::VirtAddr::new(dest_vaddr + (i as u64) * 4096);
124 let frame = PhysFrame::<Size4KiB>::containing_address(phys);
125
126 match map_fb_page_inner(pml4_phys, virt, frame, &mut allocator) {
127 Ok(()) => Ok(count + 1),
128 Err(_) => Err((KernelError::ResourceExhausted, count)),
129 }
130 });
131
132 ctx.rax = match result {
133 Ok(n) => {
134 crate::show!(
135 fb,
136 "pid {} mapped {} pages at virt {:#x} phys {:#x} {} bytes",
137 pid.raw(),
138 n,
139 dest_vaddr,
140 fb.phys_addr,
141 fb.byte_size
142 );
143 SyscallResult::success(n as u64).raw()
144 }
145 Err((e, mapped)) => {
146 crate::show!(
147 fb,
148 error,
149 "pid {} failed after {} of {} pages {:?}",
150 pid.raw(),
151 mapped,
152 page_count,
153 e
154 );
155 (0..mapped).for_each(|i| {
156 let virt = x86_64::VirtAddr::new(dest_vaddr + (i as u64) * 4096);
157 let _ = crate::proc::address_space::unmap_user_page(pml4_phys, virt);
158 });
159 SyscallResult::error(e).raw()
160 }
161 };
162}
163
164pub fn sys_fb_create_cap(ctx: &mut CpuContext) {
165 let pid = crate::arch::syscall::current_pid();
166 if pid != crate::types::Pid::new(0) {
167 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw();
168 return;
169 }
170
171 let dest_addr = ctx.rdi;
172
173 let fb = match crate::arch::boot::framebuffer() {
174 Some(fb) => fb,
175 None => {
176 ctx.rax = SyscallResult::error(KernelError::NotFound).raw();
177 return;
178 }
179 };
180
181 let hhdm_offset = crate::mem::addr::hhdm_offset();
182 let fb_virt = fb.addr() as u64;
183 let fb_phys = fb_virt - hhdm_offset;
184 let pitch = fb.pitch() as u32;
185 let width = fb.width() as u32;
186 let height = fb.height() as u32;
187 let bpp = fb.bpp() as u16;
188 let byte_size = (pitch as u64) * (height as u64);
189
190 if width == 0 || height == 0 || bpp == 0 {
191 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
192 return;
193 }
194 let bytes_per_pixel = match (bpp as u32).checked_div(8) {
195 Some(v) => v,
196 None => {
197 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
198 return;
199 }
200 };
201 let min_pitch = match width.checked_mul(bytes_per_pixel) {
202 Some(v) => v,
203 None => {
204 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
205 return;
206 }
207 };
208 if pitch < min_pitch {
209 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
210 return;
211 }
212
213 let obj_phys = match crate::cap::kernel_objects::alloc_slot() {
214 Some(p) => p,
215 None => {
216 ctx.rax = SyscallResult::error(KernelError::PoolExhausted).raw();
217 return;
218 }
219 };
220
221 let header = KernelObjectHeader::new(ObjectTag::Framebuffer, 0, 64);
222 let mut obj = FramebufferObject::init_default(header);
223 obj.phys_addr = fb_phys;
224 obj.width = width;
225 obj.height = height;
226 obj.pitch = pitch;
227 obj.bpp = bpp;
228 obj.byte_size = byte_size;
229 crate::cap::kernel_objects::write_at(obj_phys, obj);
230
231 let ptable = PROCESSES.lock();
232 let (cnode_id, cnode_gen, depth, gv, gb) = try_syscall!(ctx, cnode::cnode_coords(pid, &ptable));
233 let mut pool = POOL.lock_after(&ptable);
234
235 ctx.rax = match ops::insert_phys_cap_via_cnode(
236 &mut pool,
237 cnode_id,
238 cnode_gen,
239 dest_addr,
240 depth,
241 gv,
242 gb,
243 ObjectTag::Framebuffer,
244 obj_phys,
245 Rights::ALL,
246 ) {
247 Ok(_phys) => SyscallResult::ok().raw(),
248 Err(e) => {
249 crate::cap::kernel_objects::free_slot(obj_phys);
250 SyscallResult::error(e).raw()
251 }
252 };
253}
254
255pub fn sys_console_ring_create_cap(ctx: &mut CpuContext) {
256 let pid = crate::arch::syscall::current_pid();
257 if pid != crate::types::Pid::new(0) {
258 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw();
259 return;
260 }
261
262 let dest_base = ctx.rdi;
263
264 let (phys_addrs, frame_count) = match crate::console::ring_frame_info() {
265 Some(info) => info,
266 None => {
267 ctx.rax = SyscallResult::error(KernelError::NotFound).raw();
268 return;
269 }
270 };
271
272 let ptable = PROCESSES.lock();
273 let (cnode_id, cnode_gen, depth, gv, gb) = try_syscall!(ctx, cnode::cnode_coords(pid, &ptable));
274 let mut pool = POOL.lock_after(&ptable);
275
276 let result = (0..frame_count as u64).try_fold(0u64, |count, i| {
277 let obj_phys =
278 crate::cap::kernel_objects::alloc_slot().ok_or(KernelError::PoolExhausted)?;
279 let header = KernelObjectHeader::new(ObjectTag::Frame, 0, 64);
280 let mut frame_obj = FrameObject::init_default(header);
281 frame_obj.phys_addr = phys_addrs[i as usize];
282 frame_obj.size_bits = 12;
283 crate::cap::kernel_objects::write_at(obj_phys, frame_obj);
284
285 match ops::insert_phys_cap_via_cnode(
286 &mut pool,
287 cnode_id,
288 cnode_gen,
289 dest_base + i,
290 depth,
291 gv,
292 gb,
293 ObjectTag::Frame,
294 obj_phys,
295 Rights::ALL,
296 ) {
297 Ok(_) => Ok(count + 1),
298 Err(e) => {
299 crate::cap::kernel_objects::free_slot(obj_phys);
300 Err(e)
301 }
302 }
303 });
304
305 ctx.rax = match result {
306 Ok(n) => SyscallResult::success(n).raw(),
307 Err(e) => SyscallResult::error(e).raw(),
308 };
309}