entry.S jumps to rust implementation of start()

feat/start
hheik 2024-05-02 16:36:54 +03:00
parent d57cdc9d6c
commit cf55a8faa1
6 changed files with 359 additions and 43 deletions

View File

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

View File

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

View File

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

13
theseus/src/param.rs Normal file
View File

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

View File

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

54
theseus/src/start.rs Normal file
View File

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