remove remaining M-Mode & K210 code. improve docs in context.rs

master
WangRunji 6 years ago
parent ff82679ddc
commit 01a0f961e9

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

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

@ -1,10 +1,4 @@
# Constants / Macros defined in Rust code: # Constants / Macros defined in Rust code:
# xscratch
# xstatus
# xepc
# xcause
# xtval
# XRET
# XLENB # XLENB
# LOAD # LOAD
# STORE # STORE
@ -14,10 +8,10 @@
# If coming from userspace, preserve the user stack pointer and load # If coming from userspace, preserve the user stack pointer and load
# the kernel stack pointer. If we came from the kernel, sscratch # the kernel stack pointer. If we came from the kernel, sscratch
# will contain 0, and we should continue on the current stack. # will contain 0, and we should continue on the current stack.
csrrw sp, (xscratch), sp csrrw sp, sscratch, sp
bnez sp, trap_from_user bnez sp, trap_from_user
trap_from_kernel: trap_from_kernel:
csrr sp, (xscratch) csrr sp, sscratch
STORE gp, -1 STORE gp, -1
# sscratch = previous-sp, sp = kernel-sp # sscratch = previous-sp, sp = kernel-sp
trap_from_user: trap_from_user:
@ -60,11 +54,11 @@ trap_from_user:
# get sp, sstatus, sepc, stval, scause # get sp, sstatus, sepc, stval, scause
# set sscratch = 0 # set sscratch = 0
csrrw s0, (xscratch), x0 csrrw s0, sscratch, x0
csrr s1, (xstatus) csrr s1, sstatus
csrr s2, (xepc) csrr s2, sepc
csrr s3, (xtval) csrr s3, stval
csrr s4, (xcause) csrr s4, scause
# store sp, sstatus, sepc, sbadvaddr, scause # store sp, sstatus, sepc, sbadvaddr, scause
STORE s0, 2 STORE s0, 2
STORE s1, 32 STORE s1, 32
@ -76,16 +70,16 @@ trap_from_user:
.macro RESTORE_ALL .macro RESTORE_ALL
LOAD s1, 32 # s1 = sstatus LOAD s1, 32 # s1 = sstatus
LOAD s2, 33 # s2 = sepc 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? bnez s0, _to_kernel # s0 = back to kernel?
_to_user: _to_user:
addi s0, sp, 37*XLENB 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] STORE gp, 36 # store hartid from gp to sp[36]
_to_kernel: _to_kernel:
# restore sstatus, sepc # restore sstatus, sepc
csrw (xstatus), s1 csrw sstatus, s1
csrw (xepc), s2 csrw sepc, s2
# restore x registers except x2 (sp) # restore x registers except x2 (sp)
LOAD x1, 1 LOAD x1, 1
@ -132,4 +126,4 @@ trap_entry:
trap_return: trap_return:
RESTORE_ALL RESTORE_ALL
# return from supervisor call # return from supervisor call
XRET sret

@ -1,67 +1,58 @@
use riscv::register::{ use riscv::register::{
sstatus as xstatus, sstatus,
sstatus::Sstatus as Xstatus, sstatus::Sstatus,
mcause::Mcause, scause::Scause,
}; };
/// Saved registers on a trap.
#[derive(Clone)] #[derive(Clone)]
#[repr(C)] #[repr(C)]
pub struct TrapFrame { pub struct TrapFrame {
pub x: [usize; 32], // general registers /// General registers
pub sstatus: Xstatus, // Supervisor Status Register pub x: [usize; 32],
pub sepc: usize, // Supervisor exception program counter, save the trap virtual address (here is used to save the process program entry addr?) /// Supervisor Status
pub stval: usize, // Supervisor trap value pub sstatus: Sstatus,
pub scause: Mcause, // scause register: record the cause of exception/interrupt/trap /// Supervisor Exception Program Counter
pub _hartid: usize, // reserve space 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 { impl TrapFrame {
/* /// Constructs TrapFrame for a new kernel thread.
* @param: ///
* entry: program entry for the thread /// The new thread starts at function `entry` with an usize argument `arg`.
* arg: a0 /// The stack pointer will be set to `sp`.
* sp: stack top
* @brief:
* generate a trapfram for building a new kernel thread
* @retval:
* the trapframe for new kernel thread
*/
fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, sp: usize) -> Self { fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, sp: usize) -> Self {
use core::mem::zeroed; use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() }; let mut tf: Self = unsafe { zeroed() };
tf.x[10] = arg; // a0 tf.x[10] = arg; // a0
tf.x[2] = sp; tf.x[2] = sp;
tf.sepc = entry as usize; tf.sepc = entry as usize;
tf.sstatus = xstatus::read(); tf.sstatus = sstatus::read();
{
tf.sstatus.set_spie(true); tf.sstatus.set_spie(true);
tf.sstatus.set_sie(false); tf.sstatus.set_sie(false);
tf.sstatus.set_spp(xstatus::SPP::Supervisor); tf.sstatus.set_spp(sstatus::SPP::Supervisor);
}
tf tf
} }
/* /// Constructs TrapFrame for a new user thread.
* @param: ///
* entry_addr: program entry for the thread /// The new thread starts at `entry_addr`.
* sp: stack top /// The stack pointer will be set to `sp`.
* @brief:
* generate a trapfram for building a new user thread
* @retval:
* the trapframe for new user thread
*/
fn new_user_thread(entry_addr: usize, sp: usize) -> Self { fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
use core::mem::zeroed; use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() }; let mut tf: Self = unsafe { zeroed() };
tf.x[2] = sp; tf.x[2] = sp;
tf.sepc = entry_addr; tf.sepc = entry_addr;
tf.sstatus = xstatus::read(); tf.sstatus = sstatus::read();
{
tf.sstatus.set_spie(true); tf.sstatus.set_spie(true);
tf.sstatus.set_sie(false); tf.sstatus.set_sie(false);
tf.sstatus.set_spp(xstatus::SPP::User); tf.sstatus.set_spp(sstatus::SPP::User);
}
tf tf
} }
} }
@ -85,12 +76,12 @@ impl Debug for TrapFrame {
.field("sstatus", &self.sstatus) .field("sstatus", &self.sstatus)
.field("sepc", &self.sepc) .field("sepc", &self.sepc)
.field("stval", &self.stval) .field("stval", &self.stval)
.field("scause", &self.scause) .field("scause", &self.scause.cause())
.finish() .finish()
} }
} }
/// kernel stack contents for a new thread /// Kernel stack contents for a new thread
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct InitStack { pub struct InitStack {
@ -99,18 +90,11 @@ pub struct InitStack {
} }
impl InitStack { impl InitStack {
/* /// Push the InitStack on the stack and transfer to a Context.
* @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
*/
unsafe fn push_at(self, stack_top: usize) -> 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; *ptr = self;
Context(ptr as usize) Context { sp: ptr as usize }
} }
} }
@ -118,24 +102,32 @@ extern {
fn trap_return(); fn trap_return();
} }
/// Saved registers for kernel context switches.
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[repr(C)] #[repr(C)]
struct ContextData { struct ContextData {
/// Return address
ra: usize, ra: usize,
/// Page table token
satp: usize, satp: usize,
/// Callee-saved registers
s: [usize; 12], s: [usize; 12],
} }
impl ContextData { impl ContextData {
fn new(satp: usize) -> Self { 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() } ContextData { ra: trap_return as usize, satp, ..ContextData::default() }
} }
} }
/// A struct only contain one usize element /// Context of a kernel thread.
#[derive(Debug)] #[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 { impl Context {
/// Switch to another kernel thread. /// Switch to another kernel thread.
@ -208,66 +200,43 @@ impl Context {
: : : : "volatile" ) : : : : "volatile" )
} }
/* /// Constructs a null Context for the current running thread.
* @brief:
* generate a null Context
* @retval:
* a null Context
*/
pub unsafe fn null() -> Self { pub unsafe fn null() -> Self {
Context(0) Context { sp: 0 }
} }
/* /// Constructs Context for a new kernel thread.
* @param: ///
* entry: program entry for the thread /// The new thread starts at function `entry` with an usize argument `arg`.
* arg: a0 /// The stack pointer will be set to `kstack_top`.
* kstack_top: kernel stack top /// The SATP register will be set to `satp`.
* cr3: cr3 register, save the physical address of Page directory pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, satp: usize) -> Self {
* @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 {
InitStack { InitStack {
context: ContextData::new(cr3), context: ContextData::new(satp),
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top), tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
}.push_at(kstack_top) }.push_at(kstack_top)
} }
/* /// Constructs Context for a new user thread.
* @param: ///
* entry_addr: program entry for the thread /// The new thread starts at `entry_addr`.
* ustack_top: user stack top /// The stack pointer of user and kernel mode will be set to `ustack_top`, `kstack_top`.
* kstack_top: kernel stack top /// The SATP register will be set to `satp`.
* is32: whether the cpu is 32 bit or not pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, _is32: bool, satp: usize) -> Self {
* 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 {
InitStack { InitStack {
context: ContextData::new(cr3), context: ContextData::new(satp),
tf: TrapFrame::new_user_thread(entry_addr, ustack_top), tf: TrapFrame::new_user_thread(entry_addr, ustack_top),
}.push_at(kstack_top) }.push_at(kstack_top)
} }
/* /// Fork a user process and get the new Context.
* @param: ///
* TrapFrame: the trapframe of the forked process(thread) /// The stack pointer in kernel mode will be set to `kstack_top`.
* kstack_top: kernel stack top /// The SATP register will be set to `satp`.
* cr3: cr3 register, save the physical address of Page directory /// All the other registers are same as the original.
* @brief: pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Self {
* 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 {
InitStack { InitStack {
context: ContextData::new(cr3), context: ContextData::new(satp),
tf: { tf: {
let mut tf = tf.clone(); let mut tf = tf.clone();
// fork function's ret value, the new process is 0 // fork function's ret value, the new process is 0
@ -277,9 +246,16 @@ impl Context {
}.push_at(kstack_top) }.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 { InitStack {
context: ContextData::new(cr3), context: ContextData::new(satp),
tf: { tf: {
let mut tf = tf.clone(); let mut tf = tf.clone();
tf.x[2] = ustack_top; // sp tf.x[2] = ustack_top; // sp
@ -290,9 +266,8 @@ impl Context {
}.push_at(kstack_top) }.push_at(kstack_top)
} }
/// Called at a new user context /// Used for getting the init TrapFrame of a new user context in `sys_exec`.
/// To get the init TrapFrame in sys_exec
pub unsafe fn get_init_tf(&self) -> TrapFrame { pub unsafe fn get_init_tf(&self) -> TrapFrame {
(*(self.0 as *const InitStack)).tf.clone() (*(self.sp as *const InitStack)).tf.clone()
} }
} }

@ -1,9 +1,4 @@
use riscv::register::{ use riscv::register::*;
sstatus as xstatus,
sscratch as xscratch,
stvec as xtvec,
};
use riscv::register::{mcause, mepc, sie, mie};
use crate::drivers::DRIVERS; use crate::drivers::DRIVERS;
pub use self::context::*; pub use self::context::*;
use log::*; use log::*;
@ -22,17 +17,14 @@ pub fn init() {
unsafe { unsafe {
// Set sscratch register to 0, indicating to exception vector that we are // Set sscratch register to 0, indicating to exception vector that we are
// presently executing in the kernel // presently executing in the kernel
xscratch::write(0); sscratch::write(0);
// Set the exception vector address // 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 // Enable IPI
sie::set_ssoft(); sie::set_ssoft();
// Enable external interrupt // Enable external interrupt
if super::cpu::id() == super::BOOT_HART_ID { if super::cpu::id() == super::BOOT_HART_ID {
sie::set_sext(); 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"); info!("interrupt: init end");
@ -44,13 +36,13 @@ pub fn init() {
*/ */
#[inline] #[inline]
pub unsafe fn enable() { pub unsafe fn enable() {
xstatus::set_sie(); sstatus::set_sie();
} }
#[inline] #[inline]
pub unsafe fn disable_and_store() -> usize { pub unsafe fn disable_and_store() -> usize {
let e = xstatus::read().sie() as usize; let e = sstatus::read().sie() as usize;
xstatus::clear_sie(); sstatus::clear_sie();
e e
} }
@ -75,19 +67,12 @@ pub unsafe fn restore(flags: usize) {
*/ */
#[no_mangle] #[no_mangle]
pub extern fn rust_trap(tf: &mut TrapFrame) { 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()); trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), tf.scause.cause());
match 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::SupervisorExternal) => external(),
Trap::Interrupt(I::SupervisorSoft) => ipi(), Trap::Interrupt(I::SupervisorSoft) => ipi(),
Trap::Interrupt(I::SupervisorTimer) => timer(), Trap::Interrupt(I::SupervisorTimer) => timer(),
Trap::Exception(E::IllegalInstruction) => illegal_inst(tf),
Trap::Exception(E::UserEnvCall) => syscall(tf), Trap::Exception(E::UserEnvCall) => syscall(tf),
Trap::Exception(E::LoadPageFault) => page_fault(tf), Trap::Exception(E::LoadPageFault) => page_fault(tf),
Trap::Exception(E::StorePageFault) => 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"); 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() { fn external() {
#[cfg(feature = "board_u540")] #[cfg(feature = "board_u540")]
unsafe { super::board::handle_external_interrupt(); } unsafe { super::board::handle_external_interrupt(); }
@ -161,17 +140,6 @@ fn syscall(tf: &mut TrapFrame) {
tf.x[10] = ret as usize; 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: * @param:
* TrapFrame: the Trapframe for the page fault exception * TrapFrame: the Trapframe for the page fault exception

@ -16,22 +16,21 @@ mod sbi;
use log::*; use log::*;
#[no_mangle] #[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) // An initial recursive page table has been set by BBL (shared by all cores)
unsafe { cpu::set_cpu_id(hartid); } unsafe { cpu::set_cpu_id(hartid); }
if hartid != BOOT_HART_ID { if hartid != BOOT_HART_ID {
while unsafe { !cpu::has_started(hartid) } { } 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(); others_main();
//other_main -> ! //other_main -> !
} }
unsafe { memory::clear_bss(); } 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(); crate::logging::init();
interrupt::init(); interrupt::init();
@ -61,18 +60,6 @@ const BOOT_HART_ID: usize = 0;
const BOOT_HART_ID: usize = 1; const BOOT_HART_ID: usize = 1;
/// Constant & Macro for `trap.asm` /// 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")] #[cfg(target_arch = "riscv32")]
global_asm!(r" global_asm!(r"
.equ XLENB, 4 .equ XLENB, 4
@ -99,21 +86,3 @@ global_asm!(r"
global_asm!(include_str!("boot/entry.asm")); global_asm!(include_str!("boot/entry.asm"));
global_asm!(include_str!("boot/trap.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() };
}

Loading…
Cancel
Save