2 * FILE: hal/halx86/generic/irq.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: Software, System and Hardware IRQ Management
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
8 /* INCLUDES ******************************************************************/
10 /* Enable this (and the define in spinlock.c) to make UP HAL work for MP Kernel */
11 /* #define CONFIG_SMP */
14 #include <internal/i386/asmmacro.S>
15 .intel_syntax noprefix
17 /* GLOBALS *******************************************************************/
22 .short 0x20 /* Port */
23 .byte 0x11 /* Edge, cascade, CAI 8, ICW4 */
24 .byte PRIMARY_VECTOR_BASE /* Base */
25 .byte 4 /* IRQ 4 connected to slave */
26 .byte 1 /* Non buffered, not nested, 8086 */
29 .short 0xA0 /* Port */
30 .byte 0x11 /* Edge, cascade, CAI 8, ICW4 */
31 .byte PRIMARY_VECTOR_BASE + 8 /* Base */
32 .byte 2 /* Slave ID: Slave 2 */
33 .byte 1 /* Non buffered, not nested, 8086 */
35 /* End of initialization table */
43 .long 0xFF800000 /* IRQL 4 */
44 .long 0xFFC00000 /* IRQL 5 */
45 .long 0xFFE00000 /* IRQL 6 */
46 .long 0xFFF00000 /* IRQL 7 */
47 .long 0xFFF80000 /* IRQL 8 */
48 .long 0xFFFC0000 /* IRQL 9 */
49 .long 0xFFFE0000 /* IRQL 10 */
50 .long 0xFFFF0000 /* IRQL 11 */
51 .long 0xFFFF8000 /* IRQL 12 */
52 .long 0xFFFFC000 /* IRQL 13 */
53 .long 0xFFFFE000 /* IRQL 14 */
54 .long 0xFFFFF000 /* IRQL 15 */
55 .long 0xFFFFF800 /* IRQL 16 */
56 .long 0xFFFFFC00 /* IRQL 17 */
57 .long 0xFFFFFE00 /* IRQL 18 */
58 .long 0xFFFFFE00 /* IRQL 19 */
59 .long 0xFFFFFE80 /* IRQL 20 */
60 .long 0xFFFFFEC0 /* IRQL 21 */
61 .long 0xFFFFFEE0 /* IRQL 22 */
62 .long 0xFFFFFEF0 /* IRQL 23 */
63 .long 0xFFFFFEF8 /* IRQL 24 */
64 .long 0xFFFFFEF8 /* IRQL 25 */
65 .long 0xFFFFFEFA /* IRQL 26 */
66 .long 0xFFFFFFFA /* IRQL 27 */
67 .long 0xFFFFFFFB /* IRQL 28 */
68 .long 0xFFFFFFFB /* IRQL 29 */
69 .long 0xFFFFFFFB /* IRQL 30 */
70 .long 0xFFFFFFFB /* IRQL 31 */
73 .long 0xFFFFFFFE /* IRQL 0 */
74 .long 0xFFFFFFFC /* IRQL 1 */
75 .long 0xFFFFFFF8 /* IRQL 2 */
76 .long 0xFFFFFFF0 /* IRQL 3 */
77 .long 0x7FFFFF0 /* IRQL 4 */
78 .long 0x3FFFFF0 /* IRQL 5 */
79 .long 0x1FFFFF0 /* IRQL 6 */
80 .long 0x0FFFFF0 /* IRQL 7 */
81 .long 0x7FFFF0 /* IRQL 8 */
82 .long 0x3FFFF0 /* IRQL 9 */
83 .long 0x1FFFF0 /* IRQL 10 */
84 .long 0x0FFFF0 /* IRQL 11 */
85 .long 0x7FFF0 /* IRQL 12 */
86 .long 0x3FFF0 /* IRQL 13 */
87 .long 0x1FFF0 /* IRQL 14 */
88 .long 0x0FFF0 /* IRQL 15 */
89 .long 0x7FF0 /* IRQL 16 */
90 .long 0x3FF0 /* IRQL 17 */
91 .long 0x1FF0 /* IRQL 18 */
92 .long 0x1FF0 /* IRQL 19 */
93 .long 0x17F0 /* IRQL 20 */
94 .long 0x13F0 /* IRQL 21 */
95 .long 0x11F0 /* IRQL 22 */
96 .long 0x10F0 /* IRQL 23 */
97 .long 0x1070 /* IRQL 24 */
98 .long 0x1030 /* IRQL 25 */
99 .long 0x1010 /* IRQL 26 */
100 .long 0x10 /* IRQL 27 */
101 .long 0 /* IRQL 28 */
102 .long 0 /* IRQL 29 */
103 .long 0 /* IRQL 30 */
104 .long 0 /* IRQL 31 */
106 HalpSpecialDismissTable:
108 .long GenericIRQ /* IRQ 0-7 */
110 .long IRQ7 /* IRQ 7 */
112 .long GenericIRQ /* IRQ 8-12 */
114 .long IRQ13 /* IRQ 13 */
115 .long GenericIRQ /* IRQ 14 */
116 .long IRQ15 /* IRQ 15 */
118 .long GenericIRQ /* IRQ 16-35 */
122 .long InvalidIRQ /* IRQ 36-207 */
126 HalpSpecialDismissLevelTable:
128 .long GenericIRQLevel /* IRQ 0-7 */
130 .long IRQ7Level /* IRQ 7 */
132 .long GenericIRQLevel /* IRQ 8-12 */
134 .long IRQ13Level /* IRQ 13 */
135 .long GenericIRQLevel /* IRQ 14 */
136 .long IRQ15Level /* IRQ 15 */
138 SWInterruptLookUpTable:
139 .byte PASSIVE_LEVEL /* IRR 0 */
140 .byte PASSIVE_LEVEL /* IRR 1 */
141 .byte APC_LEVEL /* IRR 2 */
142 .byte APC_LEVEL /* IRR 3 */
143 .byte DISPATCH_LEVEL /* IRR 4 */
144 .byte DISPATCH_LEVEL /* IRR 5 */
145 .byte DISPATCH_LEVEL /* IRR 6 */
146 .byte DISPATCH_LEVEL /* IRR 7 */
148 SWInterruptHandlerTable:
149 .long _KiUnexpectedInterrupt /* PASSIVE_LEVEL */
150 .long _HalpApcInterrupt /* APC_LEVEL */
151 .long _HalpDispatchInterrupt /* DISPATCH_LEVEL */
153 SWInterruptHandlerTable2:
154 .long _KiUnexpectedInterrupt /* PASSIVE_LEVEL */
155 .long _HalpApcInterrupt2ndEntry /* APC_LEVEL */
156 .long _HalpDispatchInterrupt2ndEntry /* DISPATCH_LEVEL */
159 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
161 /* FUNCTIONS *****************************************************************/
163 /* HAL interrupt handlers */
164 GENERATE_HAL_INT_HANDLERS
166 .globl _HalpHardwareInterruptLevel
167 .func HalpHardwareInterruptLevel
168 _HalpHardwareInterruptLevel:
170 /* Get IRQL and check for pending interrupts */
171 mov eax, PCR[KPCR_IRQL]
172 mov ecx, PCR[KPCR_IRR]
173 and ecx, FindHigherIrqlMask[eax*4]
176 /* Check the active IRR */
177 test dword ptr PCR[KPCR_IRR_ACTIVE], 0xFFFFFFF0
180 /* Check for pending software interrupts */
187 xor PCR[KPCR_IRR], eax
189 /* Now dispatch the interrupt */
190 call SWInterruptHandlerTable[ecx*4]
196 .globl _HalpInitPICs@0
200 /* Save ESI and disable interrupts */
205 /* Read the init table */
206 lea esi, PICInitTable
211 /* Put the port in EDX */
214 /* Initialize the PIC, using a delay for each command */
225 /* Mask all interrupts */
229 /* Check if we're done, otherwise initialize next PIC */
234 /* Read EISA Edge/Level Register */
241 /* Clear reserved bits and see if there's anything there */
249 /* Restore interrupts and return */
256 .globl @HalClearSoftwareInterrupt@4
257 .func @HalClearSoftwareInterrupt@4, @HalClearSoftwareInterrupt@4
258 @HalClearSoftwareInterrupt@4:
266 and PCR[KPCR_IRR], eax
270 .globl @HalRequestSoftwareInterrupt@4
271 .func @HalRequestSoftwareInterrupt@4, @HalRequestSoftwareInterrupt@4
272 @HalRequestSoftwareInterrupt@4:
278 /* Disable interrupts */
282 /* Set IRR and get IRQL */
283 or PCR[KPCR_IRR], eax
284 mov ecx, PCR[KPCR_IRQL]
286 /* Get software IRR mask */
287 mov eax, PCR[KPCR_IRR]
290 /* Get highest pending software interrupt and check if it's higher */
292 mov dl, SWInterruptLookUpTable[eax]
296 /* Call the pending interrupt */
297 call SWInterruptHandlerTable[edx*4]
301 /* Retore interrupts and return */
306 .globl _HalDisableSystemInterrupt@8
307 .func HalDisableSystemInterrupt@8
308 _HalDisableSystemInterrupt@8:
310 /* Convert to vector */
311 movzx ecx, byte ptr [esp+4]
312 sub ecx, PRIMARY_VECTOR_BASE
314 /* Disable interrupts and set the new IDR */
318 or PCR[KPCR_IDR], edx
320 /* Get the current mask */
326 /* Mask off the interrupt and write the new mask */
332 /* Return with interrupts enabled */
338 .globl _HalEnableSystemInterrupt@12
339 .func HalEnableSystemInterrupt@12
340 _HalEnableSystemInterrupt@12:
342 /* Get the vector and validate it */
343 movzx ecx, byte ptr [esp+4]
344 sub ecx, PRIMARY_VECTOR_BASE
346 cmp ecx, CLOCK2_LEVEL
350 /* Is PCI IRQ Routing enabled? */
351 cmp byte ptr _HalpIrqMiniportInitialized, 0
358 /* Check if this is an EISA IRQ */
359 bt _HalpEisaIrqIgnore, ecx
362 /* Clear the EISA Edge/Level Control Register */
363 btr _HalpEisaELCR, ecx
365 /* Get the interrupt type */
370 /* Check the register again */
371 bt _HalpEisaELCR, ecx
374 /* Check if the miniport is active */
375 cmp byte ptr _HalpIrqMiniportInitialized, 0
378 /* Update the EISA Edge/Level Control Register */
379 bts _HalpEisaELCR, ecx
382 /* Use the level hardware interrupt handler */
383 mov dword ptr SWInterruptHandlerTableHardware[ecx*4], offset _HalpHardwareInterruptLevel
384 mov edx, HalpSpecialDismissLevelTable[ecx*4]
385 mov HalpSpecialDismissTable[ecx*4], edx
388 /* Is PCI IRQ Routing enabled? */
389 cmp byte ptr _HalpIrqMiniportInitialized, 0
396 /* Calculate the new IDR */
401 and PCR[KPCR_IDR], eax
403 /* Get the current IRQL and mask the IRQs in the PIC */
404 mov eax, PCR[KPCR_IRQL]
405 mov eax, KiI8259MaskTable[eax*4]
406 or eax, PCR[KPCR_IDR]
411 /* Enable interrupts and return TRUE */
418 /* Fail, invalid IRQ */
426 .globl _HalBeginSystemInterrupt@12
427 .func HalBeginSystemInterrupt@12
428 _HalBeginSystemInterrupt@12:
430 /* Convert to IRQ and call the handler */
432 mov cl, byte ptr [esp+8]
433 sub ecx, PRIMARY_VECTOR_BASE
434 jmp HalpSpecialDismissTable[ecx*4]
437 /* This is IRQ 15, check if it's spurious */
445 /* Cascaded interrupt... dismiss it and return FALSE */
453 /* This is IRQ 7, check if it's spurious */
461 /* It is, return FALSE */
466 /* AT 80287 latch clear */
471 /* Get current and new IRQL */
473 mov al, byte ptr [esp+4]
474 mov ebx, PCR[KPCR_IRQL]
476 /* Set and save old */
477 mov PCR[KPCR_IRQL], eax
481 /* Set IRQ mask in the PIC */
482 mov eax, KiI8259MaskTable[eax*4]
483 or eax, PCR[KPCR_IDR]
488 /* Check to which PIC the EOI was sent */
493 /* Write mask to master PIC */
497 /* Enable interrupts and return TRUE */
503 /* Write mask to slave PIC */
509 /* Enable interrupts and return TRUE */
523 /* This is IRQ 15, check if it's spurious */
530 jmp CascadedInterrupt
533 /* This is IRQ 7, check if it's spurious */
541 /* It is, return FALSE */
547 /* AT 80287 latch clear */
556 /* Set IRQ mask in the PIC */
557 mov eax, KiI8259MaskTable[eax*4]
558 or eax, PCR[KPCR_IDR]
563 /* Compute new IRR */
568 or PCR[KPCR_IRR], ebx
572 mov bl, PCR[KPCR_IRQL]
575 /* Check to which PIC the EOI was sent */
579 /* Write mask to master PIC */
583 /* Check for spurious */
585 jbe SpuriousInterrupt
587 /* Write IRQL values */
589 mov PCR[KPCR_IRQL], ecx
592 /* Enable interrupts and return TRUE */
598 /* Write mask to slave and master PIC */
604 /* Was this a lower interrupt? */
606 jbe SpuriousInterrupt
608 /* Write IRQL values */
610 mov PCR[KPCR_IRQL], ecx
613 /* Enable interrupts and return TRUE */
618 .globl _HalEndSystemInterrupt@8
619 .func HalEndSystemInterrupt@8
620 _HalEndSystemInterrupt@8:
626 /* Check if it's a software interrupt */
627 cmp dword ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
630 /* Hardware interrupt, mask the appropriate IRQs in the PIC */
631 mov eax, KiI8259MaskTable[ecx*4]
632 or eax, PCR[KPCR_IDR]
639 /* Set IRQL and check if there are pending software interrupts */
640 mov PCR[KPCR_IRQL], ecx
641 mov eax, PCR[KPCR_IRR]
642 mov al, SWInterruptLookUpTable[eax]
649 /* There are pending software interrupts, call their handlers */
651 jmp SWInterruptHandlerTable2[eax*4]
654 .globl @KfLowerIrql@4
664 cmp cl, PCR[KPCR_IRQL]
668 /* Save flags since we'll disable interrupts */
672 /* Disable interrupts and check if IRQL is below DISPATCH_LEVEL */
673 cmp dword ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
676 /* Clear interrupt masks since there's a pending hardware interrupt */
677 mov eax, KiI8259MaskTable[ecx*4]
678 or eax, PCR[KPCR_IDR]
685 /* Set the new IRQL and check if there's a pending software interrupt */
686 mov PCR[KPCR_IRQL], ecx
687 mov eax, PCR[KPCR_IRR]
688 mov al, SWInterruptLookUpTable[eax]
692 /* Restore interrupts and return */
699 mov eax, PCR[KPCR_IRQL]
700 mov dword ptr PCR[KPCR_IRQL], HIGH_LEVEL
702 /* Bugcheck the system */
707 push IRQL_NOT_LESS_OR_EQUAL
708 call _KeBugCheckEx@20
712 /* There is, call it */
713 call SWInterruptHandlerTable[eax*4]
715 /* Restore interrupts and return */
720 .globl @KfRaiseIrql@4
727 mov eax, PCR[KPCR_IRQL]
735 /* Check if it's in the software level */
736 cmp cl, DISPATCH_LEVEL
739 /* Save the current IRQL */
742 /* It's a hardware IRQL, so disable interrupts */
746 /* Set the new IRQL */
747 mov PCR[KPCR_IRQL], ecx
749 /* Mask the interrupts in the PIC */
750 mov eax, KiI8259MaskTable[ecx*4]
751 or eax, PCR[KPCR_IDR]
756 /* Restore interrupts and return old IRQL */
762 /* Set the IRQL and return */
763 mov PCR[KPCR_IRQL], ecx
769 mov dword ptr PCR[KPCR_IRQL], PASSIVE_LEVEL
771 /* Bugcheck the system */
776 push IRQL_NOT_GREATER_OR_EQUAL
777 call _KeBugCheckEx@20
781 .globl _KeGetCurrentIrql@0
782 .func KeGetCurrentIrql@0
785 /* Return the IRQL */
786 mov eax, PCR[KPCR_IRQL]
790 .globl _KeRaiseIrqlToDpcLevel@0
791 .func KeRaiseIrqlToDpcLevel@0
792 _KeRaiseIrqlToDpcLevel@0:
794 /* Get the current IRQL */
795 mov eax, PCR[KPCR_IRQL]
797 /* Set DISPATCH_LEVEL */
798 mov dword ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
801 /* Make sure we were not higher then synch */
802 cmp eax, DISPATCH_LEVEL
809 /* Bugcheck the system */
814 push IRQL_NOT_GREATER_OR_EQUAL
815 call _KeBugCheckEx@20
819 .globl _KeRaiseIrqlToSynchLevel@0
820 .func KeRaiseIrqlToSynchLevel@0
821 _KeRaiseIrqlToSynchLevel@0:
823 /* Get the current IRQL */
824 mov eax, PCR[KPCR_IRQL]
826 /* Set SYNCH_LEVEL */
827 mov dword ptr PCR[KPCR_IRQL], SYNCH_LEVEL
830 /* Make sure we were not higher then dispatch */
838 /* Bugcheck the system */
843 push IRQL_NOT_GREATER_OR_EQUAL
844 call _KeBugCheckEx@20
848 .globl _HalpApcInterrupt
849 .func HalpApcInterrupt
850 TRAP_FIXUPS hapc_a, hapc_t, DoFixupV86, DoFixupAbios
853 /* Create fake interrupt stack */
859 /* Enter interrupt */
860 INT_PROLOG hapc_a, hapc_t, DoPushFakeErrorCode
863 .globl _HalpApcInterrupt2ndEntry
864 .func HalpApcInterrupt2ndEntry
865 _HalpApcInterrupt2ndEntry:
867 /* Save current IRQL and set to APC level */
869 mov dword ptr PCR[KPCR_IRQL], APC_LEVEL
870 and dword ptr PCR[KPCR_IRR], ~(1 << APC_LEVEL)
872 /* Enable interrupts and check if we came from User/V86 mode */
874 mov eax, [ebp+KTRAP_FRAME_CS]
876 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
879 /* Set user mode delivery */
884 /* Deliver the APCs */
888 call _KiDeliverApc@12
890 /* Disable interrupts and end it */
892 call _HalpEndSoftwareInterrupt@4
893 jmp _Kei386EoiHelper@0
896 .globl _HalpDispatchInterrupt
897 .func HalpDispatchInterrupt
898 TRAP_FIXUPS hdpc_a, hdpc_t, DoFixupV86, DoFixupAbios
899 _HalpDispatchInterrupt:
901 /* Create fake interrupt stack */
907 /* Enter interrupt */
908 INT_PROLOG hdpc_a, hdpc_t, DoPushFakeErrorCode
911 .globl _HalpDispatchInterrupt2ndEntry
912 .func HalpDispatchInterrupt2ndEntry
913 _HalpDispatchInterrupt2ndEntry:
915 /* Save current IRQL and set to DPC level */
917 mov dword ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
918 and dword ptr PCR[KPCR_IRR], ~(1 << DISPATCH_LEVEL)
920 /* Enable interrupts and let the kernel handle this */
922 call _KiDispatchInterrupt@0
924 /* Disable interrupts and end it */
926 call _HalpEndSoftwareInterrupt@4
927 jmp _Kei386EoiHelper@0
930 .globl _HalpEndSoftwareInterrupt@4
931 .func HalpEndSoftwareInterrupt@4
932 _HalpEndSoftwareInterrupt@4:
934 /* Get the IRQL and check if we're in the software region */
935 movzx ecx, byte ptr [esp+4]
936 cmp dword ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
939 /* Set the right mask in the PIC for the hardware IRQ */
940 mov eax, KiI8259MaskTable[ecx*4]
941 or eax, PCR[KPCR_IDR]
947 /* Check if there are pending software interrupts */
948 mov PCR[KPCR_IRQL], ecx
949 mov eax, PCR[KPCR_IRR]
950 mov al, SWInterruptLookUpTable[eax]
956 /* There are pending softwate interrupts, call their handlers */
958 jmp SWInterruptHandlerTable2[eax*4]