Adds syscall for sleep and print and makes process work in user mode

This commit is contained in:
2026-02-12 11:36:04 +01:00
parent 8a5c17482c
commit 369ff5fef4
9 changed files with 210 additions and 75 deletions

View File

@@ -5,6 +5,7 @@ edition = "2024"
[profile.dev] [profile.dev]
panic = "abort" panic = "abort"
opt-level = 0
[profile.release] [profile.release]
panic = "abort" panic = "abort"

View File

@@ -39,6 +39,7 @@ pub extern "C" fn machine_mode_entry() {
// Delegate timer interrupt // Delegate timer interrupt
set_csr!(mideleg, 1 << 5); set_csr!(mideleg, 1 << 5);
set_csr!(medeleg, 1 << 8);
unsafe { unsafe {
setup_supervisor_trap_handler(); setup_supervisor_trap_handler();

View File

@@ -1,11 +1,11 @@
#[non_exhaustive] #[non_exhaustive]
#[repr(u64)] #[repr(usize)]
pub enum EextensionID { pub enum EextensionID {
Time = 0x54494D45, Time = 0x54494D45,
} }
#[non_exhaustive] #[non_exhaustive]
#[repr(u64)] #[repr(usize)]
pub enum TimerFunctionID { pub enum TimerFunctionID {
SetTimer = 0x0, SetTimer = 0x0,
} }

View File

@@ -1,20 +1,29 @@
use alloc::str;
use log::info;
use crate::{ use crate::{
boot::sbi::{EextensionID, TimerFunctionID}, boot::sbi::{EextensionID, TimerFunctionID},
clear_csr, generate_trap_handler, clear_csr, generate_trap_handler,
process::ExecutionContext, process::{sleep, ExecutionContext},
read_csr, read_csr,
riscv::disable_interrupt, riscv::disable_interrupt,
scheduler::scheduler, scheduler::scheduler,
set_csr, set_csr,
syscall::SysCall,
time::{setup_next_timer_interrupt, IRQ_M_TIMER}, time::{setup_next_timer_interrupt, IRQ_M_TIMER},
write_csr, write_csr,
}; };
use core::arch::naked_asm; use core::{arch::naked_asm, time::Duration};
use crate::time::{setup_timer_interrupt, timer_interrupt}; use crate::time::{setup_timer_interrupt, timer_interrupt};
#[unsafe(no_mangle)] #[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 mepc = read_csr!(mepc);
let mtval = read_csr!(mtval); let mtval = read_csr!(mtval);
if mcause & (1 << 63) == 0 { 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", 8 => "Environment call from U-mode",
9 => { 9 => {
// Environment call from S-mode // Environment call from S-mode
let eid: u64; let eid = unsafe { (*interrupt_state).a[7] };
let fid: u64; let fid = unsafe { (*interrupt_state).a[6] };
unsafe {
core::arch::asm!(
"mv {}, a7",
"mv {}, a6",
out(reg) eid,
out(reg) fid,
);
}
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
match eid { match eid {
c if c == EextensionID::Time as u64 => match fid { c if c == EextensionID::Time as usize => match fid {
c if c == TimerFunctionID::SetTimer as u64 => { c if c == TimerFunctionID::SetTimer as usize => {
clear_csr!(mip, 1 << 5); clear_csr!(mip, 1 << 5);
setup_next_timer_interrupt(); setup_next_timer_interrupt();
} }
_ => {} _ => {}
}, },
_ => {} _ => panic!("Unhandled SBI call eid={eid}, fid={fid}"),
} }
// Advance mepc to exit the ecall // Advance mepc to exit the ecall
@@ -86,11 +87,40 @@ unsafe extern "C" fn machine_trap_handler(mcause: u64, mie: u64, mip: u64) {
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
unsafe extern "C" fn supervisor_trap_handler( unsafe extern "C" fn supervisor_trap_handler(
interrupt_state: *const ExecutionContext, interrupt_state: *mut ExecutionContext,
scause: u64, scause: u64,
_sie: u64, _sie: u64,
_sip: u64, _sip: u64,
) -> *const ExecutionContext { ) -> *const ExecutionContext {
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);
}
}
_ => {}
}
} else {
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
match scause & !(1 << 63) { match scause & !(1 << 63) {
5 => { 5 => {
@@ -107,6 +137,7 @@ unsafe extern "C" fn supervisor_trap_handler(
} }
_ => {} _ => {}
} }
}
interrupt_state interrupt_state
} }
@@ -147,6 +178,7 @@ unsafe extern "C" fn _machine_mode_trap() {
csrr a0, mcause csrr a0, mcause
csrr a1, mie csrr a1, mie
csrr a2, mip csrr a2, mip
mv a3, sp
jal machine_trap_handler jal machine_trap_handler
# Restore registers # Restore registers
@@ -240,8 +272,8 @@ macro_rules! generate_trap_handler {
# Restore registers # Restore registers
ld t0, 248(a0) ld t0, 248(a0)
csrw sepc, t0 csrw sepc, t0
// ld t0, 256(a0) ld t0, 256(a0)
// csrw sstatus, t0 csrw sstatus, t0
ld ra, 0(a0) ld ra, 0(a0)
ld sp, 8(a0) ld sp, 8(a0)
ld gp, 16(a0) ld gp, 16(a0)
@@ -275,8 +307,6 @@ macro_rules! generate_trap_handler {
ld a0, 32(a0) ld a0, 32(a0)
// addi sp, sp, 264
", ",
stringify!($mode), stringify!($mode),
"ret" "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,
}

View File

@@ -1,18 +1,22 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![allow(static_mut_refs)] #![allow(static_mut_refs)]
#![feature(riscv_ext_intrinsics, const_trait_impl, iter_map_windows)] #![feature(
riscv_ext_intrinsics,
use core::{arch::riscv64::wfi, time::Duration}; const_trait_impl,
iter_map_windows,
str_from_raw_parts
)]
use embedded_alloc::LlffHeap as Heap; use embedded_alloc::LlffHeap as Heap;
use log::info; use log::info;
use crate::{ use crate::{
io::init_log, io::init_log,
process::{create_processus, sleep}, process::create_processus,
riscv::enable_supervisor_interrupt, riscv::enable_supervisor_interrupt,
scheduler::{idle, scheduler_init}, scheduler::{idle, scheduler_init},
user::{proc2, test},
vga::{Color, Vga}, vga::{Color, Vga},
}; };
@@ -26,31 +30,18 @@ mod panic_handler;
mod process; mod process;
mod riscv; mod riscv;
mod scheduler; mod scheduler;
mod syscall;
mod time; mod time;
mod uart; mod uart;
mod user;
mod vga; mod vga;
pub const HEAP_SIZE: usize = 4096; pub const HEAP_SIZE: usize = 4096;
#[global_allocator] #[global_allocator]
static HEAP: Heap = Heap::empty(); static HEAP: Heap = Heap::empty();
extern "C" fn test() { // Usize is assumed to be an u64 in the whole kernel
loop { const _: () = assert!(size_of::<usize>() == size_of::<u64>());
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() };
}
}
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
pub extern "C" fn supervisor_mode_entry() { pub extern "C" fn supervisor_mode_entry() {
@@ -59,7 +50,7 @@ pub extern "C" fn supervisor_mode_entry() {
init_log().unwrap(); init_log().unwrap();
Vga::init(); Vga::init();
scheduler_init(); scheduler_init();
enable_supervisor_interrupt(); // enable_supervisor_interrupt();
} }
info!("Hello World !"); info!("Hello World !");
@@ -68,5 +59,6 @@ pub extern "C" fn supervisor_mode_entry() {
create_processus(test, "proc1"); create_processus(test, "proc1");
create_processus(proc2, "proc2"); create_processus(proc2, "proc2");
enable_supervisor_interrupt();
idle(); idle();
} }

View File

@@ -20,15 +20,15 @@ pub enum ProcessState {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct ExecutionContext { pub struct ExecutionContext {
pub ra: *const usize, pub ra: *const u64,
pub sp: *const usize, pub sp: *const u64,
pub gp: usize, pub gp: u64,
pub tp: usize, pub tp: u64,
pub a: [usize; 8], pub a: [u64; 8],
pub t: [usize; 7], pub t: [u64; 7],
pub s: [usize; 12], pub s: [u64; 12],
pub mepc: *const usize, pub mepc: *const u64,
pub mstatus: usize, pub mstatus: u64,
} }
pub struct Process { pub struct Process {
@@ -37,8 +37,7 @@ pub struct Process {
pub state: ProcessState, pub state: ProcessState,
pub wake_time: Duration, pub wake_time: Duration,
pub ctx: ExecutionContext, pub ctx: ExecutionContext,
pub entry_point: Option<extern "C" fn()>, pub stack: [u64; STACK_SIZE],
pub stack: [usize; STACK_SIZE],
} }
impl core::fmt::Debug for Process { impl core::fmt::Debug for Process {
@@ -49,7 +48,6 @@ impl core::fmt::Debug for Process {
.field("state", &self.state) .field("state", &self.state)
.field("wake_time", &self.wake_time) .field("wake_time", &self.wake_time)
.field("ctx", &self.ctx) .field("ctx", &self.ctx)
.field("entry_point", &self.entry_point)
.field("stack", &format!("[_; {}]", STACK_SIZE)) .field("stack", &format!("[_; {}]", STACK_SIZE))
.finish() .finish()
} }
@@ -71,10 +69,9 @@ pub fn create_processus<T: Into<String>>(code: extern "C" fn(), name: T) -> i64
PROCESS_TABLE[next_pid].pid = next_pid as i64; PROCESS_TABLE[next_pid].pid = next_pid as i64;
PROCESS_TABLE[next_pid].name = name.into(); PROCESS_TABLE[next_pid].name = name.into();
PROCESS_TABLE[next_pid].state = ProcessState::Activable; 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 as u64;
PROCESS_TABLE[next_pid].ctx.a[0] = code as usize;
PROCESS_TABLE[next_pid].ctx.mepc = processus_launcher as *const _; 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]; PROCESS_TABLE[next_pid].ctx.sp = &raw const PROCESS_TABLE[next_pid].stack[STACK_SIZE - 1];
} }

View File

@@ -28,14 +28,14 @@ pub static mut PROCESS_TABLE: LazyCell<[Process; PROCESSUS_COUNT]> = LazyCell::n
mepc: core::ptr::null(), mepc: core::ptr::null(),
mstatus: 0, mstatus: 0,
}, },
entry_point: None,
stack: [0; _], stack: [0; _],
}) })
}); });
pub extern "C" fn idle() { pub extern "C" fn idle() {
loop { loop {
// enable_supervisor_interrupt(); // write_string_temp("idle");
// info!("idle");
unsafe { unsafe {
wfi(); wfi();
} }

88
src/syscall.rs Normal file
View File

@@ -0,0 +1,88 @@
use core::time::Duration;
#[repr(u64)]
pub enum SysCall {
NanoSleep = 101,
WriteTemp = 999,
Unimplemented = 1 << 31,
}
impl From<u64> 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
);
}
}

19
src/user.rs Normal file
View File

@@ -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));
}
}