feat(kernel): kernel-owned memory model
- FrameTable: per-frame owner/use, replaces PagePool + ProcessMemory - Quota per process, page tables charged to owner - Regions for shared mem + device MMIO, torn down w/ owner - Platform: create/destroy AS, map/unmap, zero_frame; drop translate_va - RequestPages/ReleasePages/MapPage(move) checked vs kernel records - user window 0x1000..32MiB, private pts by construction - boot loader + device setup go through kernel api - kernel built in place, boot allocator bounded - isolation tests, randomized invariant test, FrameTable kani proofs - fixes: inflated release, unmapped release, dst va unchecked, heap overflow, unbounded pt alloc, unzeroed frames, double free
This commit is contained in:
@@ -1,3 +1,84 @@
|
||||
pub mod gpu_setup;
|
||||
pub mod input_setup;
|
||||
pub mod storage_setup;
|
||||
|
||||
use crate::hw::uart::Uart;
|
||||
use types::address::{PhysicalAddress, VirtualAddress};
|
||||
use types::bounded::PageCount;
|
||||
use types::id::ProcessId;
|
||||
use types::mapping::PagePerms;
|
||||
|
||||
// Boot-time device wiring. Everything here goes through the kernel's
|
||||
// mapping API so the kernel knows about every page a driver can touch.
|
||||
// P5 replaces these hardcoded grants with capabilities handed to init.
|
||||
|
||||
fn kern() -> &'static mut kernel::Kernel<crate::platform::RiscVPlatform> {
|
||||
unsafe { &mut *crate::kernel_ptr() }
|
||||
}
|
||||
|
||||
fn pages(uart: &Uart, n: usize) -> PageCount {
|
||||
u16::try_from(n)
|
||||
.ok()
|
||||
.and_then(PageCount::new)
|
||||
.unwrap_or_else(|| crate::halt(uart, "bad page count"))
|
||||
}
|
||||
|
||||
/// Maps device MMIO at `pa` into `pid` at `va`.
|
||||
pub(crate) fn map_mmio(uart: &Uart, pid: ProcessId, va: usize, pa: usize, n: usize) {
|
||||
let id = kern()
|
||||
.create_device_region(pid, PhysicalAddress::from_raw(pa), pages(uart, n))
|
||||
.unwrap_or_else(|_| crate::halt(uart, "device region failed"));
|
||||
kern()
|
||||
.map_region(id, pid, VirtualAddress::from_raw(va), PagePerms::ReadWrite)
|
||||
.unwrap_or_else(|_| crate::halt(uart, "device map failed"));
|
||||
}
|
||||
|
||||
/// Physically contiguous, zeroed DMA memory for `owner`, mapped read-write
|
||||
/// at `va`. Returns its physical base for programming the device.
|
||||
pub(crate) fn dma_buffer(uart: &Uart, owner: ProcessId, va: usize, n: usize) -> usize {
|
||||
let id = kern()
|
||||
.create_pool_region(owner, pages(uart, n))
|
||||
.unwrap_or_else(|_| crate::halt(uart, "DMA region failed"));
|
||||
kern()
|
||||
.map_region(
|
||||
id,
|
||||
owner,
|
||||
VirtualAddress::from_raw(va),
|
||||
PagePerms::ReadWrite,
|
||||
)
|
||||
.unwrap_or_else(|_| crate::halt(uart, "DMA map failed"));
|
||||
kern()
|
||||
.region_base(id)
|
||||
.unwrap_or_else(|| crate::halt(uart, "DMA region vanished"))
|
||||
.raw()
|
||||
}
|
||||
|
||||
/// Shares a fresh region between `owner` and `other` at the same `va`.
|
||||
pub(crate) fn shared_buffer(uart: &Uart, owner: ProcessId, other: ProcessId, va: usize, n: usize) {
|
||||
let id = kern()
|
||||
.create_pool_region(owner, pages(uart, n))
|
||||
.unwrap_or_else(|_| crate::halt(uart, "shared region failed"));
|
||||
for pid in [owner, other] {
|
||||
kern()
|
||||
.map_region(id, pid, VirtualAddress::from_raw(va), PagePerms::ReadWrite)
|
||||
.unwrap_or_else(|_| crate::halt(uart, "shared map failed"));
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes `words` into a fresh page mapped at `va` in `pid`, so a driver
|
||||
/// can learn the physical addresses of its DMA buffers.
|
||||
pub(crate) fn info_page(uart: &Uart, pid: ProcessId, va: usize, words: &[u64]) {
|
||||
let va = VirtualAddress::from_raw(va);
|
||||
kern()
|
||||
.map_fresh_range(pid, va, 1, PagePerms::ReadOnly)
|
||||
.unwrap_or_else(|_| crate::halt(uart, "info page failed"));
|
||||
let pa = kern()
|
||||
.user_page_frame(pid, va)
|
||||
.unwrap_or_else(|| crate::halt(uart, "info page vanished"));
|
||||
let info = pa.raw() as *mut u64;
|
||||
for (i, &w) in words.iter().enumerate() {
|
||||
// SAFETY: `pa` is a pool frame just mapped for `pid`, identity
|
||||
// mapped in kernel space, and `words` fits in one page.
|
||||
unsafe { core::ptr::write_volatile(info.add(i), w) };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user