- Add inital support for PCI and ISA interrupts.
authorStefan Ginsberg <stefanginsberg@gmail.com>
Wed, 11 Nov 2009 22:29:16 +0000 (22:29 +0000)
committerStefan Ginsberg <stefanginsberg@gmail.com>
Wed, 11 Nov 2009 22:29:16 +0000 (22:29 +0000)
- Use different register allocation to be more efficient on certain systems.
- Add tables and initial code for Lazy IRQL support.

svn path=/trunk/; revision=44115

reactos/hal/halx86/generic/irq.S
reactos/ntoskrnl/include/internal/i386/asmmacro.S

index 7220499..ae78a4b 100644 (file)
@@ -69,25 +69,73 @@ KiI8259MaskTable:
     .long 0xFFFFFFFB                    /* IRQL 30 */
     .long 0xFFFFFFFB                    /* IRQL 31 */
 
-HalpSysIntHandler:
-.rept 7
+FindHigherIrqlMask:
+    .long 0xFFFFFFFE                    /* IRQL  0 */
+    .long 0xFFFFFFFC                    /* IRQL 1 */
+    .long 0xFFFFFFF8                    /* IRQL 2 */
+    .long 0xFFFFFFF0                    /* IRQL 3 */
+    .long 0x7FFFFF0                     /* IRQL 4 */
+    .long 0x3FFFFF0                     /* IRQL 5 */
+    .long 0x1FFFFF0                     /* IRQL 6 */
+    .long 0x0FFFFF0                     /* IRQL 7 */
+    .long 0x7FFFF0                      /* IRQL 8 */
+    .long 0x3FFFF0                      /* IRQL 9 */
+    .long 0x1FFFF0                      /* IRQL 10 */
+    .long 0x0FFFF0                      /* IRQL 11 */
+    .long 0x7FFF0                       /* IRQL 12 */
+    .long 0x3FFF0                       /* IRQL 13 */
+    .long 0x1FFF0                       /* IRQL 14 */
+    .long 0x0FFF0                       /* IRQL 15 */
+    .long 0x7FF0                        /* IRQL 16 */
+    .long 0x3FF0                        /* IRQL 17 */
+    .long 0x1FF0                        /* IRQL 18 */
+    .long 0x1FF0                        /* IRQL 19 */
+    .long 0x17F0                        /* IRQL 20 */
+    .long 0x13F0                        /* IRQL 21 */
+    .long 0x11F0                        /* IRQL 22 */
+    .long 0x10F0                        /* IRQL 23 */
+    .long 0x1070                        /* IRQL 24 */
+    .long 0x1030                        /* IRQL 25 */
+    .long 0x1010                        /* IRQL 26 */
+    .long 0x10                          /* IRQL 27 */
+    .long 0                             /* IRQL 28 */
+    .long 0                             /* IRQL 29 */
+    .long 0                             /* IRQL 30 */
+    .long 0                             /* IRQL 31 */
+
+HalpSpecialDismissTable:
+    .rept 7
     .long GenericIRQ                    /* IRQ 0-7 */
-.endr
+    .endr
     .long IRQ7                          /* IRQ 7 */
-.rept 7
-    .long GenericIRQ                    /* IRQ 8-15 */
-.endr
+    .rept 5
+    .long GenericIRQ                    /* IRQ 8-12 */
+    .endr
+    .long IRQ13                         /* IRQ 13 */
+    .long GenericIRQ                    /* IRQ 14 */
     .long IRQ15                         /* IRQ 15 */
-.rept 20
+    .rept 20
     .long GenericIRQ                    /* IRQ 16-35 */
-.endr
+    .endr
 #if DBG
 .rept 172
     .long InvalidIRQ                    /* IRQ 36-207 */
 .endr
 #endif
 
-SoftIntByteTable:
+HalpSpecialDismissLevelTable:
+    .rept 7
+    .long GenericIRQLevel               /* IRQ 0-7 */
+    .endr
+    .long IRQ7Level                     /* IRQ 7 */
+    .rept 5
+    .long GenericIRQLevel               /* IRQ 8-12 */
+    .endr
+    .long IRQ13Level                    /* IRQ 13 */
+    .long GenericIRQLevel               /* IRQ 14 */
+    .long IRQ15Level                    /* IRQ 15 */
+
+SWInterruptLookUpTable:
     .byte PASSIVE_LEVEL                 /* IRR 0 */
     .byte PASSIVE_LEVEL                 /* IRR 1 */
     .byte APC_LEVEL                     /* IRR 2 */
@@ -97,12 +145,12 @@ SoftIntByteTable:
     .byte DISPATCH_LEVEL                /* IRR 6 */
     .byte DISPATCH_LEVEL                /* IRR 7 */
 
-SoftIntHandlerTable:
+SWInterruptHandlerTable:
     .long _KiUnexpectedInterrupt        /* PASSIVE_LEVEL */
     .long _HalpApcInterrupt             /* APC_LEVEL */
     .long _HalpDispatchInterrupt        /* DISPATCH_LEVEL */
 
-SoftIntHandlerTable2:
+SWInterruptHandlerTable2:
     .long _KiUnexpectedInterrupt        /* PASSIVE_LEVEL */
     .long _HalpApcInterrupt2ndEntry     /* APC_LEVEL */
     .long _HalpDispatchInterrupt2ndEntry /* DISPATCH_LEVEL */
@@ -112,6 +160,39 @@ _UnhandledMsg:
 
 /* FUNCTIONS *****************************************************************/
 
+/* HAL interrupt handlers */
+GENERATE_HAL_INT_HANDLERS
+
+.globl _HalpHardwareInterruptLevel
+.func HalpHardwareInterruptLevel
+_HalpHardwareInterruptLevel:
+
+    /* Get IRQL and check for pending interrupts */
+    mov eax, PCR[KPCR_IRQL]
+    mov ecx, PCR[KPCR_IRR]
+    and ecx, FindHigherIrqlMask[eax*4]
+    jz NothingHardware
+
+    /* Check the active IRR */
+    test dword ptr PCR[KPCR_IRR_ACTIVE], 0xFFFFFFF0
+    jnz NothingHardware
+
+    /* Check for pending software interrupts */
+    mov eax, ecx
+    bsr ecx, eax
+    mov eax, 1
+    shl eax, cl
+
+    /* Clear IRR */
+    xor PCR[KPCR_IRR], eax
+
+    /* Now dispatch the interrupt */
+    call SWInterruptHandlerTable[ecx*4]
+
+NothingHardware:
+    ret
+.endfunc
+
 .globl _HalpInitPICs@0
 .func HalpInitPICs@0
 _HalpInitPICs@0:
@@ -150,7 +231,23 @@ InitLoop:
     cmp ax, 0
     jnz InitLoop
 
-    /* Restore interrupts and return */
+    /* Read EISA Edge/Level Register */
+    mov edx, 0x4D1
+    in al, dx
+    mov ah, al
+    dec edx
+    in al, dx
+
+    /* Clear reserved bits and see if there's anything there */
+    and eax, 0xDEF8
+    cmp eax, 0xDEF8
+    jz NoEisa
+
+    /* FIXME */
+    //UNHANDLED_PATH
+
+/* Restore interrupts and return */
+NoEisa:
     popf
     pop esi
     ret
@@ -192,12 +289,12 @@ InitLoop:
 
     /* Get highest pending software interrupt and check if it's higher */
     xor edx, edx
-    mov dl, SoftIntByteTable[eax]
+    mov dl, SWInterruptLookUpTable[eax]
     cmp dl, cl
     jbe AfterCall
 
     /* Call the pending interrupt */
-    call SoftIntHandlerTable[edx*4]
+    call SWInterruptHandlerTable[edx*4]
 
 AfterCall:
 
@@ -249,38 +346,53 @@ _HalEnableSystemInterrupt@12:
     cmp ecx, CLOCK2_LEVEL
     jnb Invalid
 
-    /* Get the current PCI Edge/Level control registers */
-    mov edx, 0x4D1
-    in al, dx
-    shl ax, 8
-    mov edx, 0x4D0
-    in al, dx
-    mov dx, 1
-    shl dx, cl
-    and dx, 0xDEF8
+#if 0
+    /* Is PCI IRQ Routing enabled? */
+    cmp byte ptr _HalpIrqMiniportInitialized, 0
+    jz NoMiniport
 
-    /* Check if this is a latched interrupt */
-    cmp dword ptr [esp+12], 0
+    /* UNHANDLED */
+    UNHANDLED_PATH
+
+NoMiniport:
+    /* Check if this is an EISA IRQ */
+    bt _HalpEisaIrqIgnore, ecx
+    jb IgnoredIrq
+
+    /* Clear the EISA Edge/Level Control Register */
+    btr _HalpEisaELCR, ecx
+
+    /* Get the interrupt type */
+    mov al, [esp+12]
+    cmp al, 0
     jnz Latched
 
-    /* Use OR for edge interrupt */
-    or ax, dx
-    jmp AfterMask
-Latched:
+    /* Check the register again */
+    bt _HalpEisaELCR, ecx
+    jb Dismiss
 
-    /* Mask it out for level interrupt */
-    not dx
-    and ax, dx
+    /* Check if the miniport is active */
+    cmp byte ptr _HalpIrqMiniportInitialized, 0
+    jz Dismiss
 
-AfterMask:
+    /* Update the EISA Edge/Level Control Register */
+    bts _HalpEisaELCR, ecx
 
-    /* Set the PCI Edge/Level control registers */
-    mov edx, 0x4D0
-    out dx, al
-    shr ax, 8
-    mov edx, 0x4D1
-    out dx, al
+Dismiss:
+    /* Use the level hardware interrupt handler */
+    mov dword ptr SWInterruptHandlerTableHardware[ecx*4], offset _HalpHardwareInterruptLevel
+    mov edx, HalpSpecialDismissLevelTable[ecx*4]
+    mov HalpSpecialDismissTable[ecx*4], edx
+
+Latched:
+    /* Is PCI IRQ Routing enabled? */
+    cmp byte ptr _HalpIrqMiniportInitialized, 0
+    jz IgnoredIrq
 
+    /* UNHANDLED */
+    UNHANDLED_PATH
+#endif
+IgnoredIrq:
     /* Calculate the new IDR */
     mov eax, 1
     shl eax, cl
@@ -316,9 +428,10 @@ Invalid:
 _HalBeginSystemInterrupt@12:
 
     /* Convert to IRQ and call the handler */
-    movzx ebx, byte ptr [esp+8]
-    sub ebx, PRIMARY_VECTOR_BASE
-    jmp HalpSysIntHandler[ebx*4]
+    xor ecx, ecx
+    mov cl, byte ptr [esp+8]
+    sub ecx, PRIMARY_VECTOR_BASE
+    jmp HalpSpecialDismissTable[ecx*4]
 
 IRQ15:
     /* This is IRQ 15, check if it's spurious */
@@ -330,6 +443,7 @@ IRQ15:
     jnz GenericIRQ
 
     /* Cascaded interrupt... dismiss it and return FALSE */
+CascadedInterrupt:
     mov al, 0x62
     out 0x20, al
     mov eax, 0
@@ -348,15 +462,21 @@ IRQ7:
     mov eax, 0
     ret 12
 
+IRQ13:
+    /* AT 80287 latch clear */
+    xor al, al
+    out 0xF0, al
+
 GenericIRQ:
-    /* Return the current IRQL */
-    mov eax, [esp+12]
-    mov ecx, PCR[KPCR_IRQL]
-    mov [eax], cl
+    /* Get current and new IRQL */
+    xor eax, eax
+    mov al, byte ptr [esp+4]
+    mov ebx, PCR[KPCR_IRQL]
 
-    /* Set the new IRQL */
-    movzx eax, byte ptr [esp+4]
+    /* Set and save old */
     mov PCR[KPCR_IRQL], eax
+    mov edx, [esp+12]
+    mov [edx], bl
 
     /* Set IRQ mask in the PIC */
     mov eax, KiI8259MaskTable[eax*4]
@@ -366,14 +486,18 @@ GenericIRQ:
     out 0xA1, al
 
     /* Check to which PIC the EOI was sent */
-    mov eax, ebx
+    mov eax, ecx
     cmp eax, 8
     jnb Pic1
 
     /* Write mask to master PIC */
     or al, 0x60
     out 0x20, al
-    jmp DoneBegin
+
+    /* Enable interrupts and return TRUE */
+    sti
+    mov eax, 1
+    ret 12
 
 Pic1:
     /* Write mask to slave PIC */
@@ -382,9 +506,7 @@ Pic1:
     mov al, 0x62
     out 0x20, al
 
-DoneBegin:
     /* Enable interrupts and return TRUE */
-    in al, 0x21
     sti
     mov eax, 1
     ret 12
@@ -397,12 +519,111 @@ InvalidIRQ:
 #endif
 .endfunc
 
+IRQ15Level:
+    /* This is IRQ 15, check if it's spurious */
+    mov al, 0xB
+    out 0xA0, al
+    jmp $+2
+    in al, 0xA0
+    test al, 0x80
+    jnz GenericIRQLevel
+    jmp CascadedInterrupt
+
+IRQ7Level:
+    /* This is IRQ 7, check if it's spurious */
+    mov al, 0xB
+    out 0x20, al
+    jmp $+2
+    in al, 0x20
+    test al, 0x80
+    jnz GenericIRQLevel
+
+    /* It is, return FALSE */
+SpuriousInterrupt:
+    mov eax, 0
+    ret 12
+
+IRQ13Level:
+    /* AT 80287 latch clear */
+    xor al, al
+    out 0xF0, al
+
+GenericIRQLevel:
+    /* Save IRQL */
+    xor eax, eax
+    mov al, [esp+4]
+
+    /* Set IRQ mask in the PIC */
+    mov eax, KiI8259MaskTable[eax*4]
+    or eax, PCR[KPCR_IDR]
+    out 0x21, al
+    shr eax, 8
+    out 0xA1, al
+
+    /* Compute new IRR */
+    mov eax, ecx
+    mov ebx, 1
+    add ecx, 4
+    shl ebx, cl
+    or PCR[KPCR_IRR], ebx
+
+    /* Get IRQLs */
+    mov cl, [esp+4]
+    mov bl, PCR[KPCR_IRQL]
+    mov edx, [esp+12]
+
+    /* Check to which PIC the EOI was sent */
+    cmp eax, 8
+    jnb Pic1Level
+
+    /* Write mask to master PIC */
+    or al, 0x60
+    out 0x20, al
+
+    /* Check for spurious */
+    cmp cl, bl
+    jbe SpuriousInterrupt
+
+    /* Write IRQL values */
+    movzx ecx, cl
+    mov PCR[KPCR_IRQL], ecx
+    mov [edx], bl
+
+    /* Enable interrupts and return TRUE */
+    sti
+    mov eax, 1
+    ret 12
+
+Pic1Level:
+    /* Write mask to slave and master PIC */
+    add al, 0x58
+    out 0xA0, al
+    mov al, 0x62
+    out 0x20, al
+
+    /* Was this a lower interrupt? */
+    cmp cl, bl
+    jbe SpuriousInterrupt
+
+    /* Write IRQL values */
+    movzx ecx, cl
+    mov PCR[KPCR_IRQL], ecx
+    mov [edx], bl
+
+    /* Enable interrupts and return TRUE */
+    sti
+    mov eax, 1
+    ret 12
+
 .globl _HalEndSystemInterrupt@8
 .func HalEndSystemInterrupt@8
 _HalEndSystemInterrupt@8:
 
-    /* Get the IRQL and check if it's a software interrupt */
-    movzx ecx, byte ptr [esp+4]
+    /* Read IRQL */
+    xor ecx, ecx
+    mov cl, [esp+4]
+
+    /* Check if it's a software interrupt */
     cmp dword ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
     jbe SkipMask2
 
@@ -418,7 +639,7 @@ SkipMask2:
     /* Set IRQL and check if there are pending software interrupts */
     mov PCR[KPCR_IRQL], ecx
     mov eax, PCR[KPCR_IRR]
-    mov al, SoftIntByteTable[eax]
+    mov al, SWInterruptLookUpTable[eax]
     cmp al, cl
     ja DoCall
     ret 8
@@ -427,7 +648,7 @@ DoCall:
 
     /* There are pending software interrupts, call their handlers */
     add esp, 12
-    jmp SoftIntHandlerTable2[eax*4]
+    jmp SWInterruptHandlerTable2[eax*4]
 .endfunc
 
 .globl @KfLowerIrql@4
@@ -435,19 +656,21 @@ DoCall:
 _@KfLowerIrql@4:
 @KfLowerIrql@4:
 
-    /* Save flags since we'll disable interrupts */
-    pushf
+    /* Cleanup IRQL */
+    and ecx, 0xFF
 
     /* Validate IRQL */
-    movzx ecx, cl
-#if DBG
+    #if DBG
     cmp cl, PCR[KPCR_IRQL]
     ja InvalidIrql
-#endif
+    #endif
+
+    /* Save flags since we'll disable interrupts */
+    pushf
+    cli
 
     /* Disable interrupts and check if IRQL is below DISPATCH_LEVEL */
     cmp dword ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
-    cli
     jbe SkipMask
 
     /* Clear interrupt masks since there's a pending hardware interrupt */
@@ -462,7 +685,7 @@ SkipMask:
     /* Set the new IRQL and check if there's a pending software interrupt */
     mov PCR[KPCR_IRQL], ecx
     mov eax, PCR[KPCR_IRR]
-    mov al, SoftIntByteTable[eax]
+    mov al, SWInterruptLookUpTable[eax]
     cmp al, cl
     ja DoCall3
 
@@ -487,7 +710,7 @@ InvalidIrql:
 
 DoCall3:
     /* There is, call it */
-    call SoftIntHandlerTable[eax*4]
+    call SWInterruptHandlerTable[eax*4]
 
     /* Restore interrupts and return */
     popf
@@ -499,9 +722,9 @@ DoCall3:
 _@KfRaiseIrql@4:
 @KfRaiseIrql@4:
 
-    /* Get the IRQL  */
-    mov eax, PCR[KPCR_IRQL]
+    /* Get the IRQL */
     movzx ecx, cl
+    mov eax, PCR[KPCR_IRQL]
 
 #if DBG
     /* Validate it */
@@ -521,7 +744,7 @@ _@KfRaiseIrql@4:
     cli
 
     /* Set the new IRQL */
-    mov PCR[KPCR_IRQL], cl
+    mov PCR[KPCR_IRQL], ecx
 
     /* Mask the interrupts in the PIC */
     mov eax, KiI8259MaskTable[ecx*4]
@@ -536,7 +759,6 @@ _@KfRaiseIrql@4:
     ret
 
 SetIrql:
-
     /* Set the IRQL and return */
     mov PCR[KPCR_IRQL], ecx
     ret
@@ -598,29 +820,17 @@ InvalidRaise:
 .func KeRaiseIrqlToSynchLevel@0
 _KeRaiseIrqlToSynchLevel@0:
 
-    /* Disable interrupts */
-    pushf
-    cli
-
-    /* Mask out interrupts */
-    mov eax, KiI8259MaskTable[SYNCH_LEVEL*4]
-    or eax, PCR[KPCR_IDR]
-    out 0x21, al
-    shr eax, 8
-    out 0xA1, al
-
-    /* Return the old IRQL, enable interrupts and set to SYNCH */
+    /* Get the current IRQL */
     mov eax, PCR[KPCR_IRQL]
+
+    /* Set SYNCH_LEVEL */
     mov dword ptr PCR[KPCR_IRQL], SYNCH_LEVEL
-    popf
 
 #if DBG
-    /* Validate raise */
+    /* Make sure we were not higher then dispatch */
     cmp eax, SYNCH_LEVEL
     ja InvalidSyRaise
 #endif
-
-    /* Return */
     ret
 
 #if DBG
@@ -737,7 +947,7 @@ SoftwareInt:
     /* Check if there are pending software interrupts */
     mov PCR[KPCR_IRQL], ecx
     mov eax, PCR[KPCR_IRR]
-    mov al, SoftIntByteTable[eax]
+    mov al, SWInterruptLookUpTable[eax]
     cmp al, cl
     ja DoCall2
     ret 4
@@ -745,5 +955,5 @@ SoftwareInt:
 DoCall2:
     /* There are pending softwate interrupts, call their handlers */
     add esp, 8
-    jmp SoftIntHandlerTable2[eax*4]
+    jmp SWInterruptHandlerTable2[eax*4]
 .endfunc
index fcc78c8..e445ca4 100644 (file)
@@ -191,6 +191,40 @@ _KiUnexpectedInterrupt&Number:
 .endr
 .endm
 
+//
+// @name GENERATE_HAL_INT_HANDLER
+//
+// This macro creates a HAL hardware interrupt handler.
+//
+// @param None.
+//
+// @remark None.
+//
+.macro GENERATE_HAL_INT_HANDLER Number
+.func HalpHardwareInterrupt&Number
+_HalpHardwareInterrupt&Number:
+    int PRIMARY_VECTOR_BASE + Number
+    ret
+.endfunc
+.endm
+
+//
+// @name GENERATE_HAL_INT_HANDLERS
+//
+// This macro creates the unexpected interrupt handlers.
+//
+// @param None.
+//
+// @remark None.
+//
+.macro GENERATE_HAL_INT_HANDLERS
+.set i, 0
+.rept 16
+    GENERATE_HAL_INT_HANDLER %i
+    .set i, i + 1
+.endr
+.endm
+
 //
 // @name INVALID_V86_OPCODE
 //