; ; IsrStubs.asm ; Hardware interrupt (IRQ) entry stubs for APIC (SMP-aware with SWAPGS) ; Copyright (c) 2025-2026 Daniel Hammer ; [bits 64] section .text ; External C++ handler function extern HalIrqDispatch ; ==================================================================== ; IRQ stub macro with SWAPGS support ; Each stub checks the saved CS to determine if we came from user mode. ; If so, SWAPGS is executed to switch GS to per-CPU data. ; ==================================================================== %macro IRQ_STUB 1 global IrqStub%1 IrqStub%1: cmp qword [rsp + 8], 0x08 ; check saved CS: kernel? je %%from_kernel swapgs ; from user mode: swap to kernel GS %%from_kernel: push rax ; save rax (used for IRQ number) mov rax, %1 ; IRQ number jmp IrqCommon %endmacro ; ==================================================================== ; Common IRQ handler: saves all general-purpose registers, ; calls the C++ dispatch function, restores registers, and returns. ; ==================================================================== IrqCommon: ; rax is already on the stack and holds the IRQ number push rcx push rdx push rbx push rbp push rsi push rdi push r8 push r9 push r10 push r11 push r12 push r13 push r14 push r15 ; Pass IRQ number as first argument (rdi) mov rdi, rax ; Pass the saved CS as the second argument. Fifteen saved GPRs occupy ; 120 bytes, and CS is eight bytes after the interrupt-frame RIP. mov rsi, [rsp + 128] ; An IRQ that interrupted ring 0 can arrive at any kernel stack depth, so ; the saved frame is not guaranteed to satisfy the SysV call alignment. ; RBX is already saved above and is callee-saved, making it a safe place to ; retain the exact frame pointer while aligning down for the C++ call. mov rbx, rsp and rsp, -16 cld call HalIrqDispatch mov rsp, rbx pop r15 pop r14 pop r13 pop r12 pop r11 pop r10 pop r9 pop r8 pop rdi pop rsi pop rbp pop rbx pop rdx pop rcx pop rax ; SWAPGS back if returning to user mode cmp qword [rsp + 8], 0x08 ; check saved CS: kernel? je .from_kernel_exit swapgs ; returning to user mode: restore user GS .from_kernel_exit: iretq ; ==================================================================== ; Define stubs for IRQs 0..47 (vectors 32..79) ; 0-23: legacy ISA IRQs via IOAPIC, 24-45: MSI, 46-47: kernel IPIs ; ==================================================================== IRQ_STUB 0 IRQ_STUB 1 IRQ_STUB 2 IRQ_STUB 3 IRQ_STUB 4 IRQ_STUB 5 IRQ_STUB 6 IRQ_STUB 7 IRQ_STUB 8 IRQ_STUB 9 IRQ_STUB 10 IRQ_STUB 11 IRQ_STUB 12 IRQ_STUB 13 IRQ_STUB 14 IRQ_STUB 15 IRQ_STUB 16 IRQ_STUB 17 IRQ_STUB 18 IRQ_STUB 19 IRQ_STUB 20 IRQ_STUB 21 IRQ_STUB 22 IRQ_STUB 23 IRQ_STUB 24 IRQ_STUB 25 IRQ_STUB 26 IRQ_STUB 27 IRQ_STUB 28 IRQ_STUB 29 IRQ_STUB 30 IRQ_STUB 31 IRQ_STUB 32 IRQ_STUB 33 IRQ_STUB 34 IRQ_STUB 35 IRQ_STUB 36 IRQ_STUB 37 IRQ_STUB 38 IRQ_STUB 39 IRQ_STUB 40 IRQ_STUB 41 IRQ_STUB 42 IRQ_STUB 43 IRQ_STUB 44 IRQ_STUB 45 IRQ_STUB 46 IRQ_STUB 47 ; Spurious interrupt handler (vector 0xFF) - do nothing, no EOI global IrqStubSpurious IrqStubSpurious: iretq ; ==================================================================== ; Export the stub table for C++ to reference ; ==================================================================== section .data global IrqStubTable IrqStubTable: dq IrqStub0 dq IrqStub1 dq IrqStub2 dq IrqStub3 dq IrqStub4 dq IrqStub5 dq IrqStub6 dq IrqStub7 dq IrqStub8 dq IrqStub9 dq IrqStub10 dq IrqStub11 dq IrqStub12 dq IrqStub13 dq IrqStub14 dq IrqStub15 dq IrqStub16 dq IrqStub17 dq IrqStub18 dq IrqStub19 dq IrqStub20 dq IrqStub21 dq IrqStub22 dq IrqStub23 dq IrqStub24 dq IrqStub25 dq IrqStub26 dq IrqStub27 dq IrqStub28 dq IrqStub29 dq IrqStub30 dq IrqStub31 dq IrqStub32 dq IrqStub33 dq IrqStub34 dq IrqStub35 dq IrqStub36 dq IrqStub37 dq IrqStub38 dq IrqStub39 dq IrqStub40 dq IrqStub41 dq IrqStub42 dq IrqStub43 dq IrqStub44 dq IrqStub45 dq IrqStub46 dq IrqStub47