feat(userspace): terminal server + shell desktop; US keymap w/ shift; libkos allocator multi-page fix; panics print

This commit is contained in:
2026-10-27 16:50:35 +01:00
parent 2845d190f0
commit b80303f553
26 changed files with 739 additions and 53 deletions

View File

@@ -39,22 +39,21 @@ impl KosAllocator {
}
impl AllocatorInner {
fn request_page(&mut self) -> *mut u8 {
if self.page_count >= MAX_PAGES {
/// `n` pages in one piece, so an allocation larger than a page fits.
fn request_pages(&mut self, n: usize) -> *mut u8 {
if self.page_count + n > MAX_PAGES {
return ptr::null_mut();
}
let count = match types::bounded::PageCount::new(1) {
Some(c) => c,
None => return ptr::null_mut(),
let Some(count) = u16::try_from(n).ok().and_then(types::bounded::PageCount::new) else {
return ptr::null_mut();
};
let va = match crate::syscall::request_pages(count) {
Some(va) => va,
None => return ptr::null_mut(),
let Some(va) = crate::syscall::request_pages(count) else {
return ptr::null_mut();
};
self.pages[self.page_count] = va.raw();
self.page_count += 1;
if let Some(slot) = self.pages.get_mut(self.page_count) {
*slot = va.raw();
}
self.page_count += n;
va.raw() as *mut u8
}
@@ -125,14 +124,13 @@ unsafe impl GlobalAlloc for KosAllocator {
return ptr;
}
let pages_needed = (size + PAGE_SIZE - 1) / PAGE_SIZE;
for _ in 0..pages_needed {
let page = inner.request_page();
if page.is_null() {
return ptr::null_mut();
}
inner.add_to_free_list(page, PAGE_SIZE);
// Alignment can cost up to `align` bytes of the block.
let pages_needed = (size + align + PAGE_SIZE - 1) / PAGE_SIZE;
let block = inner.request_pages(pages_needed);
if block.is_null() {
return ptr::null_mut();
}
inner.add_to_free_list(block, pages_needed * PAGE_SIZE);
inner.alloc_from_free_list(size, align)
}

View File

@@ -12,6 +12,7 @@ pub mod io;
mod rt;
pub mod spawn;
pub mod start;
pub mod terminal;
pub mod syscall;
#[cfg(target_os = "none")]

View File

@@ -18,6 +18,7 @@ _start:
#[cfg(target_os = "none")]
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
fn panic(info: &core::panic::PanicInfo) -> ! {
crate::println!("panic: {}", info);
crate::syscall::exit();
}

View File

@@ -0,0 +1,29 @@
//! The terminal (`types::terminal`). Output is the log protocol, so a
//! process prints to a terminal by making it its log (`start::set_log`).
use crate::syscall;
use types::bounded::CapSlot;
/// Reads a typed line into `buf`, newline included if it fits; how much.
pub fn read_line(terminal: CapSlot, buf: &mut [u8]) -> usize {
let mut n = 0;
while n < buf.len() {
let Ok(words) = syscall::request(terminal, [types::terminal::READ, 0, 0, 0]) else {
break;
};
let Some((bytes, len)) = types::log::text_of(words) else {
break;
};
let take = len.min(buf.len() - n);
buf[n..n + take].copy_from_slice(&bytes[..take]);
n += take;
if bytes[..len].last() == Some(&b'\n') || len == 0 {
break;
}
}
n
}
pub fn clear(terminal: CapSlot) {
let _ = syscall::request(terminal, [types::terminal::CLEAR, 0, 0, 0]);
}