Update entry code, switch to spin crate for spinlocks

This commit is contained in:
gil 2024-05-20 02:35:16 -05:00
parent e5b51efb87
commit 5dfd3f780f
6 changed files with 114 additions and 94 deletions

22
Cargo.lock generated
View file

@ -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",
]

View file

@ -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"

View file

@ -1,4 +1,4 @@
/* src/script.lds */
/* lds/kernel.lds */
OUTPUT_ARCH("riscv")
ENTRY(_entry)

View file

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

37
src/entry_alt.S Normal file
View file

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

View file

@ -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<Option<Device>> = Spinlock::new(None);
pub static CONSOLE: Mutex<Option<Device>> = 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<spinning_top::RawSpinlock, Option<Device>> = CONSOLE.lock();
let mut console = CONSOLE.lock();
*console = Some(Device::new(base));
}