Files
k-os/crates/servers/display-server/src/host.rs

95 lines
3.4 KiB
Rust

//! `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<CapSlot>,
/// 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<CapSlot>) -> Self {
Self { ep, input, buffers: [const { None }; MAX_WINDOWS] }
}
}
impl Host for KernelHost {
fn buffer(&mut self, index: usize, pixels: usize) -> Option<CapSlot> {
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<CapSlot> {
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)
}
}