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?r…
==============================================================================
--- 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 _HalBeginSystemInterrupt@12
-.func HalBeginSystemInterrupt@12
-_HalBeginSystemInterrupt@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 _HalEndSystemInterrupt@8
.func HalEndSystemInterrupt@8
_HalEndSystemInterrupt@8:
Modified: trunk/reactos/hal/halx86/generic/pic.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/pic.c?r…
==============================================================================
--- 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?…
==============================================================================
--- 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
//