refactor: unsafe only in adapter + libkos; forbid(unsafe_code) everywhere else; libkos Window (volatile, bounds-checked MMIO/DMA/shared mem), entry!, thread::spawn; MapRegion returns pages; kernel const-built (with_cores/install_platform); newtype addrs

This commit is contained in:
2026-10-27 21:43:24 +01:00
parent 83809bbe94
commit 842d14987c
107 changed files with 771 additions and 647 deletions

View File

@@ -1,33 +1,33 @@
#![no_std]
#![forbid(unsafe_code)]
use libkos::Window;
use port_input_device::{InputDevice, InputEvent, Key};
use types::address::VirtualAddress;
const UART_VA: usize = 0x20000;
const UART_VA: VirtualAddress = VirtualAddress::from_raw(0x20000);
const UART_IER_OFFSET: usize = 1;
const UART_LSR_OFFSET: usize = 5;
/// IER bit: interrupt when a received byte is waiting (cleared by reading
/// it, so `acknowledge` has nothing to do).
const IER_RX_READY: u8 = 1;
pub struct UartInputDevice;
/// The UART's registers, one byte each.
pub struct UartInputDevice {
regs: Window,
}
impl UartInputDevice {
/// Maps the 16550 UART whose region `mmio` names and enables its
/// receive interrupt.
pub fn new(mmio: types::bounded::CapSlot) -> Option<Self> {
libkos::device::map_mmio(mmio, UART_VA).ok()?;
// SAFETY: UART_VA now maps the UART's registers.
unsafe { core::ptr::write_volatile((UART_VA + UART_IER_OFFSET) as *mut u8, IER_RX_READY) };
Some(Self)
let regs = libkos::device::map_mmio(mmio, UART_VA).ok()?;
regs.write(UART_IER_OFFSET, IER_RX_READY);
Some(Self { regs })
}
fn read_byte(&self) -> Option<u8> {
let lsr = unsafe { core::ptr::read_volatile((UART_VA + UART_LSR_OFFSET) as *const u8) };
if lsr & 1 != 0 {
Some(unsafe { core::ptr::read_volatile(UART_VA as *const u8) })
} else {
None
}
self.has_event().then(|| self.regs.read(0))
}
fn byte_to_key(byte: u8) -> Key {
@@ -50,7 +50,6 @@ impl InputDevice for UartInputDevice {
}
fn has_event(&self) -> bool {
let lsr = unsafe { core::ptr::read_volatile((UART_VA + UART_LSR_OFFSET) as *const u8) };
lsr & 1 != 0
self.regs.read::<u8>(UART_LSR_OFFSET) & 1 != 0
}
}

View File

@@ -1,35 +1,37 @@
#![no_std]
#![forbid(unsafe_code)]
mod keymap;
use hw_virtio::mmio::MmioAccess;
use core::sync::atomic::{Ordering, fence};
use hw_virtio::mmio::{MmioAccess, Registers};
use libkos::Window;
use port_input_device::{InputDevice, InputEvent};
use types::address::{PhysicalAddress, VirtualAddress};
use types::bounded::PageCount;
const INPUT_MMIO_VA: usize = 0x25000;
const VQUEUE_VA: usize = 0x26000;
const EVBUF_VA: usize = 0x28000;
const INPUT_MMIO_VA: VirtualAddress = VirtualAddress::from_raw(0x25000);
const VQUEUE_VA: VirtualAddress = VirtualAddress::from_raw(0x26000);
const EVBUF_VA: VirtualAddress = VirtualAddress::from_raw(0x28000);
const QUEUE_SIZE: usize = 32;
const EVENT_SIZE: usize = 8;
const DESC_SIZE: usize = 16;
/// Where the legacy layout puts the available and used rings.
const AVAIL: usize = QUEUE_SIZE * DESC_SIZE;
const USED: usize = 4096;
const EV_KEY: u16 = 1;
const KEY_PRESS: u32 = 1;
struct MmioInput;
impl hw_virtio::mmio::MmioAccess for MmioInput {
fn read(&self, offset: usize) -> u32 {
unsafe { core::ptr::read_volatile((INPUT_MMIO_VA + offset) as *const u32) }
}
fn write(&self, offset: usize, val: u32) {
unsafe { core::ptr::write_volatile((INPUT_MMIO_VA + offset) as *mut u32, val) }
}
}
pub struct VirtioInputDevice {
regs: Registers,
/// The queue's rings, and the buffers the device writes events into.
rings: Window,
events: Window,
events_pa: PhysicalAddress,
last_used: u16,
next_avail: u16,
evbuf_pa: usize,
shift: bool,
ctrl: bool,
}
@@ -38,87 +40,68 @@ impl VirtioInputDevice {
/// Takes over the virtio input device behind `mmio`. `None` if it is
/// not one or any step fails.
pub fn try_new(mmio: types::bounded::CapSlot) -> Option<Self> {
libkos::device::map_mmio(mmio, INPUT_MMIO_VA).ok()?;
let regs = MmioInput;
let regs = Registers::new(libkos::device::map_mmio(mmio, INPUT_MMIO_VA).ok()?);
if regs.read(hw_virtio::mmio::REG_MAGIC) != hw_virtio::mmio::MAGIC
|| regs.read(hw_virtio::mmio::REG_DEVICE_ID) != hw_virtio::mmio::DEVICE_ID_INPUT
{
return None;
}
let vq_pa = libkos::device::dma(2, VQUEUE_VA).ok()?;
let evbuf_pa = libkos::device::dma(1, EVBUF_VA).ok()?;
hw_virtio::mmio::init_legacy_device(&regs, vq_pa, QUEUE_SIZE as u32);
let rings = libkos::device::dma(PageCount::new(2)?, VQUEUE_VA).ok()?;
let events = libkos::device::dma(PageCount::new(1)?, EVBUF_VA).ok()?;
hw_virtio::mmio::init_legacy_device(&regs, rings.physical, QUEUE_SIZE as u32);
let mut dev = Self { last_used: 0, next_avail: 0, evbuf_pa, shift: false, ctrl: false };
let mut dev = Self {
regs,
rings: rings.window,
events: events.window,
events_pa: events.physical,
last_used: 0,
next_avail: 0,
shift: false,
ctrl: false,
};
dev.fill_queue();
Some(dev)
}
/// Every buffer goes to the device, one event each.
fn fill_queue(&mut self) {
let evbuf_phys = self.evbuf_pa;
let desc_base = VQUEUE_VA;
let avail_base = VQUEUE_VA + QUEUE_SIZE * 16;
for i in 0..QUEUE_SIZE {
let desc = desc_base + i * 16;
let buf_pa = evbuf_phys + i * EVENT_SIZE;
unsafe {
core::ptr::write_volatile(desc as *mut u64, buf_pa as u64);
core::ptr::write_volatile((desc + 8) as *mut u32, EVENT_SIZE as u32);
core::ptr::write_volatile((desc + 12) as *mut u16, 2); // WRITE flag
core::ptr::write_volatile((desc + 14) as *mut u16, 0); // no next
}
unsafe {
let ring_entry = avail_base + 4 + (i % QUEUE_SIZE) * 2;
core::ptr::write_volatile(ring_entry as *mut u16, i as u16);
}
let desc = i * DESC_SIZE;
self.rings.write(desc, (self.events_pa.raw() + i * EVENT_SIZE) as u64);
self.rings.write(desc + 8, EVENT_SIZE as u32);
self.rings.write(desc + 12, 2u16); // WRITE flag
self.rings.write(desc + 14, 0u16); // no next
self.rings.write(AVAIL + 4 + i * 2, i as u16);
}
unsafe {
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
core::ptr::write_volatile((avail_base + 2) as *mut u16, QUEUE_SIZE as u16);
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
}
let mmio = MmioInput;
mmio.write(hw_virtio::mmio::REG_QUEUE_NOTIFY, 0);
fence(Ordering::SeqCst);
self.rings.write(AVAIL + 2, QUEUE_SIZE as u16);
fence(Ordering::SeqCst);
self.regs.write(hw_virtio::mmio::REG_QUEUE_NOTIFY, 0);
self.next_avail = QUEUE_SIZE as u16;
}
fn resubmit(&mut self, desc_idx: u16) {
let avail_base = VQUEUE_VA + QUEUE_SIZE * 16;
let slot = self.next_avail as usize % QUEUE_SIZE;
unsafe {
core::ptr::write_volatile((avail_base + 4 + slot * 2) as *mut u16, desc_idx);
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
self.next_avail = self.next_avail.wrapping_add(1);
core::ptr::write_volatile((avail_base + 2) as *mut u16, self.next_avail);
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
}
let mmio = MmioInput;
mmio.write(hw_virtio::mmio::REG_QUEUE_NOTIFY, 0);
self.rings.write(AVAIL + 4 + slot * 2, desc_idx);
fence(Ordering::SeqCst);
self.next_avail = self.next_avail.wrapping_add(1);
self.rings.write(AVAIL + 2, self.next_avail);
fence(Ordering::SeqCst);
self.regs.write(hw_virtio::mmio::REG_QUEUE_NOTIFY, 0);
}
fn read_event(&self, desc_idx: u16) -> (u16, u16, u32) {
let buf_va = EVBUF_VA + (desc_idx as usize) * EVENT_SIZE;
unsafe {
let ev_type = core::ptr::read_volatile(buf_va as *const u16);
let ev_code = core::ptr::read_volatile((buf_va + 2) as *const u16);
let ev_value = core::ptr::read_volatile((buf_va + 4) as *const u32);
(ev_type, ev_code, ev_value)
}
let at = desc_idx as usize % QUEUE_SIZE * EVENT_SIZE;
(self.events.read(at), self.events.read(at + 2), self.events.read(at + 4))
}
fn used_idx(&self) -> u16 {
let used_base = VQUEUE_VA + 4096;
unsafe { core::ptr::read_volatile((used_base + 2) as *const u16) }
self.rings.read(USED + 2)
}
fn used_entry_id(&self, idx: u16) -> u16 {
let used_base = VQUEUE_VA + 4096;
let entry = used_base + 4 + (idx as usize % QUEUE_SIZE) * 8;
unsafe { core::ptr::read_volatile(entry as *const u32) as u16 }
self.rings.read::<u32>(USED + 4 + (idx as usize % QUEUE_SIZE) * 8) as u16
}
}
@@ -163,8 +146,7 @@ impl InputDevice for VirtioInputDevice {
}
fn acknowledge(&mut self) {
let regs = MmioInput;
let status = regs.read(hw_virtio::mmio::REG_INTERRUPT_STATUS);
regs.write(hw_virtio::mmio::REG_INTERRUPT_ACK, status);
let status = self.regs.read(hw_virtio::mmio::REG_INTERRUPT_STATUS);
self.regs.write(hw_virtio::mmio::REG_INTERRUPT_ACK, status);
}
}