diff --git a/kernel/src/arch/riscv32/board/k210/boot.asm b/kernel/src/arch/riscv32/board/k210/boot.asm deleted file mode 100644 index 92db963..0000000 --- a/kernel/src/arch/riscv32/board/k210/boot.asm +++ /dev/null @@ -1,38 +0,0 @@ - .section .text.boot -boot: - csrwi mie, 0 - csrwi mip, 0 - csrwi mscratch, 0 - csrwi medeleg, 0 - csrwi mideleg, 0 - - // enable float unit - li t0, 0x00006000 // MSTATUS_FS - csrw mstatus, t0 - - // uart init - lui x1, 0x38000 - - li t0, 3384 - sw t0, 0x18(x1) - - li t0, 1 - sw t0, 0x8(x1) - sw t0, 0xc(x1) - - li t0, 3 - sw t0, 0x14(x1) - sw x0, 0x10(x1) - - -1: // test - lw t0, 0(x1) - blt t0, zero, 1b - // write - li t0, 0x21 - sw t0, 0(x1) - - csrr a0, mhartid - // FIXME: enable core 1 - li a2, 0 // hart_mask - j _start \ No newline at end of file diff --git a/kernel/src/arch/riscv32/board/k210/linker.ld b/kernel/src/arch/riscv32/board/k210/linker.ld deleted file mode 100644 index f318b99..0000000 --- a/kernel/src/arch/riscv32/board/k210/linker.ld +++ /dev/null @@ -1,49 +0,0 @@ -/* Copy from bbl-ucore : https://ring00.github.io/bbl-ucore */ - -/* Simple linker script for the ucore kernel. - See the GNU ld 'info' manual ("info ld") to learn the syntax. */ - -OUTPUT_ARCH(riscv) -ENTRY(_start) - -BASE_ADDRESS = 0x40000000; - -SECTIONS -{ - /* Load the kernel at this address: "." means the current address */ - . = BASE_ADDRESS; - start = .; - - .text : { - stext = .; - KEEP(*(.text.boot)) - *(.text .text.*) - . = ALIGN(4K); - etext = .; - } - - .rodata : { - srodata = .; - *(.rodata .rodata.*) - . = ALIGN(4K); - erodata = .; - } - - .data : { - sdata = .; - *(.data .data.*) - edata = .; - } - - .stack : { - *(.bss.stack) - } - - .bss : { - sbss = .; - *(.bss .bss.* .sbss.*) - ebss = .; - } - - PROVIDE(end = .); -} diff --git a/kernel/src/arch/riscv32/boot/trap.asm b/kernel/src/arch/riscv32/boot/trap.asm index 3ebd1ed..17ff77e 100644 --- a/kernel/src/arch/riscv32/boot/trap.asm +++ b/kernel/src/arch/riscv32/boot/trap.asm @@ -1,10 +1,4 @@ # Constants / Macros defined in Rust code: -# xscratch -# xstatus -# xepc -# xcause -# xtval -# XRET # XLENB # LOAD # STORE @@ -14,10 +8,10 @@ # If coming from userspace, preserve the user stack pointer and load # the kernel stack pointer. If we came from the kernel, sscratch # will contain 0, and we should continue on the current stack. - csrrw sp, (xscratch), sp + csrrw sp, sscratch, sp bnez sp, trap_from_user trap_from_kernel: - csrr sp, (xscratch) + csrr sp, sscratch STORE gp, -1 # sscratch = previous-sp, sp = kernel-sp trap_from_user: @@ -60,11 +54,11 @@ trap_from_user: # get sp, sstatus, sepc, stval, scause # set sscratch = 0 - csrrw s0, (xscratch), x0 - csrr s1, (xstatus) - csrr s2, (xepc) - csrr s3, (xtval) - csrr s4, (xcause) + csrrw s0, sscratch, x0 + csrr s1, sstatus + csrr s2, sepc + csrr s3, stval + csrr s4, scause # store sp, sstatus, sepc, sbadvaddr, scause STORE s0, 2 STORE s1, 32 @@ -76,16 +70,16 @@ trap_from_user: .macro RESTORE_ALL LOAD s1, 32 # s1 = sstatus LOAD s2, 33 # s2 = sepc - TEST_BACK_TO_KERNEL + andi s0, s1, 1 << 8 # sstatus.SPP = 1 bnez s0, _to_kernel # s0 = back to kernel? _to_user: addi s0, sp, 37*XLENB - csrw (xscratch), s0 # sscratch = kernel-sp + csrw sscratch, s0 # sscratch = kernel-sp STORE gp, 36 # store hartid from gp to sp[36] _to_kernel: # restore sstatus, sepc - csrw (xstatus), s1 - csrw (xepc), s2 + csrw sstatus, s1 + csrw sepc, s2 # restore x registers except x2 (sp) LOAD x1, 1 @@ -132,4 +126,4 @@ trap_entry: trap_return: RESTORE_ALL # return from supervisor call - XRET + sret diff --git a/kernel/src/arch/riscv32/context.rs b/kernel/src/arch/riscv32/context.rs index e53d1ca..a8b6e5f 100644 --- a/kernel/src/arch/riscv32/context.rs +++ b/kernel/src/arch/riscv32/context.rs @@ -1,67 +1,58 @@ use riscv::register::{ - sstatus as xstatus, - sstatus::Sstatus as Xstatus, - mcause::Mcause, + sstatus, + sstatus::Sstatus, + scause::Scause, }; +/// Saved registers on a trap. #[derive(Clone)] #[repr(C)] pub struct TrapFrame { - pub x: [usize; 32], // general registers - pub sstatus: Xstatus, // Supervisor Status Register - pub sepc: usize, // Supervisor exception program counter, save the trap virtual address (here is used to save the process program entry addr?) - pub stval: usize, // Supervisor trap value - pub scause: Mcause, // scause register: record the cause of exception/interrupt/trap - pub _hartid: usize, // reserve space + /// General registers + pub x: [usize; 32], + /// Supervisor Status + pub sstatus: Sstatus, + /// Supervisor Exception Program Counter + pub sepc: usize, + /// Supervisor Trap Value + pub stval: usize, + /// Supervisor Cause + pub scause: Scause, + /// Reserve space for hartid + pub _hartid: usize, } -/// Generate the trapframe for building new thread in kernel impl TrapFrame { - /* - * @param: - * entry: program entry for the thread - * arg: a0 - * sp: stack top - * @brief: - * generate a trapfram for building a new kernel thread - * @retval: - * the trapframe for new kernel thread - */ + /// Constructs TrapFrame for a new kernel thread. + /// + /// The new thread starts at function `entry` with an usize argument `arg`. + /// The stack pointer will be set to `sp`. fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; tf.x[10] = arg; // a0 tf.x[2] = sp; tf.sepc = entry as usize; - tf.sstatus = xstatus::read(); - { - tf.sstatus.set_spie(true); - tf.sstatus.set_sie(false); - tf.sstatus.set_spp(xstatus::SPP::Supervisor); - } + tf.sstatus = sstatus::read(); + tf.sstatus.set_spie(true); + tf.sstatus.set_sie(false); + tf.sstatus.set_spp(sstatus::SPP::Supervisor); tf } - /* - * @param: - * entry_addr: program entry for the thread - * sp: stack top - * @brief: - * generate a trapfram for building a new user thread - * @retval: - * the trapframe for new user thread - */ + /// Constructs TrapFrame for a new user thread. + /// + /// The new thread starts at `entry_addr`. + /// The stack pointer will be set to `sp`. fn new_user_thread(entry_addr: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; tf.x[2] = sp; tf.sepc = entry_addr; - tf.sstatus = xstatus::read(); - { - tf.sstatus.set_spie(true); - tf.sstatus.set_sie(false); - tf.sstatus.set_spp(xstatus::SPP::User); - } + tf.sstatus = sstatus::read(); + tf.sstatus.set_spie(true); + tf.sstatus.set_sie(false); + tf.sstatus.set_spp(sstatus::SPP::User); tf } } @@ -85,12 +76,12 @@ impl Debug for TrapFrame { .field("sstatus", &self.sstatus) .field("sepc", &self.sepc) .field("stval", &self.stval) - .field("scause", &self.scause) + .field("scause", &self.scause.cause()) .finish() } } -/// kernel stack contents for a new thread +/// Kernel stack contents for a new thread #[derive(Debug)] #[repr(C)] pub struct InitStack { @@ -99,18 +90,11 @@ pub struct InitStack { } impl InitStack { - /* - * @param: - * stack_top: the pointer to kernel stack stop - * @brief: - * save the InitStack on the kernel stack stop - * @retval: - * a Context with ptr in it - */ + /// Push the InitStack on the stack and transfer to a Context. unsafe fn push_at(self, stack_top: usize) -> Context { - let ptr = (stack_top as *mut Self).offset(-1); //real kernel stack top + let ptr = (stack_top as *mut Self).sub(1); //real kernel stack top *ptr = self; - Context(ptr as usize) + Context { sp: ptr as usize } } } @@ -118,24 +102,32 @@ extern { fn trap_return(); } +/// Saved registers for kernel context switches. #[derive(Debug, Default)] #[repr(C)] struct ContextData { + /// Return address ra: usize, + /// Page table token satp: usize, + /// Callee-saved registers s: [usize; 12], } impl ContextData { fn new(satp: usize) -> Self { - // satp(asid) just like cr3, save the physical address for Page directory? ContextData { ra: trap_return as usize, satp, ..ContextData::default() } } } -/// A struct only contain one usize element +/// Context of a kernel thread. #[derive(Debug)] -pub struct Context(usize); +#[repr(C)] +pub struct Context { + /// The stack pointer of the suspended thread. + /// A `ContextData` is stored here. + sp: usize, +} impl Context { /// Switch to another kernel thread. @@ -208,66 +200,43 @@ impl Context { : : : : "volatile" ) } - /* - * @brief: - * generate a null Context - * @retval: - * a null Context - */ + /// Constructs a null Context for the current running thread. pub unsafe fn null() -> Self { - Context(0) + Context { sp: 0 } } - /* - * @param: - * entry: program entry for the thread - * arg: a0 - * kstack_top: kernel stack top - * cr3: cr3 register, save the physical address of Page directory - * @brief: - * generate the content of kernel stack for the new kernel thread and save it's address at kernel stack top - 1 - * @retval: - * a Context struct with the pointer to the kernel stack top - 1 as its only element - */ - pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, cr3: usize) -> Self { + /// Constructs Context for a new kernel thread. + /// + /// The new thread starts at function `entry` with an usize argument `arg`. + /// The stack pointer will be set to `kstack_top`. + /// The SATP register will be set to `satp`. + pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, satp: usize) -> Self { InitStack { - context: ContextData::new(cr3), + context: ContextData::new(satp), tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top), }.push_at(kstack_top) } - /* - * @param: - * entry_addr: program entry for the thread - * ustack_top: user stack top - * kstack_top: kernel stack top - * is32: whether the cpu is 32 bit or not - * cr3: cr3 register, save the physical address of Page directory - * @brief: - * generate the content of kernel stack for the new user thread and save it's address at kernel stack top - 1 - * @retval: - * a Context struct with the pointer to the kernel stack top - 1 as its only element - */ - pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, _is32: bool, cr3: usize) -> Self { + /// Constructs Context for a new user thread. + /// + /// The new thread starts at `entry_addr`. + /// The stack pointer of user and kernel mode will be set to `ustack_top`, `kstack_top`. + /// The SATP register will be set to `satp`. + pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, _is32: bool, satp: usize) -> Self { InitStack { - context: ContextData::new(cr3), + context: ContextData::new(satp), tf: TrapFrame::new_user_thread(entry_addr, ustack_top), }.push_at(kstack_top) } - /* - * @param: - * TrapFrame: the trapframe of the forked process(thread) - * kstack_top: kernel stack top - * cr3: cr3 register, save the physical address of Page directory - * @brief: - * fork and generate a new process(thread) Context according to the TrapFrame and save it's address at kernel stack top - 1 - * @retval: - * a Context struct with the pointer to the kernel stack top - 1 as its only element - */ - pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { + /// Fork a user process and get the new Context. + /// + /// The stack pointer in kernel mode will be set to `kstack_top`. + /// The SATP register will be set to `satp`. + /// All the other registers are same as the original. + pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Self { InitStack { - context: ContextData::new(cr3), + context: ContextData::new(satp), tf: { let mut tf = tf.clone(); // fork function's ret value, the new process is 0 @@ -277,9 +246,16 @@ impl Context { }.push_at(kstack_top) } - pub unsafe fn new_clone(tf: &TrapFrame, ustack_top: usize, kstack_top: usize, cr3: usize, tls: usize) -> Self { + /// Fork a user thread and get the new Context. + /// + /// The stack pointer in kernel mode will be set to `kstack_top`. + /// The SATP register will be set to `satp`. + /// The new user stack will be set to `ustack_top`. + /// The new thread pointer will be set to `tls`. + /// All the other registers are same as the original. + pub unsafe fn new_clone(tf: &TrapFrame, ustack_top: usize, kstack_top: usize, satp: usize, tls: usize) -> Self { InitStack { - context: ContextData::new(cr3), + context: ContextData::new(satp), tf: { let mut tf = tf.clone(); tf.x[2] = ustack_top; // sp @@ -290,9 +266,8 @@ impl Context { }.push_at(kstack_top) } - /// Called at a new user context - /// To get the init TrapFrame in sys_exec + /// Used for getting the init TrapFrame of a new user context in `sys_exec`. pub unsafe fn get_init_tf(&self) -> TrapFrame { - (*(self.0 as *const InitStack)).tf.clone() + (*(self.sp as *const InitStack)).tf.clone() } } diff --git a/kernel/src/arch/riscv32/interrupt.rs b/kernel/src/arch/riscv32/interrupt.rs index 8d78b28..26fb688 100644 --- a/kernel/src/arch/riscv32/interrupt.rs +++ b/kernel/src/arch/riscv32/interrupt.rs @@ -1,9 +1,4 @@ -use riscv::register::{ - sstatus as xstatus, - sscratch as xscratch, - stvec as xtvec, -}; -use riscv::register::{mcause, mepc, sie, mie}; +use riscv::register::*; use crate::drivers::DRIVERS; pub use self::context::*; use log::*; @@ -22,17 +17,14 @@ pub fn init() { unsafe { // Set sscratch register to 0, indicating to exception vector that we are // presently executing in the kernel - xscratch::write(0); + sscratch::write(0); // Set the exception vector address - xtvec::write(trap_entry as usize, xtvec::TrapMode::Direct); + stvec::write(trap_entry as usize, stvec::TrapMode::Direct); // Enable IPI sie::set_ssoft(); // Enable external interrupt if super::cpu::id() == super::BOOT_HART_ID { sie::set_sext(); - // NOTE: In M-mode: mie.MSIE is set by BBL. - // mie.MEIE can not be set in QEMU v3.0 - // (seems like a bug) } } info!("interrupt: init end"); @@ -44,13 +36,13 @@ pub fn init() { */ #[inline] pub unsafe fn enable() { - xstatus::set_sie(); + sstatus::set_sie(); } #[inline] pub unsafe fn disable_and_store() -> usize { - let e = xstatus::read().sie() as usize; - xstatus::clear_sie(); + let e = sstatus::read().sie() as usize; + sstatus::clear_sie(); e } @@ -75,19 +67,12 @@ pub unsafe fn restore(flags: usize) { */ #[no_mangle] pub extern fn rust_trap(tf: &mut TrapFrame) { - use self::mcause::{Trap, Interrupt as I, Exception as E}; + use self::scause::{Trap, Interrupt as I, Exception as E}; trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), tf.scause.cause()); match tf.scause.cause() { - // M-mode only - Trap::Interrupt(I::MachineExternal) => external(), - Trap::Interrupt(I::MachineSoft) => ipi(), - Trap::Interrupt(I::MachineTimer) => timer(), - Trap::Exception(E::MachineEnvCall) => sbi(tf), - Trap::Interrupt(I::SupervisorExternal) => external(), Trap::Interrupt(I::SupervisorSoft) => ipi(), Trap::Interrupt(I::SupervisorTimer) => timer(), - Trap::Exception(E::IllegalInstruction) => illegal_inst(tf), Trap::Exception(E::UserEnvCall) => syscall(tf), Trap::Exception(E::LoadPageFault) => page_fault(tf), Trap::Exception(E::StorePageFault) => page_fault(tf), @@ -97,12 +82,6 @@ pub extern fn rust_trap(tf: &mut TrapFrame) { trace!("Interrupt end"); } -/// Call BBL SBI functions for M-mode kernel -fn sbi(tf: &mut TrapFrame) { - (super::BBL.mcall_trap)(tf.x.as_ptr(), tf.scause.bits(), tf.sepc); - tf.sepc += 4; -} - fn external() { #[cfg(feature = "board_u540")] unsafe { super::board::handle_external_interrupt(); } @@ -161,17 +140,6 @@ fn syscall(tf: &mut TrapFrame) { tf.x[10] = ret as usize; } -/* -* @param: -* TrapFrame: the Trapframe for the illegal inst exception -* @brief: -* process IllegalInstruction exception -*/ -fn illegal_inst(tf: &mut TrapFrame) { - (super::BBL.illegal_insn_trap)(tf.x.as_ptr(), tf.scause.bits(), tf.sepc); - tf.sepc = mepc::read(); -} - /* * @param: * TrapFrame: the Trapframe for the page fault exception diff --git a/kernel/src/arch/riscv32/mod.rs b/kernel/src/arch/riscv32/mod.rs index ecee7b5..bdd6d6f 100644 --- a/kernel/src/arch/riscv32/mod.rs +++ b/kernel/src/arch/riscv32/mod.rs @@ -16,22 +16,21 @@ mod sbi; use log::*; #[no_mangle] -pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize, functions: usize) -> ! { +pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! { // An initial recursive page table has been set by BBL (shared by all cores) unsafe { cpu::set_cpu_id(hartid); } if hartid != BOOT_HART_ID { while unsafe { !cpu::has_started(hartid) } { } - println!("Hello RISCV! in hart {}, dtb @ {:#x}, functions @ {:#x}", hartid, dtb, functions); + println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb); others_main(); //other_main -> ! } unsafe { memory::clear_bss(); } - unsafe { BBL_FUNCTIONS_PTR = functions as *const _; } - println!("Hello RISCV! in hart {}, dtb @ {:#x}, functions @ {:#x}", hartid, dtb, functions); + println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb); crate::logging::init(); interrupt::init(); @@ -61,18 +60,6 @@ const BOOT_HART_ID: usize = 0; const BOOT_HART_ID: usize = 1; /// Constant & Macro for `trap.asm` -global_asm!(" - .equ xstatus, 0x100 - .equ xscratch, 0x140 - .equ xepc, 0x141 - .equ xcause, 0x142 - .equ xtval, 0x143 - .macro XRET\n sret\n .endm - .macro TEST_BACK_TO_KERNEL - andi s0, s1, 1 << 8 // sstatus.SPP = 1 - .endm -"); - #[cfg(target_arch = "riscv32")] global_asm!(r" .equ XLENB, 4 @@ -99,21 +86,3 @@ global_asm!(r" global_asm!(include_str!("boot/entry.asm")); global_asm!(include_str!("boot/trap.asm")); - - -/// Some symbols passed from BBL. -/// Used in M-mode kernel. -#[repr(C)] -struct BBLFunctions { - mcall_trap: BBLTrapHandler, - illegal_insn_trap: BBLTrapHandler, - mcall_console_putchar: extern fn(u8), - mcall_console_getchar: extern fn() -> usize, -} - -type BBLTrapHandler = extern fn(regs: *const usize, mcause: usize, mepc: usize); -static mut BBL_FUNCTIONS_PTR: *const BBLFunctions = ::core::ptr::null(); -use lazy_static::lazy_static; -lazy_static! { - static ref BBL: BBLFunctions = unsafe { BBL_FUNCTIONS_PTR.read() }; -}