diff --git a/reactos/hal/halx86/generic/irq.S b/reactos/hal/halx86/generic/irq.S index b72f7ad4e1f..bf67d2aac1e 100644 --- a/reactos/hal/halx86/generic/irq.S +++ b/reactos/hal/halx86/generic/irq.S @@ -84,38 +84,6 @@ FindHigherIrqlMask: .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 @@ AfterCall: 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: diff --git a/reactos/hal/halx86/generic/pic.c b/reactos/hal/halx86/generic/pic.c index 8656dab86b0..168758ec0fa 100644 --- a/reactos/hal/halx86/generic/pic.c +++ b/reactos/hal/halx86/generic/pic.c @@ -14,6 +14,58 @@ /* 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 @@ HalClearSoftwareInterrupt(IN KIRQL Irql) 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 @@ HalDisableSystemInterrupt(IN UCHAR Vector, /* 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); +} diff --git a/reactos/hal/halx86/include/halp.h b/reactos/hal/halx86/include/halp.h index 790a10903af..5bbc2fa2326 100644 --- a/reactos/hal/halx86/include/halp.h +++ b/reactos/hal/halx86/include/halp.h @@ -179,6 +179,26 @@ typedef enum _I8259_ICW4_BUFFERED_MODE 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 // @@ -243,6 +263,52 @@ typedef union _I8259_ICW4 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) // P. 34, 35 @@ -295,6 +361,53 @@ typedef struct _PIC_MASK }; } 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 //