feat(boot): gatekeeper gates boot (init→UI→gatekeeper→data); keystore disk + virtio-rng discovery; terminal READ_SECRET; storage SET_KEY; PageCount ≤8192, alloc cap gone; device window 0x01D0_0000; test-qemu types passcode over 2 boots

This commit is contained in:
2026-10-27 23:43:47 +01:00
parent b7ef67ffd8
commit 3b7d004285
36 changed files with 455 additions and 74 deletions

View File

@@ -1,8 +1,9 @@
//! Finds the board's devices (`types::bootinfo`): disk, GPU, and keyboard
//! (or the UART when there is none).
use hw_virtio::block::CONFIG_CAPACITY;
use hw_virtio::mmio::{
DEVICE_ID_BLOCK, DEVICE_ID_GPU, DEVICE_ID_INPUT, MAGIC, REG_DEVICE_ID, REG_MAGIC,
DEVICE_ID_BLOCK, DEVICE_ID_GPU, DEVICE_ID_INPUT, DEVICE_ID_RNG, MAGIC, REG_DEVICE_ID, REG_MAGIC,
};
use libkos::device::{self, Device};
use libkos::syscall;
@@ -19,8 +20,14 @@ pub struct Devices {
pub disk: Device,
pub gpu: Device,
pub input: Device,
/// The gatekeeper's: a small disk of its own for the key slots.
pub keystore: Device,
pub random: Device,
}
/// A block device this small (1 MiB) is the keystore, not the disk.
const KEYSTORE_MAX_SECTORS: u64 = 2048;
fn slot(raw: u64) -> Option<CapSlot> {
if raw == NO_SLOT {
return None;
@@ -28,21 +35,30 @@ fn slot(raw: u64) -> Option<CapSlot> {
CapSlot::new(u8::try_from(raw).ok()?)
}
/// The virtio device id behind `region`, 0 for an empty slot. Read through
/// a copy of the capability, mapped only while looking and then dropped,
/// which unmaps it.
fn virtio_id(region: CapSlot) -> u32 {
/// The virtio device id behind `region` (0 for an empty slot) and, for a
/// block device, its size in sectors. Read through a copy of the
/// capability, mapped only while looking and then dropped, which unmaps it.
fn virtio_id(region: CapSlot) -> (u32, u64) {
let perms = PermissionSet::empty().with(Permission::Read).with(Permission::Write);
let Ok(copy) = syscall::mint(region, Badge::NONE, perms) else {
return 0;
return (0, 0);
};
let id = match device::map_mmio(copy, PROBE_VA) {
// The registers stay mapped until the drop below.
Ok(regs) => match regs.read::<u32>(REG_MAGIC) == MAGIC {
true => regs.read(REG_DEVICE_ID),
false => 0,
true => {
let id = regs.read(REG_DEVICE_ID);
let size = match id {
DEVICE_ID_BLOCK => {
regs.read::<u32>(CONFIG_CAPACITY) as u64 | (regs.read::<u32>(CONFIG_CAPACITY + 4) as u64) << 32
}
_ => 0,
};
(id, size)
}
false => (0, 0),
},
Err(_) => 0,
Err(_) => (0, 0),
};
syscall::drop_cap(copy);
id
@@ -74,7 +90,13 @@ pub fn console() -> Option<CapSlot> {
/// Sorts the board's devices out.
pub fn discover() -> Devices {
let info = boot_info();
let mut found = Devices { disk: Device::NONE, gpu: Device::NONE, input: Device::NONE };
let mut found = Devices {
disk: Device::NONE,
gpu: Device::NONE,
input: Device::NONE,
keystore: Device::NONE,
random: Device::NONE,
};
let mut uart = Device::NONE;
for d in info.devices() {
let Some(region) = slot(d.region_slot) else {
@@ -84,9 +106,11 @@ pub fn discover() -> Devices {
let place = match d.kind {
KIND_UART_16550 => &mut uart,
KIND_VIRTIO => match virtio_id(region) {
DEVICE_ID_BLOCK => &mut found.disk,
DEVICE_ID_GPU => &mut found.gpu,
DEVICE_ID_INPUT => &mut found.input,
(DEVICE_ID_BLOCK, size) if size <= KEYSTORE_MAX_SECTORS => &mut found.keystore,
(DEVICE_ID_BLOCK, _) => &mut found.disk,
(DEVICE_ID_GPU, _) => &mut found.gpu,
(DEVICE_ID_INPUT, _) => &mut found.input,
(DEVICE_ID_RNG, _) => &mut found.random,
_ => continue,
},
_ => continue,