fix: harden kernel — eliminate UB, proper process cleanup
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)
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
use crate::hw::uart::Uart;
|
use crate::hw::uart::Uart;
|
||||||
use crate::kernel_ref;
|
|
||||||
use types::id::ProcessId;
|
use types::id::ProcessId;
|
||||||
|
|
||||||
|
fn kern() -> &'static mut kernel::Kernel<crate::platform::RiscVPlatform> {
|
||||||
|
unsafe { &mut *crate::kernel_ptr() }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn grant_all(
|
pub fn grant_all(
|
||||||
uart: &Uart,
|
uart: &Uart,
|
||||||
init_pid: ProcessId,
|
init_pid: ProcessId,
|
||||||
@@ -19,48 +22,37 @@ pub fn grant_all(
|
|||||||
.with(types::permission::Permission::Read)
|
.with(types::permission::Permission::Read)
|
||||||
.with(types::permission::Permission::Execute);
|
.with(types::permission::Permission::Execute);
|
||||||
|
|
||||||
// Storage endpoint
|
let storage_ep = kern().create_endpoint()
|
||||||
let storage_ep = kernel_ref().create_endpoint()
|
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "storage endpoint failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "storage endpoint failed"));
|
||||||
|
|
||||||
// Init: slot 0 = ProcessCreate (from boot)
|
kern().grant_capability(init_pid, domain::resource::Resource::Process(storage_pid), all_perms)
|
||||||
// slot 1 = Process(storage)
|
|
||||||
// slot 2 = Endpoint(storage)
|
|
||||||
kernel_ref().grant_capability(init_pid, domain::resource::Resource::Process(storage_pid), all_perms)
|
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
||||||
kernel_ref().grant_capability(init_pid, domain::resource::Resource::Endpoint(storage_ep), all_perms)
|
kern().grant_capability(init_pid, domain::resource::Resource::Endpoint(storage_ep), all_perms)
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
||||||
|
|
||||||
// Storage: slot 0 = Endpoint
|
kern().grant_capability(storage_pid, domain::resource::Resource::Endpoint(storage_ep), ipc_perms)
|
||||||
kernel_ref().grant_capability(storage_pid, domain::resource::Resource::Endpoint(storage_ep), ipc_perms)
|
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
||||||
|
|
||||||
// Display endpoint
|
let display_ep = kern().create_endpoint()
|
||||||
let display_ep = kernel_ref().create_endpoint()
|
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "display endpoint failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "display endpoint failed"));
|
||||||
|
|
||||||
// Display: slot 0 = Endpoint
|
kern().grant_capability(display_pid, domain::resource::Resource::Endpoint(display_ep), ipc_perms)
|
||||||
kernel_ref().grant_capability(display_pid, domain::resource::Resource::Endpoint(display_ep), ipc_perms)
|
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
||||||
|
|
||||||
// Init: slot 3 = Endpoint(display), slot 4 = Process(display)
|
kern().grant_capability(init_pid, domain::resource::Resource::Endpoint(display_ep), all_perms)
|
||||||
kernel_ref().grant_capability(init_pid, domain::resource::Resource::Endpoint(display_ep), all_perms)
|
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
||||||
kernel_ref().grant_capability(init_pid, domain::resource::Resource::Process(display_pid), all_perms)
|
kern().grant_capability(init_pid, domain::resource::Resource::Process(display_pid), all_perms)
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
||||||
|
|
||||||
// Input endpoint
|
let input_ep = kern().create_endpoint()
|
||||||
let input_ep = kernel_ref().create_endpoint()
|
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "input endpoint failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "input endpoint failed"));
|
||||||
|
|
||||||
// Input: slot 0 = Endpoint
|
kern().grant_capability(input_pid, domain::resource::Resource::Endpoint(input_ep), ipc_perms)
|
||||||
kernel_ref().grant_capability(input_pid, domain::resource::Resource::Endpoint(input_ep), ipc_perms)
|
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
||||||
|
|
||||||
// Init: slot 5 = Endpoint(input), slot 6 = Process(input)
|
kern().grant_capability(init_pid, domain::resource::Resource::Endpoint(input_ep), all_perms)
|
||||||
kernel_ref().grant_capability(init_pid, domain::resource::Resource::Endpoint(input_ep), all_perms)
|
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
||||||
kernel_ref().grant_capability(init_pid, domain::resource::Resource::Process(input_pid), all_perms)
|
kern().grant_capability(init_pid, domain::resource::Resource::Process(input_pid), all_perms)
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "grant failed"));
|
||||||
|
|
||||||
uart.write_str("k-os: capabilities granted\n");
|
uart.write_str("k-os: capabilities granted\n");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::hw::uart::Uart;
|
use crate::hw::uart::Uart;
|
||||||
use crate::hw::virtio_blk::VirtioBlk;
|
use crate::hw::virtio_blk::VirtioBlk;
|
||||||
use crate::{board, boot_fs, kernel_ref, mmu};
|
use crate::{boot_fs, mmu};
|
||||||
use types::id::{ProcessId, ThreadId};
|
use types::id::{ProcessId, ThreadId};
|
||||||
|
|
||||||
const USER_VA_BASE: usize = 0x10000;
|
const USER_VA_BASE: usize = 0x10000;
|
||||||
@@ -11,12 +11,16 @@ pub struct LoadedProcess {
|
|||||||
pub entry: usize,
|
pub entry: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn kern() -> &'static mut kernel::Kernel<crate::platform::RiscVPlatform> {
|
||||||
|
unsafe { &mut *crate::kernel_ptr() }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_init(
|
pub fn load_init(
|
||||||
uart: &Uart,
|
uart: &Uart,
|
||||||
blk: &mut VirtioBlk,
|
blk: &mut VirtioBlk,
|
||||||
kernel_pt: &mmu::PageTable,
|
kernel_pt: &mmu::PageTable,
|
||||||
) -> (LoadedProcess, ThreadId) {
|
) -> (LoadedProcess, ThreadId) {
|
||||||
let (pid, tid) = kernel_ref()
|
let (pid, tid) = kern()
|
||||||
.boot(types::bounded::Priority::DEFAULT, types::time::TimeSlice::DEFAULT)
|
.boot(types::bounded::Priority::DEFAULT, types::time::TimeSlice::DEFAULT)
|
||||||
.unwrap_or_else(|_| crate::halt(uart, "boot failed"));
|
.unwrap_or_else(|_| crate::halt(uart, "boot failed"));
|
||||||
|
|
||||||
@@ -35,11 +39,11 @@ pub fn load_server(
|
|||||||
filename: &[u8],
|
filename: &[u8],
|
||||||
label: &str,
|
label: &str,
|
||||||
) -> LoadedProcess {
|
) -> LoadedProcess {
|
||||||
let pid = kernel_ref().create_process_internal()
|
let pid = kern().create_process_internal()
|
||||||
.unwrap_or_else(|| crate::halt(uart, "process create failed"));
|
.unwrap_or_else(|| crate::halt(uart, "process create failed"));
|
||||||
let entry = load_elf(blk, kernel_pt, pid, filename);
|
let entry = load_elf(blk, kernel_pt, pid, filename);
|
||||||
if entry == 0 { crate::halt(uart, "elf not found"); }
|
if entry == 0 { crate::halt(uart, "elf not found"); }
|
||||||
let tid = kernel_ref().spawn_thread_internal(pid)
|
let tid = kern().spawn_thread_internal(pid)
|
||||||
.unwrap_or_else(|| crate::halt(uart, "thread spawn failed"));
|
.unwrap_or_else(|| crate::halt(uart, "thread spawn failed"));
|
||||||
setup_thread(tid, entry);
|
setup_thread(tid, entry);
|
||||||
uart.write_str("k-os: ");
|
uart.write_str("k-os: ");
|
||||||
@@ -50,8 +54,7 @@ pub fn load_server(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_userspace(pid: ProcessId, entry: usize, shared_buf_va: usize) -> ! {
|
pub fn enter_userspace(pid: ProcessId, entry: usize, shared_buf_va: usize) -> ! {
|
||||||
let kern = kernel_ref();
|
let pt_addr = kern().platform_mut().page_table_for(pid);
|
||||||
let pt_addr = kern.platform_mut().page_table_for(pid);
|
|
||||||
if pt_addr != 0 {
|
if pt_addr != 0 {
|
||||||
mmu::activate(unsafe { &*(pt_addr as *const mmu::PageTable) });
|
mmu::activate(unsafe { &*(pt_addr as *const mmu::PageTable) });
|
||||||
}
|
}
|
||||||
@@ -79,7 +82,7 @@ pub fn enter_userspace(pid: ProcessId, entry: usize, shared_buf_va: usize) -> !
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_thread(tid: ThreadId, entry: usize) {
|
fn setup_thread(tid: ThreadId, entry: usize) {
|
||||||
if let Some(ctx) = kernel_ref().thread_context_mut(tid) {
|
if let Some(ctx) = kern().thread_context_mut(tid) {
|
||||||
ctx.set_pc(entry);
|
ctx.set_pc(entry);
|
||||||
ctx.registers_mut()[2] = USER_VA_BASE;
|
ctx.registers_mut()[2] = USER_VA_BASE;
|
||||||
ctx.set_status(1 << 5);
|
ctx.set_status(1 << 5);
|
||||||
@@ -168,6 +171,6 @@ fn load_elf(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel_ref().platform_mut().set_page_table(pid, user_pt as *const mmu::PageTable as usize);
|
kern().platform_mut().set_page_table(pid, user_pt as *const mmu::PageTable as usize);
|
||||||
elf_info.entry_point
|
elf_info.entry_point
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
use crate::hw::uart::Uart;
|
use crate::hw::uart::Uart;
|
||||||
use crate::hw::virtio_gpu::VirtioGpu;
|
use crate::hw::virtio_gpu::VirtioGpu;
|
||||||
use crate::{kernel_ref, mmu};
|
use crate::mmu;
|
||||||
use types::display::Dimension;
|
use types::display::Dimension;
|
||||||
use types::id::ProcessId;
|
use types::id::ProcessId;
|
||||||
|
|
||||||
|
fn kern() -> &'static mut kernel::Kernel<crate::platform::RiscVPlatform> {
|
||||||
|
unsafe { &mut *crate::kernel_ptr() }
|
||||||
|
}
|
||||||
|
|
||||||
const GPU_VA: usize = 0x20000;
|
const GPU_VA: usize = 0x20000;
|
||||||
const VQUEUE_VA: usize = 0x21000;
|
const VQUEUE_VA: usize = 0x21000;
|
||||||
const CMDBUF_VA: usize = 0x23000;
|
const CMDBUF_VA: usize = 0x23000;
|
||||||
@@ -23,7 +27,7 @@ pub fn configure(uart: &Uart, display_pid: ProcessId) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let pt_addr = kernel_ref().platform_mut().page_table_for(display_pid);
|
let pt_addr = kern().platform_mut().page_table_for(display_pid);
|
||||||
let pt = unsafe { &mut *(pt_addr as *mut mmu::PageTable) };
|
let pt = unsafe { &mut *(pt_addr as *mut mmu::PageTable) };
|
||||||
|
|
||||||
map_page(pt, GPU_VA, gpu.base());
|
map_page(pt, GPU_VA, gpu.base());
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use crate::hw::uart::Uart;
|
use crate::hw::uart::Uart;
|
||||||
use crate::{board, kernel_ref, mmu};
|
use crate::{board, mmu};
|
||||||
use types::id::ProcessId;
|
use types::id::ProcessId;
|
||||||
|
|
||||||
const UART_VA: usize = 0x20000;
|
const UART_VA: usize = 0x20000;
|
||||||
|
|
||||||
pub fn configure(uart: &Uart, input_pid: ProcessId) {
|
pub fn configure(uart: &Uart, input_pid: ProcessId) {
|
||||||
let pt_addr = kernel_ref().platform_mut().page_table_for(input_pid);
|
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||||
|
let pt_addr = kern.platform_mut().page_table_for(input_pid);
|
||||||
let pt = unsafe { &mut *(pt_addr as *mut mmu::PageTable) };
|
let pt = unsafe { &mut *(pt_addr as *mut mmu::PageTable) };
|
||||||
|
|
||||||
mmu::map(pt, mmu::Mapping {
|
mmu::map(pt, mmu::Mapping {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
use crate::hw::uart::Uart;
|
use crate::hw::uart::Uart;
|
||||||
use crate::{kernel_ref, mmu};
|
use crate::mmu;
|
||||||
use types::id::ProcessId;
|
use types::id::ProcessId;
|
||||||
|
|
||||||
|
fn kern() -> &'static mut kernel::Kernel<crate::platform::RiscVPlatform> {
|
||||||
|
unsafe { &mut *crate::kernel_ptr() }
|
||||||
|
}
|
||||||
|
|
||||||
const VIRTIO_VA: usize = 0x20000;
|
const VIRTIO_VA: usize = 0x20000;
|
||||||
const VQUEUE_VA: usize = 0x21000;
|
const VQUEUE_VA: usize = 0x21000;
|
||||||
const REQHDR_VA: usize = 0x23000;
|
const REQHDR_VA: usize = 0x23000;
|
||||||
@@ -30,7 +34,7 @@ pub fn configure(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_pt(pid: ProcessId) -> &'static mut mmu::PageTable {
|
fn get_pt(pid: ProcessId) -> &'static mut mmu::PageTable {
|
||||||
let addr = kernel_ref().platform_mut().page_table_for(pid);
|
let addr = kern().platform_mut().page_table_for(pid);
|
||||||
unsafe { &mut *(addr as *mut mmu::PageTable) }
|
unsafe { &mut *(addr as *mut mmu::PageTable) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub struct KernelCell<T> {
|
|||||||
inner: UnsafeCell<MaybeUninit<T>>,
|
inner: UnsafeCell<MaybeUninit<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single-core: no concurrent access. Initialized once before traps are enabled.
|
// Single-core, interrupts disabled during kernel access.
|
||||||
unsafe impl<T> Sync for KernelCell<T> {}
|
unsafe impl<T> Sync for KernelCell<T> {}
|
||||||
|
|
||||||
impl<T> KernelCell<T> {
|
impl<T> KernelCell<T> {
|
||||||
@@ -23,13 +23,11 @@ impl<T> KernelCell<T> {
|
|||||||
self.initialized.store(true, Ordering::Release);
|
self.initialized.store(true, Ordering::Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> &T {
|
/// Returns a raw pointer to the kernel. Callers must ensure
|
||||||
|
/// no aliasing `&mut` references exist. Safe on single-core
|
||||||
|
/// with interrupts disabled during kernel calls.
|
||||||
|
pub fn as_ptr(&self) -> *mut T {
|
||||||
debug_assert!(self.initialized.load(Ordering::Acquire));
|
debug_assert!(self.initialized.load(Ordering::Acquire));
|
||||||
unsafe { (*self.inner.get()).assume_init_ref() }
|
unsafe { (*self.inner.get()).as_mut_ptr() }
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_mut(&self) -> &mut T {
|
|
||||||
debug_assert!(self.initialized.load(Ordering::Acquire));
|
|
||||||
unsafe { (*self.inner.get()).assume_init_mut() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ use kernel_cell::KernelCell;
|
|||||||
|
|
||||||
static KERNEL: KernelCell<kernel::Kernel<platform::RiscVPlatform>> = KernelCell::uninit();
|
static KERNEL: KernelCell<kernel::Kernel<platform::RiscVPlatform>> = KernelCell::uninit();
|
||||||
|
|
||||||
pub fn kernel_ref() -> &'static mut kernel::Kernel<platform::RiscVPlatform> {
|
pub fn kernel_ptr() -> *mut kernel::Kernel<platform::RiscVPlatform> {
|
||||||
KERNEL.get_mut()
|
KERNEL.as_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
global_asm!(
|
global_asm!(
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ fn load_context_to_frame(ctx: &domain::thread::SavedContext, frame: &mut TrapFra
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn apply_pending_result(frame: &mut TrapFrame, tid: types::id::ThreadId) {
|
fn apply_pending_result(frame: &mut TrapFrame, tid: types::id::ThreadId) {
|
||||||
let kern = crate::kernel_ref();
|
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||||
if let Some(result) = kern.take_pending_result(tid) {
|
if let Some(result) = kern.take_pending_result(tid) {
|
||||||
write_result_direct(frame, &result);
|
write_result_direct(frame, &result);
|
||||||
}
|
}
|
||||||
@@ -316,7 +316,7 @@ fn write_result_direct(frame: &mut TrapFrame, result: &kernel::SyscallResult) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn switch_to_thread(frame: &mut TrapFrame, current_tid: types::id::ThreadId, next_tid: types::id::ThreadId) {
|
fn switch_to_thread(frame: &mut TrapFrame, current_tid: types::id::ThreadId, next_tid: types::id::ThreadId) {
|
||||||
let kern = crate::kernel_ref();
|
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||||
|
|
||||||
if let Some(ctx) = kern.thread_context_mut(current_tid) {
|
if let Some(ctx) = kern.thread_context_mut(current_tid) {
|
||||||
save_frame_to_context(frame, ctx);
|
save_frame_to_context(frame, ctx);
|
||||||
@@ -343,7 +343,7 @@ fn switch_to_thread(frame: &mut TrapFrame, current_tid: types::id::ThreadId, nex
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn switch_to_next(frame: &mut TrapFrame, current_tid: types::id::ThreadId) {
|
fn switch_to_next(frame: &mut TrapFrame, current_tid: types::id::ThreadId) {
|
||||||
let kern = crate::kernel_ref();
|
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||||
|
|
||||||
if let Some(ctx) = kern.thread_context_mut(current_tid) {
|
if let Some(ctx) = kern.thread_context_mut(current_tid) {
|
||||||
save_frame_to_context(frame, ctx);
|
save_frame_to_context(frame, ctx);
|
||||||
@@ -392,7 +392,7 @@ fn handle_interrupt(frame: &mut TrapFrame, cause: usize) {
|
|||||||
match cause {
|
match cause {
|
||||||
CAUSE_S_TIMER => {
|
CAUSE_S_TIMER => {
|
||||||
crate::hw::timer::handle_interrupt();
|
crate::hw::timer::handle_interrupt();
|
||||||
let kern = crate::kernel_ref();
|
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||||
let core = types::id::CoreId::from_raw(0);
|
let core = types::id::CoreId::from_raw(0);
|
||||||
if let Some(current_tid) = kern.current_thread() {
|
if let Some(current_tid) = kern.current_thread() {
|
||||||
let decision = kern.handle_tick(core);
|
let decision = kern.handle_tick(core);
|
||||||
@@ -404,7 +404,7 @@ fn handle_interrupt(frame: &mut TrapFrame, cause: usize) {
|
|||||||
CAUSE_S_EXTERNAL => {
|
CAUSE_S_EXTERNAL => {
|
||||||
let irq_num = crate::hw::plic::Plic::claim();
|
let irq_num = crate::hw::plic::Plic::claim();
|
||||||
if irq_num != 0 {
|
if irq_num != 0 {
|
||||||
let kern = crate::kernel_ref();
|
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||||
let irq = types::id::IrqId::from_raw(irq_num as u16);
|
let irq = types::id::IrqId::from_raw(irq_num as u16);
|
||||||
kern.handle_interrupt(irq);
|
kern.handle_interrupt(irq);
|
||||||
crate::hw::plic::Plic::complete(irq_num);
|
crate::hw::plic::Plic::complete(irq_num);
|
||||||
@@ -420,7 +420,7 @@ fn handle_exception(frame: &mut TrapFrame, scause: usize) {
|
|||||||
frame.sepc += 4;
|
frame.sepc += 4;
|
||||||
|
|
||||||
if let Some(syscall) = decode_syscall(frame) {
|
if let Some(syscall) = decode_syscall(frame) {
|
||||||
let kern = crate::kernel_ref();
|
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||||
let current_tid = kern.current_thread();
|
let current_tid = kern.current_thread();
|
||||||
let outcome = kern.handle_syscall(syscall);
|
let outcome = kern.handle_syscall(syscall);
|
||||||
write_result(frame, &outcome);
|
write_result(frame, &outcome);
|
||||||
@@ -459,7 +459,7 @@ fn handle_exception(frame: &mut TrapFrame, scause: usize) {
|
|||||||
uart.write_hex(frame.sepc);
|
uart.write_hex(frame.sepc);
|
||||||
uart.put_char(b'\n');
|
uart.put_char(b'\n');
|
||||||
|
|
||||||
let kern = crate::kernel_ref();
|
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||||
if let Some(current_tid) = kern.current_thread() {
|
if let Some(current_tid) = kern.current_thread() {
|
||||||
let fault = match scause {
|
let fault = match scause {
|
||||||
2 => domain::fault::Fault::IllegalInstruction,
|
2 => domain::fault::Fault::IllegalInstruction,
|
||||||
|
|||||||
@@ -217,6 +217,43 @@ impl<P: Platform> Kernel<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn destroy_process(&mut self, pid: ProcessId) {
|
||||||
|
// Collect thread IDs before cleanup
|
||||||
|
let thread_ids: [Option<ThreadId>; 4] = match self.processes.get(pid) {
|
||||||
|
Ok(p) => {
|
||||||
|
let mut ids = [None; 4];
|
||||||
|
for (i, tid) in p.thread_ids().enumerate() {
|
||||||
|
if i < 4 { ids[i] = Some(tid); }
|
||||||
|
}
|
||||||
|
ids
|
||||||
|
}
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.cleanup_threads(&thread_ids);
|
||||||
|
|
||||||
|
// Free allocated pages back to pool
|
||||||
|
if let Some(pm) = &self.process_memory[pid.raw() as usize] {
|
||||||
|
let page_count = pm.page_count();
|
||||||
|
if page_count > 0 {
|
||||||
|
// Pages were allocated from the pool but we don't track individual
|
||||||
|
// addresses. The page pool uses contiguous allocation, so we can't
|
||||||
|
// free without knowing the base address. Mark as returned for accounting.
|
||||||
|
// Full page tracking is a future improvement.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unblock threads in other processes that were blocked waiting
|
||||||
|
// on endpoints where this process's threads were the other side.
|
||||||
|
// The cleanup_threads call above already removed this process's
|
||||||
|
// threads from all endpoint wait queues. Threads blocked waiting
|
||||||
|
// for this process will eventually time out or be rescheduled
|
||||||
|
// when the endpoint is revoked.
|
||||||
|
|
||||||
|
let _ = self.processes.destroy(pid);
|
||||||
|
self.process_memory[pid.raw() as usize] = None;
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn cleanup_threads(&mut self, thread_ids: &[Option<ThreadId>; 4]) {
|
pub(crate) fn cleanup_threads(&mut self, thread_ids: &[Option<ThreadId>; 4]) {
|
||||||
use domain::scheduler::Scheduler;
|
use domain::scheduler::Scheduler;
|
||||||
for slot in thread_ids {
|
for slot in thread_ids {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ impl<P: Platform> Kernel<P> {
|
|||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Try to deliver fault to a fault handler endpoint (if configured)
|
||||||
if let Ok(process) = self.processes.get(pid) {
|
if let Ok(process) = self.processes.get(pid) {
|
||||||
if let Some(handler_slot) = process.fault_handler() {
|
if let Some(handler_slot) = process.fault_handler() {
|
||||||
if let Ok(cap) = process.capabilities().get(handler_slot) {
|
if let Ok(cap) = process.capabilities().get(handler_slot) {
|
||||||
@@ -46,21 +47,6 @@ impl<P: Platform> Kernel<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let thread_ids: [Option<types::id::ThreadId>; 4] = {
|
self.destroy_process(pid);
|
||||||
match self.processes.get(pid) {
|
|
||||||
Ok(p) => {
|
|
||||||
let mut ids = [None; 4];
|
|
||||||
for (i, t) in p.thread_ids().enumerate() {
|
|
||||||
if i < 4 { ids[i] = Some(t); }
|
|
||||||
}
|
|
||||||
ids
|
|
||||||
}
|
|
||||||
Err(_) => return,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.cleanup_threads(&thread_ids);
|
|
||||||
let _ = self.processes.destroy(pid);
|
|
||||||
self.process_memory[pid.raw() as usize] = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,6 +151,8 @@ impl<P: Platform> Kernel<P> {
|
|||||||
|
|
||||||
let message = self.pending_messages[sender_tid.raw() as usize]
|
let message = self.pending_messages[sender_tid.raw() as usize]
|
||||||
.take()
|
.take()
|
||||||
|
// A sender in the wait queue must have a pending message.
|
||||||
|
// If not, the kernel state is inconsistent.
|
||||||
.unwrap_or_else(|| domain::message::Message::empty());
|
.unwrap_or_else(|| domain::message::Message::empty());
|
||||||
|
|
||||||
self.pending_results[sender_tid.raw() as usize] = Some(SyscallResult::Ok);
|
self.pending_results[sender_tid.raw() as usize] = Some(SyscallResult::Ok);
|
||||||
|
|||||||
@@ -50,25 +50,7 @@ impl<P: Platform> Kernel<P> {
|
|||||||
_caller_tid: types::id::ThreadId,
|
_caller_tid: types::id::ThreadId,
|
||||||
pid: types::id::ProcessId,
|
pid: types::id::ProcessId,
|
||||||
) -> SyscallOutcome {
|
) -> SyscallOutcome {
|
||||||
let thread_ids: [Option<types::id::ThreadId>; 4] = {
|
self.destroy_process(pid);
|
||||||
match self.processes.get(pid) {
|
|
||||||
Ok(p) => {
|
|
||||||
let mut ids = [None; 4];
|
|
||||||
for (i, tid) in p.thread_ids().enumerate() {
|
|
||||||
if i < 4 {
|
|
||||||
ids[i] = Some(tid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ids
|
|
||||||
}
|
|
||||||
Err(_) => return SyscallOutcome::TerminateCaller,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.cleanup_threads(&thread_ids);
|
|
||||||
|
|
||||||
let _ = self.processes.destroy(pid);
|
|
||||||
self.process_memory[pid.raw() as usize] = None;
|
|
||||||
SyscallOutcome::TerminateCaller
|
SyscallOutcome::TerminateCaller
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,8 +67,7 @@ impl<P: Platform> Kernel<P> {
|
|||||||
if let Ok(process) = self.processes.get_mut(pid) {
|
if let Ok(process) = self.processes.get_mut(pid) {
|
||||||
process.remove_thread(caller_tid);
|
process.remove_thread(caller_tid);
|
||||||
if process.thread_ids().count() == 0 {
|
if process.thread_ids().count() == 0 {
|
||||||
let _ = self.processes.destroy(pid);
|
self.destroy_process(pid);
|
||||||
self.process_memory[pid.raw() as usize] = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user