Refactor interrupt mod and add some docs

master
WangRunji 7 years ago
parent f4091c4d7e
commit 6c135bca24

@ -53,13 +53,16 @@ ld := $(prefix)ld
objdump := $(prefix)objdump
cc := $(prefix)gcc
.PHONY: all clean run iso kernel build debug_asm
.PHONY: all clean run iso kernel build debug_asm doc
all: $(kernel)
clean:
@rm -r build target
doc:
@cargo rustdoc -- --document-private-items
run: $(iso)
@qemu-system-$(arch) $(qemu_opts) || [ $$? -eq 11 ] # run qemu and assert it exit 11

@ -7,7 +7,7 @@ pub fn init() {
lazy_static! {
static ref IDT: Idt = {
use arch::interrupt::{handler::*, consts::*};
use arch::interrupt::consts::*;
use arch::gdt::DOUBLE_FAULT_IST_INDEX;
use x86_64::PrivilegeLevel;
use core::mem::transmute;
@ -19,7 +19,7 @@ lazy_static! {
// * 某些保留中断号不允许设置会触发panic
// 于是下面用了一些trick绕过了它们
let ring3 = [T_SWITCH_TOK, T_SYSCALL, 0x80];
let ring3 = [T_SWITCH_TOK, T_SYSCALL, T_SYSCALL32];
let mut idt = Idt::new();
let entries = unsafe{ &mut *(&mut idt as *mut _ as *mut [IdtEntry<HandlerFunc>; 256]) };

@ -27,6 +27,8 @@ pub const IRQ_IDE : u8 = 14;
pub const IRQ_ERROR : u8 = 19;
pub const IRQ_SPURIOUS : u8 = 31;
pub const T_SYSCALL: u8 = 0x40;
// SYSCALL, ONLY FOR THIS PROJ
// xv6 x86_64 syscall
pub const T_SYSCALL32: u8 = 0x80;
// ucore syscall
pub const T_SWITCH_TOU : u8 = 120; // user/kernel switch
pub const T_SWITCH_TOK : u8 = 121; // user/kernel switch

@ -1,3 +1,67 @@
//! 中断服务例程
//!
//! # 中断处理总流程
//!
//! * 中断发生时CPU首先完成以下工作
//! * 设置rsp的值Ring3->0 或 DoubleFault在TSS中设置
//! * 向栈中push一些值Ring0时3项Ring3时5项某些中断还有错误码
//! * 跳转到`vector{i}`符号(位于`vector.asm`
//! * 进入中断服务例程后,完成以下工作:
//! * `vector{i}`向栈中push空错误码如CPU没有做和中断号
//! * 跳转到`__alltraps`(位于`trap.asm`
//! * `__alltraps`向栈中push全部寄存器的值
//! * 调用`rust_trap`并把此时的rsp传过来也就是`TrapFrame`的指针
//! * `rust_trap`完成以下工作:
//! * 根据tf中的中断号再次分发到具体的中断处理函数。
//! 一些函数可能会修改rsp的值以完成进程切换。
//! * 在离开前检查新的tf中的cs段如果是用户态向TSS中设置下一次中断时重置rsp的值使其指向该用户线程的内核栈
//! * 返回新的rsp的值
//! * `__alltraps`完成以下工作:
//! * 重置rsp
//! * 从栈中pop全部寄存器的值pop中断号和错误码
//! * 执行iretCPU从栈中pop一些值若其中的CS是Ring03项否则5项重置rip和rspRing3时
use super::TrapFrame;
#[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."),
}
#[cfg(feature = "use_apic")]
use arch::driver::apic::ack;
#[cfg(not(feature = "use_apic"))]
use arch::driver::pic::ack;
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 breakpoint() {
error!("\nEXCEPTION: Breakpoint");
}
@ -30,11 +94,6 @@ fn invalid_opcode() {
loop {}
}
#[cfg(feature = "use_apic")]
use arch::driver::apic::ack;
#[cfg(not(feature = "use_apic"))]
use arch::driver::pic::ack;
use super::consts::*;
fn keyboard() {
@ -90,41 +149,6 @@ fn syscall32(tf: &mut TrapFrame, rsp: &mut usize) {
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::Cpu;
use core::mem::size_of;
@ -132,33 +156,3 @@ fn set_return_rsp(tf: &TrapFrame) {
Cpu::current().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,
}

@ -1,33 +1,12 @@
use x86_64;
use arch::driver::{apic::IOAPIC, pic};
pub mod handler;
pub mod consts;
mod handler;
mod trapframe;
pub use self::handler::TrapFrame;
impl TrapFrame {
pub fn new_kernel_thread(entry: extern fn(), rsp: usize) -> Self {
use arch::gdt;
let mut tf = TrapFrame::default();
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.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
}
}
pub use self::trapframe::TrapFrame;
pub use self::handler::rust_trap;
#[inline(always)]
pub unsafe fn enable() {

@ -0,0 +1,57 @@
#[derive(Debug, Clone, Default)]
pub struct TrapFrame {
// Pushed by __alltraps at 'trap.asm'
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,
// Pushed by vector{i} at 'vector.asm'
pub trap_num: usize,
pub error_code: usize,
// Pushed by CPU
pub rip: usize,
pub cs: usize,
pub rflags: usize,
// Pushed by CPU when Ring3->0
pub rsp: usize,
pub ss: usize,
}
/// 用于在内核栈中构造新线程的中断帧
impl TrapFrame {
pub fn new_kernel_thread(entry: extern fn(), rsp: usize) -> Self {
use arch::gdt;
let mut tf = TrapFrame::default();
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.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
}
}

@ -127,7 +127,7 @@ pub extern "C" fn other_main() -> ! {
loop {}
}
pub use arch::interrupt::handler::rust_trap;
pub use arch::interrupt::rust_trap;
use linked_list_allocator::LockedHeap;

Loading…
Cancel
Save