mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-22 16:16:16 +04:00
Add exception handler for MIPS.
This commit is contained in:
parent
9bdac887f0
commit
bcff364b1a
55
kernel/src/arch/mipsel/boot/regdef.h
Normal file
55
kernel/src/arch/mipsel/boot/regdef.h
Normal file
@ -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 */
|
150
kernel/src/arch/mipsel/boot/trap.S
Normal file
150
kernel/src/arch/mipsel/boot/trap.S
Normal file
@ -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};
|
||||
// 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");
|
||||
// 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");
|
||||
}
|
||||
|
||||
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…
Reference in New Issue
Block a user