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?re... ============================================================================== --- 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?re... ============================================================================== --- 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?r... ============================================================================== --- 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 //