Nothing to see here, move along
at main 309 lines 9.3 kB view raw
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}