Nothing to see here, move along
1use crate::cap::cnode;
2use crate::cap::object::ObjectTag;
3use crate::cap::pool::POOL;
4use crate::cap::table::Rights;
5use crate::error::KernelError;
6use crate::proc::PROCESSES;
7use crate::proc::address_space::map_fb_page_inner;
8use crate::proc::context::CpuContext;
9use crate::syscall::{SyscallResult, try_syscall, validate_user_vaddr};
10
11use x86_64::PhysAddr;
12use x86_64::structures::paging::{PhysFrame, Size4KiB};
13
14pub fn sys_fb_info(ctx: &mut CpuContext) {
15 let cap_addr = ctx.rdi;
16 let pid = crate::arch::syscall::current_pid();
17
18 let cap = {
19 let ptable = PROCESSES.lock();
20 let pool = POOL.lock_after(&ptable);
21 try_syscall!(
22 ctx,
23 cnode::resolve_caller_validate(pid, cap_addr, ObjectTag::Framebuffer, Rights::READ, &ptable, &pool)
24 )
25 };
26
27 let fb_data = {
28 let pool = POOL.lock();
29 match pool
30 .get(cap.object_id(), cap.generation())
31 .and_then(|d| d.as_framebuffer())
32 {
33 Ok(d) => *d,
34 Err(e) => {
35 ctx.rax = SyscallResult::error(e).raw();
36 return;
37 }
38 }
39 };
40
41 ctx.rax = ((fb_data.height() as u64) << 32) | (fb_data.width() as u64);
42 ctx.rsi = fb_data.pitch() as u64;
43 ctx.rdx = fb_data.bpp() as u64;
44 ctx.r8 = fb_data.byte_size();
45}
46
47pub fn sys_fb_map(ctx: &mut CpuContext) {
48 let cap_addr = ctx.rdi;
49 let dest_vaddr = ctx.rsi;
50 let pid = crate::arch::syscall::current_pid();
51
52 let _ = try_syscall!(ctx, validate_user_vaddr(dest_vaddr));
53
54 match dest_vaddr & 0xFFF {
55 0 => {}
56 _ => {
57 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw();
58 return;
59 }
60 }
61
62 let ptable = PROCESSES.lock();
63 let (cap, pml4_phys) = {
64 let pool = POOL.lock_after(&ptable);
65 match cnode::resolve_caller_validate(pid, cap_addr, ObjectTag::Framebuffer, Rights::WRITE, &ptable, &pool) {
66 Ok(c) => {
67 let pml4 = ptable.get(pid).map(|p| p.pml4_phys).ok_or(KernelError::InvalidObject);
68 match pml4 {
69 Ok(pml4_phys) => (c, pml4_phys),
70 Err(e) => {
71 ctx.rax = SyscallResult::error(e).raw();
72 return;
73 }
74 }
75 }
76 Err(e) => {
77 ctx.rax = SyscallResult::error(e).raw();
78 return;
79 }
80 }
81 };
82
83 let fb_data = {
84 let pool = POOL.lock_after(&ptable);
85 match pool
86 .get(cap.object_id(), cap.generation())
87 .and_then(|d| d.as_framebuffer())
88 {
89 Ok(d) => *d,
90 Err(e) => {
91 ctx.rax = SyscallResult::error(e).raw();
92 return;
93 }
94 }
95 };
96
97 let page_count = fb_data.byte_size().div_ceil(4096) as usize;
98
99 match dest_vaddr.checked_add((page_count as u64) * 4096) {
100 Some(end) if end <= super::USER_ADDR_LIMIT => {}
101 _ => {
102 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw();
103 return;
104 }
105 }
106
107 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
108
109 let result = (0..page_count).try_fold(0usize, |count, i| {
110 let phys = PhysAddr::new(fb_data.phys_addr() + (i as u64) * 4096);
111 let virt = x86_64::VirtAddr::new(dest_vaddr + (i as u64) * 4096);
112 let frame = PhysFrame::<Size4KiB>::containing_address(phys);
113
114 match map_fb_page_inner(pml4_phys, virt, frame, &mut allocator) {
115 Ok(()) => Ok(count + 1),
116 Err(_) => Err((KernelError::ResourceExhausted, count)),
117 }
118 });
119
120 ctx.rax = match result {
121 Ok(n) => {
122 crate::show!(fb,
123 "pid {} mapped {} pages at virt {:#x} phys {:#x} {} bytes",
124 pid.raw(),
125 n,
126 dest_vaddr,
127 fb_data.phys_addr(),
128 fb_data.byte_size()
129 );
130 SyscallResult::success(n as u64).raw()
131 }
132 Err((e, mapped)) => {
133 crate::show!(fb, error,
134 "pid {} failed after {} of {} pages {:?}",
135 pid.raw(),
136 mapped,
137 page_count,
138 e
139 );
140 (0..mapped).for_each(|i| {
141 let virt = x86_64::VirtAddr::new(dest_vaddr + (i as u64) * 4096);
142 let _ = crate::proc::address_space::unmap_user_page(pml4_phys, virt);
143 });
144 SyscallResult::error(e).raw()
145 }
146 };
147}