diff --git a/Cargo.toml b/Cargo.toml index bd4d18f..23a2856 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [profile.dev] panic = "abort" +opt-level = 0 [profile.release] panic = "abort" diff --git a/src/boot.rs b/src/boot.rs index e504b76..ece09b2 100644 --- a/src/boot.rs +++ b/src/boot.rs @@ -39,6 +39,7 @@ pub extern "C" fn machine_mode_entry() { // Delegate timer interrupt set_csr!(mideleg, 1 << 5); + set_csr!(medeleg, 1 << 8); unsafe { setup_supervisor_trap_handler(); diff --git a/src/boot/sbi.rs b/src/boot/sbi.rs index 2b77a90..3d4eab1 100644 --- a/src/boot/sbi.rs +++ b/src/boot/sbi.rs @@ -1,11 +1,11 @@ #[non_exhaustive] -#[repr(u64)] +#[repr(usize)] pub enum EextensionID { Time = 0x54494D45, } #[non_exhaustive] -#[repr(u64)] +#[repr(usize)] pub enum TimerFunctionID { SetTimer = 0x0, } diff --git a/src/interrupt.rs b/src/interrupt.rs index a009811..5f05327 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -1,20 +1,29 @@ +use alloc::str; +use log::info; + use crate::{ boot::sbi::{EextensionID, TimerFunctionID}, clear_csr, generate_trap_handler, - process::ExecutionContext, + process::{sleep, ExecutionContext}, read_csr, riscv::disable_interrupt, scheduler::scheduler, set_csr, + syscall::SysCall, time::{setup_next_timer_interrupt, IRQ_M_TIMER}, write_csr, }; -use core::arch::naked_asm; +use core::{arch::naked_asm, time::Duration}; use crate::time::{setup_timer_interrupt, timer_interrupt}; #[unsafe(no_mangle)] -unsafe extern "C" fn machine_trap_handler(mcause: u64, mie: u64, mip: u64) { +unsafe extern "C" fn machine_trap_handler( + mcause: u64, + mie: u64, + mip: u64, + interrupt_state: *const MachineInterruptState, +) { let mepc = read_csr!(mepc); let mtval = read_csr!(mtval); if mcause & (1 << 63) == 0 { @@ -30,27 +39,19 @@ unsafe extern "C" fn machine_trap_handler(mcause: u64, mie: u64, mip: u64) { 8 => "Environment call from U-mode", 9 => { // Environment call from S-mode - let eid: u64; - let fid: u64; - unsafe { - core::arch::asm!( - "mv {}, a7", - "mv {}, a6", - out(reg) eid, - out(reg) fid, - ); - } + let eid = unsafe { (*interrupt_state).a[7] }; + let fid = unsafe { (*interrupt_state).a[6] }; #[allow(clippy::single_match)] match eid { - c if c == EextensionID::Time as u64 => match fid { - c if c == TimerFunctionID::SetTimer as u64 => { + c if c == EextensionID::Time as usize => match fid { + c if c == TimerFunctionID::SetTimer as usize => { clear_csr!(mip, 1 << 5); setup_next_timer_interrupt(); } _ => {} }, - _ => {} + _ => panic!("Unhandled SBI call eid={eid}, fid={fid}"), } // Advance mepc to exit the ecall @@ -86,26 +87,56 @@ unsafe extern "C" fn machine_trap_handler(mcause: u64, mie: u64, mip: u64) { #[unsafe(no_mangle)] unsafe extern "C" fn supervisor_trap_handler( - interrupt_state: *const ExecutionContext, + interrupt_state: *mut ExecutionContext, scause: u64, _sie: u64, _sip: u64, ) -> *const ExecutionContext { - #[allow(clippy::single_match)] - match scause & !(1 << 63) { - 5 => { - unsafe { - core::arch::asm!( - "ecall", - in("a0") 0, - in("a6") TimerFunctionID::SetTimer as u64, - in("a7") EextensionID::Time as u64, - ); + if scause & (1 << 63) == 0 { + #[allow(clippy::single_match)] + match scause & !(1 << 63) { + 8 => { + // Environment call from S-mode + let syscall_u64: u64 = unsafe { (*interrupt_state).a[0] }; + let a1: u64 = unsafe { (*interrupt_state).a[1] }; + let a2: u64 = unsafe { (*interrupt_state).a[2] }; + let syscall: SysCall = syscall_u64.into(); + match syscall { + SysCall::NanoSleep => sleep(Duration::new(a1, a2 as u32)), + SysCall::WriteTemp => { + info!("{}", unsafe { + str::from_raw_parts(a1 as *const u8, a2 as usize) + }) + } + SysCall::Unimplemented => { + unimplemented!("Syscall {syscall_u64} is not implemented") + } + } + + // Advance sepc to exit the ecall + unsafe { + (*interrupt_state).mepc = (*interrupt_state).mepc.byte_add(4); + } } - timer_interrupt(); - return scheduler(unsafe { *interrupt_state }); + _ => {} + } + } else { + #[allow(clippy::single_match)] + match scause & !(1 << 63) { + 5 => { + unsafe { + core::arch::asm!( + "ecall", + in("a0") 0, + in("a6") TimerFunctionID::SetTimer as u64, + in("a7") EextensionID::Time as u64, + ); + } + timer_interrupt(); + return scheduler(unsafe { *interrupt_state }); + } + _ => {} } - _ => {} } interrupt_state } @@ -147,6 +178,7 @@ unsafe extern "C" fn _machine_mode_trap() { csrr a0, mcause csrr a1, mie csrr a2, mip + mv a3, sp jal machine_trap_handler # Restore registers @@ -240,8 +272,8 @@ macro_rules! generate_trap_handler { # Restore registers ld t0, 248(a0) csrw sepc, t0 - // ld t0, 256(a0) - // csrw sstatus, t0 + ld t0, 256(a0) + csrw sstatus, t0 ld ra, 0(a0) ld sp, 8(a0) ld gp, 16(a0) @@ -275,8 +307,6 @@ macro_rules! generate_trap_handler { ld a0, 32(a0) - // addi sp, sp, 264 - ", stringify!($mode), "ret" @@ -284,3 +314,10 @@ macro_rules! generate_trap_handler { } }; } + +#[repr(C)] +struct MachineInterruptState { + pub a: [usize; 8], + pub t: [usize; 7], + pub ra: usize, +} diff --git a/src/main.rs b/src/main.rs index f288aa8..0ba881f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,22 @@ #![no_std] #![no_main] #![allow(static_mut_refs)] -#![feature(riscv_ext_intrinsics, const_trait_impl, iter_map_windows)] - -use core::{arch::riscv64::wfi, time::Duration}; +#![feature( + riscv_ext_intrinsics, + const_trait_impl, + iter_map_windows, + str_from_raw_parts +)] use embedded_alloc::LlffHeap as Heap; use log::info; use crate::{ io::init_log, - process::{create_processus, sleep}, + process::create_processus, riscv::enable_supervisor_interrupt, scheduler::{idle, scheduler_init}, + user::{proc2, test}, vga::{Color, Vga}, }; @@ -26,31 +30,18 @@ mod panic_handler; mod process; mod riscv; mod scheduler; +mod syscall; mod time; mod uart; +mod user; mod vga; pub const HEAP_SIZE: usize = 4096; #[global_allocator] static HEAP: Heap = Heap::empty(); -extern "C" fn test() { - loop { - info!("test"); - enable_supervisor_interrupt(); - sleep(Duration::new(2, 0)); - unsafe { wfi() }; - } -} - -extern "C" fn proc2() { - loop { - info!("proc2"); - enable_supervisor_interrupt(); - sleep(Duration::new(3, 0)); - unsafe { wfi() }; - } -} +// Usize is assumed to be an u64 in the whole kernel +const _: () = assert!(size_of::() == size_of::()); #[unsafe(no_mangle)] pub extern "C" fn supervisor_mode_entry() { @@ -59,7 +50,7 @@ pub extern "C" fn supervisor_mode_entry() { init_log().unwrap(); Vga::init(); scheduler_init(); - enable_supervisor_interrupt(); + // enable_supervisor_interrupt(); } info!("Hello World !"); @@ -68,5 +59,6 @@ pub extern "C" fn supervisor_mode_entry() { create_processus(test, "proc1"); create_processus(proc2, "proc2"); + enable_supervisor_interrupt(); idle(); } diff --git a/src/process.rs b/src/process.rs index 1bdf074..27ffe88 100644 --- a/src/process.rs +++ b/src/process.rs @@ -20,15 +20,15 @@ pub enum ProcessState { #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct ExecutionContext { - pub ra: *const usize, - pub sp: *const usize, - pub gp: usize, - pub tp: usize, - pub a: [usize; 8], - pub t: [usize; 7], - pub s: [usize; 12], - pub mepc: *const usize, - pub mstatus: usize, + pub ra: *const u64, + pub sp: *const u64, + pub gp: u64, + pub tp: u64, + pub a: [u64; 8], + pub t: [u64; 7], + pub s: [u64; 12], + pub mepc: *const u64, + pub mstatus: u64, } pub struct Process { @@ -37,8 +37,7 @@ pub struct Process { pub state: ProcessState, pub wake_time: Duration, pub ctx: ExecutionContext, - pub entry_point: Option, - pub stack: [usize; STACK_SIZE], + pub stack: [u64; STACK_SIZE], } impl core::fmt::Debug for Process { @@ -49,7 +48,6 @@ impl core::fmt::Debug for Process { .field("state", &self.state) .field("wake_time", &self.wake_time) .field("ctx", &self.ctx) - .field("entry_point", &self.entry_point) .field("stack", &format!("[_; {}]", STACK_SIZE)) .finish() } @@ -71,10 +69,9 @@ pub fn create_processus>(code: extern "C" fn(), name: T) -> i64 PROCESS_TABLE[next_pid].pid = next_pid as i64; PROCESS_TABLE[next_pid].name = name.into(); PROCESS_TABLE[next_pid].state = ProcessState::Activable; - PROCESS_TABLE[next_pid].entry_point = Some(code); - PROCESS_TABLE[next_pid].ctx.a[0] = code as usize; + PROCESS_TABLE[next_pid].ctx.a[0] = code as usize as u64; PROCESS_TABLE[next_pid].ctx.mepc = processus_launcher as *const _; - PROCESS_TABLE[next_pid].ctx.mstatus = 1 << 11; + PROCESS_TABLE[next_pid].ctx.mstatus = 1 << 1 | 1 << 5; PROCESS_TABLE[next_pid].ctx.sp = &raw const PROCESS_TABLE[next_pid].stack[STACK_SIZE - 1]; } diff --git a/src/scheduler.rs b/src/scheduler.rs index 8b34cc0..05c5f0d 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -28,14 +28,14 @@ pub static mut PROCESS_TABLE: LazyCell<[Process; PROCESSUS_COUNT]> = LazyCell::n mepc: core::ptr::null(), mstatus: 0, }, - entry_point: None, stack: [0; _], }) }); pub extern "C" fn idle() { loop { - // enable_supervisor_interrupt(); + // write_string_temp("idle"); + // info!("idle"); unsafe { wfi(); } diff --git a/src/syscall.rs b/src/syscall.rs new file mode 100644 index 0000000..44e6936 --- /dev/null +++ b/src/syscall.rs @@ -0,0 +1,88 @@ +use core::time::Duration; + +#[repr(u64)] +pub enum SysCall { + NanoSleep = 101, + WriteTemp = 999, + Unimplemented = 1 << 31, +} + +impl From for SysCall { + fn from(value: u64) -> Self { + match value { + 101 => SysCall::NanoSleep, + 999 => SysCall::WriteTemp, + _ => SysCall::Unimplemented, + } + } +} + +#[allow(clippy::too_many_arguments)] +unsafe fn _syscall( + syscall: SysCall, + a1: u64, + a2: u64, + a3: u64, + a4: u64, + a5: u64, + a6: u64, + a7: u64, +) { + unsafe { + core::arch::asm!( + "ecall", + in("a0") syscall as usize, + in("a1") a1, + in("a2") a2, + in("a3") a3, + in("a4") a4, + in("a5") a5, + in("a6") a6, + in("a7") a7, + ); + } +} + +macro_rules! syscall { + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr, $a7:expr) => { + _syscall($syscall, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => { + syscall!($syscall, $a1, $a2, $a3, $a4, $a5, $a6, 0) + }; + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => { + syscall!($syscall, $a1, $a2, $a3, $a4, $a5, 0) + }; + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => { + syscall!($syscall, $a1, $a2, $a3, $a4, 0) + }; + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr) => { + syscall!($syscall, $a1, $a2, $a3, 0) + }; + ($syscall:expr, $a1:expr, $a2:expr) => { + syscall!($syscall, $a1, $a2, 0) + }; + ($syscall:expr, $a1:expr) => { + syscall!($syscall, $a1, 0) + }; + ($syscall:expr) => { + syscall!($syscall, 0) + }; +} + +pub fn sleep(duration: Duration) { + unsafe { + let (duration_secs, duration_nanos) = (duration.as_secs(), duration.subsec_nanos() as u64); + syscall!(SysCall::NanoSleep, duration_secs, duration_nanos); + } +} + +pub fn write_string_temp(content: &str) { + unsafe { + syscall!( + SysCall::WriteTemp, + content.as_ptr() as u64, + content.len() as u64 + ); + } +} diff --git a/src/user.rs b/src/user.rs new file mode 100644 index 0000000..5082b30 --- /dev/null +++ b/src/user.rs @@ -0,0 +1,19 @@ +use core::time::Duration; + +use crate::syscall::{sleep, write_string_temp}; + +pub extern "C" fn test() { + loop { + write_string_temp("test"); + // enable_supervisor_interrupt(); + sleep(Duration::new(2, 0)); + } +} + +pub extern "C" fn proc2() { + loop { + write_string_temp("proc2"); + // enable_supervisor_interrupt(); + sleep(Duration::new(3, 0)); + } +}