Switch to newly refactored init process, update readme
This commit is contained in:
parent
eee7c6f02b
commit
2aad0977f1
BIN
20240521-hello_harts.png
Normal file
BIN
20240521-hello_harts.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
|
@ -15,6 +15,10 @@ A kernel for RISC-V written in Rust. Currently focused on running on QEMU generi
|
|||
|
||||

|
||||
|
||||
* **2024-05-21:** I've removed the original `entry.s` and replaced it with what was formerly `entry_alt.s`. The new start() and main() functions are based on the implementations in the xv6 kernel. Next steps are setting up the page tables and process tables, so that everything works better.
|
||||
|
||||

|
||||
|
||||
## Research and implement
|
||||
|
||||
- [ ] Basics
|
||||
|
|
36
src/entry.S
36
src/entry.S
|
@ -1,32 +1,30 @@
|
|||
# entry.S
|
||||
# entry.s
|
||||
.option norvc
|
||||
.section .data
|
||||
|
||||
.section .text.init
|
||||
.global _entry
|
||||
_entry:
|
||||
# Any hardware threads (hart) that are not bootstrapping
|
||||
# need to wait for an IPI
|
||||
csrr t0, mhartid
|
||||
bnez t0, 3f
|
||||
|
||||
# SATP should be zero, but let's make sure
|
||||
csrw satp, zero
|
||||
|
||||
# Set global pointer (gp)
|
||||
# Important to have relaxation off for this instruction
|
||||
.option push
|
||||
.option norelax
|
||||
la gp, _global_pointer
|
||||
la gp, _global_pointer
|
||||
.option pop
|
||||
|
||||
li t5, 0xffff
|
||||
csrw medeleg, t5
|
||||
csrw mideleg, t5
|
||||
# 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
|
||||
|
||||
li t0, (0b11 << 11) | (1 << 7) | (1 << 3)
|
||||
csrw mstatus, 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
|
||||
|
@ -35,9 +33,5 @@ _entry:
|
|||
addi t0, t0, 1
|
||||
bne t0, t1, 1b
|
||||
2:
|
||||
j 4f
|
||||
3:
|
||||
wfi
|
||||
j 3b
|
||||
4:
|
||||
tail start
|
||||
# Tail call Rust start function
|
||||
tail start
|
||||
|
|
33
src/entry.rs
33
src/entry.rs
|
@ -1,7 +1,16 @@
|
|||
// src/entry.rs
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use crate::uart;
|
||||
|
||||
mod heap;
|
||||
mod uart;
|
||||
|
||||
static INIT_LOCK: spin::Once<()> = spin::Once::new();
|
||||
|
||||
core::arch::global_asm!(include_str!("entry.s"));
|
||||
|
||||
/// After some initialization in asm/entry.S, the kernel will jump here and
|
||||
/// each hart will have its own setup sequence.
|
||||
#[no_mangle]
|
||||
|
@ -45,7 +54,7 @@ extern "C" fn main() {
|
|||
INIT_LOCK.call_once(|| {
|
||||
// Disable machine interrupts while initializing
|
||||
interrupt::machine::disable();
|
||||
// TODO Initialize console
|
||||
console_init();
|
||||
// TODO Write boot message
|
||||
|
||||
// TODO Set up paging
|
||||
|
@ -64,6 +73,12 @@ extern "C" fn main() {
|
|||
|
||||
riscv::asm::fence(); // Emit a fence just in case
|
||||
});
|
||||
|
||||
// poll console for input and print characters back
|
||||
loop {
|
||||
let c = crate::uart::CONSOLE.lock().as_mut().and_then(crate::uart::Device::get);
|
||||
if let Some(c) = c { crate::print!("{}", c as char); }
|
||||
}
|
||||
} else {
|
||||
INIT_LOCK.wait();
|
||||
riscv::asm::fence(); // Emit a fence just in case
|
||||
|
@ -71,14 +86,18 @@ extern "C" fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn kinit() {
|
||||
use crate::uart;
|
||||
uart::Device::new(0x1000_0000);
|
||||
fn console_init() {
|
||||
// Initialize heap
|
||||
unsafe { crate::heap::init(); };
|
||||
|
||||
// Set up UART and print to console
|
||||
crate::uart::init_console(0x1000_0000);
|
||||
crate::println!("Hello from hart {}!", hartid());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn kinit_hart() {}
|
||||
fn kinit() {}
|
||||
|
||||
fn kinit_hart() {}
|
||||
|
||||
#[inline]
|
||||
fn hartid() -> usize {
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
# 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
|
124
src/main.rs
124
src/main.rs
|
@ -5,40 +5,120 @@
|
|||
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
mod entry;
|
||||
mod heap;
|
||||
mod trap;
|
||||
mod uart;
|
||||
|
||||
core::arch::global_asm!(include_str!("entry.S"));
|
||||
static INIT_LOCK: spin::Once<()> = spin::Once::new();
|
||||
|
||||
core::arch::global_asm!(include_str!("entry.s"));
|
||||
|
||||
/// After some initialization in asm/entry.s, the kernel will jump here and
|
||||
/// each hart will have its own setup sequence.
|
||||
#[no_mangle]
|
||||
extern "C" fn start() -> ! {
|
||||
// UNSAFE: Called exactly once, right here.
|
||||
unsafe { heap::init() };
|
||||
unsafe extern "C" fn start() {
|
||||
use core::arch::asm;
|
||||
use riscv::register::{mepc, mstatus, satp, sie, sstatus};
|
||||
|
||||
// Now we're free to use dynamic allocation!
|
||||
// {
|
||||
// extern crate alloc;
|
||||
// use alloc::boxed::Box;
|
||||
// let _my_heap_pointer = Box::new(10);
|
||||
// // _my_heap_pointer lives on the heap!
|
||||
// }
|
||||
// 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);
|
||||
|
||||
// println!("This should not print because the console is not initialised.");
|
||||
uart::init_console(0x1000_0000);
|
||||
println!("Hello, world!");
|
||||
// Disable paging
|
||||
satp::write(0);
|
||||
|
||||
// print current hartid
|
||||
println!("hartid: {}", riscv::register::mhartid::read());
|
||||
// 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",);
|
||||
|
||||
// poll console for input and print characters back
|
||||
loop {
|
||||
let c = uart::CONSOLE.lock().as_mut().and_then(uart::Device::get);
|
||||
if let Some(c) = c { print!("{}", c as char); }
|
||||
// Enable S-mode external, timer, and software interrupts
|
||||
sie::set_sext();
|
||||
sie::set_stimer();
|
||||
sie::set_ssoft();
|
||||
|
||||
// TODO configure PMP
|
||||
// TODO timer init
|
||||
|
||||
// Trying to figure out why I can't use mret here. Might need
|
||||
// asm!(
|
||||
// "la t1, 1f",
|
||||
// "csrw mepc, t1",
|
||||
// "la ra, 1f",
|
||||
// "mret",
|
||||
// "1:",
|
||||
// );
|
||||
|
||||
main();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use riscv::interrupt;
|
||||
use riscv::register::{mstatus, sstatus};
|
||||
|
||||
if hartid() == 0 {
|
||||
INIT_LOCK.call_once(|| {
|
||||
// Disable machine interrupts while initializing
|
||||
interrupt::machine::disable();
|
||||
console_init();
|
||||
// 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(); // Emit a fence just in case
|
||||
});
|
||||
|
||||
// poll console for input and print characters back
|
||||
loop {
|
||||
let c = uart::CONSOLE.lock().as_mut().and_then(uart::Device::get);
|
||||
if let Some(c) = c { print!("{}", c as char); }
|
||||
}
|
||||
} else {
|
||||
INIT_LOCK.wait();
|
||||
riscv::asm::fence(); // Emit a fence just in case
|
||||
kinit_hart();
|
||||
println!("Hello from hart {}!", hartid());
|
||||
}
|
||||
}
|
||||
|
||||
fn console_init() {
|
||||
// Initialize heap
|
||||
unsafe { heap::init(); };
|
||||
|
||||
// Set up UART and print to console
|
||||
uart::init_console(0x1000_0000);
|
||||
println!("Hello from hart {}!", hartid());
|
||||
}
|
||||
|
||||
fn kinit() {}
|
||||
|
||||
fn kinit_hart() {}
|
||||
|
||||
#[inline]
|
||||
fn hartid() -> usize {
|
||||
use core::arch::asm;
|
||||
let id: usize;
|
||||
unsafe {
|
||||
asm!(
|
||||
"mv {id}, tp",
|
||||
id = out(reg) id,
|
||||
);
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn eh_personality() {}
|
||||
|
||||
|
|
Loading…
Reference in a new issue