1 TITLE CpuInterrupt.asm:
2 ;------------------------------------------------------------------------------
4 ;* Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
5 ;* This program and the accompanying materials
6 ;* are licensed and made available under the terms and conditions of the BSD License
7 ;* which accompanies this distribution. The full text of the license may be found at
8 ;* http://opensource.org/licenses/bsd-license.php
10 ;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 ;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 ;------------------------------------------------------------------------------
19 EXTERNDEF mExceptionCodeSize:DWORD
23 EXTERN TimerHandler: FAR
24 EXTERN ExceptionHandler: NEAR
25 EXTERN mTimerVector: QWORD
27 mExceptionCodeSize DD 9
30 lea rax, [GDT_BASE] ; RAX=PHYSICAL address of gdt
31 mov qword ptr [gdtr + 2], rax ; Put address of gdt into the gdtr
36 lea rax, [IDT_BASE] ; RAX=PHYSICAL address of idt
37 mov qword ptr [idtr + 2], rax ; Put address of idt into the idtr
43 ; InstallInterruptHandler (
44 ; UINTN Vector, // rcx
45 ; void (*Handler)(void) // rdx
47 InstallInterruptHandler PROC
50 cli ; turn off interrupts
51 sub rsp, 10h ; open some space on the stack
53 sidt [rbx] ; get fword address of IDT
54 mov rbx, [rbx+2] ; move offset of IDT into RBX
55 add rsp, 10h ; correct stack
56 mov rax, rcx ; Get vector number
57 shl rax, 4 ; multiply by 16 to get offset
58 add rbx, rax ; add to IDT base to get entry
59 mov rax, rdx ; load new address into IDT entry
60 mov word ptr [rbx], ax ; write bits 15..0 of offset
61 shr rax, 16 ; use ax to copy 31..16 to descriptors
62 mov word ptr [rbx+6], ax ; write bits 31..16 of offset
63 shr rax, 16 ; use eax to copy 63..32 to descriptors
64 mov dword ptr [rbx+8], eax ; write bits 63..32 of offset
65 popfq ; restore flags (possible enabling interrupts)
69 InstallInterruptHandler ENDP
71 JmpCommonIdtEntry macro
72 ; jmp commonIdtEntry - this must be hand coded to keep the assembler from
73 ; using a 8 bit reletive jump when the entries are
74 ; within 255 bytes of the common entry. This must
75 ; be done to maintain the consistency of the size
77 db 0e9h ; jmp 16 bit reletive
78 dd commonIdtEntry - $ - 4 ; offset to jump to
82 SystemExceptionHandler PROC
84 push 0h ; push error code place holder on the stack
87 ; db 0e9h ; jmp 16 bit reletive
88 ; dd commonIdtEntry - $ - 4 ; offset to jump to
91 push 0h ; push error code place holder on the stack
96 push 0h ; push error code place holder on the stack
101 push 0h ; push error code place holder on the stack
106 push 0h ; push error code place holder on the stack
111 push 0h ; push error code place holder on the stack
116 push 0h ; push error code place holder on the stack
121 push 0h ; push error code place holder on the stack
126 ; Double fault causes an error code to be pushed so no phony push necessary
133 push 0h ; push error code place holder on the stack
138 ; Invalid TSS causes an error code to be pushed so no phony push necessary
145 ; Segment Not Present causes an error code to be pushed so no phony push necessary
152 ; Stack fault causes an error code to be pushed so no phony push necessary
159 ; GP fault causes an error code to be pushed so no phony push necessary
166 ; Page fault causes an error code to be pushed so no phony push necessary
173 push 0h ; push error code place holder on the stack
178 push 0h ; push error code place holder on the stack
183 ; Alignment check causes an error code to be pushed so no phony push necessary
190 push 0h ; push error code place holder on the stack
195 push 0h ; push error code place holder on the stack
201 push 0h ; push error code place holder on the stack
202 ; push xxh ; push vector number
204 db ( $ - INTUnknown - 3 ) / 9 + 20 ; vector number
207 SystemExceptionHandler ENDP
209 SystemTimerHandler PROC
213 SystemTimerHandler ENDP
216 ; +---------------------+ <-- 16-byte aligned ensured by processor
218 ; +---------------------+
220 ; +---------------------+
222 ; +---------------------+
224 ; +---------------------+
226 ; +---------------------+
228 ; +---------------------+
230 ; +---------------------+
232 ; +---------------------+ <-- RBP, 16-byte aligned
239 ; Since here the stack pointer is 16-byte aligned, so
240 ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
244 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
245 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
258 push qword ptr [rbp + 6 * 8] ; RSP
259 push qword ptr [rbp] ; RBP
263 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
264 movzx rax, word ptr [rbp + 7 * 8]
266 movzx rax, word ptr [rbp + 4 * 8]
278 push qword ptr [rbp + 3 * 8]
280 ;; UINT64 Gdtr[2], Idtr[2];
294 push qword ptr [rbp + 5 * 8]
296 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
312 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
315 ;; clear Dr7 while executing debugger itself
321 ;; insure all status bits in dr6 are clear...
334 ;; FX_SAVE_STATE_X64 FxSaveState;
338 db 0fh, 0aeh, 00000111y ;fxsave [rdi]
340 ;; UINT32 ExceptionData;
341 push qword ptr [rbp + 2 * 8]
343 ;; call into exception handler
344 ;; Prepare parameter and call
345 mov rcx, qword ptr [rbp + 1 * 8]
348 ; Per X64 calling convention, allocate maximum parameter stack space
349 ; and make sure RSP is 16-byte aligned
357 call ExceptionHandler
362 ;; UINT64 ExceptionData;
365 ;; FX_SAVE_STATE_X64 FxSaveState;
368 db 0fh, 0aeh, 00001110y ; fxrstor [rsi]
371 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
380 ;; skip restore of dr6. We cleared dr6 during the context save.
385 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
388 add rsp, 8 ; not for Cr1
399 pop qword ptr [rbp + 5 * 8]
402 ;; UINT64 Gdtr[2], Idtr[2];
403 ;; Best not let anyone mess with these particular registers...
407 pop qword ptr [rbp + 3 * 8]
409 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
411 ; mov gs, rax ; not for gs
413 ; mov fs, rax ; not for fs
414 ; (X64 will not use fs and gs, so we do not restore it)
419 pop qword ptr [rbp + 4 * 8] ; for cs
420 pop qword ptr [rbp + 7 * 8] ; for ss
422 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
423 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
426 add rsp, 8 ; not for rbp
427 pop qword ptr [rbp + 6 * 8] ; for rsp
446 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
448 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
451 gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit
452 dq 0 ; (GDT base gets set above)
453 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
454 ; global descriptor table (GDT)
455 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
457 align 010h ; make GDT 16-byte align
462 NULL_SEL equ $-GDT_BASE ; Selector [0x0]
467 db 0 ; limit 19:16, flags
470 ; linear data segment descriptor
471 LINEAR_SEL equ $-GDT_BASE ; Selector [0x8]
472 dw 0FFFFh ; limit 0xFFFFF
475 db 092h ; present, ring 0, data, expand-up, writable
476 db 0CFh ; page-granular, 32-bit
479 ; linear code segment descriptor
480 LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10]
481 dw 0FFFFh ; limit 0xFFFFF
484 db 09Ah ; present, ring 0, code, expand-up, writable
485 db 0CFh ; page-granular, 32-bit
488 ; system data segment descriptor
489 SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18]
490 dw 0FFFFh ; limit 0xFFFFF
493 db 092h ; present, ring 0, data, expand-up, writable
494 db 0CFh ; page-granular, 32-bit
497 ; system code segment descriptor
498 SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20]
499 dw 0FFFFh ; limit 0xFFFFF
502 db 09Ah ; present, ring 0, code, expand-up, writable
503 db 0CFh ; page-granular, 32-bit
506 ; spare segment descriptor
507 SPARE3_SEL equ $-GDT_BASE ; Selector [0x28]
515 ; system data segment descriptor
516 SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30]
517 dw 0FFFFh ; limit 0xFFFFF
520 db 092h ; present, ring 0, data, expand-up, writable
521 db 0CFh ; page-granular, 32-bit
524 ; system code segment descriptor
525 SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38]
526 dw 0FFFFh ; limit 0xFFFFF
529 db 09Ah ; present, ring 0, code, expand-up, writable
530 db 0AFh ; page-granular, 64-bit
533 ; spare segment descriptor
534 SPARE4_SEL equ $-GDT_BASE ; Selector [0x40]
544 idtr dw IDT_END - IDT_BASE - 1 ; IDT limit
545 dq 0 ; (IDT base gets set above)
547 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
548 ; interrupt descriptor table (IDT)
550 ; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ
551 ; mappings. This implementation only uses the system timer and all other
552 ; IRQs will remain masked. The descriptors for vectors 33+ are provided
554 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
556 align 08h ; make IDT 8-byte align
560 ; divide by zero (INT 0)
561 DIV_ZERO_SEL equ $-IDT_BASE
563 dw SYS_CODE64_SEL ; selector 15:0
564 db 0 ; 0 for interrupt gate
565 db 0eh OR 80h ; type = 386 interrupt gate, present
568 dd 0 ; 0 for reserved
570 ; debug exception (INT 1)
571 DEBUG_EXCEPT_SEL equ $-IDT_BASE
573 dw SYS_CODE64_SEL ; selector 15:0
574 db 0 ; 0 for interrupt gate
575 db 0eh OR 80h ; type = 386 interrupt gate, present
578 dd 0 ; 0 for reserved
581 NMI_SEL equ $-IDT_BASE
583 dw SYS_CODE64_SEL ; selector 15:0
584 db 0 ; 0 for interrupt gate
585 db 0eh OR 80h ; type = 386 interrupt gate, present
588 dd 0 ; 0 for reserved
590 ; soft breakpoint (INT 3)
591 BREAKPOINT_SEL equ $-IDT_BASE
593 dw SYS_CODE64_SEL ; selector 15:0
594 db 0 ; 0 for interrupt gate
595 db 0eh OR 80h ; type = 386 interrupt gate, present
598 dd 0 ; 0 for reserved
601 OVERFLOW_SEL equ $-IDT_BASE
603 dw SYS_CODE64_SEL ; selector 15:0
604 db 0 ; 0 for interrupt gate
605 db 0eh OR 80h ; type = 386 interrupt gate, present
608 dd 0 ; 0 for reserved
610 ; bounds check (INT 5)
611 BOUNDS_CHECK_SEL equ $-IDT_BASE
613 dw SYS_CODE64_SEL ; selector 15:0
614 db 0 ; 0 for interrupt gate
615 db 0eh OR 80h ; type = 386 interrupt gate, present
618 dd 0 ; 0 for reserved
620 ; invalid opcode (INT 6)
621 INVALID_OPCODE_SEL equ $-IDT_BASE
623 dw SYS_CODE64_SEL ; selector 15:0
624 db 0 ; 0 for interrupt gate
625 db 0eh OR 80h ; type = 386 interrupt gate, present
628 dd 0 ; 0 for reserved
630 ; device not available (INT 7)
631 DEV_NOT_AVAIL_SEL equ $-IDT_BASE
633 dw SYS_CODE64_SEL ; selector 15:0
634 db 0 ; 0 for interrupt gate
635 db 0eh OR 80h ; type = 386 interrupt gate, present
638 dd 0 ; 0 for reserved
640 ; double fault (INT 8)
641 DOUBLE_FAULT_SEL equ $-IDT_BASE
643 dw SYS_CODE64_SEL ; selector 15:0
644 db 0 ; 0 for interrupt gate
645 db 0eh OR 80h ; type = 386 interrupt gate, present
648 dd 0 ; 0 for reserved
650 ; Coprocessor segment overrun - reserved (INT 9)
651 RSVD_INTR_SEL1 equ $-IDT_BASE
653 dw SYS_CODE64_SEL ; selector 15:0
654 db 0 ; 0 for interrupt gate
655 db 0eh OR 80h ; type = 386 interrupt gate, present
658 dd 0 ; 0 for reserved
660 ; invalid TSS (INT 0ah)
661 INVALID_TSS_SEL equ $-IDT_BASE
663 dw SYS_CODE64_SEL ; selector 15:0
664 db 0 ; 0 for interrupt gate
665 db 0eh OR 80h ; type = 386 interrupt gate, present
668 dd 0 ; 0 for reserved
670 ; segment not present (INT 0bh)
671 SEG_NOT_PRESENT_SEL equ $-IDT_BASE
673 dw SYS_CODE64_SEL ; selector 15:0
674 db 0 ; 0 for interrupt gate
675 db 0eh OR 80h ; type = 386 interrupt gate, present
678 dd 0 ; 0 for reserved
680 ; stack fault (INT 0ch)
681 STACK_FAULT_SEL equ $-IDT_BASE
683 dw SYS_CODE64_SEL ; selector 15:0
684 db 0 ; 0 for interrupt gate
685 db 0eh OR 80h ; type = 386 interrupt gate, present
688 dd 0 ; 0 for reserved
690 ; general protection (INT 0dh)
691 GP_FAULT_SEL equ $-IDT_BASE
693 dw SYS_CODE64_SEL ; selector 15:0
694 db 0 ; 0 for interrupt gate
695 db 0eh OR 80h ; type = 386 interrupt gate, present
698 dd 0 ; 0 for reserved
700 ; page fault (INT 0eh)
701 PAGE_FAULT_SEL equ $-IDT_BASE
703 dw SYS_CODE64_SEL ; selector 15:0
704 db 0 ; 0 for interrupt gate
705 db 0eh OR 80h ; type = 386 interrupt gate, present
708 dd 0 ; 0 for reserved
710 ; Intel reserved - do not use (INT 0fh)
711 RSVD_INTR_SEL2 equ $-IDT_BASE
713 dw SYS_CODE64_SEL ; selector 15:0
714 db 0 ; 0 for interrupt gate
715 db 0eh OR 80h ; type = 386 interrupt gate, present
718 dd 0 ; 0 for reserved
720 ; floating point error (INT 10h)
721 FLT_POINT_ERR_SEL equ $-IDT_BASE
723 dw SYS_CODE64_SEL ; selector 15:0
724 db 0 ; 0 for interrupt gate
725 db 0eh OR 80h ; type = 386 interrupt gate, present
728 dd 0 ; 0 for reserved
730 ; alignment check (INT 11h)
731 ALIGNMENT_CHECK_SEL equ $-IDT_BASE
733 dw SYS_CODE64_SEL ; selector 15:0
734 db 0 ; 0 for interrupt gate
735 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
738 dd 0 ; 0 for reserved
740 ; machine check (INT 12h)
741 MACHINE_CHECK_SEL equ $-IDT_BASE
743 dw SYS_CODE64_SEL ; selector 15:0
744 db 0 ; 0 for interrupt gate
745 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
748 dd 0 ; 0 for reserved
750 ; SIMD floating-point exception (INT 13h)
751 SIMD_EXCEPTION_SEL equ $-IDT_BASE
753 dw SYS_CODE64_SEL ; selector 15:0
754 db 0 ; 0 for interrupt gate
755 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
758 dd 0 ; 0 for reserved
762 dw SYS_CODE64_SEL ; selector 15:0
763 db 0 ; 0 for interrupt gate
764 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
767 dd 0 ; 0 for reserved
770 ; 72 unspecified descriptors
773 ; IRQ 0 (System timer) - (INT 68h)
774 IRQ0_SEL equ $-IDT_BASE
776 dw SYS_CODE64_SEL ; selector 15:0
777 db 0 ; 0 for interrupt gate
778 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
781 dd 0 ; 0 for reserved
783 ; IRQ 1 (8042 Keyboard controller) - (INT 69h)
784 IRQ1_SEL equ $-IDT_BASE
786 dw SYS_CODE64_SEL ; selector 15:0
787 db 0 ; 0 for interrupt gate
788 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
791 dd 0 ; 0 for reserved
793 ; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah)
794 IRQ2_SEL equ $-IDT_BASE
796 dw SYS_CODE64_SEL ; selector 15:0
797 db 0 ; 0 for interrupt gate
798 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
801 dd 0 ; 0 for reserved
803 ; IRQ 3 (COM 2) - (INT 6bh)
804 IRQ3_SEL equ $-IDT_BASE
806 dw SYS_CODE64_SEL ; selector 15:0
807 db 0 ; 0 for interrupt gate
808 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
811 dd 0 ; 0 for reserved
813 ; IRQ 4 (COM 1) - (INT 6ch)
814 IRQ4_SEL equ $-IDT_BASE
816 dw SYS_CODE64_SEL ; selector 15:0
817 db 0 ; 0 for interrupt gate
818 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
821 dd 0 ; 0 for reserved
823 ; IRQ 5 (LPT 2) - (INT 6dh)
824 IRQ5_SEL equ $-IDT_BASE
826 dw SYS_CODE64_SEL ; selector 15:0
827 db 0 ; 0 for interrupt gate
828 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
831 dd 0 ; 0 for reserved
833 ; IRQ 6 (Floppy controller) - (INT 6eh)
834 IRQ6_SEL equ $-IDT_BASE
836 dw SYS_CODE64_SEL ; selector 15:0
837 db 0 ; 0 for interrupt gate
838 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
841 dd 0 ; 0 for reserved
843 ; IRQ 7 (LPT 1) - (INT 6fh)
844 IRQ7_SEL equ $-IDT_BASE
846 dw SYS_CODE64_SEL ; selector 15:0
847 db 0 ; 0 for interrupt gate
848 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
851 dd 0 ; 0 for reserved
853 ; IRQ 8 (RTC Alarm) - (INT 70h)
854 IRQ8_SEL equ $-IDT_BASE
856 dw SYS_CODE64_SEL ; selector 15:0
857 db 0 ; 0 for interrupt gate
858 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
861 dd 0 ; 0 for reserved
864 IRQ9_SEL equ $-IDT_BASE
866 dw SYS_CODE64_SEL ; selector 15:0
867 db 0 ; 0 for interrupt gate
868 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
871 dd 0 ; 0 for reserved
874 IRQ10_SEL equ $-IDT_BASE
876 dw SYS_CODE64_SEL ; selector 15:0
877 db 0 ; 0 for interrupt gate
878 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
881 dd 0 ; 0 for reserved
884 IRQ11_SEL equ $-IDT_BASE
886 dw SYS_CODE64_SEL ; selector 15:0
887 db 0 ; 0 for interrupt gate
888 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
891 dd 0 ; 0 for reserved
893 ; IRQ 12 (PS/2 mouse) - (INT 74h)
894 IRQ12_SEL equ $-IDT_BASE
896 dw SYS_CODE64_SEL ; selector 15:0
897 db 0 ; 0 for interrupt gate
898 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
901 dd 0 ; 0 for reserved
903 ; IRQ 13 (Floating point error) - (INT 75h)
904 IRQ13_SEL equ $-IDT_BASE
906 dw SYS_CODE64_SEL ; selector 15:0
907 db 0 ; 0 for interrupt gate
908 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
911 dd 0 ; 0 for reserved
913 ; IRQ 14 (Secondary IDE) - (INT 76h)
914 IRQ14_SEL equ $-IDT_BASE
916 dw SYS_CODE64_SEL ; selector 15:0
917 db 0 ; 0 for interrupt gate
918 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
921 dd 0 ; 0 for reserved
923 ; IRQ 15 (Primary IDE) - (INT 77h)
924 IRQ15_SEL equ $-IDT_BASE
926 dw SYS_CODE64_SEL ; selector 15:0
927 db 0 ; 0 for interrupt gate
928 db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present
931 dd 0 ; 0 for reserved