Add exception handler for MIPS.

master
Yuhao Zhou 6 years ago
parent 9bdac887f0
commit bcff364b1a

@ -0,0 +1,55 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1985 MIPS Computer Systems, Inc.
* Copyright (C) 1994, 95, 99, 2003 by Ralf Baechle
* Copyright (C) 1990 - 1992, 1999 Silicon Graphics, Inc.
*/
#ifndef _ASM_REGDEF_H
#define _ASM_REGDEF_H
/*
* Symbolic register names for 32 bit ABI
*/
#define zero $0 /* wired zero */
#define AT $1 /* assembler temp - uppercase because of ".set at" */
#define v0 $2 /* return value */
#define v1 $3
#define a0 $4 /* argument registers */
#define a1 $5
#define a2 $6
#define a3 $7
#define t0 $8 /* caller saved */
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12
#define t5 $13
#define t6 $14
#define t7 $15
#define s0 $16 /* callee saved */
#define s1 $17
#define s2 $18
#define s3 $19
#define s4 $20
#define s5 $21
#define s6 $22
#define s7 $23
#define t8 $24 /* caller saved */
#define t9 $25
#define jp $25 /* PIC jump register */
#define k0 $26 /* kernel scratch */
#define k1 $27
#define gp $28 /* global pointer */
#define sp $29 /* stack pointer */
#define fp $30 /* frame pointer */
#define s8 $30 /* same like fp! */
#define ra $31 /* return address */
#endif /* _ASM_REGDEF_H */

@ -0,0 +1,150 @@
#include "regdef.h"
.set noat
.set noreorder
.section .text
.globl trap_entry
trap_entry:
# +0x000: TLB-miss vector
b general_trap_vec
# +0x180: general vector
.org 0x180
general_trap_vec:
move k1, sp # save stack pointer to k1
mfc0 k0, $12 # read cp0.status
andi k0, k0, 0x10 # extract cp0.status.ksu
beq k0, zero, trap_from_kernel
nop # delayslot
trap_from_user:
# TODO: load kstack, we can use k0 to store something
# la k0, address_of_kstack
# addiu sp, k0, size_of_kstack
nop
trap_from_kernel:
/*
* k0 is damaged
* k1 = old stack pointer
* sp = kernel stack */
# allocate 38 words for trapframe + 4 extra words
addiu sp, sp, -168
# save general registers
sw ra, 160(sp)
sw fp, 156(sp)
sw k1, 152(sp) # k1 = old sp
sw gp, 148(sp)
sw k1, 144(sp) # real k1 is damaged
sw k0, 140(sp) # real k0 is damaged
sw t9, 136(sp)
sw t8, 132(sp)
sw s7, 128(sp)
sw s6, 124(sp)
sw s5, 120(sp)
sw s4, 116(sp)
sw s3, 112(sp)
sw s2, 108(sp)
sw s1, 104(sp)
sw s0, 100(sp)
sw t7, 96(sp)
sw t6, 92(sp)
sw t5, 88(sp)
sw t4, 84(sp)
sw t3, 80(sp)
sw t2, 76(sp)
sw t1, 72(sp)
sw t0, 68(sp)
sw a3, 64(sp)
sw a2, 60(sp)
sw a1, 56(sp)
sw a0, 52(sp)
sw v1, 48(sp)
sw v0, 44(sp)
sw AT, 40(sp)
nop
# save hi/lo
mflo t1
sw t1, 36(sp)
mfhi t0
sw t0, 32(sp)
# save special registers
mfc0 t0, $8 # cp0.vaddr
sw t0, 28(sp)
mfc0 t1, $14 # cp0.epc
sw t1, 24(sp)
mfc0 t0, $13 # cp0.cause
sw t0, 20(sp)
mfc0 t1, $12 # cp0.status
sw t1, 16(sp)
# support nested interrupt
la t0, ~0x1b # reset status.ksu, status.exl, status.ie
and t1, t1, t0
mtc0 t1, $12 # cp0.status
# prepare to call rust_trap
jal rust_trap
addiu a0, sp, 16 /* set argument */
.globl trap_return
trap_return:
# restore special registers
lw t1, 16(sp)
ori t1, t1, 0x2 # status.exl
nop
mtc0 t1, $12 # cp0.status
lw k0, 24(sp)
mtc0 k0, $14 # cp0.epc
lw t0, 32(sp)
mthi t0
lw t1, 36(sp)
mtlo t1
# restore general registers
lw AT, 40(sp)
lw v0, 44(sp)
lw v1, 48(sp)
lw a0, 52(sp)
lw a1, 56(sp)
lw a2, 60(sp)
lw a3, 64(sp)
lw t0, 68(sp)
lw t1, 72(sp)
lw t2, 76(sp)
lw t3, 80(sp)
lw t4, 84(sp)
lw t5, 88(sp)
lw t6, 92(sp)
lw t7, 96(sp)
lw s0, 100(sp)
lw s1, 104(sp)
lw s2, 108(sp)
lw s3, 112(sp)
lw s4, 116(sp)
lw s5, 120(sp)
lw s6, 124(sp)
lw s7, 128(sp)
lw t8, 132(sp)
lw t9, 136(sp)
# lw k0, 140(sp)
# lw k1, 144(sp)
lw gp, 148(sp)
lw fp, 156(sp)
lw ra, 160(sp)
lw sp, 152(sp)
eret
nop

@ -1,129 +0,0 @@
# Constants / Macros defined in Rust code:
# XLENB
# LOAD
# STORE
# TEST_BACK_TO_KERNEL
.macro SAVE_ALL
# 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, sscratch, sp
bnez sp, trap_from_user
trap_from_kernel:
csrr sp, sscratch
STORE gp, -1
# sscratch = previous-sp, sp = kernel-sp
trap_from_user:
# provide room for trap frame
addi sp, sp, -37 * XLENB
# save x registers except x2 (sp)
STORE x1, 1
STORE x3, 3
STORE x4, 4
STORE x5, 5
STORE x6, 6
STORE x7, 7
STORE x8, 8
STORE x9, 9
STORE x10, 10
STORE x11, 11
STORE x12, 12
STORE x13, 13
STORE x14, 14
STORE x15, 15
STORE x16, 16
STORE x17, 17
STORE x18, 18
STORE x19, 19
STORE x20, 20
STORE x21, 21
STORE x22, 22
STORE x23, 23
STORE x24, 24
STORE x25, 25
STORE x26, 26
STORE x27, 27
STORE x28, 28
STORE x29, 29
STORE x30, 30
STORE x31, 31
# load hartid to gp from sp[36]
LOAD gp, 36
# get sp, sstatus, sepc, stval, scause
# set sscratch = 0
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
STORE s2, 33
STORE s3, 34
STORE s4, 35
.endm
.macro RESTORE_ALL
LOAD s1, 32 # s1 = sstatus
LOAD s2, 33 # s2 = sepc
andi s0, s1, 1 << 8 # sstatus.SPP = 1
bnez s0, _to_kernel # s0 = back to kernel?
_to_user:
addi s0, sp, 37*XLENB
csrw sscratch, s0 # sscratch = kernel-sp
STORE gp, 36 # store hartid from gp to sp[36]
_to_kernel:
# restore sstatus, sepc
csrw sstatus, s1
csrw sepc, s2
# restore x registers except x2 (sp)
LOAD x1, 1
LOAD x3, 3
LOAD x4, 4
LOAD x5, 5
LOAD x6, 6
LOAD x7, 7
LOAD x8, 8
LOAD x9, 9
LOAD x10, 10
LOAD x11, 11
LOAD x12, 12
LOAD x13, 13
LOAD x14, 14
LOAD x15, 15
LOAD x16, 16
LOAD x17, 17
LOAD x18, 18
LOAD x19, 19
LOAD x20, 20
LOAD x21, 21
LOAD x22, 22
LOAD x23, 23
LOAD x24, 24
LOAD x25, 25
LOAD x26, 26
LOAD x27, 27
LOAD x28, 28
LOAD x29, 29
LOAD x30, 30
LOAD x31, 31
# restore sp last
LOAD x2, 2
.endm
.section .text
.globl trap_entry
trap_entry:
SAVE_ALL
mv a0, sp
jal rust_trap
.globl trap_return
trap_return:
RESTORE_ALL
# return from supervisor call
sret

@ -1,23 +1,27 @@
use riscv::register::{
sstatus,
sstatus::Sstatus,
scause::Scause,
};
use mips::registers;
/// Saved registers on a trap.
#[derive(Clone)]
#[repr(C)]
pub struct TrapFrame {
/// 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,
/// CP0 status register
pub status: usize;
/// CP0 cause register
pub cause: usize;
/// CP0 EPC register
pub epc: usize;
/// CP0 vaddr register
pub vaddr: usize;
/// HI/LO registers
pub hi, lo: usize;
/// General registers 1-7
pub at, v0, v1, a0, a1, a2, a3: u32;
/// General registers 8-15
pub t0, t1, t2, t3, t4, t5, t6, t7: u32;
/// General registers 16-23
pub s0, s1, s2, s3, s4, s5, s6, s7: u32;
/// General registers 24-31
pub t8, t9, k0, k1, gp, sp, fp, ra: u32;
/// Reserve space for hartid
pub _hartid: usize,
}

@ -1,4 +1,5 @@
use mips::interrupts::*;
use mips::registers::*;
use crate::drivers::DRIVERS;
pub use self::context::*;
use log::*;
@ -8,6 +9,7 @@ mod context;
/// Initialize interrupt
pub fn init() {
// TODO
// extern {
// fn trap_entry();
// }
@ -30,23 +32,23 @@ pub fn init() {
/// Enable interrupt
#[inline]
pub unsafe fn enable() {
// sstatus::set_sie();
interrupts::enable();
}
/// Disable interrupt and return current interrupt status
#[inline]
pub unsafe fn disable_and_store() -> usize {
// let e = sstatus::read().sie() as usize;
// sstatus::clear_sie();
// e
let e = cp0::status::read_u32() & 1;
interrupts::disable();
e
}
/// Enable interrupt if `flags` != 0
#[inline]
pub unsafe fn restore(flags: usize) {
// if flags != 0 {
// enable();
// }
if flags != 0 {
enable();
}
}
/// Dispatch and handle interrupt.
@ -54,22 +56,24 @@ pub unsafe fn restore(flags: usize) {
/// This function is called from `trap.asm`.
#[no_mangle]
pub extern fn rust_trap(tf: &mut TrapFrame) {
// use self::scause::{Trap, Interrupt as I, Exception as E};
// TODO
use self::scause::{Trap, Interrupt as I, Exception as E};
// trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), tf.scause.cause());
// match tf.scause.cause() {
// Trap::Interrupt(I::SupervisorExternal) => external(),
// Trap::Interrupt(I::SupervisorSoft) => ipi(),
// Trap::Interrupt(I::SupervisorTimer) => timer(),
// Trap::Exception(E::UserEnvCall) => syscall(tf),
// Trap::Exception(E::LoadPageFault) => page_fault(tf),
// Trap::Exception(E::StorePageFault) => page_fault(tf),
// Trap::Exception(E::InstructionPageFault) => page_fault(tf),
// _ => crate::trap::error(tf),
// }
// trace!("Interrupt end");
match tf.scause.cause() {
Trap::Interrupt(I::SupervisorExternal) => external(),
Trap::Interrupt(I::SupervisorSoft) => ipi(),
Trap::Interrupt(I::SupervisorTimer) => timer(),
Trap::Exception(E::UserEnvCall) => syscall(tf),
Trap::Exception(E::LoadPageFault) => page_fault(tf),
Trap::Exception(E::StorePageFault) => page_fault(tf),
Trap::Exception(E::InstructionPageFault) => page_fault(tf),
_ => crate::trap::error(tf),
}
trace!("Interrupt end");
}
fn external() {
// TODO
#[cfg(feature = "board_u540")]
unsafe { super::board::handle_external_interrupt(); }
@ -83,6 +87,7 @@ fn external() {
}
fn try_process_serial() -> bool {
// TODO
match super::io::getchar_option() {
Some(ch) => {
crate::trap::serial(ch);
@ -93,6 +98,7 @@ fn try_process_serial() -> bool {
}
fn try_process_drivers() -> bool {
// TODO
for driver in DRIVERS.read().iter() {
if driver.try_handle_interrupt(None) == true {
return true
@ -102,8 +108,9 @@ fn try_process_drivers() -> bool {
}
fn ipi() {
// TODO
debug!("IPI");
super::sbi::clear_ipi();
// super::sbi::clear_ipi();
}
fn timer() {
@ -112,12 +119,14 @@ fn timer() {
}
fn syscall(tf: &mut TrapFrame) {
// TODO
tf.sepc += 4; // Must before syscall, because of fork.
let ret = crate::syscall::syscall(tf.x[17], [tf.x[10], tf.x[11], tf.x[12], tf.x[13], tf.x[14], tf.x[15]], tf);
tf.x[10] = ret as usize;
}
fn page_fault(tf: &mut TrapFrame) {
// TODO
let addr = tf.stval;
trace!("\nEXCEPTION: Page Fault @ {:#x}", addr);

Loading…
Cancel
Save