From 5dfd3f780fd6c5be33b50343500a9ab37db511ee Mon Sep 17 00:00:00 2001 From: gil Date: Mon, 20 May 2024 02:35:16 -0500 Subject: [PATCH] Update entry code, switch to spin crate for spinlocks --- Cargo.lock | 22 ++++---- Cargo.toml | 2 +- lds/kernel.lds | 2 +- src/entry.rs | 139 +++++++++++++++++++++--------------------------- src/entry_alt.S | 37 +++++++++++++ src/uart.rs | 6 +-- 6 files changed, 114 insertions(+), 94 deletions(-) create mode 100644 src/entry_alt.S diff --git a/Cargo.lock b/Cargo.lock index bcc3d91..08d314c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,7 +26,7 @@ version = "0.1.0" dependencies = [ "linked_list_allocator", "riscv", - "spinning_top 0.3.0", + "spin", ] [[package]] @@ -35,7 +35,7 @@ version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" dependencies = [ - "spinning_top 0.2.5", + "spinning_top", ] [[package]] @@ -64,6 +64,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.2.5" @@ -72,12 +81,3 @@ checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" dependencies = [ "lock_api", ] - -[[package]] -name = "spinning_top" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" -dependencies = [ - "lock_api", -] diff --git a/Cargo.toml b/Cargo.toml index de64d7d..889f503 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" [dependencies] linked_list_allocator = "0.10.5" riscv = "0.11.1" -spinning_top = "0.3.0" +spin = "0.9.8" diff --git a/lds/kernel.lds b/lds/kernel.lds index 242ed20..085be83 100644 --- a/lds/kernel.lds +++ b/lds/kernel.lds @@ -1,4 +1,4 @@ -/* src/script.lds */ +/* lds/kernel.lds */ OUTPUT_ARCH("riscv") ENTRY(_entry) diff --git a/src/entry.rs b/src/entry.rs index 4f17779..6c6c223 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,92 +1,86 @@ // src/entry.rs -/// This is the first function called when the system boots. In this function, -/// we set up important control status registers (CSR) such as `mstatus` and -/// `satp`. The global, stack, and thread pointers are also configured here. +static READY: spin::Once<()> = spin::Once::new(); + +/// After some initialization in asm/entry.S, the kernel will jump here and +/// each hart will have its own setup sequence. #[no_mangle] -#[link_section = ".text.init"] -unsafe extern "C" fn entry() { +unsafe extern "C" fn _start() { use core::arch::asm; - use riscv::register::{mhartid, mstatus, satp, sstatus}; + use riscv::register::{mepc, mstatus, satp, sie, sstatus}; - // Global pointer `gp` - // - // Push current option stack to temporarily disable relaxation, load - // _global_pointer symbol (provided by linker), then pop option stack. - // - // Important to keep relaxation off for this instruction, so that - // the instruction is emitted as: - // 1: - // auipc gp, %pcrel_hi(_global_pointer) - // addi gp, gp, %pcrel_lo(1b)" - // instead of: - // mv gp, gp - asm!( - ".option push", - ".option norelax", - "la gp, _global_pointer", - ".option pop", - ); - - // Stack pointer `sp` - // - // Set up the stack pointer for each hart, since each hart will have its own stack. - asm!("la sp, _stack_end"); - - // Thread pointer `tp` - // - // Set up the thread pointer, which will hold the hart id for each hart. - write_tp(&mhartid::read()); - - satp::write(0); - - mstatus::set_mpp(mstatus::MPP::Machine); + // Set previous privilege for all harts to M-mode, set previous interrupt + // enable, and set floating-point unit to initial state + mstatus::set_mpp(mstatus::MPP::Supervisor); + mstatus::set_mpie(); mstatus::set_fs(sstatus::FS::Initial); - asm!( - "csrw mie, x0", + // Store ref to main in M-mode exception program counter + mepc::write(main as usize); - "la t1, {kinit}", - "csrw mepc, t1", + // Disable paging + satp::write(0); - "la ra, 2f", - "mret", - "2:", - kinit = sym kinit, - ); + // Delegate all traps to S-mode, using inline assembly since we have not + // provided a wrapper for it yet + asm!("li t0, 0xffff", "csrw medeleg, t0", "csrw mideleg, t0",); + + // Enable S-mode external, timer, and software interrupts + sie::set_sext(); + sie::set_stimer(); + sie::set_ssoft(); + + // TODO configure PMP + // TODO timer init + + // Use mret to jump to main + asm!("mret"); } -// TODO ...then kinit +extern "C" fn main() { + use riscv::interrupt; + use riscv::register::{mstatus, sstatus}; + + if hartid() == 0 { + READY.call_once(|| { + // Disable machine interrupts while initializing + interrupt::machine::disable(); + // TODO Initialize console + // TODO Write boot message + + // TODO Set up paging + // TODO Set up processes + + // TODO Set up trap vectors + // TODO Set up PLIC + + kinit(); + unsafe { + mstatus::set_mpp(mstatus::MPP::User); + mstatus::set_mpie(); + mstatus::set_spie(); + mstatus::set_fs(sstatus::FS::Initial); + } + + riscv::asm::fence(); + }); + } else { + READY.wait(); + kinit_hart(); + } +} #[no_mangle] extern "C" fn kinit() { use crate::uart; - use core::arch::asm; uart::Device::new(0x1000_0000); - - if read_tp() == 0 { - // Clear bss and set stack pointer - // Only hart 0 does this - unsafe { - asm!( - "la t0, _bss_start", - "la t1, _bss_end", - "bgeu t0, t1, 2f", - "1:", - "sw x0, (t0)", // Store zero as word at t0 - "addi t0, t0, 4", - "bne t0, t1, 1b", - "2:", - ); - } - } } #[no_mangle] extern "C" fn kinit_hart() {} #[inline] -fn read_tp() -> usize { +fn hartid() -> usize { use core::arch::asm; let id: usize; unsafe { @@ -97,14 +91,3 @@ fn read_tp() -> usize { } id } - -#[inline] -fn write_tp(id: &usize) { - use core::arch::asm; - unsafe { - asm!( - "csrw mhartid, {id}", - id = in(reg) id, - ); - } -} diff --git a/src/entry_alt.S b/src/entry_alt.S new file mode 100644 index 0000000..23d4d01 --- /dev/null +++ b/src/entry_alt.S @@ -0,0 +1,37 @@ +# entry.S +.option norvc +.section .data + +.section .text.init +.global _entry_alt +_entry_alt: + # Set global pointer (gp) + # Important to have relaxation off for this instruction +.option push +.option norelax + la gp, _global_pointer +.option pop + + # Set thread pointer (tp) to hart id + csrr tp, mhartid + + # Set stack pointer (sp) for all harts + la sp, _stack_end + li t0, 0x10000 # Give each hart plenty of space for their stacks + mul t0, t0, tp + sub sp, sp, t0 + + # Jump to start if not hart 0 + bnez tp, 2f + + # Prepare BSS section if hart 0 + la t0, _bss_start + la t1, _bss_end + bgeu t0, t1, 2f +1: + sb zero, 0(t0) + addi t0, t0, 1 + bne t0, t1, 1b +2: + # Tail call Rust start function + tail start diff --git a/src/uart.rs b/src/uart.rs index b88f4af..5834337 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -1,9 +1,9 @@ // src/uart.rs //! This module provides access to the UART console. -use spinning_top::Spinlock; +use spin::Mutex; // Replaces spinning_top crate -pub static CONSOLE: Spinlock> = Spinlock::new(None); +pub static CONSOLE: Mutex> = Mutex::new(None); /// Represents an initialised UART device. pub struct Device { @@ -65,7 +65,7 @@ impl core::fmt::Write for Device { /// # Safety /// `base` must point to the base address of a UART device. pub fn init_console(base: usize) { - let mut console: spinning_top::lock_api::MutexGuard> = CONSOLE.lock(); + let mut console = CONSOLE.lock(); *console = Some(Device::new(base)); }