lifeblood_os/src/arch/virt/trap.rs
2025-09-12 18:25:48 -07:00

251 lines
8.5 KiB
Rust

use crate::arch::virt::{plic, serial_port};
use crate::rough_panic;
use crate::syscalls::usize2sc;
use crate::trafficcontrol::{TC, context_switch, handle_syscall, MAX_TASKS, TrafficControl, Task};
use core::arch::asm;
use crate::spinlock::Spinlock;
unsafe extern "C" {
pub fn _tstack_end();
pub fn _hung_system() -> !;
}
pub static KERNEL_TRAP_FRAME: Spinlock<TrapFrame> = Spinlock::new(TrapFrame {
regs: [0; 32],
satp: 0,
trap_stack: 0,
hartid: 0,
});
#[repr(C)]
#[derive(Clone)]
pub struct TrapFrame {
pub regs: [usize; 32], // 0 - 128
pub satp: usize, // 128 - 132
pub trap_stack: usize, // 132 - 136
pub hartid: usize, // 136 - 140
}
pub fn enable_traps() {
let tf = {
let mut lock = KERNEL_TRAP_FRAME.lock();
lock.trap_stack = _tstack_end as usize;
unsafe { KERNEL_TRAP_FRAME.leak() }
};
// setup mscratch to hold trap frame
unsafe {
let addr = tf;
asm!("csrw mscratch, {}", in(reg) addr);
let mie: u32 = (1 << 3) | (1 << 7) | (1 << 11);
asm!("csrw mie, {}", in(reg) mie);
}
}
#[unsafe(no_mangle)]
extern "C" fn ktrap(
epc: usize,
tval: usize,
cause: usize,
hart: usize,
status: usize,
frame: &mut TrapFrame,
) -> usize {
#[allow(arithmetic_overflow)]
let is_async = { (cause >> 63) & 1 == 1 };
let cause_num = cause & 0xfff;
let mut return_pc = epc;
if is_async {
match cause_num {
3 => {
//send_ka(KernelAlert::MachineSoftwareInterrupt);
}
7 => {
let mtimecmp = 0x0200_4000 as *mut u64;
let mtime = 0x0200_bff8 as *const u64;
// one sec
const FREQ: u64 = 10_000_000;
const CSPS: u64 = 5000;
unsafe { mtimecmp.write_volatile(mtime.read_volatile().wrapping_add(FREQ / CSPS)) };
//send_ka(KernelAlert::TimerInterrupt);
// context switch
let mut tc = TC.lock();
if !tc.first_task_setup {
let mut first_task = MAX_TASKS + 1;
for i in 0..MAX_TASKS {
if tc.tasks[i].is_some() {
first_task = i;
break;
}
}
if first_task < MAX_TASKS {
if let Some(task) = tc.tasks[first_task].take() {
tc.first_task_setup = true;
return_pc = task.epc;
*frame = task.trap_frame.clone();
tc.tasks[first_task] = Some(task);
tc.current = first_task;
}
}
} else {
let ci = tc.current;
if tc.tasks.get(ci).is_some() {
// only switch if we have a task
let mut curtask = unsafe { tc.tasks[ci].take().unwrap_unchecked() };
if !tc.hung_system {
curtask.epc = epc;
curtask.trap_frame = frame.clone();
}
let next = context_switch(&mut tc, curtask);
if let Some(next) = next {
return_pc = next.epc;
*frame = next.trap_frame.clone();
tc.hung_system = false;
} else {
return_pc = _hung_system as usize;
tc.hung_system = true;
}
} else {
rough_panic(['n', 'm', 'p']);
}
}
}
11 => {
//send_ka(KernelAlert::MachineExternalInterrupt);
if let Some(interrupt) = plic::next() {
#[cfg(feature = "dev_virtio")]
if (1..=8).contains(&interrupt) {
// virtio
let mut tc = TC.lock();
crate::dev::virtio::handle_interrupt(interrupt, &mut tc);
}
if interrupt == 10 {
// uart
let uart = unsafe { serial_port().unwrap_unchecked() };
if let Some(c) = uart.get() {
if c != 0 {
let mut tc = TC.lock();
tc.write_inbuf(c);
}
}
}
plic::complete(interrupt);
}
}
_ => {
#[cfg(feature = "debug_messages")]
panic!("unhandled async trap cpu{} -> {}", hart, cause_num);
#[cfg(not(feature = "debug_messages"))]
rough_panic(['t', 'r', 'a'])
}
}
} else {
match cause_num {
2 => {
#[cfg(feature = "debug_messages")]
panic!(
"illegal instruction CPU#{} -> 0x{:08x}: 0x{:08x}\n",
hart, epc, tval
);
#[cfg(not(feature = "debug_messages"))]
rough_panic(['t', 'i', 'l'])
}
x if x == 8 || x == 9 || x == 11 => {
let (ret, sus) = handle_syscall(
usize2sc(frame.regs[10]),
frame.regs[11],
frame.regs[12],
frame.regs[13],
frame.regs[14],
frame.regs[15],
frame.regs[16],
);
frame.regs[10] = ret;
return_pc += 4;
if sus {
// move to another task
let mut tc = TC.lock();
let ci = tc.current;
let mut curtask = unsafe { tc.tasks[ci].take().unwrap_unchecked() };
if !tc.hung_system {
curtask.epc = return_pc;
curtask.trap_frame = frame.clone();
}
let next = context_switch(&mut tc, curtask);
if let Some(next) = next {
return_pc = next.epc;
*frame = next.trap_frame.clone();
tc.hung_system = false;
} else {
return_pc = _hung_system as usize;
tc.hung_system = true;
}
}
}
/*
9 => {
// super
//send_ka(KernelAlert::SysCall);
let ret = handle_syscall(
usize2sc(frame.regs[10]),
frame.regs[11],
frame.regs[12],
frame.regs[13],
frame.regs[14],
frame.regs[15],
frame.regs[16],
);
frame.regs[10] = ret;
return_pc += 4;
}
11 => {
// mach
//send_ka(KernelAlert::SysCall);
let ret = handle_syscall(
usize2sc(frame.regs[10]),
frame.regs[11],
frame.regs[12],
frame.regs[13],
frame.regs[14],
frame.regs[15],
frame.regs[16],
);
frame.regs[10] = ret;
return_pc += 4;
}
*/
12 => {
//send_ka(KernelAlert::IPageFault);
return_pc += 4;
}
13 => {
//send_ka(KernelAlert::LPageFault);
return_pc += 4;
}
15 => {
//send_ka(KernelAlert::SPageFault);
return_pc += 4;
}
_ => {
#[cfg(feature = "debug_messages")]
panic!("unhandled sync trap cpu{} -> {}", hart, cause_num);
#[cfg(not(feature = "debug_messages"))]
{
let uart = crate::uart::UART::new(0x1000_0000);
uart.put(b'0' + cause_num as u8);
rough_panic(['t', 'r', 's'])
}
}
}
}
if return_pc < 0x8000_0000 {
rough_panic(['r', 'a', 'n'])
}
return_pc
}