CRITICAL — MapPage privilege escalation:
handle_map_page allowed mapping kernel memory (VA >= 0x80000000)
into userspace. Any process with a Process capability could read/
write kernel data structures. Fixed: reject src_va >= USER_VA_LIMIT.
HIGH — resource leaks:
handle_kill: leaked pages (used cleanup_threads directly instead
of destroy_process). Now uses destroy_process for full cleanup.
handle_create_process: orphaned process on cap grant failure.
Now destroys process on rollback.
handle_create_endpoint: orphaned endpoint on cap grant failure.
Now destroys endpoint on rollback.
Thread ID array: hardcoded [None; 4] replaced with
[None; MAX_THREADS_PER_PROCESS] slice. cleanup_threads now
takes &[Option<ThreadId>] slice.
MEDIUM — quality fixes:
handle_request_pages: replaced unreachable!() with proper error
return + page pool rollback.
Page lifecycle:
- ProcessMemory now tracks (PhysicalAddress, count) pairs for each
allocation (up to 16). destroy_process iterates and frees all
pages back to the pool. No more permanent page leaks on exit/fault.
- RequestPages re-adds MemoryRegion entries so ReleasePages works.
Release test un-ignored, passes.
- RequestPages: VA allocation moved after pool allocation succeeds,
preventing VA leak on OOM.
IPC hardening:
- WaitQueue overflow (>16 waiters): returns WouldBlock error instead
of silently dropping the thread. Thread is not blocked if enqueue
fails.
- debug_assert on pending_messages[sender].take() — invariant that
a sender in wait queue must have a pending message.
Scheduler:
- remove() now clears current thread if the removed thread was
current on its core.
- add() asserts push succeeded; bitmap bit only set if thread was
actually added to RunList.
Cleanup:
- Priority::DEFAULT replaces Priority::new(16).unwrap() in
spawn_thread and spawn_thread_in.
36 kernel tests pass, 0 ignored.
Critical: kernel_ref() UB eliminated
- kernel_ref() returned &'static mut, creating aliasing mutable
references across trap handler + boot code (13+ call sites)
- Replaced with kernel_ptr() -> *mut Kernel, each use site does
explicit unsafe { &mut *kernel_ptr() }
- KernelCell: removed get_mut(), added as_ptr() -> *mut T
- UB is gone: raw pointer access makes the single-core invariant
explicit at every use site
Important: process cleanup on exit/fault
- New destroy_process() method consolidates cleanup:
- Removes all threads from scheduler and endpoints
- Clears pending messages and results
- Destroys process and frees ProcessMemory
- handle_exit and handle_fault both use destroy_process()
- handle_exit_thread uses destroy_process when last thread exits
IPC hardening:
- Added invariant comment on pending_messages[sender].take()
(sender in wait queue must have a pending message)
handle_release_pages:
- Now uses translate_va to convert VA→PA (was treating VA as PA)
Tests:
- IPC tests: spawn thread B explicitly (CreateProcess no longer
spawns threads since the boot logic fix)
- Memory tests: RequestPages now returns Value(va) not Slot(cap)
- MockPlatform: tracks VA→PA mappings for translate_va
- ReleasePages test: ignored (RequestPages no longer creates
regions — ReleasePages needs redesign)
CapSlot::const_new(value):
- const fn that panics at compile time for invalid values
- Replaces CapSlot::new(N).unwrap() in init, echo, snake
- Cap slot constants are now compile-time verified
Also fixes handle_release_pages to use translate_va instead of
treating VA as PA directly.
35 kernel tests pass, 1 ignored.
Complete microkernel boot pipeline: adapter loads only init + storage + display
from disk. Init bootstraps all other servers by reading binaries from the
storage server via IPC, parsing ELF, creating processes, mapping pages, and
spawning threads.
New syscalls:
- CreateEndpoint: userspace endpoint creation with full capability grant
- DebugPutchar: debug output to UART from userspace
- MapPage: cross-process page mapping (init loads binaries into children)
- SpawnThreadIn: spawn thread in another process via capability
Key fixes:
- Per-process L1 page tables for VPN[2]=0 (prevents cross-process corruption)
- Separate kernel_pt from page_tables[0] (init pid=0 overwrote kernel PT ref)
- Thread Running state set in switch_to_next (syscalls rejected without it)
- Pending IPC results applied during context switch
- SIE disabled during boot (timer can't preempt into unready processes)
- User heap VA starts at 0x40000 (avoids shared buffer at 0x30000)
- RequestPages maps at user VAs via per-process heap allocator
VirtIO GPU:
- Adapter probes for GPU device, initializes resource/scanout/backing
- Display server writes to mapped framebuffer, flushes via GPU virtqueue
- 640x480 BGRA framebuffer with transfer-to-host and resource-flush
Storage server:
- Userspace VirtIO block driver using pre-mapped MMIO and DMA pages
- FAT16 filesystem reader serving file-read requests via IPC
- Shared buffer protocol: init writes filename, storage writes file data
Echo app for IPC testing (adapter-loaded echo proved the pipeline end-to-end).
- CreateProcess only creates process + grants cap, no thread spawning
- boot::boot takes &mut BootResult instead of returning it (fixes -> ! sret convention issue)
- Init creates 6 server processes, sets up supervisor, enters receive loop
- No faults on QEMU with full boot sequence
- Halt syscall: only pid 0 (init) can halt, adapter uses SBI SRST
- Fault notification: kernel delivers fault info to process fault handler endpoint before killing
- Supervisor: tracks restart counts, back-off up to 5 restarts
- Shutdown: notifies servers, waits with timeout, calls halt
- Trap handler: faults now call kernel.handle_fault instead of halting