From cf55a8faa1c9c99295af098544914e3d8621dd11 Mon Sep 17 00:00:00 2001 From: hheik <4469778+hheik@users.noreply.github.com> Date: Thu, 2 May 2024 16:36:54 +0300 Subject: [PATCH] entry.S jumps to rust implementation of start() --- kernel/entry.S | 6 +- kernel/start.c | 40 ------ theseus/src/lib.rs | 2 + theseus/src/param.rs | 13 ++ theseus/src/riscv.rs | 287 +++++++++++++++++++++++++++++++++++++++++++ theseus/src/start.rs | 54 ++++++++ 6 files changed, 359 insertions(+), 43 deletions(-) create mode 100644 theseus/src/param.rs create mode 100644 theseus/src/start.rs diff --git a/kernel/entry.S b/kernel/entry.S index 5ab365e..574dfd0 100644 --- a/kernel/entry.S +++ b/kernel/entry.S @@ -5,8 +5,8 @@ .section .text .global _entry _entry: - # set up a stack for C. - # stack0 is declared in start.c, + # set up a stack for Rust + # stack0 is declared in start.rs, # with a 4096-byte stack per CPU. # sp = stack0 + (hartid * 4096) la sp, stack0 @@ -15,7 +15,7 @@ _entry: addi a1, a1, 1 mul a0, a0, a1 add sp, sp, a0 - # jump to start() in start.c + # jump to start() in start.rs call start spin: j spin diff --git a/kernel/start.c b/kernel/start.c index f83b619..74d8a4f 100644 --- a/kernel/start.c +++ b/kernel/start.c @@ -4,54 +4,14 @@ #include "riscv.h" #include "defs.h" -void main(); void timerinit(); -// entry.S needs one stack per CPU. -__attribute__((aligned(16))) char stack0[4096 * NCPU]; - // a scratch area per CPU for machine-mode timer interrupts. uint64 timer_scratch[NCPU][5]; // assembly code in kernelvec.S for machine-mode timer interrupt. extern void timervec(); -// entry.S jumps here in machine mode on stack0. -void start() { - // set M Previous Privilege mode to Supervisor, for mret. - unsigned long x = r_mstatus(); - x &= ~MSTATUS_MPP_MASK; - x |= MSTATUS_MPP_S; - w_mstatus(x); - - // set M Exception Program Counter to main, for mret. - // requires gcc -mcmodel=medany - w_mepc((uint64)main); - - // disable paging for now. - w_satp(0); - - // delegate all interrupts and exceptions to supervisor mode. - w_medeleg(0xffff); - w_mideleg(0xffff); - w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE); - - // configure Physical Memory Protection to give supervisor mode - // access to all of physical memory. - w_pmpaddr0(0x3fffffffffffffull); - w_pmpcfg0(0xf); - - // ask for clock interrupts. - timerinit(); - - // keep each CPU's hartid in its tp register, for cpuid(). - int id = r_mhartid(); - w_tp(id); - - // switch to supervisor mode and jump to main(). - asm volatile("mret"); -} - // arrange to receive timer interrupts. // they will arrive in machine mode at // at timervec in kernelvec.S, diff --git a/theseus/src/lib.rs b/theseus/src/lib.rs index 4f91dd2..59c5e02 100644 --- a/theseus/src/lib.rs +++ b/theseus/src/lib.rs @@ -2,8 +2,10 @@ #![crate_type = "staticlib"] pub mod memlayout; +pub mod param; pub mod riscv; pub mod spinlock; +pub mod start; pub mod uart; extern "C" { diff --git a/theseus/src/param.rs b/theseus/src/param.rs new file mode 100644 index 0000000..17b1369 --- /dev/null +++ b/theseus/src/param.rs @@ -0,0 +1,13 @@ +pub const NPROC: usize = 64; // maximum number of processes +pub const NCPU: usize = 8; // maximum number of CPUs +pub const NOFILE: usize = 16; // open files per process +pub const NFILE: usize = 100; // open files per system +pub const NINODE: usize = 50; // maximum number of active i-nodes +pub const NDEV: usize = 10; // maximum major device number +pub const ROOTDEV: usize = 1; // device number of file system root disk +pub const MAXARG: usize = 32; // max exec arguments +pub const MAXOPBLOCKS: usize = 10; // max # of blocks any FS op writes +pub const LOGSIZE: usize = MAXOPBLOCKS * 3; // max data blocks in on-disk log +pub const NBUF: usize = MAXOPBLOCKS * 3; // size of disk block cache +pub const FSSIZE: usize = 2000; // size of file system in blocks +pub const MAXPATH: usize = 128; // maximum file path name diff --git a/theseus/src/riscv.rs b/theseus/src/riscv.rs index 4a16823..7d5d7b8 100644 --- a/theseus/src/riscv.rs +++ b/theseus/src/riscv.rs @@ -1,3 +1,290 @@ +use core::arch::asm; + +// which hart (core) is this? +#[inline] +pub unsafe fn r_mhartid() -> u64 { + let x: u64; + asm!("csrr {x}, mhartid", x = out(reg) x); + x +} + +// Machine Status Register, mstatus +pub const MSTATUS_MPP_MASK: u64 = 3 << 11; // previous mode. +pub const MSTATUS_MPP_M: u64 = 3 << 11; +pub const MSTATUS_MPP_S: u64 = 1 << 11; +pub const MSTATUS_MPP_U: u64 = 0 << 11; +pub const MSTATUS_MIE: u64 = 1 << 3; // machine-mode interrupt enable. + +#[inline] +pub unsafe fn r_mstatus() -> u64 { + let x: u64; + asm!("csrr {x}, mstatus", x = out(reg) x); + x +} + +#[inline] +pub unsafe fn w_mstatus(x: u64) { + asm!("csrw mstatus, {x}", x = in(reg) x); +} + +// // machine exception program counter, holds the +// // instruction address to which a return from +// // exception will go. +#[inline] +pub unsafe fn w_mepc(x: u64) { + asm!("csrw mepc, {x}", x = in(reg) x); +} + +// // Supervisor Status Register, sstatus + +// #define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User +// #define SSTATUS_SPIE (1L << 5) // Supervisor Previous Interrupt Enable +// #define SSTATUS_UPIE (1L << 4) // User Previous Interrupt Enable +// #define SSTATUS_SIE (1L << 1) // Supervisor Interrupt Enable +// #define SSTATUS_UIE (1L << 0) // User Interrupt Enable + +#[inline] +pub unsafe fn r_sstatus() -> u64 { + let x: u64; + asm!("csrr {x}, sstatus", x = out(reg) x); + x +} + +#[inline] +pub unsafe fn w_sstatus(x: u64) { + asm!("csrw sstatus, {x}", x = in(reg) x); +} + +// // Supervisor Interrupt Pending +#[inline] +pub unsafe fn r_sip() -> u64 { + let x: u64; + asm!("csrr {x}, sip", x = out(reg) x); + x +} + +// static inline void w_sip(uint64 x) { asm volatile("csrw sip, %0" : : "r"(x)); } +#[inline] +pub unsafe fn w_sip(x: u64) { + asm!("csrw sip, {x}", x = in(reg) x); +} + +// Supervisor Interrupt Enable +pub const SIE_SEIE: u64 = 1 << 9; // external +pub const SIE_STIE: u64 = 1 << 5; // timer +pub const SIE_SSIE: u64 = 1 << 1; // software + +// static inline uint64 r_sie() { +// uint64 x; +// asm volatile("csrr %0, sie" : "=r"(x)); +// return x; +// } +#[inline] +pub unsafe fn r_sie() -> u64 { + let x: u64; + asm!("csrr {x}, sie", x = out(reg) x); + x +} + +// static inline void w_sie(uint64 x) { asm volatile("csrw sie, %0" : : "r"(x)); } +#[inline] +pub unsafe fn w_sie(x: u64) { + asm!("csrw sie, {x}", x = in(reg) x); +} + +// // Machine-mode Interrupt Enable +// #define MIE_MEIE (1L << 11) // external +// #define MIE_MTIE (1L << 7) // timer +// #define MIE_MSIE (1L << 3) // software +// static inline uint64 r_mie() { +// uint64 x; +// asm volatile("csrr %0, mie" : "=r"(x)); +// return x; +// } + +// static inline void w_mie(uint64 x) { asm volatile("csrw mie, %0" : : "r"(x)); } + +// // supervisor exception program counter, holds the +// // instruction address to which a return from +// // exception will go. +// static inline void w_sepc(uint64 x) { +// asm volatile("csrw sepc, %0" : : "r"(x)); +// } + +// static inline uint64 r_sepc() { +// uint64 x; +// asm volatile("csrr %0, sepc" : "=r"(x)); +// return x; +// } + +// // Machine Exception Delegation +// static inline uint64 r_medeleg() { +// uint64 x; +// asm volatile("csrr %0, medeleg" : "=r"(x)); +// return x; +// } + +// static inline void w_medeleg(uint64 x) { +// asm volatile("csrw medeleg, %0" : : "r"(x)); +// } +#[inline] +pub unsafe fn w_medeleg(x: u64) { + asm!("csrw medeleg, {x}", x = in(reg) x); +} + +// // Machine Interrupt Delegation +// static inline uint64 r_mideleg() { +// uint64 x; +// asm volatile("csrr %0, mideleg" : "=r"(x)); +// return x; +// } + +// static inline void w_mideleg(uint64 x) { +// asm volatile("csrw mideleg, %0" : : "r"(x)); +// } +#[inline] +pub unsafe fn w_mideleg(x: u64) { + asm!("csrw mideleg, {x}", x = in(reg) x); +} + +// // Supervisor Trap-Vector Base Address +// // low two bits are mode. +// static inline void w_stvec(uint64 x) { +// asm volatile("csrw stvec, %0" : : "r"(x)); +// } + +// static inline uint64 r_stvec() { +// uint64 x; +// asm volatile("csrr %0, stvec" : "=r"(x)); +// return x; +// } + +// // Machine-mode interrupt vector +// static inline void w_mtvec(uint64 x) { +// asm volatile("csrw mtvec, %0" : : "r"(x)); +// } + +// // Physical Memory Protection +// static inline void w_pmpcfg0(uint64 x) { +// asm volatile("csrw pmpcfg0, %0" : : "r"(x)); +// } +#[inline] +pub unsafe fn w_pmpcfg0(x: u64) { + asm!("csrw pmpcfg0, {x}", x = in(reg) x); +} + +// static inline void w_pmpaddr0(uint64 x) { +// asm volatile("csrw pmpaddr0, %0" : : "r"(x)); +// } +#[inline] +pub unsafe fn w_pmpaddr0(x: u64) { + asm!("csrw pmpaddr0, {x}", x = in(reg) x); +} + +// // use riscv's sv39 page table scheme. +// #define SATP_SV39 (8L << 60) + +// #define MAKE_SATP(pagetable) (SATP_SV39 | (((uint64)pagetable) >> 12)) + +// // supervisor address translation and protection; +// // holds the address of the page table. +// static inline void w_satp(uint64 x) { +// asm volatile("csrw satp, %0" : : "r"(x)); +// } +#[inline] +pub unsafe fn w_satp(x: u64) { + asm!("csrw satp, {x}", x = in(reg) x); +} + +// static inline uint64 r_satp() { +// uint64 x; +// asm volatile("csrr %0, satp" : "=r"(x)); +// return x; +// } + +// static inline void w_mscratch(uint64 x) { +// asm volatile("csrw mscratch, %0" : : "r"(x)); +// } + +// // Supervisor Trap Cause +// static inline uint64 r_scause() { +// uint64 x; +// asm volatile("csrr %0, scause" : "=r"(x)); +// return x; +// } + +// // Supervisor Trap Value +// static inline uint64 r_stval() { +// uint64 x; +// asm volatile("csrr %0, stval" : "=r"(x)); +// return x; +// } + +// // Machine-mode Counter-Enable +// static inline void w_mcounteren(uint64 x) { +// asm volatile("csrw mcounteren, %0" : : "r"(x)); +// } + +// static inline uint64 r_mcounteren() { +// uint64 x; +// asm volatile("csrr %0, mcounteren" : "=r"(x)); +// return x; +// } + +// // machine-mode cycle counter +// static inline uint64 r_time() { +// uint64 x; +// asm volatile("csrr %0, time" : "=r"(x)); +// return x; +// } + +// // enable device interrupts +// static inline void intr_on() { w_sstatus(r_sstatus() | SSTATUS_SIE); } + +// // disable device interrupts +// static inline void intr_off() { w_sstatus(r_sstatus() & ~SSTATUS_SIE); } + +// // are device interrupts enabled? +// static inline int intr_get() { +// uint64 x = r_sstatus(); +// return (x & SSTATUS_SIE) != 0; +// } + +// static inline uint64 r_sp() { +// uint64 x; +// asm volatile("mv %0, sp" : "=r"(x)); +// return x; +// } + +// // read and write tp, the thread pointer, which xv6 uses to hold +// // this core's hartid (core number), the index into cpus[]. +// static inline uint64 r_tp() { +// uint64 x; +// asm volatile("mv %0, tp" : "=r"(x)); +// return x; +// } + +// static inline void w_tp(uint64 x) { asm volatile("mv tp, %0" : : "r"(x)); } +#[inline] +pub unsafe fn w_tp(x: u64) { + asm!("mv tp, {x}", x = in(reg) x); +} + +// static inline uint64 r_ra() { +// uint64 x; +// asm volatile("mv %0, ra" : "=r"(x)); +// return x; +// } + +// // flush the TLB. +// static inline void sfence_vma() { +// // the zero, zero means flush all TLB entries. +// asm volatile("sfence.vma zero, zero"); +// } + +// typedef uint64 pte_t; +// typedef uint64 *pagetable_t; // 512 PTEs + pub const PGSIZE: u64 = 4096; // bytes per page pub const PGSHIFT: i32 = 12; // bits of offset within a page diff --git a/theseus/src/start.rs b/theseus/src/start.rs new file mode 100644 index 0000000..5bd0673 --- /dev/null +++ b/theseus/src/start.rs @@ -0,0 +1,54 @@ +use core::arch::asm; + +use crate::param::NCPU; +use crate::riscv as rv; + +extern "C" { + // start.c + fn timerinit(); + + // main.c + fn main(); +} + +#[repr(align(16))] +pub struct AlignedStack([u8; 4096 * NCPU]); +#[no_mangle] +pub static mut stack0: AlignedStack = AlignedStack([0; 4096 * NCPU]); + +// entry.S jumps here in machine mode on stack0. +#[no_mangle] +pub unsafe extern "C" fn start() { + // set M Previous Privilege mode to Supervisor, for mret. + let mut x = rv::r_mstatus(); + x &= !rv::MSTATUS_MPP_MASK; + x |= rv::MSTATUS_MPP_S; + rv::w_mstatus(x); + + // set M Exception Program Counter to main, for mret. + // requires gcc -mcmodel=medany + rv::w_mepc(main as *const () as u64); + + // disable paging for now. + rv::w_satp(0); + + // delegate all interrupts and exceptions to supervisor mode. + rv::w_medeleg(0xffff); + rv::w_mideleg(0xffff); + rv::w_sie(rv::r_sie() | rv::SIE_SEIE | rv::SIE_STIE | rv::SIE_SSIE); + + // configure Physical Memory Protection to give supervisor mode + // access to all of physical memory. + rv::w_pmpaddr0(0x3fffffffffffff); + rv::w_pmpcfg0(0xf); + + // ask for clock interrupts. + timerinit(); + + // keep each CPU's hartid in its tp register, for cpuid(). + let id = rv::r_mhartid(); + rv::w_tp(id); + + // switch to supervisor mode and jump to main(). + asm!("mret"); +}