Huge refactor for interrupt.

master
WangRunji 7 years ago
parent 4e35b927d2
commit f35d74c734

File diff suppressed because it is too large Load Diff

@ -11,31 +11,26 @@ pub fn init() {
use arch::gdt::DOUBLE_FAULT_IST_INDEX;
let mut idt = Idt::new();
idt[T_BRKPT].set_handler_fn(breakpoint);
idt[T_PGFLT].set_handler_fn(page_fault);
idt[T_GPFLT].set_handler_fn(general_protection_fault);
idt[T_ILLOP].set_handler_fn(invalid_opcode);
idt[T_IRQ0 + IRQ_COM1].set_handler_fn(com1);
idt[T_IRQ0 + IRQ_COM2].set_handler_fn(com2);
idt[T_IRQ0 + IRQ_KBD].set_handler_fn(keyboard);
idt[T_IRQ0 + IRQ_TIMER].set_handler_fn(timer);
for i in 0u8..=255 {
idt[i].set_handler_fn(unsafe { __vectors[i as usize] });
}
idt[T_SWITCH_TOU].set_handler_fn(to_user);
idt[T_SWITCH_TOK].set_handler_fn(to_kernel)
.set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
idt[T_SWITCH_TOK].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
// TODO: Enable interrupt during syscall
idt[T_SYSCALL].set_handler_fn(syscall)
.set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
idt[0x80].set_handler_fn(syscall32)
.set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
idt[T_SYSCALL].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
idt[0x80].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
unsafe {
idt[T_DBLFLT].set_handler_fn(double_fault)
.set_stack_index(DOUBLE_FAULT_IST_INDEX as u16);
idt[T_DBLFLT].set_stack_index(DOUBLE_FAULT_IST_INDEX as u16);
}
idt
});
let idt = unsafe{ &*Box::into_raw(idt) };
idt.load();
}
}
extern {
//noinspection RsStaticConstNaming
static __vectors: [extern fn(); 256];
}

@ -1,45 +1,34 @@
#[macro_use]
#[path = "./template.rs"]
mod template;
use self::template::*;
pub type TrapFrame = InterruptStackP;
interrupt_stack!(breakpoint, stack, {
fn breakpoint() {
error!("\nEXCEPTION: Breakpoint");
stack.dump();
});
}
interrupt_error_p!(double_fault, stack, {
fn double_fault() {
error!("\nEXCEPTION: Double Fault");
stack.dump();
loop {}
});
}
interrupt_error_p!(page_fault, stack, {
fn page_fault(tf: &mut TrapFrame) {
use x86_64::registers::control_regs::cr2;
let addr = cr2().0;
error!("\nEXCEPTION: Page Fault @ {:#x}, code: {:#x}", addr, stack.code);
error!("\nEXCEPTION: Page Fault @ {:#x}, code: {:#x}", addr, tf.error_code);
use memory::page_fault_handler;
if page_fault_handler(addr) {
return;
}
stack.dump();
loop {}
});
}
interrupt_error_p!(general_protection_fault, stack, {
fn general_protection_fault() {
error!("\nEXCEPTION: General Protection Fault");
stack.dump();
loop {}
});
}
interrupt_stack_p!(invalid_opcode, stack, {
fn invalid_opcode() {
error!("\nEXCEPTION: Invalid Opcode");
stack.dump();
loop {}
});
}
#[cfg(feature = "use_apic")]
use arch::driver::apic::ack;
@ -48,63 +37,128 @@ use arch::driver::pic::ack;
use super::consts::*;
interrupt!(keyboard, {
fn keyboard() {
use arch::driver::keyboard;
info!("\nInterupt: Keyboard");
let c = keyboard::get();
info!("Key = '{}' {}", c as u8 as char, c);
ack(IRQ_KBD);
});
}
interrupt!(com1, {
fn com1() {
use arch::driver::serial::COM1;
info!("\nInterupt: COM1");
COM1.lock().receive();
ack(IRQ_COM1);
});
}
interrupt!(com2, {
fn com2() {
use arch::driver::serial::COM2;
info!("\nInterupt: COM2");
COM2.lock().receive();
ack(IRQ_COM2);
});
}
interrupt_switch!(timer, stack, rsp, {
fn timer(tf: &mut TrapFrame, rsp: &mut usize) {
use process;
process::timer_handler(stack, &mut rsp);
ack(IRQ_TIMER);
});
process::timer_handler(tf, rsp);
}
interrupt_stack_p!(to_user, stack, {
fn to_user(tf: &mut TrapFrame) {
use arch::gdt;
info!("\nInterupt: To User");
let rsp = unsafe{ (stack as *const InterruptStackP).offset(1) } as usize;
gdt::set_ring0_rsp(rsp);
stack.iret.cs = gdt::UCODE_SELECTOR.0 as usize;
stack.iret.ss = gdt::UDATA_SELECTOR.0 as usize;
stack.iret.rflags |= 3 << 12; // 设置EFLAG的I/O特权位使得在用户态可使用in/out指令
});
interrupt_stack_p!(to_kernel, stack, {
// info!("rsp @ {:#x}", stack as *const _ as usize);
tf.cs = gdt::UCODE_SELECTOR.0 as usize;
tf.ss = gdt::UDATA_SELECTOR.0 as usize;
tf.rflags |= 3 << 12; // 设置EFLAG的I/O特权位使得在用户态可使用in/out指令
}
fn to_kernel(tf: &mut TrapFrame) {
use arch::gdt;
info!("\nInterupt: To Kernel");
stack.iret.cs = gdt::KCODE_SELECTOR.0 as usize;
stack.iret.ss = gdt::KDATA_SELECTOR.0 as usize;
});
tf.cs = gdt::KCODE_SELECTOR.0 as usize;
tf.ss = gdt::KDATA_SELECTOR.0 as usize;
}
interrupt_switch!(syscall, stack, rsp, {
info!("\nInterupt: Syscall {:#x?}", stack.scratch.rax);
fn syscall(tf: &mut TrapFrame, rsp: &mut usize) {
info!("\nInterupt: Syscall {:#x?}", tf.rax);
use syscall::syscall;
let ret = syscall(stack, &mut rsp, false);
stack.scratch.rax = ret as usize;
});
let ret = syscall(tf, rsp, false);
tf.rax = ret as usize;
}
interrupt_switch!(syscall32, stack, rsp, {
// info!("\nInterupt: Syscall {:#x?}", stack.scratch.rax);
fn syscall32(tf: &mut TrapFrame, rsp: &mut usize) {
// info!("\nInterupt: Syscall {:#x?}", tf.rax);
use syscall::syscall;
let ret = syscall(stack, &mut rsp, true);
stack.scratch.rax = ret as usize;
});
let ret = syscall(tf, rsp, true);
tf.rax = ret as usize;
}
#[no_mangle]
pub extern fn rust_trap(tf: &mut TrapFrame) -> usize {
let mut rsp = tf as *const _ as usize;
// Dispatch
match tf.trap_num as u8 {
T_BRKPT => breakpoint(),
T_DBLFLT => double_fault(),
T_PGFLT => page_fault(tf),
T_GPFLT => general_protection_fault(),
T_IRQ0...64 => {
let irq = tf.trap_num as u8 - T_IRQ0;
match irq {
IRQ_TIMER => timer(tf, &mut rsp),
IRQ_KBD => keyboard(),
IRQ_COM1 => com1(),
IRQ_COM2 => com2(),
_ => panic!("Invalid IRQ number."),
}
ack(irq);
}
T_SWITCH_TOK => to_kernel(tf),
T_SWITCH_TOU => to_user(tf),
T_SYSCALL => syscall(tf, &mut rsp),
0x80 => syscall32(tf, &mut rsp),
_ => panic!("Unhandled interrupt {:x}", tf.trap_num),
}
// Set return rsp if to user
let tf = unsafe { &*(rsp as *const TrapFrame) };
set_return_rsp(tf);
rsp
}
fn set_return_rsp(tf: &TrapFrame) {
use arch::gdt;
use core::mem::size_of;
if tf.cs & 0x3 == 3 {
gdt::set_ring0_rsp(tf as *const _ as usize + size_of::<TrapFrame>());
}
}
#[derive(Debug, Clone, Default)]
pub struct TrapFrame {
pub r15: usize,
pub r14: usize,
pub r13: usize,
pub r12: usize,
pub rbp: usize,
pub rbx: usize,
pub r11: usize,
pub r10: usize,
pub r9: usize,
pub r8: usize,
pub rsi: usize,
pub rdi: usize,
pub rdx: usize,
pub rcx: usize,
pub rax: usize,
pub trap_num: usize,
pub error_code: usize,
pub rip: usize,
pub cs: usize,
pub rflags: usize,
pub rsp: usize,
pub ss: usize,
}

@ -10,21 +10,21 @@ impl TrapFrame {
pub fn new_kernel_thread(entry: extern fn(), rsp: usize) -> Self {
use arch::gdt;
let mut tf = TrapFrame::default();
tf.iret.cs = gdt::KCODE_SELECTOR.0 as usize;
tf.iret.rip = entry as usize;
tf.iret.ss = gdt::KDATA_SELECTOR.0 as usize;
tf.iret.rsp = rsp;
tf.iret.rflags = 0x282;
tf.cs = gdt::KCODE_SELECTOR.0 as usize;
tf.rip = entry as usize;
tf.ss = gdt::KDATA_SELECTOR.0 as usize;
tf.rsp = rsp;
tf.rflags = 0x282;
tf
}
pub fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self {
use arch::gdt;
let mut tf = TrapFrame::default();
tf.iret.cs = if is32 { gdt::UCODE32_SELECTOR.0 } else { gdt::UCODE_SELECTOR.0 } as usize;
tf.iret.rip = entry_addr;
tf.iret.ss = if is32 { gdt::UDATA32_SELECTOR.0 } else { gdt::UDATA_SELECTOR.0 } as usize;
tf.iret.rsp = rsp;
tf.iret.rflags = 0x282;
tf.cs = if is32 { gdt::UCODE32_SELECTOR.0 } else { gdt::UCODE_SELECTOR.0 } as usize;
tf.rip = entry_addr;
tf.ss = if is32 { gdt::UDATA32_SELECTOR.0 } else { gdt::UDATA_SELECTOR.0 } as usize;
tf.rsp = rsp;
tf.rflags = 0x282;
tf
}
}

@ -1,452 +0,0 @@
//! Copy from Redox
#[allow(dead_code)]
#[repr(packed)]
#[derive(Clone, Default)]
pub struct ScratchRegisters {
pub r11: usize,
pub r10: usize,
pub r9: usize,
pub r8: usize,
pub rsi: usize,
pub rdi: usize,
pub rdx: usize,
pub rcx: usize,
pub rax: usize,
}
impl ScratchRegisters {
pub fn dump(&self) {
println!("RAX: {:>016X}", { self.rax });
println!("RCX: {:>016X}", { self.rcx });
println!("RDX: {:>016X}", { self.rdx });
println!("RDI: {:>016X}", { self.rdi });
println!("RSI: {:>016X}", { self.rsi });
println!("R8: {:>016X}", { self.r8 });
println!("R9: {:>016X}", { self.r9 });
println!("R10: {:>016X}", { self.r10 });
println!("R11: {:>016X}", { self.r11 });
}
}
macro_rules! scratch_push {
() => (asm!(
"push rax
push rcx
push rdx
push rdi
push rsi
push r8
push r9
push r10
push r11"
: : : : "intel", "volatile"
));
}
macro_rules! scratch_pop {
() => (asm!(
"pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rdx
pop rcx
pop rax"
: : : : "intel", "volatile"
));
}
#[allow(dead_code)]
#[repr(packed)]
#[derive(Clone, Default)]
pub struct PreservedRegisters {
pub r15: usize,
pub r14: usize,
pub r13: usize,
pub r12: usize,
pub rbp: usize,
pub rbx: usize,
}
impl PreservedRegisters {
pub fn dump(&self) {
println!("RBX: {:>016X}", { self.rbx });
println!("RBP: {:>016X}", { self.rbp });
println!("R12: {:>016X}", { self.r12 });
println!("R13: {:>016X}", { self.r13 });
println!("R14: {:>016X}", { self.r14 });
println!("R15: {:>016X}", { self.r15 });
}
}
macro_rules! preserved_push {
() => (asm!(
"push rbx
push rbp
push r12
push r13
push r14
push r15"
: : : : "intel", "volatile"
));
}
macro_rules! preserved_pop {
() => (asm!(
"pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx"
: : : : "intel", "volatile"
));
}
macro_rules! fs_push {
() => (asm!(
"push fs
mov rax, 0x18
mov fs, ax"
: : : : "intel", "volatile"
));
}
macro_rules! fs_pop {
() => (asm!(
"pop fs"
: : : : "intel", "volatile"
));
}
#[allow(dead_code)]
#[repr(packed)]
#[derive(Clone, Default)]
pub struct IretRegisters {
pub rip: usize,
pub cs: usize,
pub rflags: usize,
pub rsp: usize,
pub ss: usize,
}
impl IretRegisters {
pub fn dump(&self) {
println!("SS: {:>016X}", { self.ss });
println!("RSP: {:>016X}", { self.rsp });
println!("RFLAG: {:>016X}", { self.rflags });
println!("CS: {:>016X}", { self.cs });
println!("RIP: {:>016X}", { self.rip });
}
}
macro_rules! iret {
() => (asm!(
"iretq"
: : : : "intel", "volatile"
));
}
/// Create an interrupt function that can safely run rust code
macro_rules! interrupt {
($name:ident, $func:block) => {
#[naked]
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner() {
$func
}
// Push scratch registers
scratch_push!();
fs_push!();
// Map kernel
// $crate::arch::x86_64::pti::map();
// Call inner rust function
inner();
// Unmap kernel
// $crate::arch::x86_64::pti::unmap();
// Pop scratch registers and return
fs_pop!();
scratch_pop!();
iret!();
}
};
}
#[allow(dead_code)]
#[repr(packed)]
pub struct InterruptStack {
pub fs: usize,
pub scratch: ScratchRegisters,
pub iret: IretRegisters,
}
impl InterruptStack {
pub fn dump(&self) {
self.iret.dump();
self.scratch.dump();
println!("FS: {:>016X}", { self.fs });
}
}
macro_rules! interrupt_stack {
($name:ident, $stack: ident, $func:block) => {
#[naked]
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner($stack: &mut InterruptStack) {
$func
}
// Push scratch registers
scratch_push!();
fs_push!();
// Get reference to stack variables
let rsp: usize;
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
// Map kernel
// $crate::arch::x86_64::pti::map();
// Call inner rust function
inner(&mut *(rsp as *mut InterruptStack));
// Unmap kernel
// $crate::arch::x86_64::pti::unmap();
// Pop scratch registers and return
fs_pop!();
scratch_pop!();
iret!();
}
};
}
#[allow(dead_code)]
#[repr(packed)]
pub struct InterruptErrorStack {
pub fs: usize,
pub scratch: ScratchRegisters,
pub code: usize,
pub iret: IretRegisters,
}
impl InterruptErrorStack {
pub fn dump(&self) {
self.iret.dump();
println!("CODE: {:>016X}", { self.code });
self.scratch.dump();
println!("FS: {:>016X}", { self.fs });
}
}
macro_rules! interrupt_error {
($name:ident, $stack:ident, $func:block) => {
#[naked]
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner($stack: &InterruptErrorStack) {
$func
}
// Push scratch registers
scratch_push!();
fs_push!();
// Get reference to stack variables
let rsp: usize;
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
// Map kernel
// $crate::arch::x86_64::pti::map();
// Call inner rust function
inner(&*(rsp as *const InterruptErrorStack));
// Unmap kernel
// $crate::arch::x86_64::pti::unmap();
// Pop scratch registers, error code, and return
fs_pop!();
scratch_pop!();
asm!("add rsp, 8" : : : : "intel", "volatile");
iret!();
}
};
}
#[allow(dead_code)]
#[repr(packed)]
#[derive(Clone, Default)]
pub struct InterruptStackP {
pub fs: usize,
pub preserved: PreservedRegisters,
pub scratch: ScratchRegisters,
pub iret: IretRegisters,
}
impl InterruptStackP {
pub fn dump(&self) {
self.iret.dump();
self.scratch.dump();
self.preserved.dump();
println!("FS: {:>016X}", { self.fs });
}
}
use core::fmt::Debug;
use core::fmt::Formatter;
use core::fmt::Error;
impl Debug for InterruptStackP {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
self.dump();
Ok(())
}
}
macro_rules! interrupt_switch {
($name:ident, $stack: ident, $rsp: ident, $func:block) => {
#[naked]
pub unsafe extern fn $name () {
// WARNING: Don't do anything outside the inner function.
// rbp is not pointing to kernel stack!
#[inline(never)]
unsafe fn inner($stack: &mut InterruptStackP) -> usize {
let mut $rsp = $stack as *const _ as usize;
$func
// Set return rsp if to user
use arch::gdt;
use core::mem::size_of;
let tf = &mut *($rsp as *mut TrapFrame);
if tf.iret.cs & 0x3 == 3 {
gdt::set_ring0_rsp($rsp + size_of::<TrapFrame>());
}
$rsp
}
// Push scratch registers
scratch_push!();
preserved_push!();
fs_push!();
// Get reference to stack variables
let rsp: usize;
asm!("mov rbp, rsp" : "={rsp}"(rsp) : : : "intel", "volatile");
// "mov rbp, rsp" <-- Fix a lot of bugs!
// Call inner rust function
let rsp = inner(&mut *(rsp as *mut InterruptStackP));
asm!("" : : "{rsp}"(rsp) : : "intel", "volatile");
// Pop scratch registers and return
fs_pop!();
preserved_pop!();
scratch_pop!();
iret!();
}
};
}
macro_rules! interrupt_stack_p {
($name:ident, $stack: ident, $func:block) => {
#[naked]
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner($stack: &mut InterruptStackP) {
$func
}
// Push scratch registers
scratch_push!();
preserved_push!();
fs_push!();
// Get reference to stack variables
let rsp: usize;
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
// Map kernel
// $crate::arch::x86_64::pti::map();
// Call inner rust function
inner(&mut *(rsp as *mut InterruptStackP));
// Unmap kernel
// $crate::arch::x86_64::pti::unmap();
// Pop scratch registers and return
fs_pop!();
preserved_pop!();
scratch_pop!();
iret!();
}
};
}
#[allow(dead_code)]
#[repr(packed)]
pub struct InterruptErrorStackP {
pub fs: usize,
pub preserved: PreservedRegisters,
pub scratch: ScratchRegisters,
pub code: usize,
pub iret: IretRegisters,
}
impl InterruptErrorStackP {
pub fn dump(&self) {
self.iret.dump();
println!("CODE: {:>016X}", { self.code });
self.scratch.dump();
self.preserved.dump();
println!("FS: {:>016X}", { self.fs });
}
}
macro_rules! interrupt_error_p {
($name:ident, $stack:ident, $func:block) => {
#[naked]
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner($stack: &InterruptErrorStackP) {
$func
}
// Push scratch registers
scratch_push!();
preserved_push!();
fs_push!();
// Get reference to stack variables
let rsp: usize;
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
// Map kernel
// $crate::arch::x86_64::pti::map();
// Call inner rust function
inner(&*(rsp as *const InterruptErrorStackP));
// Unmap kernel
// $crate::arch::x86_64::pti::unmap();
// Pop scratch registers, error code, and return
fs_pop!();
preserved_pop!();
scratch_pop!();
asm!("add rsp, 8" : : : : "intel", "volatile");
iret!();
}
};
}

@ -128,6 +128,8 @@ pub extern "C" fn other_main() -> ! {
loop {}
}
pub use arch::interrupt::handler::rust_trap;
use linked_list_allocator::LockedHeap;
/// Global heap allocator

@ -160,7 +160,7 @@ impl Process {
// Allocate kernel stack and push trap frame
let kstack = mc.alloc_stack(7).unwrap();
let mut tf = tf.clone();
tf.scratch.rax = 0; // sys_fork return 0 for child
tf.rax = 0; // sys_fork return 0 for child
let rsp = kstack.push_at_top(tf);
Process {
@ -178,7 +178,7 @@ impl Process {
pub fn set_return_value(&self, value: usize) {
let tf = unsafe { &mut *(self.rsp as *mut TrapFrame) };
tf.scratch.rax = value;
tf.rax = value;
}
pub fn exit_code(&self) -> Option<ErrorCode> {
match self.status {

@ -2,16 +2,16 @@ use super::*;
use process;
use arch::interrupt::TrapFrame;
pub unsafe fn syscall(tf: &TrapFrame, rsp: &mut usize, is32: bool) -> i32 {
pub fn syscall(tf: &TrapFrame, rsp: &mut usize, is32: bool) -> i32 {
let id = match is32 {
false => Syscall::Xv6(tf.scratch.rax),
true => Syscall::Ucore(tf.scratch.rax),
false => Syscall::Xv6(tf.rax),
true => Syscall::Ucore(tf.rax),
};
let args = match is32 {
// For ucore x86
true => [tf.scratch.rdx, tf.scratch.rcx, tf.preserved.rbx, tf.scratch.rdi, tf.scratch.rsi, 0],
true => [tf.rdx, tf.rcx, tf.rbx, tf.rdi, tf.rsi, 0],
// For xv6 x86_64
false => [tf.scratch.rdi, tf.scratch.rsi, tf.scratch.rdx, tf.scratch.rcx, tf.scratch.r8, tf.scratch.r9],
false => [tf.rdi, tf.rsi, tf.rdx, tf.rcx, tf.r8, tf.r9],
};
match id {

Loading…
Cancel
Save