From f9fba69adb94e221a4542d77c9e40df9d1edfc48 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Fri, 6 Dec 2024 03:55:43 -0600 Subject: [PATCH] add some more docs about timer --- .vscode/settings.json | 7 +++++++ Cargo.toml | 2 ++ scripts/start.ps1 | 6 ++++++ src/asm/entry.S | 9 +++++++++ src/main.rs | 7 +++++++ src/riscv.rs | 21 +++++++++++++++++++++ src/timer.rs | 20 ++++++++++++++++++++ 7 files changed, 72 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 scripts/start.ps1 create mode 100644 src/riscv.rs create mode 100644 src/timer.rs diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f40301c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "rust-analyzer.cargo.allTargets": false, + "rust-analyzer.cargo.extraArgs": [ + "--target", + "riscv64gc-unknown-none-elf" + ] +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 76d55ef..83b4c1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,5 @@ panic = "abort" [dependencies] contracts = "0.6.3" + +[features] diff --git a/scripts/start.ps1 b/scripts/start.ps1 new file mode 100644 index 0000000..1d6613c --- /dev/null +++ b/scripts/start.ps1 @@ -0,0 +1,6 @@ +qemu-system-riscv64.exe ` + -nographic ` + -machine virt ` + -bios none ` + -m 3G ` + -kernel "$($args[0])" \ No newline at end of file diff --git a/src/asm/entry.S b/src/asm/entry.S index d35b39a..9dc96b8 100644 --- a/src/asm/entry.S +++ b/src/asm/entry.S @@ -1,3 +1,12 @@ +// This is the assembly entry point of the language + +// It is "called" by: +// 1. It's included as global_asm! into the kernel binary (see main.rs) +// 2. It's set as the entry point as set by the ELF file in the linker script + +// It then sets up a stack and calls the rust start +// idk how the asm works yet, I just cribbed it from xv6 + .attribute arch, "rv64gc" .section .text.start diff --git a/src/main.rs b/src/main.rs index 5da22a2..2c610b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,13 @@ #![no_std] #![no_main] +mod riscv; +mod timer; + use core::{arch::global_asm, panic::PanicInfo, ptr}; +use timer::timer_init; + global_asm!(include_str!("asm/entry.S")); #[panic_handler] @@ -15,6 +20,8 @@ static HELLO: &[u8] = b"meow\n"; #[no_mangle] pub unsafe extern "C" fn start() -> ! { + timer_init(); + for c in HELLO.iter() { while ptr::read_volatile((UART0 + 5) as *const u8) & (1 << 5) == 0 {} diff --git a/src/riscv.rs b/src/riscv.rs new file mode 100644 index 0000000..5a4df41 --- /dev/null +++ b/src/riscv.rs @@ -0,0 +1,21 @@ +// Here lie RISC-V-specific procedures and constants +// Cribbed shamelessly from https://github.com/mit-pdos/xv6-riscv/blob/de247db5e6384b138f270e0a7c745989b5a9c23b/kernel/riscv.h#L99 + +use core::arch::asm; + +/// Machine interrupt enable +pub const MIE_STIE: u64 = 1 << 5; + +/// Read from the "Machine interrupt-enable" register +#[inline] +pub unsafe fn r_mie() -> u64 { + let value: u64; + asm!("csrr {value}, mie", value = out(reg) value); + value +} + +/// Write to the "Machine interrupt-enable" register +#[inline] +pub unsafe fn w_mie(value: u64) { + asm!("csrw mie, {value}", value = in(reg) value) +} diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..d4773e0 --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,20 @@ +// Set up timer interrupts for pre-emption +// Every now and then we want the timer to pause a running process +// and return control to the operating system so we can do some scheduling +// otherwise the process could retain full control for a very long time +// and starve other processes + +// This is done in xv6 here: +// https://github.com/mit-pdos/xv6-riscv/blob/de247db5e6384b138f270e0a7c745989b5a9c23b/kernel/start.c#L53 +// This implementation seems to be using some CSR (control/status registers) in RISC-V +// This page also documents some: +// https://book.rvemu.app/hardware-components/03-csrs.html + +use crate::riscv::{r_mie, w_mie, MIE_STIE}; + +/// Ask the hardware to provide clock interrupts +pub fn timer_init() { + unsafe { + w_mie(r_mie() | MIE_STIE); + } +}