diff --git a/Makefile b/Makefile index fc059f6..641c3ce 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs index 2014323..c7e5230 100644 --- a/src/arch/x86_64/idt.rs +++ b/src/arch/x86_64/idt.rs @@ -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; 256]) }; diff --git a/src/arch/x86_64/interrupt/consts.rs b/src/arch/x86_64/interrupt/consts.rs index a43869f..bb087a0 100644 --- a/src/arch/x86_64/interrupt/consts.rs +++ b/src/arch/x86_64/interrupt/consts.rs @@ -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 \ No newline at end of file diff --git a/src/arch/x86_64/interrupt/handler.rs b/src/arch/x86_64/interrupt/handler.rs index cd83f8e..ee9ca0f 100644 --- a/src/arch/x86_64/interrupt/handler.rs +++ b/src/arch/x86_64/interrupt/handler.rs @@ -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中断号和错误码 +//! * 执行iret,CPU从栈中pop一些值(若其中的CS是Ring0,3项,否则5项),重置rip和rsp(Ring3时) + +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::()); } } - -#[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, -} \ No newline at end of file diff --git a/src/arch/x86_64/interrupt/mod.rs b/src/arch/x86_64/interrupt/mod.rs index 4a74fd7..2aa9f87 100644 --- a/src/arch/x86_64/interrupt/mod.rs +++ b/src/arch/x86_64/interrupt/mod.rs @@ -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() { diff --git a/src/arch/x86_64/interrupt/trapframe.rs b/src/arch/x86_64/interrupt/trapframe.rs new file mode 100644 index 0000000..2c5eb76 --- /dev/null +++ b/src/arch/x86_64/interrupt/trapframe.rs @@ -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 + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b190b9f..d14444c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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;