Too late but it kinda works
This commit is contained in:
@@ -8,6 +8,7 @@ panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
debug = true
|
||||
|
||||
[dependencies]
|
||||
embedded-alloc = "0.7"
|
||||
|
||||
115
kernel.svg
Normal file
115
kernel.svg
Normal file
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="1000"
|
||||
height="1000"
|
||||
viewBox="0 0 264.58333 264.58333"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
|
||||
sodipodi:docname="kernel.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
showguides="true"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.1688587"
|
||||
inkscape:cx="148.00762"
|
||||
inkscape:cy="533.85408"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1026"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1">
|
||||
<inkscape:grid
|
||||
id="grid3"
|
||||
units="px"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingx="0.26458333"
|
||||
spacingy="0.26458333"
|
||||
empcolor="#0099e5"
|
||||
empopacity="0.30196078"
|
||||
color="#0099e5"
|
||||
opacity="0.14901961"
|
||||
empspacing="5"
|
||||
enabled="true"
|
||||
visible="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="User Mode" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Supervisor Mode" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="Machine Mode">
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#05668d;stroke-width:1.05833332;stroke-linejoin:round;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="M 0,88.106249 H 264.58333"
|
||||
id="path3"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#05668d;stroke-width:1.05833332;stroke-linejoin:round;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="M 0,176.2125 H 264.58332"
|
||||
id="path3-3"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.05556px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;fill:#05668d;fill-opacity:1;stroke:none;stroke-width:1.05833;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
x="0.68901867"
|
||||
y="6.6834888"
|
||||
id="text3"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.05556px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#05668d;fill-opacity:1;stroke:none;stroke-width:1.05833"
|
||||
x="0.68901867"
|
||||
y="6.6834888">Machine</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.05556px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#05668d;fill-opacity:1;stroke:none;stroke-width:1.05833"
|
||||
x="0.68901867"
|
||||
y="15.502938"
|
||||
id="tspan5" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.05556px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;fill:#05668d;fill-opacity:1;stroke:none;stroke-width:1.05833;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
x="0.99907744"
|
||||
y="94.789734"
|
||||
id="text3-5"><tspan
|
||||
sodipodi:role="line"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.05556px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#05668d;fill-opacity:1;stroke:none;stroke-width:1.05833"
|
||||
x="0.99907744"
|
||||
y="94.789734"
|
||||
id="tspan4">Supervisor</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.05556px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;fill:#05668d;fill-opacity:1;stroke:none;stroke-width:1.05833;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
x="0.99907744"
|
||||
y="182.89598"
|
||||
id="text3-5-8"><tspan
|
||||
sodipodi:role="line"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.05556px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#05668d;fill-opacity:1;stroke:none;stroke-width:1.05833"
|
||||
x="0.99907744"
|
||||
y="182.89598"
|
||||
id="tspan6">User</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
@@ -1,11 +1,11 @@
|
||||
#[non_exhaustive]
|
||||
#[repr(u64)]
|
||||
pub enum EID {
|
||||
pub enum EextensionID {
|
||||
Time = 0x54494D45,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[repr(u64)]
|
||||
pub enum TimeFID {
|
||||
pub enum TimerFunctionID {
|
||||
SetTimer = 0x0,
|
||||
}
|
||||
|
||||
183
src/interrupt.rs
183
src/interrupt.rs
@@ -1,17 +1,19 @@
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
boot::sbi::{TimeFID, EID},
|
||||
clear_csr, generate_trap_handler, read_csr,
|
||||
riscv::disable_interrupt,
|
||||
set_csr,
|
||||
time::{setup_next_timer_interrupt, IRQ_M_TIMER},
|
||||
write_csr,
|
||||
boot::sbi::{EextensionID, TimerFunctionID}, clear_csr, generate_trap_handler, process::ExecutionContext, read_csr, riscv::disable_interrupt, set_csr, time::{IRQ_M_TIMER, setup_next_timer_interrupt}, write_csr
|
||||
};
|
||||
use core::arch::naked_asm;
|
||||
|
||||
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(
|
||||
_interrupt_state: *const ExecutionContext,
|
||||
mcause: u64,
|
||||
mie: u64,
|
||||
mip: u64,
|
||||
) {
|
||||
let mepc = read_csr!(mepc);
|
||||
let mtval = read_csr!(mtval);
|
||||
if mcause & (1 << 63) == 0 {
|
||||
@@ -40,8 +42,8 @@ unsafe extern "C" fn machine_trap_handler(mcause: u64, mie: u64, mip: u64) {
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match eid {
|
||||
c if c == EID::Time as u64 => match fid {
|
||||
c if c == TimeFID::SetTimer as u64 => {
|
||||
c if c == EextensionID::Time as u64 => match fid {
|
||||
c if c == TimerFunctionID::SetTimer as u64 => {
|
||||
clear_csr!(mip, 1 << 5);
|
||||
setup_next_timer_interrupt();
|
||||
}
|
||||
@@ -82,7 +84,12 @@ unsafe extern "C" fn machine_trap_handler(mcause: u64, mie: u64, mip: u64) {
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
unsafe extern "C" fn supervisor_trap_handler(scause: u64, _sie: u64, _sip: u64) {
|
||||
unsafe extern "C" fn supervisor_trap_handler(
|
||||
interrupt_state: *const ExecutionContext,
|
||||
scause: u64,
|
||||
_sie: u64,
|
||||
_sip: u64,
|
||||
) {
|
||||
#[allow(clippy::single_match)]
|
||||
match scause & !(1 << 63) {
|
||||
5 => {
|
||||
@@ -90,11 +97,11 @@ unsafe extern "C" fn supervisor_trap_handler(scause: u64, _sie: u64, _sip: u64)
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
in("a0") 0,
|
||||
in("a6") TimeFID::SetTimer as u64,
|
||||
in("a7") EID::Time as u64,
|
||||
in("a6") TimerFunctionID::SetTimer as u64,
|
||||
in("a7") EextensionID::Time as u64,
|
||||
);
|
||||
}
|
||||
timer_interrupt();
|
||||
timer_interrupt(unsafe { *interrupt_state });
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -124,52 +131,128 @@ macro_rules! generate_trap_handler {
|
||||
unsafe extern "C" fn $name() {
|
||||
naked_asm!(
|
||||
concat!("
|
||||
addi sp, sp, -128
|
||||
addi sp, sp, -264
|
||||
|
||||
sd ra, 120(sp)
|
||||
# Store the current frame
|
||||
sd ra, 0(sp)
|
||||
sd sp, 8(sp)
|
||||
sd gp, 16(sp)
|
||||
sd tp, 24(sp)
|
||||
sd a0, 32(sp)
|
||||
sd a1, 40(sp)
|
||||
sd a2, 48(sp)
|
||||
sd a3, 56(sp)
|
||||
sd a4, 64(sp)
|
||||
sd a5, 72(sp)
|
||||
sd a6, 80(sp)
|
||||
sd a7, 88(sp)
|
||||
sd t0, 96(sp)
|
||||
sd t1, 104(sp)
|
||||
sd t2, 112(sp)
|
||||
sd t3, 120(sp)
|
||||
sd t4, 128(sp)
|
||||
sd t5, 136(sp)
|
||||
sd t6, 144(sp)
|
||||
sd s0, 152(sp)
|
||||
sd s1, 160(sp)
|
||||
sd s2, 168(sp)
|
||||
sd s3, 176(sp)
|
||||
sd s4, 184(sp)
|
||||
sd s5, 192(sp)
|
||||
sd s6, 200(sp)
|
||||
sd s7, 208(sp)
|
||||
sd s8, 216(sp)
|
||||
sd s9, 224(sp)
|
||||
sd s10, 232(sp)
|
||||
sd s11, 240(sp)
|
||||
csrr t0, sepc
|
||||
sd t0, 248(sp)
|
||||
csrr t0, sstatus
|
||||
sd t0, 256(sp)
|
||||
|
||||
// sd ra, 120(sp)
|
||||
|
||||
sd a0, 0(sp)
|
||||
sd a1, 8(sp)
|
||||
sd a2, 16(sp)
|
||||
sd a3, 24(sp)
|
||||
sd a4, 32(sp)
|
||||
sd a5, 40(sp)
|
||||
sd a6, 48(sp)
|
||||
sd a7, 56(sp)
|
||||
// sd a0, 0(sp)
|
||||
// sd a1, 8(sp)
|
||||
// sd a2, 16(sp)
|
||||
// sd a3, 24(sp)
|
||||
// sd a4, 32(sp)
|
||||
// sd a5, 40(sp)
|
||||
// sd a6, 48(sp)
|
||||
// sd a7, 56(sp)
|
||||
|
||||
sd t0, 64(sp)
|
||||
sd t1, 72(sp)
|
||||
sd t2, 80(sp)
|
||||
sd t3, 88(sp)
|
||||
sd t4, 96(sp)
|
||||
sd t5, 104(sp)
|
||||
sd t6, 112(sp)
|
||||
// sd t0, 64(sp)
|
||||
// sd t1, 72(sp)
|
||||
// sd t2, 80(sp)
|
||||
// sd t3, 88(sp)
|
||||
// sd t4, 96(sp)
|
||||
// sd t5, 104(sp)
|
||||
// sd t6, 112(sp)
|
||||
|
||||
csrr a0, ", stringify!($mode),"cause
|
||||
csrr a1, ", stringify!($mode),"ie
|
||||
csrr a2, ", stringify!($mode),"ip
|
||||
mv a0, sp
|
||||
csrr a1, ", stringify!($mode),"cause
|
||||
csrr a2, ", stringify!($mode),"ie
|
||||
csrr a3, ", stringify!($mode),"ip
|
||||
jal ", stringify!($jump_to), "
|
||||
|
||||
ld a0, 0(sp)
|
||||
ld a1, 8(sp)
|
||||
ld a2, 16(sp)
|
||||
ld a3, 24(sp)
|
||||
ld a4, 32(sp)
|
||||
ld a5, 40(sp)
|
||||
ld a6, 48(sp)
|
||||
ld a7, 56(sp)
|
||||
# Restore registers
|
||||
ld t0, 248(sp)
|
||||
csrw sepc, t0
|
||||
ld t0, 256(sp)
|
||||
csrw sstatus, t0
|
||||
ld ra, 0(sp)
|
||||
ld gp, 16(sp)
|
||||
ld tp, 24(sp)
|
||||
ld a0, 32(sp)
|
||||
ld a1, 40(sp)
|
||||
ld a2, 48(sp)
|
||||
ld a3, 56(sp)
|
||||
ld a4, 64(sp)
|
||||
ld a5, 72(sp)
|
||||
ld a6, 80(sp)
|
||||
ld a7, 88(sp)
|
||||
ld t0, 96(sp)
|
||||
ld t1, 104(sp)
|
||||
ld t2, 112(sp)
|
||||
ld t3, 120(sp)
|
||||
ld t4, 128(sp)
|
||||
ld t5, 136(sp)
|
||||
ld t6, 144(sp)
|
||||
ld s0, 152(sp)
|
||||
ld s1, 160(sp)
|
||||
ld s2, 168(sp)
|
||||
ld s3, 176(sp)
|
||||
ld s4, 184(sp)
|
||||
ld s5, 192(sp)
|
||||
ld s6, 200(sp)
|
||||
ld s7, 208(sp)
|
||||
ld s8, 216(sp)
|
||||
ld s9, 224(sp)
|
||||
ld s10, 232(sp)
|
||||
ld s11, 240(sp)
|
||||
|
||||
ld t0, 64(sp)
|
||||
ld t1, 72(sp)
|
||||
ld t2, 80(sp)
|
||||
ld t3, 88(sp)
|
||||
ld t4, 96(sp)
|
||||
ld t5, 104(sp)
|
||||
ld t6, 112(sp)
|
||||
ld sp, 8(sp)
|
||||
|
||||
ld ra, 120(sp)
|
||||
// ld a0, 0(sp)
|
||||
// ld a1, 8(sp)
|
||||
// ld a2, 16(sp)
|
||||
// ld a3, 24(sp)
|
||||
// ld a4, 32(sp)
|
||||
// ld a5, 40(sp)
|
||||
// ld a6, 48(sp)
|
||||
// ld a7, 56(sp)
|
||||
|
||||
// ld t0, 64(sp)
|
||||
// ld t1, 72(sp)
|
||||
// ld t2, 80(sp)
|
||||
// ld t3, 88(sp)
|
||||
// ld t4, 96(sp)
|
||||
// ld t5, 104(sp)
|
||||
// ld t6, 112(sp)
|
||||
|
||||
// ld ra, 120(sp)
|
||||
|
||||
addi sp, sp, 128
|
||||
addi sp, sp, 264
|
||||
|
||||
", stringify!($mode),"ret")
|
||||
)
|
||||
|
||||
31
src/main.rs
31
src/main.rs
@@ -1,16 +1,18 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![allow(static_mut_refs)]
|
||||
#![feature(riscv_ext_intrinsics)]
|
||||
#![feature(riscv_ext_intrinsics, const_trait_impl, iter_map_windows)]
|
||||
|
||||
use core::arch::riscv64::wfi;
|
||||
use core::{arch::riscv64::wfi, time::Duration};
|
||||
|
||||
use embedded_alloc::LlffHeap as Heap;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
io::init_log,
|
||||
process::{create_processus, sleep},
|
||||
riscv::enable_supervisor_interrupt,
|
||||
scheduler::scheduler_init,
|
||||
vga::{Color, Vga},
|
||||
};
|
||||
|
||||
@@ -21,27 +23,50 @@ mod critical_section;
|
||||
mod interrupt;
|
||||
mod io;
|
||||
mod panic_handler;
|
||||
mod process;
|
||||
mod riscv;
|
||||
mod scheduler;
|
||||
mod time;
|
||||
mod uart;
|
||||
mod vga;
|
||||
|
||||
pub const HEAP_SIZE: usize = 40960;
|
||||
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() };
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn supervisor_mode_entry() {
|
||||
unsafe {
|
||||
embedded_alloc::init!(HEAP, HEAP_SIZE);
|
||||
init_log().unwrap();
|
||||
Vga::init();
|
||||
scheduler_init();
|
||||
enable_supervisor_interrupt();
|
||||
}
|
||||
|
||||
info!("Hello World !");
|
||||
unsafe { Vga::draw_string(10, 10, "Hello World !", Color::WHITE, Color::BLACK) };
|
||||
|
||||
create_processus(test, "proc1");
|
||||
create_processus(proc2, "proc2");
|
||||
loop {
|
||||
unsafe { wfi() }
|
||||
}
|
||||
|
||||
107
src/process.rs
Normal file
107
src/process.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use core::{arch::riscv64::wfi, time::Duration};
|
||||
|
||||
use alloc::{format, string::String};
|
||||
|
||||
use crate::{
|
||||
scheduler::{scheduler, ACTIVE_PID, PROCESSUS_COUNT, PROCESS_TABLE},
|
||||
time::elapsed_time_since_startup,
|
||||
};
|
||||
|
||||
const STACK_SIZE: usize = 4096;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ProcessState {
|
||||
Active,
|
||||
Activable,
|
||||
Dead,
|
||||
Asleep,
|
||||
}
|
||||
|
||||
#[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; 11],
|
||||
pub mepc: usize,
|
||||
pub mstatus: usize,
|
||||
}
|
||||
|
||||
pub struct Process {
|
||||
pub pid: i64,
|
||||
pub name: String,
|
||||
pub state: ProcessState,
|
||||
pub wake_time: Duration,
|
||||
pub ctx: ExecutionContext,
|
||||
pub entry_point: Option<extern "C" fn()>,
|
||||
pub stack: [usize; STACK_SIZE],
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Process {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("Process")
|
||||
.field("pid", &self.pid)
|
||||
.field("name", &self.name)
|
||||
.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()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_processus<T: Into<String>>(code: extern "C" fn(), name: T) -> i64 {
|
||||
let mut next_pid = 0;
|
||||
while next_pid < PROCESSUS_COUNT
|
||||
&& unsafe { PROCESS_TABLE[next_pid].state != ProcessState::Dead }
|
||||
{
|
||||
next_pid += 1;
|
||||
}
|
||||
|
||||
if next_pid >= PROCESSUS_COUNT {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
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.ra = processus_launcher as *const _;
|
||||
PROCESS_TABLE[next_pid].ctx.sp = &raw const PROCESS_TABLE[next_pid].stack[STACK_SIZE - 1];
|
||||
}
|
||||
|
||||
next_pid as i64
|
||||
}
|
||||
|
||||
extern "C" fn processus_launcher(code: extern "C" fn()) {
|
||||
code();
|
||||
terminate_processus();
|
||||
}
|
||||
|
||||
fn terminate_processus() {
|
||||
unsafe {
|
||||
PROCESS_TABLE[ACTIVE_PID].state = ProcessState::Dead;
|
||||
}
|
||||
unsafe {
|
||||
wfi();
|
||||
}
|
||||
// scheduler();
|
||||
}
|
||||
|
||||
pub fn sleep(duration: Duration) {
|
||||
unsafe {
|
||||
PROCESS_TABLE[ACTIVE_PID].wake_time = elapsed_time_since_startup() + duration;
|
||||
PROCESS_TABLE[ACTIVE_PID].state = ProcessState::Asleep;
|
||||
}
|
||||
unsafe {
|
||||
wfi();
|
||||
}
|
||||
// scheduler();
|
||||
}
|
||||
173
src/scheduler.rs
Normal file
173
src/scheduler.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
use core::{
|
||||
arch::{naked_asm, riscv64::wfi},
|
||||
array,
|
||||
cell::LazyCell,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use alloc::string::String;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
process::{create_processus, ExecutionContext, Process, ProcessState},
|
||||
riscv::enable_supervisor_interrupt,
|
||||
time,
|
||||
};
|
||||
|
||||
pub const PROCESSUS_COUNT: usize = 16;
|
||||
|
||||
pub static mut ACTIVE_PID: usize = 0;
|
||||
pub static mut PROCESS_TABLE: LazyCell<[Process; PROCESSUS_COUNT]> = LazyCell::new(|| {
|
||||
array::from_fn(|_| Process {
|
||||
pid: -1,
|
||||
name: String::new(),
|
||||
state: ProcessState::Dead,
|
||||
wake_time: Duration::new(0, 0),
|
||||
ctx: ExecutionContext {
|
||||
ra: core::ptr::null(),
|
||||
sp: core::ptr::null(),
|
||||
gp: 0,
|
||||
tp: 0,
|
||||
a: [0; _],
|
||||
t: [0; _],
|
||||
s: [0; _],
|
||||
mepc: 0,
|
||||
mstatus: 0,
|
||||
},
|
||||
entry_point: None,
|
||||
stack: [0; _],
|
||||
})
|
||||
});
|
||||
|
||||
pub extern "C" fn idle() {
|
||||
loop {
|
||||
enable_supervisor_interrupt();
|
||||
unsafe {
|
||||
wfi();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scheduler_init() {
|
||||
info!("scheduler init");
|
||||
for pid in 0..PROCESSUS_COUNT {
|
||||
unsafe {
|
||||
PROCESS_TABLE[pid].state = ProcessState::Dead;
|
||||
}
|
||||
}
|
||||
|
||||
create_processus(idle, "idle");
|
||||
unsafe {
|
||||
PROCESS_TABLE[0].state = ProcessState::Active;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scheduler(interrupt_state: ExecutionContext) -> usize {
|
||||
// info!("scheduler");
|
||||
unsafe {
|
||||
let prev_pid = ACTIVE_PID;
|
||||
|
||||
if PROCESS_TABLE[ACTIVE_PID].state == ProcessState::Active {
|
||||
PROCESS_TABLE[ACTIVE_PID].state = ProcessState::Activable;
|
||||
}
|
||||
|
||||
loop {
|
||||
if PROCESS_TABLE[ACTIVE_PID].state == ProcessState::Asleep
|
||||
&& time::elapsed_time_since_startup() > PROCESS_TABLE[ACTIVE_PID].wake_time
|
||||
{
|
||||
PROCESS_TABLE[ACTIVE_PID].state = ProcessState::Activable;
|
||||
}
|
||||
ACTIVE_PID = (ACTIVE_PID + 1) % PROCESSUS_COUNT;
|
||||
if PROCESS_TABLE[ACTIVE_PID].state == ProcessState::Activable {
|
||||
break;
|
||||
}
|
||||
}
|
||||
PROCESS_TABLE[ACTIVE_PID].state = ProcessState::Active;
|
||||
|
||||
PROCESS_TABLE[prev_pid].ctx = interrupt_state;
|
||||
// PROCESS_TABLE[prev_pid].ctx.t = interrupt_state.t;
|
||||
// PROCESS_TABLE[prev_pid].ctx.ra = interrupt_state.ra;
|
||||
context_switch(
|
||||
PROCESS_TABLE[ACTIVE_PID].entry_point.unwrap(),
|
||||
&raw mut PROCESS_TABLE[prev_pid].ctx,
|
||||
&raw mut PROCESS_TABLE[ACTIVE_PID].ctx,
|
||||
);
|
||||
prev_pid
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(naked)]
|
||||
pub extern "C" fn context_switch(
|
||||
code: extern "C" fn(),
|
||||
current: *mut ExecutionContext,
|
||||
next: *mut ExecutionContext,
|
||||
) {
|
||||
naked_asm!(
|
||||
"
|
||||
// sd ra, 0(a1)
|
||||
// sd sp, 8(a1)
|
||||
// sd gp, 16(a1)
|
||||
// sd tp, 24(a1)
|
||||
// sd s0, 152(a1)
|
||||
// sd s1, 160(a1)
|
||||
// sd s2, 168(a1)
|
||||
// sd s3, 176(a1)
|
||||
// sd s4, 184(a1)
|
||||
// sd s5, 192(a1)
|
||||
// sd s6, 200(a1)
|
||||
// sd s7, 208(a1)
|
||||
// sd s8, 216(a1)
|
||||
// sd s9, 224(a1)
|
||||
// sd s10, 232(a1)
|
||||
// sd s11, 240(a1)
|
||||
// csrr t0, sepc
|
||||
// sd t0, 248(a1)
|
||||
// csrr t0, sstatus
|
||||
// sd t0, 256(a1)
|
||||
|
||||
# Load next execution context
|
||||
ld t0, 248(a2)
|
||||
csrw sepc, t0
|
||||
ld t0, 256(a2)
|
||||
csrw sstatus, t0
|
||||
|
||||
ld ra, 0(a2)
|
||||
ld sp, 8(a2)
|
||||
ld gp, 16(a2)
|
||||
ld tp, 24(a2)
|
||||
ld a0, 32(a2)
|
||||
ld a1, 40(a2)
|
||||
// Skip a2 since it used as a pointer
|
||||
ld a3, 56(a2)
|
||||
ld a4, 64(a2)
|
||||
ld a5, 72(a2)
|
||||
ld a6, 80(a2)
|
||||
ld a7, 88(a2)
|
||||
ld t0, 96(a2)
|
||||
ld t1, 104(a2)
|
||||
ld t2, 112(a2)
|
||||
ld t3, 120(a2)
|
||||
ld t4, 128(a2)
|
||||
ld t5, 136(a2)
|
||||
ld t6, 144(a2)
|
||||
ld s0, 152(a2)
|
||||
ld s1, 160(a2)
|
||||
ld s2, 168(a2)
|
||||
ld s3, 176(a2)
|
||||
ld s4, 184(a2)
|
||||
ld s5, 192(a2)
|
||||
ld s6, 200(a2)
|
||||
ld s7, 208(a2)
|
||||
ld s8, 216(a2)
|
||||
ld s9, 224(a2)
|
||||
ld s10, 232(a2)
|
||||
ld s11, 240(a2)
|
||||
|
||||
// Restore a2 at the end
|
||||
ld a2, 48(a2)
|
||||
|
||||
addi sp, sp, 264
|
||||
|
||||
sret"
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
use core::time::Duration;
|
||||
|
||||
use alloc::format;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
set_csr,
|
||||
vga::{Color, Vga, FONT_WIDTH, WIDTH},
|
||||
process::ExecutionContext, scheduler::scheduler, set_csr, vga::{Color, FONT_WIDTH, Vga, WIDTH}
|
||||
};
|
||||
|
||||
pub const IRQ_M_TIMER: u8 = 1 << 7;
|
||||
@@ -30,7 +30,7 @@ pub fn setup_next_timer_interrupt() {
|
||||
);
|
||||
}
|
||||
}
|
||||
pub fn timer_interrupt() {
|
||||
pub fn timer_interrupt(interrupt_state: ExecutionContext) -> usize {
|
||||
let current_time = elapsed_time_since_startup();
|
||||
let seconds = current_time.as_secs();
|
||||
let minutes = seconds / 60 % 60;
|
||||
@@ -46,6 +46,7 @@ pub fn timer_interrupt() {
|
||||
Color::BLACK,
|
||||
)
|
||||
};
|
||||
scheduler(interrupt_state)
|
||||
}
|
||||
|
||||
pub fn elapsed_time_since_startup() -> Duration {
|
||||
|
||||
@@ -5,5 +5,11 @@ pub fn write_char_uart(c: char) {
|
||||
}
|
||||
|
||||
pub fn write_uart<T: AsRef<str>>(print: T) {
|
||||
print.as_ref().chars().for_each(write_char_uart);
|
||||
print.as_ref().chars().for_each(|a| {
|
||||
// Add \r if needed
|
||||
write_char_uart(a);
|
||||
if a == '\n' {
|
||||
write_char_uart('\r');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user