Author: sir_richard
Date: Mon Jan 25 00:30:43 2010
New Revision: 45237

URL: http://svn.reactos.org/svn/reactos?rev=45237&view=rev
Log:
[HAL]: Implement and document the HalpSpecialDismissTable. Explain how each IRQ 
should be handled and what the special cases are. Implement said special cases 
(based on ISA System Architecture, 3rd Edition).
[HAL]: Implement HalBeginSystemInterrupt in C instead of ASM, it jumps into one 
of the IRQ handlers registered in the HalpSpecialDismissTable.

Modified:
    trunk/reactos/hal/halx86/generic/irq.S
    trunk/reactos/hal/halx86/generic/pic.c
    trunk/reactos/hal/halx86/include/halp.h

Modified: trunk/reactos/hal/halx86/generic/irq.S
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/irq.S?rev=45237&r1=45236&r2=45237&view=diff
==============================================================================
--- trunk/reactos/hal/halx86/generic/irq.S [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/generic/irq.S [iso-8859-1] Mon Jan 25 00:30:43 2010
@@ -84,38 +84,6 @@
     .long 0                             /* IRQL 30 */
     .long 0                             /* IRQL 31 */
 
-HalpSpecialDismissTable:
-    .rept 7
-    .long GenericIRQ                    /* IRQ 0-7 */
-    .endr
-    .long IRQ7                          /* IRQ 7 */
-    .rept 5
-    .long GenericIRQ                    /* IRQ 8-12 */
-    .endr
-    .long IRQ13                         /* IRQ 13 */
-    .long GenericIRQ                    /* IRQ 14 */
-    .long IRQ15                         /* IRQ 15 */
-    .rept 20
-    .long GenericIRQ                    /* IRQ 16-35 */
-    .endr
-#if DBG
-.rept 172
-    .long InvalidIRQ                    /* IRQ 36-207 */
-.endr
-#endif
-
-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 */
@@ -210,198 +178,6 @@
     ret
 .endfunc
 
-.globl _halbeginsysteminterr...@12
-.func halbeginsysteminterr...@12
-_halbeginsysteminterr...@12:
-
-    /* Convert to IRQ and call the handler */
-    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 */
-    mov al, 0xB
-    out 0xA0, al
-    jmp $+2
-    in al, 0xA0
-    test al, 0x80
-    jnz GenericIRQ
-
-    /* Cascaded interrupt... dismiss it and return FALSE */
-CascadedInterrupt:
-    mov al, 0x62
-    out 0x20, al
-    mov eax, 0
-    ret 12
-
-IRQ7:
-    /* This is IRQ 7, check if it's spurious */
-    mov al, 0xB
-    out 0x20, al
-    jmp $+2
-    in al, 0x20
-    test al, 0x80
-    jnz GenericIRQ
-
-    /* It is, return FALSE */
-    mov eax, 0
-    ret 12
-
-IRQ13:
-    /* AT 80287 latch clear */
-    xor al, al
-    out 0xF0, al
-
-GenericIRQ:
-    /* Get current and new IRQL */
-    xor eax, eax
-    mov al, byte ptr [esp+4]
-    mov ebx, PCR[KPCR_IRQL]
-
-    /* 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]
-    or eax, PCR[KPCR_IDR]
-    out 0x21, al
-    shr eax, 8
-    out 0xA1, al
-
-    /* Check to which PIC the EOI was sent */
-    mov eax, ecx
-    cmp eax, 8
-    jnb Pic1
-
-    /* Write mask to master PIC */
-    or al, 0x60
-    out 0x20, al
-
-    /* Enable interrupts and return TRUE */
-    sti
-    mov eax, 1
-    ret 12
-
-Pic1:
-    /* Write mask to slave PIC */
-    mov al, 0x20
-    out 0xA0, al
-    mov al, 0x62
-    out 0x20, al
-
-    /* Enable interrupts and return TRUE */
-    sti
-    mov eax, 1
-    ret 12
-
-#if DBG
-InvalidIRQ:
-    /* Dismiss it */
-    mov eax, 0
-    ret 12
-#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 _halendsysteminterr...@8
 .func halendsysteminterr...@8
 _halendsysteminterr...@8:

Modified: trunk/reactos/hal/halx86/generic/pic.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/pic.c?rev=45237&r1=45236&r2=45237&view=diff
==============================================================================
--- trunk/reactos/hal/halx86/generic/pic.c [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/generic/pic.c [iso-8859-1] Mon Jan 25 00:30:43 2010
@@ -13,6 +13,58 @@
 #include <debug.h>
 
 /* GLOBALS 
********************************************************************/
+
+/*
+ * This table basically keeps track of level vs edge triggered interrupts.
+ * Windows has 250+ entries, but it seems stupid to replicate that since the 
PIC
+ * can't actually have that many.
+ *
+ * When a level interrupt is registered, the respective pointer in this table 
is
+ * modified to point to a dimiss routine for level interrupts instead.
+ *
+ * The other thing this table does is special case IRQ7, IRQ13 and IRQ15:
+ *
+ * - If an IRQ line is deasserted before it is acknowledged due to a noise 
spike
+ *   generated by an expansion device (since the IRQ line is low during the 1st
+ *   acknowledge bus cycle), the i8259 will keep the line low for at least 
100ns
+ *   When the spike passes, a pull-up resistor will return the IRQ line to 
high.
+ *   Since the PIC requires the input be high until the first acknowledge, the
+ *   i8259 knows that this was a spurious interrupt, and on the second 
interrupt
+ *   acknowledge cycle, it reports this to the CPU. Since no valid interrupt 
has
+ *   actually happened Intel hardcoded the chip to report IRQ7 on the master 
PIC
+ *   and IRQ15 on the slave PIC (IR7 either way).
+ *
+ *   "ISA System Architecture", 3rd Edition, states that these cases should be
+ *   handled by reading the respective Interrupt Service Request (ISR) bits 
from
+ *   the affected PIC, and validate whether or not IR7 is set. If it isn't, 
then
+ *   the interrupt is spurious and should be ignored.
+ *
+ *   Note that for a spurious IRQ15, we DO have to send an EOI to the master 
for
+ *   IRQ2 since the line was asserted by the slave when it received the 
spurious
+ *   IRQ15!
+ *
+ * - When the 80287/80387 math co-processor generates an FPU/NPX trap, this is 
+ *   connected to IRQ13, so we have to clear the busy latch on the NPX port.
+ */
+PHAL_DISMISS_INTERRUPT HalpSpecialDismissTable[16] =
+{
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrq07,
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrqGeneric,
+    HalpDismissIrq13,
+    HalpDismissIrqGeneric,
+    HalpDismissIrq15
+};
 
 /* This table contains the static x86 PIC mapping between IRQLs and IRQs */
 ULONG KiI8259MaskTable[32] =
@@ -342,6 +394,139 @@
     KeGetPcr()->IRR &= ~(1 << Irql);
 }
 
+/* INTERRUPT DISMISSAL FUNCTIONS 
**********************************************/
+
+BOOLEAN
+FORCEINLINE
+_HalpDismissIrqGeneric(IN KIRQL Irql,
+                       IN ULONG Irq,
+                       OUT PKIRQL OldIrql)
+{
+    PIC_MASK Mask;
+    KIRQL CurrentIrql;
+    I8259_OCW2 Ocw2;
+    PKPCR Pcr = KeGetPcr();
+
+    /* First save current IRQL and compare it to the requested one */
+    CurrentIrql = Pcr->Irql;
+
+    /* Set the new IRQL and return the current one */
+    Pcr->Irql = Irql;
+    *OldIrql = CurrentIrql;
+
+    /* Set new PIC mask */
+    Mask.Both = KiI8259MaskTable[Irql] | Pcr->IDR;
+    __outbyte(PIC1_DATA_PORT, Mask.Master);
+    __outbyte(PIC2_DATA_PORT, Mask.Slave);
+    
+    /* Prepare OCW2 for EOI */
+    Ocw2.Bits = 0;
+    Ocw2.EoiMode = SpecificEoi;
+
+    /* Check which PIC needs the EOI */
+    if (Irq > 8)
+    {
+        /* Send the EOI for the IRQ */
+        __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | (Irq - 8));
+    
+        /* Send the EOI for IRQ2 on the master because this was cascaded */
+        __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
+    }
+    else
+    {
+        /* Send the EOI for the IRQ */
+        __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | Irq);
+    }
+    
+    /* Enable interrupts and return success */
+    _enable();
+    return TRUE;
+}
+
+BOOLEAN
+__attribute__((regparm(3)))
+HalpDismissIrqGeneric(IN KIRQL Irql,
+                      IN ULONG Irq,
+                      OUT PKIRQL OldIrql)
+{
+    /* Run the inline code */
+    return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
+}
+
+BOOLEAN
+__attribute__((regparm(3)))
+HalpDismissIrq15(IN KIRQL Irql,
+                 IN ULONG Irq,
+                 OUT PKIRQL OldIrql)
+{
+    I8259_OCW3 Ocw3;
+    I8259_OCW2 Ocw2;
+    I8259_ISR Isr;
+        
+    /* Request the ISR */
+    Ocw3.Bits = 0;
+    Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
+    Ocw3.ReadRequest = ReadIsr;
+    __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
+    
+    /* Read the ISR */
+    Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
+    
+    /* Is IRQ15 really active (this is IR7) */
+    if (Isr.Irq7 == FALSE)
+    {
+        /* It isn't, so we have to EOI IRQ2 because this was cascaded */
+        Ocw2.Bits = 0;
+        Ocw2.EoiMode = SpecificEoi;
+        __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
+        
+        /* And now fail since this was spurious */
+        return FALSE;
+    }
+
+    /* Do normal interrupt dismiss */
+    return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
+}
+
+
+BOOLEAN
+__attribute__((regparm(3)))
+HalpDismissIrq13(IN KIRQL Irql,
+                 IN ULONG Irq,
+                 OUT PKIRQL OldIrql)
+{
+    /* Clear the FPU busy latch */
+    __outbyte(0xF0, 0);
+    
+    /* Do normal interrupt dismiss */
+    return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
+}
+
+BOOLEAN
+__attribute__((regparm(3)))
+HalpDismissIrq07(IN KIRQL Irql,
+                 IN ULONG Irq,
+                 OUT PKIRQL OldIrql)
+{
+    I8259_OCW3 Ocw3;
+    I8259_ISR Isr;
+        
+    /* Request the ISR */
+    Ocw3.Bits = 0;
+    Ocw3.Sbo = 1;
+    Ocw3.ReadRequest = ReadIsr;
+    __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
+    
+    /* Read the ISR */
+    Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
+    
+    /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
+    if (Isr.Irq7 == FALSE) return FALSE;
+    
+    /* Do normal interrupt dismiss */
+    return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
+}
+
 /* SYSTEM INTERRUPTS 
**********************************************************/
 
 /*
@@ -420,3 +605,19 @@
     /* Bring interrupts back */
     _enable();
 }
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+HalBeginSystemInterrupt(IN KIRQL Irql,
+                        IN UCHAR Vector,
+                        OUT PKIRQL OldIrql)
+{
+    ULONG Irq;
+    
+    /* Get the IRQ and call the proper routine to handle it */
+    Irq = Vector - PRIMARY_VECTOR_BASE;
+    return HalpSpecialDismissTable[Irq](Irql, Irq, OldIrql);
+}

Modified: trunk/reactos/hal/halx86/include/halp.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/include/halp.h?rev=45237&r1=45236&r2=45237&view=diff
==============================================================================
--- trunk/reactos/hal/halx86/include/halp.h [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/include/halp.h [iso-8859-1] Mon Jan 25 00:30:43 
2010
@@ -178,6 +178,26 @@
     BufferedSlave,
     BufferedMaster
 } I8259_ICW4_BUFFERED_MODE;
+
+typedef enum _I8259_READ_REQUEST
+{
+    InvalidRequest,
+    InvalidRequest2,
+    ReadIdr,
+    ReadIsr
+} I8259_READ_REQUEST;
+
+typedef enum _I8259_EOI_MODE
+{
+    RotateAutoEoiClear,
+    NonSpecificEoi,
+    InvalidEoiMode,
+    SpecificEoi,
+    RotateAutoEoiSet,
+    RotateNonSpecific,
+    SetPriority,
+    RotateSpecific
+} I8259_EOI_MODE;
 
 //
 // Definitions for ICW Registers
@@ -242,6 +262,52 @@
     };
     UCHAR Bits;
 } I8259_ICW4, *PI8259_ICW4;
+
+typedef union _I8259_OCW2
+{
+    struct
+    {
+        UCHAR IrqNumber:3;
+        UCHAR Sbz:2;
+        I8259_EOI_MODE EoiMode:3;
+    };
+    UCHAR Bits;
+} I8259_OCW2, *PI8259_OCW2;
+
+typedef union _I8259_OCW3
+{
+    struct
+    {
+        I8259_READ_REQUEST ReadRequest:2;
+        UCHAR PollCommand:1;
+        UCHAR Sbo:1;
+        UCHAR Sbz:1;
+        UCHAR SpecialMaskMode:2;
+        UCHAR Reserved:1;
+    };
+    UCHAR Bits;
+} I8259_OCW3, *PI8259_OCW3;
+
+typedef union _I8259_ISR
+{
+    union
+    {
+        struct
+        {
+            UCHAR Irq0:1;
+            UCHAR Irq1:1;
+            UCHAR Irq2:1;
+            UCHAR Irq3:1;
+            UCHAR Irq4:1;
+            UCHAR Irq5:1;
+            UCHAR Irq6:1;
+            UCHAR Irq7:1;
+        };
+    };
+    UCHAR Bits;
+} I8259_ISR, *PI8259_ISR;
+
+typedef I8259_ISR I8259_IDR, *PI8259_IDR;
 
 //
 // See EISA System Architecture 2nd Edition (Tom Shanley, Don Anderson, John 
Swindle)
@@ -295,6 +361,53 @@
     };    
 } PIC_MASK, *PPIC_MASK;
 
+typedef
+VOID
+(*PHAL_SW_INTERRUPT_HANDLER)(
+    VOID
+);
+
+typedef
+BOOLEAN
+__attribute__((regparm(3)))
+(*PHAL_DISMISS_INTERRUPT)(
+    IN KIRQL Irql,
+    IN ULONG Irq,
+    OUT PKIRQL OldIrql
+);
+
+BOOLEAN
+__attribute__((regparm(3)))
+HalpDismissIrqGeneric(
+    IN KIRQL Irql,
+    IN ULONG Irq,
+    OUT PKIRQL OldIrql
+);
+
+BOOLEAN
+__attribute__((regparm(3)))
+HalpDismissIrq15(
+    IN KIRQL Irql,
+    IN ULONG Irq,
+    OUT PKIRQL OldIrql
+);
+
+BOOLEAN
+__attribute__((regparm(3)))
+HalpDismissIrq13(
+    IN KIRQL Irql,
+    IN ULONG Irq,
+    OUT PKIRQL OldIrql
+);
+
+BOOLEAN
+__attribute__((regparm(3)))
+HalpDismissIrq07(
+    IN KIRQL Irql,
+    IN ULONG Irq,
+    OUT PKIRQL OldIrql
+);
+
 //
 // Mm PTE/PDE to Hal PTE/PDE
 //


Reply via email to