Files
danos/library/kernel/memory/memory.zig
Daniel Samson 4e7cbc9792 iommu: DMA-region capabilities — per-grant reachability, protocol flag-day
Replaces L2's interim DMA pool (every buffer reachable by every claimed
device) with true per-grant confinement: a device reaches only buffers
whose capability was delegated to its driver.

Kernel:
- DmaRegionObject (handle kind 2): a delegation token naming a dma_alloc'd
  region, passable across processes on the IPC cap slot like an endpoint
  or shared-memory object. Frames stay owned by the allocating address
  space (freed on dma_free/teardown as before); the token carries a `dead`
  flag so a stale downstream handle can no longer bind a freed region.
- dma_alloc gains the dma_shareable flag: it returns a capability handle
  in r8 and every region is tracked in a registry. A task's own regions
  auto-bind into the devices it claims (its rings just work); foreign
  buffers are bound explicitly.
- dma_bind / dma_unbind / handle_close syscalls (51-53). dma_bind maps a
  held region (or shared-memory) capability into a claimed device's domain;
  it is idempotent. handle_close reclaims a table slot (raised 16 -> 32).
- dma_free and task death unmap a region from every domain and invalidate
  BEFORE its frames return to the allocator — the stale-IOTLB use-after-
  free window, closed structurally.

Protocols (flag-day): block gains attach, usb-transfer gains dma_attach —
each carries a region capability on the cap slot. fat allocates its bounce
buffer shareable and attaches it; usb-storage allocates its transport
buffers shareable, attaches them to the controller, and forwards fat's
capability downstream; usb-xhci-bus binds and closes; virtio-gpu binds its
shared scanout surface. The physical addresses on the wire are unchanged
(identity IOVA), so no register-programming code moved.

Cross-process DMA (fat -> usb-storage -> xHC) now flows only through
delegated capabilities. iommu-usb-storage / iommu-usb-hid / iommu-fault
all green under per-grant enforcement; 104/104 overall (fail-open paths
unchanged).
2026-07-26 18:31:27 +01:00

50 lines
2.2 KiB
Zig

//! library/kernel/memory — the process's memory interface: the heap allocator, DMA-capable
//! buffers, shared-memory regions, and the raw `mmap` grant they all sit on. One flat module
//! (formerly runtime.heap / runtime.dma / runtime.shared_memory, plus the `mmap` wrappers that
//! lived in the system.zig dumping ground). Its private files are heap.zig, dma.zig, and
//! shared-memory.zig — imported only here, so the heap's state and C symbols exist once.
const abi = @import("abi");
const sc = @import("system-call");
const heap = @import("heap.zig");
const dma = @import("dma.zig");
const shared = @import("shared-memory.zig");
// --- the heap: a std.mem.Allocator over a first-fit free list (C malloc/free are also
// exported from heap.zig, compiled once here) ---
pub const allocator = heap.allocator;
// --- the raw grant every allocation sits on ---
pub const PROT_READ: usize = abi.prot_read;
pub const PROT_WRITE: usize = abi.prot_write;
pub const PROT_EXEC: usize = abi.prot_exec;
/// Grant `len` bytes (rounded up to whole pages) of fresh, zeroed, writable memory and
/// return the base virtual address. On failure returns a value in the top page (`mmapFailed`).
pub fn mmap(len: usize, prot: usize) usize {
return sc.systemCall2(.mmap, len, prot);
}
/// Release a range previously handed out by `mmap`.
pub fn munmap(base: usize, len: usize) usize {
return sc.systemCall2(.munmap, base, len);
}
/// Whether an `mmap` return value is an error (a wrapped -errno lands in the top page).
pub inline fn mmapFailed(ret: usize) bool {
return ret > ~@as(usize, 0) - 4095;
}
// --- DMA-capable buffers: physically contiguous, pinned, uncacheable, physical address known ---
pub const DmaRegion = dma.Region;
pub const dma_coherent = dma.coherent;
pub const dma_write_combining = dma.write_combining;
pub const dma_below_4g = dma.below_4g;
pub const dma_shareable = dma.shareable;
pub const dmaAlloc = dma.alloc;
pub const dmaFree = dma.free;
// --- shared-memory regions: a capability handed to another process over an ipc_call send_cap ---
pub const SharedRegion = shared.Region;
pub const sharedCreate = shared.create;
pub const sharedMap = shared.map;
pub const sharedPhysical = shared.physical;