Compare commits
3 Commits
d57cdc9d6c
...
d3ba78c326
| Author | SHA1 | Date |
|---|---|---|
|
|
d3ba78c326 | |
|
|
9eba9bb925 | |
|
|
cf55a8faa1 |
1
Makefile
1
Makefile
|
|
@ -3,7 +3,6 @@ U=user
|
||||||
|
|
||||||
OBJS = \
|
OBJS = \
|
||||||
$K/entry.o \
|
$K/entry.o \
|
||||||
$K/start.o \
|
|
||||||
$K/console.o \
|
$K/console.o \
|
||||||
$K/printf.o \
|
$K/printf.o \
|
||||||
$K/kalloc.o \
|
$K/kalloc.o \
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
.section .text
|
.section .text
|
||||||
.global _entry
|
.global _entry
|
||||||
_entry:
|
_entry:
|
||||||
# set up a stack for C.
|
# set up a stack for Rust
|
||||||
# stack0 is declared in start.c,
|
# stack0 is declared in start.rs,
|
||||||
# with a 4096-byte stack per CPU.
|
# with a 4096-byte stack per CPU.
|
||||||
# sp = stack0 + (hartid * 4096)
|
# sp = stack0 + (hartid * 4096)
|
||||||
la sp, stack0
|
la sp, stack0
|
||||||
|
|
@ -15,7 +15,7 @@ _entry:
|
||||||
addi a1, a1, 1
|
addi a1, a1, 1
|
||||||
mul a0, a0, a1
|
mul a0, a0, a1
|
||||||
add sp, sp, a0
|
add sp, sp, a0
|
||||||
# jump to start() in start.c
|
# jump to start() in start.rs
|
||||||
call start
|
call start
|
||||||
spin:
|
spin:
|
||||||
j spin
|
j spin
|
||||||
|
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
#include "types.h"
|
|
||||||
#include "param.h"
|
|
||||||
#include "memlayout.h"
|
|
||||||
#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,
|
|
||||||
// which turns them into software interrupts for
|
|
||||||
// devintr() in trap.c.
|
|
||||||
void timerinit() {
|
|
||||||
// each CPU has a separate source of timer interrupts.
|
|
||||||
int id = r_mhartid();
|
|
||||||
|
|
||||||
// ask the CLINT for a timer interrupt.
|
|
||||||
int interval = 1000000; // cycles; about 1/10th second in qemu.
|
|
||||||
*(uint64 *)CLINT_MTIMECMP(id) = *(uint64 *)CLINT_MTIME + interval;
|
|
||||||
|
|
||||||
// prepare information in scratch[] for timervec.
|
|
||||||
// scratch[0..2] : space for timervec to save registers.
|
|
||||||
// scratch[3] : address of CLINT MTIMECMP register.
|
|
||||||
// scratch[4] : desired interval (in cycles) between timer interrupts.
|
|
||||||
uint64 *scratch = &timer_scratch[id][0];
|
|
||||||
scratch[3] = CLINT_MTIMECMP(id);
|
|
||||||
scratch[4] = interval;
|
|
||||||
w_mscratch((uint64)scratch);
|
|
||||||
|
|
||||||
// set the machine-mode trap handler.
|
|
||||||
w_mtvec((uint64)timervec);
|
|
||||||
|
|
||||||
// enable machine-mode interrupts.
|
|
||||||
w_mstatus(r_mstatus() | MSTATUS_MIE);
|
|
||||||
|
|
||||||
// enable machine-mode timer interrupts.
|
|
||||||
w_mie(r_mie() | MIE_MTIE);
|
|
||||||
}
|
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
#![crate_type = "staticlib"]
|
#![crate_type = "staticlib"]
|
||||||
|
|
||||||
pub mod memlayout;
|
pub mod memlayout;
|
||||||
|
pub mod param;
|
||||||
pub mod riscv;
|
pub mod riscv;
|
||||||
pub mod spinlock;
|
pub mod spinlock;
|
||||||
|
pub mod start;
|
||||||
pub mod uart;
|
pub mod uart;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,12 @@ pub const VIRTIO0: i32 = 0x10001000;
|
||||||
pub const VIRTIO0_IRQ: i32 = 1;
|
pub const VIRTIO0_IRQ: i32 = 1;
|
||||||
|
|
||||||
// core local interruptor (CLINT), which contains the timer.
|
// core local interruptor (CLINT), which contains the timer.
|
||||||
pub const CLINT: i64 = 0x2000000;
|
pub const CLINT: u64 = 0x2000000;
|
||||||
// const CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8 * (hartid));
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn CLINT_MTIMECMP(hartid: i32) -> i64 {
|
pub fn CLINT_MTIMECMP(hartid: u64) -> *mut u64 {
|
||||||
CLINT + 0x4000 + 8 * hartid as i64
|
(CLINT + 0x4000 + 8 * hartid) as *mut u64
|
||||||
}
|
}
|
||||||
pub const CLINT_MTIME: i64 = CLINT + 0xBFF8; // cycles since boot.
|
pub const CLINT_MTIME: *mut u64 = (CLINT + 0xBFF8) as *mut u64; // cycles since boot.
|
||||||
|
|
||||||
// qemu puts platform-level interrupt controller (PLIC) here.
|
// qemu puts platform-level interrupt controller (PLIC) here.
|
||||||
pub const PLIC: i64 = 0x0c000000;
|
pub const PLIC: i64 = 0x0c000000;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -1,3 +1,282 @@
|
||||||
|
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
|
||||||
|
pub const MIE_MEIE: u64 = 1 << 11; // external
|
||||||
|
pub const MIE_MTIE: u64 = 1 << 7; // timer
|
||||||
|
pub const MIE_MSIE: u64 = 1 << 3; // software
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn r_mie() -> u64 {
|
||||||
|
let x: u64;
|
||||||
|
asm!("csrr {x}, mie", x = out(reg) x);
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn w_mie(x: u64) {
|
||||||
|
asm!("csrw mie, {x}", x = in(reg) 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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[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
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn w_mtvec(x: u64) {
|
||||||
|
asm!("csrw mtvec, {x}", x = in(reg) x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physical Memory Protection
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn w_pmpcfg0(x: u64) {
|
||||||
|
asm!("csrw pmpcfg0, {x}", x = in(reg) 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.
|
||||||
|
#[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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn w_mscratch(x: u64) {
|
||||||
|
asm!("csrw mscratch, {x}", x = in(reg) 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 PGSIZE: u64 = 4096; // bytes per page
|
||||||
pub const PGSHIFT: i32 = 12; // bits of offset within a page
|
pub const PGSHIFT: i32 = 12; // bits of offset within a page
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
use core::arch::asm;
|
||||||
|
use core::usize;
|
||||||
|
|
||||||
|
use crate::memlayout::{CLINT_MTIME, CLINT_MTIMECMP};
|
||||||
|
use crate::param::NCPU;
|
||||||
|
use crate::riscv as rv;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
// assembly code in kernelvec.S for machine-mode timer interrupt.
|
||||||
|
fn timervec();
|
||||||
|
|
||||||
|
// main.c
|
||||||
|
fn main();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(align(16))]
|
||||||
|
pub struct EntryStack([u8; 4096 * NCPU]);
|
||||||
|
|
||||||
|
// entry.S needs one stack per CPU.
|
||||||
|
#[no_mangle]
|
||||||
|
pub static mut stack0: EntryStack = EntryStack([0; 4096 * NCPU]);
|
||||||
|
|
||||||
|
// a scratch area per CPU for machine-mode timer interrupts.
|
||||||
|
static mut timer_scratch: [[u64; 5]; NCPU] = [[0; 5]; 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// arrange to receive timer interrupts.
|
||||||
|
// they will arrive in machine mode at
|
||||||
|
// at timervec in kernelvec.S,
|
||||||
|
// which turns them into software interrupts for
|
||||||
|
// devintr() in trap.c.
|
||||||
|
unsafe fn timerinit() {
|
||||||
|
// each CPU has a separate source of timer interrupts.
|
||||||
|
let id = rv::r_mhartid();
|
||||||
|
|
||||||
|
// ask the CLINT for a timer interrupt.
|
||||||
|
let interval: u64 = 1000000; // cycles; about 1/10th second in qemu.
|
||||||
|
*CLINT_MTIMECMP(id) = *CLINT_MTIME + interval;
|
||||||
|
|
||||||
|
// prepare information in scratch[] for timervec.
|
||||||
|
// scratch[0..2] : space for timervec to save registers.
|
||||||
|
// scratch[3] : address of CLINT MTIMECMP register.
|
||||||
|
// scratch[4] : desired interval (in cycles) between timer interrupts.
|
||||||
|
timer_scratch[id as usize][3] = CLINT_MTIMECMP(id) as u64;
|
||||||
|
timer_scratch[id as usize][4] = interval;
|
||||||
|
|
||||||
|
// w_mscratch((uint64)scratch);
|
||||||
|
rv::w_mscratch(timer_scratch[id as usize].as_ptr() as u64);
|
||||||
|
|
||||||
|
// set the machine-mode trap handler.
|
||||||
|
rv::w_mtvec(timervec as *const () as u64);
|
||||||
|
|
||||||
|
// enable machine-mode interrupts.
|
||||||
|
rv::w_mstatus(rv::r_mstatus() | rv::MSTATUS_MIE);
|
||||||
|
|
||||||
|
// enable machine-mode timer interrupts.
|
||||||
|
rv::w_mie(rv::r_mie() | rv::MIE_MTIE);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue