feat(kernel): SystemControl cap for halt, board device table + boot caps to init, RegionAddress syscall, idle loop services irqs
This commit is contained in:
@@ -218,32 +218,66 @@ fn switch_to_next(frame: &mut TrapFrame, current_tid: types::id::ThreadId) {
|
||||
save_frame_to_context(frame, ctx);
|
||||
}
|
||||
|
||||
if let Some(next_tid) = kern.pick_next_thread() {
|
||||
let next_pid = kern.thread_process(next_tid);
|
||||
let current_pid = kern.thread_process(current_tid);
|
||||
let next_tid = next_runnable();
|
||||
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||
let next_pid = kern.thread_process(next_tid);
|
||||
let current_pid = kern.thread_process(current_tid);
|
||||
|
||||
let core = types::id::CoreId::from_raw(0);
|
||||
let _ = kern.set_thread_running(next_tid, core);
|
||||
let core = types::id::CoreId::from_raw(0);
|
||||
let _ = kern.set_thread_running(next_tid, core);
|
||||
|
||||
if let Some(ctx) = kern.thread_context(next_tid) {
|
||||
load_context_to_frame(ctx, frame);
|
||||
if let Some(ctx) = kern.thread_context(next_tid) {
|
||||
load_context_to_frame(ctx, frame);
|
||||
}
|
||||
|
||||
apply_pending_result(frame, next_tid);
|
||||
|
||||
if next_pid != current_pid
|
||||
&& let Some(pid) = next_pid
|
||||
{
|
||||
let pt_addr = kern.platform_mut().page_table_for(pid);
|
||||
if pt_addr != 0 {
|
||||
let pt = unsafe { &*(pt_addr as *const crate::mmu::PageTable) };
|
||||
crate::mmu::activate(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply_pending_result(frame, next_tid);
|
||||
/// The next thread to run, idling until an interrupt makes one ready.
|
||||
///
|
||||
/// We are inside a trap, so SIE is clear and interrupts are not taken.
|
||||
/// `wfi` still wakes once one is pending, and it is then serviced here by
|
||||
/// polling `sip`, which is how a driver blocked on its IRQ notification
|
||||
/// gets woken when nothing else can run.
|
||||
fn next_runnable() -> types::id::ThreadId {
|
||||
loop {
|
||||
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||
if let Some(tid) = kern.pick_next_thread() {
|
||||
return tid;
|
||||
}
|
||||
unsafe { core::arch::asm!("wfi") };
|
||||
let sip: usize;
|
||||
unsafe { core::arch::asm!("csrr {0}, sip", out(reg) sip) };
|
||||
if sip & (1 << CAUSE_S_TIMER) != 0 {
|
||||
// No thread is running, so there is no time slice to charge.
|
||||
crate::hw::timer::handle_interrupt();
|
||||
}
|
||||
if sip & (1 << CAUSE_S_EXTERNAL) != 0 {
|
||||
dispatch_external();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if next_pid != current_pid
|
||||
&& let Some(pid) = next_pid
|
||||
{
|
||||
let pt_addr = kern.platform_mut().page_table_for(pid);
|
||||
if pt_addr != 0 {
|
||||
let pt = unsafe { &*(pt_addr as *const crate::mmu::PageTable) };
|
||||
crate::mmu::activate(pt);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
loop {
|
||||
unsafe { core::arch::asm!("wfi") };
|
||||
/// Claims every pending PLIC interrupt and hands each to the kernel.
|
||||
fn dispatch_external() {
|
||||
loop {
|
||||
let irq_num = crate::hw::plic::Plic::claim();
|
||||
if irq_num == 0 {
|
||||
return;
|
||||
}
|
||||
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||
kern.handle_interrupt(types::id::IrqId::from_raw(irq_num as u16));
|
||||
crate::hw::plic::Plic::complete(irq_num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,15 +306,7 @@ fn handle_interrupt(frame: &mut TrapFrame, cause: usize) {
|
||||
}
|
||||
}
|
||||
}
|
||||
CAUSE_S_EXTERNAL => {
|
||||
let irq_num = crate::hw::plic::Plic::claim();
|
||||
if irq_num != 0 {
|
||||
let kern = unsafe { &mut *crate::kernel_ptr() };
|
||||
let irq = types::id::IrqId::from_raw(irq_num as u16);
|
||||
kern.handle_interrupt(irq);
|
||||
crate::hw::plic::Plic::complete(irq_num);
|
||||
}
|
||||
}
|
||||
CAUSE_S_EXTERNAL => dispatch_external(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user