Files
k-os/crates/bins/display-qemu/src/main.rs

134 lines
4.8 KiB
Rust

#![no_std]
#![forbid(unsafe_code)]
#![no_main]
extern crate libkos;
use types::bounded::CapSlot;
/// Where init put them (see init's manifest: own endpoint, then `uses`).
const EP: CapSlot = CapSlot::const_new(0);
const INPUT: CapSlot = CapSlot::const_new(1);
/// `themes/`, read-only.
const THEMES: CapSlot = CapSlot::const_new(2);
/// Where storage's buffer is mapped while the themes are read.
const STORAGE_BUF_VA: types::address::VirtualAddress = types::address::VirtualAddress::from_raw(0x1800_0000);
/// The longest theme file read.
const THEME_BYTES: usize = 4096;
libkos::entry!(main);
fn main() {
// Init hands over the GPU, or nothing if the machine has none.
let dev = libkos::device::receive_device(EP);
let input = subscribe_to_input();
if let Some(fb) = dev.mmio.and_then(driver_framebuffer_virtio::VirtioFramebuffer::try_new) {
run_virtio(fb, input);
}
libkos::println!("display: no GPU, running headless");
run_headless(input);
}
/// Has the input server signal this thread whenever events arrive; the
/// server then passes them on to the app in focus.
fn subscribe_to_input() -> Option<CapSlot> {
use types::badge::Badge;
use types::permission::{Permission, PermissionSet};
let notify = libkos::syscall::create_notification().ok()?;
libkos::syscall::bind_notification(notify).ok()?;
let signal = PermissionSet::empty().with(Permission::Write).with(Permission::Delegate);
let copy = libkos::syscall::mint(notify, Badge::NONE, signal).ok()?;
let sent = libkos::syscall::call(INPUT, [types::input::SUBSCRIBE, 0, 0, 0], Some(copy.into()));
libkos::syscall::drop_cap(copy);
sent.ok().map(|_| INPUT)
}
fn server<F: port_framebuffer::Framebuffer>(fb: F, input: Option<CapSlot>) -> display_server::server::DisplayServer<F, display_server::host::KernelHost> {
display_server::server::DisplayServer::new(fb, display_server::host::KernelHost::new(EP, input), themes())
}
/// Every theme in `themes/` that reads and passes contrast; the built-in
/// one if none does.
fn themes() -> display_server::themes::Themes {
let mut themes = display_server::themes::Themes::new();
let Ok(mut fs) = libkos::fs::Storage::attach(THEMES, STORAGE_BUF_VA) else {
libkos::println!("display: no themes folder; the built-in theme only");
return themes;
};
let mut names = [([0u8; types::storage::DIR_NAME_SIZE], 0usize); display_server::themes::MAX_THEMES];
let mut found = 0;
let _ = fs.list_dir(b"", |e| {
if !e.is_dir && e.name().ends_with(b".toml") && found < names.len() {
names[found] = (e.name, e.name_len);
found += 1;
}
});
let mut text = [0u8; THEME_BYTES];
for (name, len) in &names[..found] {
let name = &name[..*len];
let read = fs.open(name).and_then(|h| {
let n = fs.read(h, &mut text);
let _ = fs.close(h);
n
});
let shown = core::str::from_utf8(name).unwrap_or("?");
match read.ok().and_then(|n| core::str::from_utf8(&text[..n]).ok()) {
Some(t) => {
if let Err(e) = themes.add(t) {
libkos::println!("display: theme {} refused: {:?}", shown, e);
}
}
None => libkos::println!("display: cannot read theme {}", shown),
}
}
fs.detach();
// Storage has few connections to give; this one is done with.
let _ = libkos::fs::release(THEMES);
themes
}
#[inline(never)]
fn run_virtio(fb: driver_framebuffer_virtio::VirtioFramebuffer, input: Option<CapSlot>) -> ! {
let mut srv = server(fb, input);
server_framework::serve(&mut srv, EP)
}
/// No GPU: clients still get answers (and the dimensions they draw for);
/// pixels go nowhere.
struct Headless;
impl port_framebuffer::Framebuffer for Headless {
fn width(&self) -> types::display::Dimension {
types::display::Dimension::new(640)
}
fn height(&self) -> types::display::Dimension {
types::display::Dimension::new(480)
}
fn write_pixel(&mut self, _: types::display::ScreenCoord, _: types::display::ScreenCoord, _: types::display::Color) {}
fn fill_rect(
&mut self,
_: types::display::ScreenCoord,
_: types::display::ScreenCoord,
_: types::display::Dimension,
_: types::display::Dimension,
_: types::display::Color,
) {
}
fn clear(&mut self, _: types::display::Color) {}
fn flush(&mut self) {}
fn scroll_up(
&mut self,
_: types::display::ScreenCoord,
_: types::display::Dimension,
_: types::display::Dimension,
_: types::display::Color,
) {
}
}
#[inline(never)]
fn run_headless(input: Option<CapSlot>) -> ! {
let mut srv = server(Headless, input);
server_framework::serve(&mut srv, EP)
}