mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 01:16:26 +04:00
run in qemu -bios none ENV
This commit is contained in:
parent
683a4fdc55
commit
1722d0d4d7
18
os/Makefile
18
os/Makefile
@ -24,7 +24,7 @@ ifeq ($(MODE), release)
|
||||
endif
|
||||
|
||||
# KERNEL ENTRY
|
||||
KERNEL_ENTRY_PA := 0x80200000
|
||||
KERNEL_ENTRY_PA := 0x80000000
|
||||
|
||||
# Binutils
|
||||
OBJDUMP := rust-objdump --arch-name=riscv64
|
||||
@ -71,7 +71,21 @@ disasm-vim: kernel
|
||||
@nvim $(DISASM_TMP)
|
||||
@rm $(DISASM_TMP)
|
||||
|
||||
run: run-inner
|
||||
run: run-inner-none
|
||||
|
||||
run-inner-none: build
|
||||
@qemu-system-riscv64 \
|
||||
-M 128m \
|
||||
-machine virt \
|
||||
-bios none \
|
||||
$(GUI_OPTION) \
|
||||
-kernel $(KERNEL_ELF) \
|
||||
-drive file=$(FS_IMG),if=none,format=raw,id=x0 \
|
||||
-device virtio-blk-device,drive=x0 \
|
||||
# -device virtio-gpu-device \
|
||||
-device virtio-keyboard-device \
|
||||
-device virtio-mouse-device \
|
||||
-serial stdio
|
||||
|
||||
run-inner: build
|
||||
@qemu-system-riscv64 \
|
||||
|
@ -2,7 +2,7 @@ pub const CLOCK_FREQ: usize = 12500000;
|
||||
|
||||
pub const MMIO: &[(usize, usize)] = &[
|
||||
(0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine
|
||||
(0x2000000, 0x10000),
|
||||
(0x2000000, 0x10000), // core local interrupter (CLINT)
|
||||
(0xc000000, 0x210000), // VIRT_PLIC in virt machine
|
||||
(0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine
|
||||
];
|
||||
@ -53,6 +53,57 @@ pub fn irq_handler() {
|
||||
plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id);
|
||||
}
|
||||
|
||||
|
||||
// core local interrupter (CLINT), which contains the timer
|
||||
pub const CLINT: usize = 0x2000000;
|
||||
pub const fn clint_mtimecmp(hartid: usize) -> usize {
|
||||
CLINT + 0x4000 + 8 * hartid
|
||||
}
|
||||
pub const CLINT_MTIME: usize = CLINT + 0xBFF8; // Cycles since boot.
|
||||
|
||||
#[naked]
|
||||
#[repr(align(16))] // if miss this alignment, a load access fault will occur.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn timervec() -> ! {
|
||||
// start.rs has set up the memory that mscratch points to:
|
||||
// scratch[0,8,16] : register save area.
|
||||
// scratch[24] : address of CLINT's MTIMECMP register.
|
||||
// scratch[32] : desired interval between interrupts.
|
||||
|
||||
// Now, mscrach has a pointer to an additional scratch space.
|
||||
// to aboid overwriting the contents of the integer registers,
|
||||
// the prologue of an interrupts handler usually begins by swapping
|
||||
// an integer register(say a0) with mscratch CSR.
|
||||
// The interrupt handler stores the integer registers
|
||||
// used for processing in this scratch space.
|
||||
// a0 saved in mscrach, a1 ~ a3 saved in scratch space.
|
||||
//loop {}
|
||||
asm!(
|
||||
"csrrw a0, mscratch, a0",
|
||||
"sd a1, 0(a0)",
|
||||
"sd a2, 8(a0)",
|
||||
"sd a3, 16(a0)",
|
||||
// schedule the next timer interrupt
|
||||
// by adding interval to mtimecmp.
|
||||
"ld a1, 24(a0)", // CLINT_MTIMECMP(hartid) contents
|
||||
"ld a2, 32(a0)", // interval
|
||||
"ld a3, 0(a1)",
|
||||
"add a3, a3, a2",
|
||||
"sd a3, 0(a1)",
|
||||
// raise a supervisor software interrupt.
|
||||
"li a1, 2",
|
||||
"csrw sip, a1",
|
||||
// restore and return
|
||||
"ld a3, 16(a0)",
|
||||
"ld a2, 8(a0)",
|
||||
"ld a1, 0(a0)",
|
||||
"csrrw a0, mscratch, a0",
|
||||
"mret",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//ref:: https://github.com/andre-richter/qemu-exit
|
||||
use core::arch::asm;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
.globl _start
|
||||
_start:
|
||||
la sp, boot_stack_top
|
||||
call rust_main
|
||||
call rust_start
|
||||
|
||||
.section .bss.stack
|
||||
.globl boot_stack_lower_bound
|
||||
|
@ -1,6 +1,6 @@
|
||||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(_start)
|
||||
BASE_ADDRESS = 0x80200000;
|
||||
BASE_ADDRESS = 0x80000000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
@ -2,6 +2,8 @@
|
||||
#![no_main]
|
||||
#![feature(panic_info_message)]
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(naked_functions)]
|
||||
#![feature(fn_align)]
|
||||
|
||||
use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};
|
||||
|
||||
@ -27,7 +29,10 @@ mod syscall;
|
||||
mod task;
|
||||
mod timer;
|
||||
mod trap;
|
||||
|
||||
//mod start;
|
||||
mod riscvregs;
|
||||
use riscvregs::registers::*;
|
||||
use riscvregs::registers::pmpcfg0::*;
|
||||
//use syscall::create_desktop; //for test
|
||||
|
||||
core::arch::global_asm!(include_str!("entry.asm"));
|
||||
@ -51,6 +56,85 @@ lazy_static! {
|
||||
unsafe { UPIntrFreeCell::new(false) };
|
||||
}
|
||||
|
||||
|
||||
#[repr(C, align(16))]
|
||||
struct Stack([u8; 4096 * 4 * 1]);
|
||||
|
||||
#[no_mangle]
|
||||
static mut STACK0: Stack = Stack([0; 4096 * 4 * 1]);
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn rust_start() -> ! {
|
||||
// set MPP mode to Supervisor, for mret
|
||||
mstatus::set_mpp(mstatus::MPP::Supervisor);
|
||||
|
||||
// set MEPC to main, for mret
|
||||
mepc::write(rust_main as usize);
|
||||
|
||||
// disable paging for now.
|
||||
satp::write(0);
|
||||
|
||||
// delegate all interrupts and exceptions to supervisor mode.
|
||||
medeleg::set_all();
|
||||
mideleg::set_all();
|
||||
sie::set_sext();
|
||||
sie::set_ssoft();
|
||||
sie::set_stimer();
|
||||
|
||||
// configure Physical Memory Protection to give supervisor mode
|
||||
// access to all of physical memory.
|
||||
pmpaddr0::write(0x3fffffffffffff);
|
||||
pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0
|
||||
|
||||
// ask for clock interrupts.
|
||||
timerinit();
|
||||
|
||||
// keep each CPU's hartid in its tp register, for cpuid().
|
||||
let id = mhartid::read();
|
||||
core::arch::asm!("mv tp, {0}", in(reg) id);
|
||||
|
||||
// switch to supervisor mode and jump to main().
|
||||
core::arch::asm!("mret");
|
||||
|
||||
extern "C" {
|
||||
fn rust_main() -> !;
|
||||
}
|
||||
core::hint::unreachable_unchecked();
|
||||
}
|
||||
|
||||
// a scratch area per CPU for machine-mode timer interrupts.
|
||||
static mut TIMER_SCRATCH: [[u64; 5]; 1] = [[0; 5]; 1];
|
||||
|
||||
unsafe fn timerinit() {
|
||||
// each CPU has a separate source of timer interrupts
|
||||
let id = mhartid::read();
|
||||
|
||||
// ask the CLINT for a timer interrupts
|
||||
let interval = 1000000u64; // cycles; about 1/10th second in qemu.
|
||||
let mtimecmp = board::clint_mtimecmp(id) as *mut u64;
|
||||
let mtime = board::CLINT_MTIME as *const u64;
|
||||
mtimecmp.write_volatile(mtime.read_volatile() + 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.
|
||||
let scratch = &mut TIMER_SCRATCH[id];
|
||||
scratch[3] = mtimecmp as u64;
|
||||
scratch[4] = interval;
|
||||
mscratch::write(scratch.as_mut_ptr() as usize);
|
||||
|
||||
// set the machine-mode trap handler
|
||||
mtvec::write(board::timervec as usize, mtvec::TrapMode::Direct);
|
||||
|
||||
// enable machine-mode interrupts.
|
||||
mstatus::set_mie();
|
||||
|
||||
// enable machime-mode timer interrupts.
|
||||
mie::set_mtimer();
|
||||
}
|
||||
|
||||
|
||||
#[no_mangle]
|
||||
pub fn rust_main() -> ! {
|
||||
clear_bss();
|
||||
@ -63,11 +147,11 @@ pub fn rust_main() -> ! {
|
||||
let _mouse = MOUSE_DEVICE.clone();
|
||||
println!("KERN: init trap");
|
||||
trap::init();
|
||||
trap::enable_timer_interrupt();
|
||||
timer::set_next_trigger();
|
||||
//trap::enable_timer_interrupt();
|
||||
//timer::set_next_trigger();
|
||||
board::device_init();
|
||||
fs::list_apps();
|
||||
gui::init_paint();
|
||||
//gui::init_paint();
|
||||
task::add_initproc();
|
||||
*DEV_NON_BLOCKING_ACCESS.exclusive_access() = true;
|
||||
task::run_tasks();
|
||||
|
614
os/src/riscvregs.rs
Normal file
614
os/src/riscvregs.rs
Normal file
@ -0,0 +1,614 @@
|
||||
// RISC-V registers
|
||||
pub mod registers {
|
||||
// hart (core) id registers
|
||||
pub mod mhartid {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline]
|
||||
pub fn read() -> usize {
|
||||
let id: usize;
|
||||
unsafe {
|
||||
asm!("csrr {}, mhartid", out(reg) id);
|
||||
}
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
// Machine Status Register, mstatus
|
||||
pub mod mstatus {
|
||||
use core::arch::asm;
|
||||
|
||||
// Machine Status Register bit
|
||||
const MPP_MASK: usize = 3 << 11;
|
||||
const MIE: usize = 1 << 3;
|
||||
|
||||
// Machine Previous Privilege mode
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum MPP {
|
||||
Machine = 3,
|
||||
Supervisor = 1,
|
||||
User = 0,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn _read() -> usize {
|
||||
let bits: usize;
|
||||
asm!("csrr {}, mstatus", out(reg) bits);
|
||||
bits
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn _write(bits: usize) {
|
||||
asm!("csrw mstatus, {}", in(reg) bits);
|
||||
}
|
||||
|
||||
// Machine Previous Privilege Mode
|
||||
#[inline]
|
||||
pub fn set_mpp(mpp: MPP) {
|
||||
unsafe {
|
||||
let mut value = _read();
|
||||
value &= !MPP_MASK;
|
||||
value |= (mpp as usize) << 11;
|
||||
_write(value);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_mie() {
|
||||
unsafe {
|
||||
asm!("csrs mstatus, {}", in(reg) MIE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// machine exception program counter, holds the
|
||||
// instruction address to which a return from
|
||||
// exception will go.
|
||||
pub mod mepc {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline]
|
||||
pub fn write(x: usize) {
|
||||
unsafe {
|
||||
asm!("csrw mepc, {}", in(reg) x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Supervisor Status Register, sstatus
|
||||
pub mod sstatus {
|
||||
use core::arch::asm;
|
||||
|
||||
// Supervisor Status Register bit
|
||||
const SPP: usize = 1 << 8; // Previous mode, 1=Supervisor, 0=user
|
||||
const SPIE: usize = 1 << 5; // Supervisor Previous Interrupt Enable
|
||||
const SIE: usize = 1 << 1; // Supervisor Interrupt Enable
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Sstatus {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Sstatus {
|
||||
// Supervisor Interrupt Enable
|
||||
#[inline]
|
||||
pub(in crate::riscvregs) fn sie(&self) -> bool {
|
||||
self.bits & SIE != 0
|
||||
}
|
||||
|
||||
// Supervisor Previous Privilege mode
|
||||
#[inline]
|
||||
pub fn spp(&self) -> SPP {
|
||||
match self.bits & SPP {
|
||||
0 => SPP::User,
|
||||
_ => SPP::Supervisor,
|
||||
}
|
||||
}
|
||||
|
||||
// restore status bits
|
||||
#[inline]
|
||||
pub fn restore(&self) {
|
||||
unsafe {
|
||||
_write(self.bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Supervisor Previous Privilege Mode
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum SPP {
|
||||
Supervisor = 1,
|
||||
User = 0,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn read() -> Sstatus {
|
||||
let bits: usize;
|
||||
unsafe { asm!("csrr {}, sstatus", out(reg) bits) }
|
||||
Sstatus { bits }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn _write(bits: usize) {
|
||||
asm!("csrw sstatus, {}", in(reg) bits);
|
||||
}
|
||||
|
||||
// bit set
|
||||
#[inline]
|
||||
unsafe fn _set(bits: usize) {
|
||||
asm!("csrs sstatus, {}", in(reg) bits);
|
||||
}
|
||||
|
||||
// bit clear
|
||||
#[inline]
|
||||
unsafe fn _clear(bits: usize) {
|
||||
asm!("csrc sstatus, {}", in(reg) bits);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(in crate::riscvregs) unsafe fn set_sie() {
|
||||
_set(SIE)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(in crate::riscvregs) unsafe fn clear_sie() {
|
||||
_clear(SIE)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set_spie() {
|
||||
_set(SPIE);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set_spp(spp: SPP) {
|
||||
match spp {
|
||||
SPP::Supervisor => _set(SPP),
|
||||
SPP::User => _clear(SPP),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Supervisor Interrupt Pending
|
||||
pub mod sip {
|
||||
use core::arch::asm;
|
||||
|
||||
const SSIP: usize = 1 << 1;
|
||||
|
||||
// Supervisor Software Interrupt Pending
|
||||
#[inline]
|
||||
pub unsafe fn clear_ssoft() {
|
||||
asm!("csrc sip, {}", in(reg) SSIP);
|
||||
}
|
||||
}
|
||||
|
||||
// Supervisor Interrupt Enable
|
||||
pub mod sie {
|
||||
use core::arch::asm;
|
||||
|
||||
const SEIE: usize = 1 << 9; // external
|
||||
const STIE: usize = 1 << 5; // timer
|
||||
const SSIE: usize = 1 << 1; // software
|
||||
|
||||
#[inline]
|
||||
unsafe fn _set(bits: usize) {
|
||||
asm!("csrs sie, {}", in(reg) bits);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set_sext() {
|
||||
_set(SEIE);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set_stimer() {
|
||||
_set(STIE);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set_ssoft() {
|
||||
_set(SSIE);
|
||||
}
|
||||
}
|
||||
|
||||
// Machine-mode Interrupt Enable
|
||||
pub mod mie {
|
||||
use core::arch::asm;
|
||||
|
||||
const MTIE: usize = 1 << 7;
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set_mtimer() {
|
||||
asm!("csrs mie, {}", in(reg) MTIE);
|
||||
}
|
||||
}
|
||||
|
||||
// supervisor exceptions program counter, holds the
|
||||
// instruction address to which a return from
|
||||
// exception will go.
|
||||
pub mod sepc {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline]
|
||||
pub fn read() -> usize {
|
||||
let bits: usize;
|
||||
unsafe {
|
||||
asm!("csrr {}, sepc", out(reg) bits);
|
||||
}
|
||||
bits
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write(bits: usize) {
|
||||
unsafe {
|
||||
asm!("csrw sepc, {}", in(reg) bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Machine Exception Delegation
|
||||
pub mod medeleg {
|
||||
use core::arch::asm;
|
||||
|
||||
pub unsafe fn set_all() {
|
||||
asm!("csrw medeleg, {}", in(reg) 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
// Machine Interrupt Delegation
|
||||
pub mod mideleg {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set_all() {
|
||||
asm!("csrw mideleg, {}", in(reg) 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
// Supervisor Trap-Vector Base Address
|
||||
// low two bits are mode.
|
||||
pub mod stvec {
|
||||
pub use super::mtvec::TrapMode;
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||
asm!("csrw stvec, {}", in(reg) addr + mode as usize);
|
||||
}
|
||||
}
|
||||
|
||||
// Machine-mode interrupt vector
|
||||
pub mod mtvec {
|
||||
use core::arch::asm;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum TrapMode {
|
||||
Direct = 0,
|
||||
Vectored = 1,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||
asm!("csrw mtvec, {}", in(reg) addr + mode as usize);
|
||||
}
|
||||
}
|
||||
|
||||
// Physical Memory Protection Configuration
|
||||
pub mod pmpcfg0 {
|
||||
use core::arch::asm;
|
||||
|
||||
// Permission enum contains all possible permission modes for pmp registers
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Permission {
|
||||
NONE = 0b000,
|
||||
R = 0b001,
|
||||
W = 0b010,
|
||||
RW = 0b011,
|
||||
X = 0b100,
|
||||
RX = 0b101,
|
||||
WX = 0b110,
|
||||
RWX = 0b111,
|
||||
}
|
||||
|
||||
// Range enum contains all possible addressing modes for pmp registers
|
||||
pub enum Range {
|
||||
OFF = 0b00,
|
||||
TOR = 0b01,
|
||||
NA4 = 0b10,
|
||||
NAPOT = 0b11,
|
||||
}
|
||||
|
||||
// Set the pmp configuration corresponging to the index
|
||||
#[inline]
|
||||
pub unsafe fn set_pmp(index: usize, range: Range, permission: Permission, locked: bool) {
|
||||
assert!(index < 8);
|
||||
let mut value = _read();
|
||||
let byte = (locked as usize) << 7 | (range as usize) << 3 | (permission as usize);
|
||||
value |= byte << (8 * index);
|
||||
_write(value);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn _read() -> usize {
|
||||
let bits: usize;
|
||||
asm!("csrr {}, pmpcfg0", out(reg) bits);
|
||||
bits
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn _write(bits: usize) {
|
||||
asm!("csrw pmpcfg0, {}", in(reg) bits);
|
||||
}
|
||||
}
|
||||
|
||||
// Physical memory protection address register
|
||||
pub mod pmpaddr0 {
|
||||
use core::arch::asm;
|
||||
|
||||
pub fn write(bits: usize) {
|
||||
unsafe {
|
||||
asm!("csrw pmpaddr0, {}", in(reg) bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Supervisor address translation and protection;
|
||||
// holds the address of the page table.
|
||||
pub mod satp {
|
||||
use core::arch::asm;
|
||||
|
||||
// stap register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Satp {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
// 64-bit satp mode
|
||||
pub enum Mode {
|
||||
// No translation or protection
|
||||
Bare = 0,
|
||||
// Page-based 39-bit virtual addressing
|
||||
Sv39 = 8,
|
||||
// Page-based 48-bit virtual addressing
|
||||
Sv48 = 9,
|
||||
// Page-based 57-bit virtual addressing
|
||||
Sv57 = 10,
|
||||
// Page-based 64-bit virtual addressing
|
||||
Sv64 = 11,
|
||||
}
|
||||
|
||||
impl Satp {
|
||||
// Return the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn read() -> Satp {
|
||||
let bits: usize;
|
||||
asm!("csrr {}, satp", out(reg) bits);
|
||||
Satp { bits }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn write(bits: usize) {
|
||||
asm!("csrw satp, {}", in(reg) bits);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn make(mode: Mode, asid: usize, ppn: usize) -> usize {
|
||||
let mut bits: usize = 0;
|
||||
bits |= (mode as usize) << 60;
|
||||
bits |= asid << 44;
|
||||
bits |= ppn >> 12;
|
||||
bits
|
||||
}
|
||||
}
|
||||
|
||||
// mscratch register
|
||||
pub mod mscratch {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline]
|
||||
pub fn write(bits: usize) {
|
||||
unsafe {
|
||||
asm!("csrw mscratch, {}", in(reg) bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Supervisor Trap Cause
|
||||
pub mod scause {
|
||||
use core::{arch::asm, mem::size_of};
|
||||
|
||||
// scause register
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Scause {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
// Trap Cause
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Trap {
|
||||
Interrupt(Interrupt),
|
||||
Exception(Exception),
|
||||
}
|
||||
|
||||
// Interrupt
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Interrupt {
|
||||
UserSoft,
|
||||
SupervisorSoft,
|
||||
UserTimer,
|
||||
SupervisorTimer,
|
||||
UserExternal,
|
||||
SupervisorExternal,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
// Exception
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Exception {
|
||||
InstructionMisaligned,
|
||||
InstructionFault,
|
||||
IllegalInstruction,
|
||||
Breakpoint,
|
||||
LoadFault,
|
||||
StoreMisaligned,
|
||||
StoreFault,
|
||||
UserEnvCall,
|
||||
InstructionPageFault,
|
||||
LoadPageFault,
|
||||
StorePageFault,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Interrupt {
|
||||
#[inline]
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Interrupt::UserSoft,
|
||||
1 => Interrupt::SupervisorSoft,
|
||||
4 => Interrupt::UserTimer,
|
||||
5 => Interrupt::SupervisorTimer,
|
||||
8 => Interrupt::UserExternal,
|
||||
9 => Interrupt::SupervisorExternal,
|
||||
_ => Interrupt::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Exception {
|
||||
#[inline]
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Exception::InstructionMisaligned,
|
||||
1 => Exception::InstructionFault,
|
||||
2 => Exception::IllegalInstruction,
|
||||
3 => Exception::Breakpoint,
|
||||
5 => Exception::LoadFault,
|
||||
6 => Exception::StoreMisaligned,
|
||||
7 => Exception::StoreFault,
|
||||
8 => Exception::UserEnvCall,
|
||||
12 => Exception::InstructionPageFault,
|
||||
13 => Exception::LoadPageFault,
|
||||
15 => Exception::StorePageFault,
|
||||
_ => Exception::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scause {
|
||||
// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
// Returns the code field
|
||||
#[inline]
|
||||
pub fn code(&self) -> usize {
|
||||
let bit = 1 << (size_of::<usize>() * 8 - 1);
|
||||
self.bits & !bit
|
||||
}
|
||||
|
||||
// Trap cause
|
||||
#[inline]
|
||||
pub fn cause(&self) -> Trap {
|
||||
if self.is_interrupt() {
|
||||
Trap::Interrupt(Interrupt::from(self.code()))
|
||||
} else {
|
||||
Trap::Exception(Exception::from(self.code()))
|
||||
}
|
||||
}
|
||||
|
||||
// Is trap cause an interrupt.
|
||||
#[inline]
|
||||
pub fn is_interrupt(&self) -> bool {
|
||||
self.bits & (1 << (size_of::<usize>() * 8 - 1)) != 0
|
||||
}
|
||||
|
||||
// Is trap cause an exception.
|
||||
#[inline]
|
||||
pub fn is_exception(&self) -> bool {
|
||||
!self.is_interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn read() -> Scause {
|
||||
let bits: usize;
|
||||
unsafe {
|
||||
asm!("csrr {}, scause", out(reg) bits);
|
||||
}
|
||||
Scause { bits }
|
||||
}
|
||||
}
|
||||
|
||||
// Supervisor Trap Value
|
||||
pub mod stval {
|
||||
use core::arch::asm;
|
||||
|
||||
#[inline]
|
||||
pub fn read() -> usize {
|
||||
let bits: usize;
|
||||
unsafe { asm!("csrr {}, stval", out(reg) bits) }
|
||||
bits
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use core::arch::asm;
|
||||
|
||||
use registers::*;
|
||||
|
||||
// enable device interrupts
|
||||
#[inline]
|
||||
pub fn intr_on() {
|
||||
unsafe {
|
||||
sstatus::set_sie();
|
||||
}
|
||||
}
|
||||
|
||||
// disable device interrupts
|
||||
#[inline]
|
||||
pub fn intr_off() {
|
||||
unsafe {
|
||||
sstatus::clear_sie();
|
||||
}
|
||||
}
|
||||
|
||||
// are device interrupts enabled?
|
||||
#[inline]
|
||||
pub fn intr_get() -> bool {
|
||||
sstatus::read().sie()
|
||||
}
|
||||
|
||||
// flush the TLB.
|
||||
#[inline]
|
||||
pub unsafe fn sfence_vma() {
|
||||
// the zero, zero means flush all TLB entries
|
||||
asm!("sfence.vma zero, zero");
|
||||
}
|
||||
|
||||
pub const PGSIZE: usize = 4096; // bytes per page
|
||||
pub const PGSHIFT: usize = 12; // bits of offset within a page
|
||||
|
||||
pub const fn pgroundup(sz: usize) -> usize {
|
||||
(sz + PGSIZE - 1) & !(PGSIZE - 1)
|
||||
}
|
||||
|
||||
pub const fn pgrounddown(sz: usize) -> usize {
|
||||
sz & !(PGSIZE - 1)
|
||||
}
|
||||
|
||||
// PTE flags
|
||||
pub mod pteflags {
|
||||
pub const PTE_V: usize = 1 << 0; // valid
|
||||
pub const PTE_R: usize = 1 << 1;
|
||||
pub const PTE_W: usize = 1 << 2;
|
||||
pub const PTE_X: usize = 1 << 3;
|
||||
pub const PTE_U: usize = 1 << 4; // user can access
|
||||
}
|
86
os/src/start.rs
Normal file
86
os/src/start.rs
Normal file
@ -0,0 +1,86 @@
|
||||
//use crate::kernelvec::*;
|
||||
//use crate::memlayout::*;
|
||||
//use crate::param::NCPU;
|
||||
//use super::main::*;
|
||||
//use crate::riscv::registers::{pmpcfg0::*, *};
|
||||
use core::arch::asm;
|
||||
use core::hint::unreachable_unchecked;
|
||||
|
||||
mod riscv;
|
||||
|
||||
#[repr(C, align(16))]
|
||||
struct Stack([u8; 4096 * 4 * NCPU]);
|
||||
|
||||
#[no_mangle]
|
||||
static mut STACK0: Stack = Stack([0; 4096 * 4 * NCPU]);
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn rust_start() -> ! {
|
||||
// set MPP mode to Supervisor, for mret
|
||||
mstatus::set_mpp(mstatus::MPP::Supervisor);
|
||||
|
||||
// set MEPC to main, for mret
|
||||
mepc::write(rust_main as usize);
|
||||
|
||||
// disable paging for now.
|
||||
satp::write(0);
|
||||
|
||||
// delegate all interrupts and exceptions to supervisor mode.
|
||||
medeleg::set_all();
|
||||
mideleg::set_all();
|
||||
sie::set_sext();
|
||||
sie::set_ssoft();
|
||||
sie::set_stimer();
|
||||
|
||||
// configure Physical Memory Protection to give supervisor mode
|
||||
// access to all of physical memory.
|
||||
pmpaddr0::write(0x3fffffffffffff);
|
||||
pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0
|
||||
|
||||
// ask for clock interrupts.
|
||||
timerinit();
|
||||
|
||||
// keep each CPU's hartid in its tp register, for cpuid().
|
||||
let id = mhartid::read();
|
||||
asm!("mv tp, {0}", in(reg) id);
|
||||
|
||||
// switch to supervisor mode and jump to main().
|
||||
asm!("mret");
|
||||
|
||||
extern "C" {
|
||||
fn rust_main() -> !;
|
||||
}
|
||||
unreachable_unchecked();
|
||||
}
|
||||
|
||||
// a scratch area per CPU for machine-mode timer interrupts.
|
||||
static mut TIMER_SCRATCH: [[u64; 5]; 1] = [[0; 5]; 1];
|
||||
|
||||
unsafe fn timerinit() {
|
||||
// each CPU has a separate source of timer interrupts
|
||||
let id = mhartid::read();
|
||||
|
||||
// ask the CLINT for a timer interrupts
|
||||
let interval = 1000000u64; // cycles; about 1/10th second in qemu.
|
||||
let mtimecmp = clint_mtimecmp(id) as *mut u64;
|
||||
let mtime = CLINT_MTIME as *const u64;
|
||||
mtimecmp.write_volatile(mtime.read_volatile() + 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.
|
||||
let scratch = &mut TIMER_SCRATCH[id];
|
||||
scratch[3] = mtimecmp as u64;
|
||||
scratch[4] = interval;
|
||||
mscratch::write(scratch.as_mut_ptr() as usize);
|
||||
|
||||
// set the machine-mode trap handler
|
||||
mtvec::write(timervec as usize, mtvec::TrapMode::Direct);
|
||||
|
||||
// enable machine-mode interrupts.
|
||||
mstatus::set_mie();
|
||||
|
||||
// enable machime-mode timer interrupts.
|
||||
mie::set_mtimer();
|
||||
}
|
Loading…
Reference in New Issue
Block a user