diff options
| author | Tianhao Wang <shrik3@mailbox.org> | 2024-06-05 07:58:47 +0200 |
|---|---|---|
| committer | Tianhao Wang <shrik3@mailbox.org> | 2024-06-11 15:17:13 +0200 |
| commit | 2c4366a804ae6c389614ff8da9b0225ffb6ce14a (patch) | |
| tree | fa2fd438ba16b6dfcbde2c0b728656f31bec30f6 | |
| parent | d6815a5903716c058c4f8bee89bfa745ee752c9d (diff) | |
interrupt: better trampolines for interrupts
1. define trampolines for both exceptions with error code (automatically
pushed to stack) and those without.
2. do not repeat vectors for unused IRQ numbers: we need 48, no need to
fill in 256.
3. also pass the pointer to trap frame (on the stack) to the handler
code
Signed-off-by: Tianhao Wang <shrik3@mailbox.org>
| -rw-r--r-- | src/arch/x86_64/asm/vectors.s | 79 | ||||
| -rw-r--r-- | src/arch/x86_64/interrupt/mod.rs | 23 |
2 files changed, 78 insertions, 24 deletions
diff --git a/src/arch/x86_64/asm/vectors.s b/src/arch/x86_64/asm/vectors.s index 80ec612..cc7a7b7 100644 --- a/src/arch/x86_64/asm/vectors.s +++ b/src/arch/x86_64/asm/vectors.s @@ -4,7 +4,7 @@ [GLOBAL idt] [GLOBAL idt_descr] [GLOBAL vectors_start] -[EXTERN interrupt_gate] +[EXTERN trap_gate] [SECTION .data.idt] ; Interrupt descriptor table with 256 entries @@ -18,30 +18,66 @@ idt_descr: dw 256*8 - 1 ; 256 entries dq idt -; NOTE: vectors MUST have fixed instruction length currently aligned to 16 -; bytes. DO NOT modify the wrapper, instead change the wrapper_body if needed. -; if the vector has to be modified into more than 16 bytes, -; arch::x86_64:: interrupt::_idt_init() must be modified accordingly [SECTION .text.vectors] -%macro vector 1 +%macro trap_without_err 1 align 16 vector_%1: - push rbp - mov rbp, rsp + push 0 push rax - push rbx mov al, %1 jmp vector_body %endmacro -; automatic generation of 256 interrupt-handling routines, based on above macro +%macro trap_with_err 1 +align 16 +vector_e_%1: + push rax + mov al, %1 + jmp vector_body +%endmacro vectors_start: -%assign i 0 -%rep 256 - vector i +; the first 32 are x86 exceptions / traps +trap_without_err 0 ; Div By Zero +trap_without_err 1 ; Debug +trap_without_err 2 ; NMI +trap_without_err 3 ; BP +trap_without_err 4 ; OF +trap_without_err 5 ; Bound Range +trap_without_err 6 ; Invalid Opcode +trap_without_err 7 ; Device N/A +trap_with_err 8 ; Double Fault +trap_without_err 9 ; Legacy (not used) +trap_with_err 10 ; Invalid TSS +trap_with_err 11 ; Segment Not Present +trap_with_err 12 ; Stack Segment Fault +trap_with_err 13 ; GPF +trap_with_err 14 ; Page Fault +trap_without_err 15 ; RESERVED +trap_without_err 16 ; x87 FP exception +trap_with_err 17 ; Alighment check +trap_without_err 18 ; Machine Check +trap_without_err 19 ; SIMD FP Exception +trap_without_err 20 ; Virtualization Exception +trap_with_err 21 ; Control Protection +trap_without_err 22 ; RESERVED +trap_without_err 23 ; RESERVED +trap_without_err 24 ; RESERVED +trap_without_err 25 ; RESERVED +trap_without_err 26 ; RESERVED +trap_without_err 27 ; RESERVED +trap_without_err 28 ; Hypervisor Injection +trap_with_err 29 ; VMM Communication +trap_with_err 30 ; Security Exception +trap_without_err 31 ; RESERVED +; 16 PIC IRQs are remapped from 32 to 47 +%assign i 32 +%rep 16 + trap_without_err i %assign i i+1 %endrep +; irqs from 48 are not valid, we define one extra vector for all of them +trap_without_err 48 ; INVALID ; common handler body vector_body: @@ -59,11 +95,14 @@ vector_body: ; the generated wrapper only gives us 8 bits, mask the rest and rax, 0xff - ; call the interrupt handling code with interrupt number as parameter + ; the first parameter is the interrupt (exception) number mov rdi, rax - mov rbx, interrupt_gate - ; TODO fix the long jump. I don't want to waste another register - call rbx + ; the second parameter is a pointer to the trap frame + mov rsi, rsp + ; For a long jump, we need to put the (large) address in an register + ; here reusing one of the caller clobbered regs (pushed above) + mov r11, trap_gate + call r11 ; restore volatile registers pop r11 @@ -75,10 +114,8 @@ vector_body: pop rdx pop rcx - ; ... also those from the vector wrapper - pop rbx pop rax - pop rbp - + ; "pop" the error code + add rsp, 8 ; done iretq diff --git a/src/arch/x86_64/interrupt/mod.rs b/src/arch/x86_64/interrupt/mod.rs index 9273ef7..6663b23 100644 --- a/src/arch/x86_64/interrupt/mod.rs +++ b/src/arch/x86_64/interrupt/mod.rs @@ -1,11 +1,14 @@ pub mod pic_8259; pub mod pit; +use crate::arch::x86_64::arch_regs::TrapFrame; use crate::io::*; use core::arch::asm; use core::slice; // TODO use P2V for extern symbol addresses // number of entries in IDT pub const IDT_CAPACITY: usize = 256; +// 32 exceptions + 16 irqs from PIC = 48 valid interrupts +pub const IDT_VALID: usize = 48; // size of interrupt handler wrapper routine (vector) pub const VECTOR_SIZE: u64 = 16; extern "C" { @@ -58,14 +61,24 @@ impl GateDescriptor64 { #[no_mangle] #[cfg(target_arch = "x86_64")] -extern "C" fn interrupt_gate(_slot: u16) { +extern "C" fn trap_gate(_nr: u16, fp: u64) { interrupt_disable(); + // let ctx_p = ptregs_addr as *mut PtRegs; + // let ctx_p = ctx_p.cast::<PtRegs>(); + // let ctx = unsafe { &mut *ctx_p }; // NOTE: the interrupt handler should NEVER block on a lock; in this case // the CGA screen is protected by a spinlock. The lock holder will never be // able to release the lock if the interrupt handler blocks on it. Try // spamming the keyboard with the following line of code uncommented: it // will deadlock! - // println!("interrupt received 0x{:x}", _slot); + println!("interrupt received 0x{:x}", _nr); + if _nr < 0x20 { + let _frame = unsafe { &mut *(fp as *mut TrapFrame) }; + println!("trap: @{:#X} {:#X?}", fp, _frame); + unsafe { + asm!("hlt"); + } + } interrupt_enable(); } @@ -91,10 +104,14 @@ fn _idt_init() { unsafe { slice::from_raw_parts_mut(idt as *mut GateDescriptor64, 256) }; // write to idt - for i in 0..IDT_CAPACITY { + for i in 0..IDT_VALID { let offset: u64 = vectors_start as u64 + (i as u64 * VECTOR_SIZE); gate_descriptors[i].set_default_interrupt(offset); } + let offset_inv: u64 = vectors_start as u64 + (IDT_VALID as u64 * VECTOR_SIZE); + for i in IDT_VALID..IDT_CAPACITY { + gate_descriptors[i].set_default_interrupt(offset_inv); + } // set idtr unsafe { asm! ("lidt [{}]", in(reg) idt_descr) } } |
