//! `Host` on the kernel: window buffers are regions of the display's own, //! made once per slot and reused (a region lives as long as its owner), so //! the display's memory has a fixed ceiling whatever apps do. use libkos::syscall; use types::address::VirtualAddress; use types::badge::Badge; use types::bounded::{CapSlot, PageCount}; use types::display::window::PIXEL_BYTES; use types::permission::{Permission, PermissionSet}; use crate::server::Host; use crate::windows::MAX_WINDOWS; /// Where slot `i`'s buffer is mapped in the display: 4 MiB apart, room for /// a 1280x800 window; high, clear of the GPU's mappings and of the heap, /// which grows from the bottom. const BUFFERS_VA: usize = 0x1000_0000; const BUFFER_SPAN: usize = 0x0040_0000; const PAGE: usize = 4096; pub struct KernelHost { /// The display's own endpoint, which window capabilities are minted /// from. ep: CapSlot, input: Option, /// Each slot's region and its pixels, mapped here as plain memory. buffers: [Option<(CapSlot, &'static mut [u8])>; MAX_WINDOWS], } impl KernelHost { pub fn new(ep: CapSlot, input: Option) -> Self { Self { ep, input, buffers: [const { None }; MAX_WINDOWS] } } } impl Host for KernelHost { fn buffer(&mut self, index: usize, pixels: usize) -> Option { let slot = self.buffers.get_mut(index)?; if slot.is_none() { let bytes = (pixels * PIXEL_BYTES).min(BUFFER_SPAN); let pages = PageCount::new(u16::try_from(bytes.div_ceil(PAGE)).ok()?)?; let region = syscall::create_region(pages).ok()?; let va = VirtualAddress::from_raw(BUFFERS_VA + index * BUFFER_SPAN); match libkos::window::map_buffer(region, va) { Ok(pixels) => *slot = Some((region, pixels)), Err(_) => { syscall::drop_cap(region); return None; } } } slot.as_ref().map(|(region, _)| *region) } fn blank(&mut self, index: usize) { if let Some((_, pixels)) = self.buffers.get_mut(index).and_then(Option::as_mut) { pixels.fill(0); } } fn pixels(&self, index: usize, from: usize, count: usize) -> &[u8] { let Some((_, pixels)) = self.buffers.get(index).and_then(Option::as_ref) else { return &[] }; let start = (from * PIXEL_BYTES).min(pixels.len()); let end = from.saturating_add(count).saturating_mul(PIXEL_BYTES).min(pixels.len()); &pixels[start..end] } fn reclaim(&mut self, index: usize) { if let Some((region, _)) = self.buffers.get(index).and_then(Option::as_ref) { // Every copy handed out goes, and with it every mapping of one. let _ = syscall::revoke(*region); } } fn mint(&mut self, badge: usize) -> Option { let perms = PermissionSet::empty().with(Permission::Execute).with(Permission::Delegate); syscall::mint(self.ep, Badge::new(badge), perms).ok() } fn revoke(&mut self, cap: CapSlot) { let _ = syscall::revoke(cap); syscall::drop_cap(cap); } fn signal(&mut self, notify: CapSlot) { let _ = syscall::signal(notify); } fn input(&mut self) -> Option<[usize; 4]> { let event = syscall::request(self.input?, [types::input::POLL_EVENT, 0, 0, 0]).ok()?; (event[0] != 0).then_some(event) } }