Update entry code, switch to spin crate for spinlocks
This commit is contained in:
parent
e5b51efb87
commit
5dfd3f780f
22
Cargo.lock
generated
22
Cargo.lock
generated
|
@ -26,7 +26,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"linked_list_allocator",
|
"linked_list_allocator",
|
||||||
"riscv",
|
"riscv",
|
||||||
"spinning_top 0.3.0",
|
"spin",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -35,7 +35,7 @@ version = "0.10.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
|
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"spinning_top 0.2.5",
|
"spinning_top",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -64,6 +64,15 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
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]]
|
[[package]]
|
||||||
name = "spinning_top"
|
name = "spinning_top"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
@ -72,12 +81,3 @@ checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lock_api",
|
"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",
|
|
||||||
]
|
|
||||||
|
|
|
@ -6,4 +6,4 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
linked_list_allocator = "0.10.5"
|
linked_list_allocator = "0.10.5"
|
||||||
riscv = "0.11.1"
|
riscv = "0.11.1"
|
||||||
spinning_top = "0.3.0"
|
spin = "0.9.8"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* src/script.lds */
|
/* lds/kernel.lds */
|
||||||
|
|
||||||
OUTPUT_ARCH("riscv")
|
OUTPUT_ARCH("riscv")
|
||||||
ENTRY(_entry)
|
ENTRY(_entry)
|
||||||
|
|
139
src/entry.rs
139
src/entry.rs
|
@ -1,92 +1,86 @@
|
||||||
// src/entry.rs
|
// src/entry.rs
|
||||||
|
|
||||||
/// This is the first function called when the system boots. In this function,
|
static READY: spin::Once<()> = spin::Once::new();
|
||||||
/// we set up important control status registers (CSR) such as `mstatus` and
|
|
||||||
/// `satp`. The global, stack, and thread pointers are also configured here.
|
/// After some initialization in asm/entry.S, the kernel will jump here and
|
||||||
|
/// each hart will have its own setup sequence.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[link_section = ".text.init"]
|
unsafe extern "C" fn _start() {
|
||||||
unsafe extern "C" fn entry() {
|
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
use riscv::register::{mhartid, mstatus, satp, sstatus};
|
use riscv::register::{mepc, mstatus, satp, sie, sstatus};
|
||||||
|
|
||||||
// Global pointer `gp`
|
// Set previous privilege for all harts to M-mode, set previous interrupt
|
||||||
//
|
// enable, and set floating-point unit to initial state
|
||||||
// Push current option stack to temporarily disable relaxation, load
|
mstatus::set_mpp(mstatus::MPP::Supervisor);
|
||||||
// _global_pointer symbol (provided by linker), then pop option stack.
|
mstatus::set_mpie();
|
||||||
//
|
|
||||||
// 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);
|
|
||||||
mstatus::set_fs(sstatus::FS::Initial);
|
mstatus::set_fs(sstatus::FS::Initial);
|
||||||
|
|
||||||
asm!(
|
// Store ref to main in M-mode exception program counter
|
||||||
"csrw mie, x0",
|
mepc::write(main as usize);
|
||||||
|
|
||||||
"la t1, {kinit}",
|
// Disable paging
|
||||||
"csrw mepc, t1",
|
satp::write(0);
|
||||||
|
|
||||||
"la ra, 2f",
|
// Delegate all traps to S-mode, using inline assembly since we have not
|
||||||
"mret",
|
// provided a wrapper for it yet
|
||||||
"2:",
|
asm!("li t0, 0xffff", "csrw medeleg, t0", "csrw mideleg, t0",);
|
||||||
kinit = sym kinit,
|
|
||||||
);
|
// 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]
|
#[no_mangle]
|
||||||
extern "C" fn kinit() {
|
extern "C" fn kinit() {
|
||||||
use crate::uart;
|
use crate::uart;
|
||||||
use core::arch::asm;
|
|
||||||
uart::Device::new(0x1000_0000);
|
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]
|
#[no_mangle]
|
||||||
extern "C" fn kinit_hart() {}
|
extern "C" fn kinit_hart() {}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_tp() -> usize {
|
fn hartid() -> usize {
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
let id: usize;
|
let id: usize;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -97,14 +91,3 @@ fn read_tp() -> usize {
|
||||||
}
|
}
|
||||||
id
|
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
37
src/entry_alt.S
Normal 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
|
|
@ -1,9 +1,9 @@
|
||||||
// src/uart.rs
|
// src/uart.rs
|
||||||
//! This module provides access to the UART console.
|
//! 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.
|
/// Represents an initialised UART device.
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
|
@ -65,7 +65,7 @@ impl core::fmt::Write for Device {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// `base` must point to the base address of a UART device.
|
/// `base` must point to the base address of a UART device.
|
||||||
pub fn init_console(base: usize) {
|
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));
|
*console = Some(Device::new(base));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue