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