add some more docs about timer

This commit is contained in:
Michael Zhang 2024-12-06 03:55:43 -06:00
parent e90a19d3a2
commit f9fba69adb
7 changed files with 72 additions and 0 deletions

7
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,7 @@
{
"rust-analyzer.cargo.allTargets": false,
"rust-analyzer.cargo.extraArgs": [
"--target",
"riscv64gc-unknown-none-elf"
]
}

View file

@ -11,3 +11,5 @@ panic = "abort"
[dependencies] [dependencies]
contracts = "0.6.3" contracts = "0.6.3"
[features]

6
scripts/start.ps1 Normal file
View file

@ -0,0 +1,6 @@
qemu-system-riscv64.exe `
-nographic `
-machine virt `
-bios none `
-m 3G `
-kernel "$($args[0])"

View file

@ -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" .attribute arch, "rv64gc"
.section .text.start .section .text.start

View file

@ -1,8 +1,13 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
mod riscv;
mod timer;
use core::{arch::global_asm, panic::PanicInfo, ptr}; use core::{arch::global_asm, panic::PanicInfo, ptr};
use timer::timer_init;
global_asm!(include_str!("asm/entry.S")); global_asm!(include_str!("asm/entry.S"));
#[panic_handler] #[panic_handler]
@ -15,6 +20,8 @@ static HELLO: &[u8] = b"meow\n";
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn start() -> ! { pub unsafe extern "C" fn start() -> ! {
timer_init();
for c in HELLO.iter() { for c in HELLO.iter() {
while ptr::read_volatile((UART0 + 5) as *const u8) & (1 << 5) == 0 {} while ptr::read_volatile((UART0 + 5) as *const u8) & (1 << 5) == 0 {}

21
src/riscv.rs Normal file
View file

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

20
src/timer.rs Normal file
View file

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