1 /* 2 * PROJECT: ReactOS HAL 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * PURPOSE: HAL PIC Management and Control Code 5 * PROGRAMMERS: ReactOS Portable Systems Group 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include <hal.h> 11 12 #define NDEBUG 13 #include <debug.h> 14 15 VOID 16 NTAPI 17 HalpEndSoftwareInterrupt(IN KIRQL OldIrql, 18 IN PKTRAP_FRAME TrapFrame); 19 20 /* GLOBALS ********************************************************************/ 21 22 #ifndef _MINIHAL_ 23 /* 24 * This table basically keeps track of level vs edge triggered interrupts. 25 * Windows has 250+ entries, but it seems stupid to replicate that since the PIC 26 * can't actually have that many. 27 * 28 * When a level interrupt is registered, the respective pointer in this table is 29 * modified to point to a dimiss routine for level interrupts instead. 30 * 31 * The other thing this table does is special case IRQ7, IRQ13 and IRQ15: 32 * 33 * - If an IRQ line is deasserted before it is acknowledged due to a noise spike 34 * generated by an expansion device (since the IRQ line is low during the 1st 35 * acknowledge bus cycle), the i8259 will keep the line low for at least 100ns 36 * When the spike passes, a pull-up resistor will return the IRQ line to high. 37 * Since the PIC requires the input be high until the first acknowledge, the 38 * i8259 knows that this was a spurious interrupt, and on the second interrupt 39 * acknowledge cycle, it reports this to the CPU. Since no valid interrupt has 40 * actually happened Intel hardcoded the chip to report IRQ7 on the master PIC 41 * and IRQ15 on the slave PIC (IR7 either way). 42 * 43 * "ISA System Architecture", 3rd Edition, states that these cases should be 44 * handled by reading the respective Interrupt Service Request (ISR) bits from 45 * the affected PIC, and validate whether or not IR7 is set. If it isn't, then 46 * the interrupt is spurious and should be ignored. 47 * 48 * Note that for a spurious IRQ15, we DO have to send an EOI to the master for 49 * IRQ2 since the line was asserted by the slave when it received the spurious 50 * IRQ15! 51 * 52 * - When the 80287/80387 math co-processor generates an FPU/NPX trap, this is 53 * connected to IRQ13, so we have to clear the busy latch on the NPX port. 54 */ 55 PHAL_DISMISS_INTERRUPT HalpSpecialDismissTable[16] = 56 { 57 HalpDismissIrqGeneric, 58 HalpDismissIrqGeneric, 59 HalpDismissIrqGeneric, 60 HalpDismissIrqGeneric, 61 HalpDismissIrqGeneric, 62 HalpDismissIrqGeneric, 63 HalpDismissIrqGeneric, 64 HalpDismissIrq07, 65 #if defined(SARCH_PC98) 66 HalpDismissIrq08, 67 #else 68 HalpDismissIrqGeneric, 69 #endif 70 HalpDismissIrqGeneric, 71 HalpDismissIrqGeneric, 72 HalpDismissIrqGeneric, 73 HalpDismissIrqGeneric, 74 #if defined(SARCH_PC98) 75 HalpDismissIrqGeneric, 76 #else 77 HalpDismissIrq13, 78 #endif 79 HalpDismissIrqGeneric, 80 HalpDismissIrq15 81 }; 82 83 /* 84 * These are the level IRQ dismissal functions that get copied in the table 85 * above if the given IRQ is actually level triggered. 86 */ 87 PHAL_DISMISS_INTERRUPT HalpSpecialDismissLevelTable[16] = 88 { 89 HalpDismissIrqLevel, 90 HalpDismissIrqLevel, 91 HalpDismissIrqLevel, 92 HalpDismissIrqLevel, 93 HalpDismissIrqLevel, 94 HalpDismissIrqLevel, 95 HalpDismissIrqLevel, 96 HalpDismissIrq07Level, 97 #if defined(SARCH_PC98) 98 HalpDismissIrq08Level, 99 #else 100 HalpDismissIrqLevel, 101 #endif 102 HalpDismissIrqLevel, 103 HalpDismissIrqLevel, 104 HalpDismissIrqLevel, 105 HalpDismissIrqLevel, 106 #if defined(SARCH_PC98) 107 HalpDismissIrqLevel, 108 #else 109 HalpDismissIrq13Level, 110 #endif 111 HalpDismissIrqLevel, 112 HalpDismissIrq15Level 113 }; 114 115 /* This table contains the static x86 PIC mapping between IRQLs and IRQs */ 116 extern ULONG KiI8259MaskTable[32]; 117 118 /* This table indicates which IRQs, if pending, can preempt a given IRQL level */ 119 extern ULONG FindHigherIrqlMask[32]; 120 121 /* Denotes minimum required IRQL before we can process pending SW interrupts */ 122 KIRQL SWInterruptLookUpTable[8] = 123 { 124 PASSIVE_LEVEL, /* IRR 0 */ 125 PASSIVE_LEVEL, /* IRR 1 */ 126 APC_LEVEL, /* IRR 2 */ 127 APC_LEVEL, /* IRR 3 */ 128 DISPATCH_LEVEL, /* IRR 4 */ 129 DISPATCH_LEVEL, /* IRR 5 */ 130 DISPATCH_LEVEL, /* IRR 6 */ 131 DISPATCH_LEVEL /* IRR 7 */ 132 }; 133 134 #if defined(__GNUC__) 135 136 #define HalpDelayedHardwareInterrupt(x) \ 137 VOID __cdecl HalpHardwareInterrupt##x(VOID); \ 138 VOID \ 139 __cdecl \ 140 HalpHardwareInterrupt##x(VOID) \ 141 { \ 142 asm volatile ("int $%c0\n"::"i"(PRIMARY_VECTOR_BASE + x)); \ 143 } 144 145 #elif defined(_MSC_VER) 146 147 #define HalpDelayedHardwareInterrupt(x) \ 148 VOID __cdecl HalpHardwareInterrupt##x(VOID); \ 149 VOID \ 150 __cdecl \ 151 HalpHardwareInterrupt##x(VOID) \ 152 { \ 153 __asm \ 154 { \ 155 int PRIMARY_VECTOR_BASE + x \ 156 } \ 157 } 158 159 #else 160 #error Unsupported compiler 161 #endif 162 163 /* Pending/delayed hardware interrupt handlers */ 164 HalpDelayedHardwareInterrupt(0); 165 HalpDelayedHardwareInterrupt(1); 166 HalpDelayedHardwareInterrupt(2); 167 HalpDelayedHardwareInterrupt(3); 168 HalpDelayedHardwareInterrupt(4); 169 HalpDelayedHardwareInterrupt(5); 170 HalpDelayedHardwareInterrupt(6); 171 HalpDelayedHardwareInterrupt(7); 172 HalpDelayedHardwareInterrupt(8); 173 HalpDelayedHardwareInterrupt(9); 174 HalpDelayedHardwareInterrupt(10); 175 HalpDelayedHardwareInterrupt(11); 176 HalpDelayedHardwareInterrupt(12); 177 HalpDelayedHardwareInterrupt(13); 178 HalpDelayedHardwareInterrupt(14); 179 HalpDelayedHardwareInterrupt(15); 180 181 /* Handlers for pending interrupts */ 182 PHAL_SW_INTERRUPT_HANDLER SWInterruptHandlerTable[20] = 183 { 184 (PHAL_SW_INTERRUPT_HANDLER)KiUnexpectedInterrupt, 185 HalpApcInterrupt, 186 HalpDispatchInterrupt, 187 (PHAL_SW_INTERRUPT_HANDLER)KiUnexpectedInterrupt, 188 HalpHardwareInterrupt0, 189 HalpHardwareInterrupt1, 190 HalpHardwareInterrupt2, 191 HalpHardwareInterrupt3, 192 HalpHardwareInterrupt4, 193 HalpHardwareInterrupt5, 194 HalpHardwareInterrupt6, 195 HalpHardwareInterrupt7, 196 HalpHardwareInterrupt8, 197 HalpHardwareInterrupt9, 198 HalpHardwareInterrupt10, 199 HalpHardwareInterrupt11, 200 HalpHardwareInterrupt12, 201 HalpHardwareInterrupt13, 202 HalpHardwareInterrupt14, 203 HalpHardwareInterrupt15 204 }; 205 206 /* Handlers for pending software interrupts when we already have a trap frame*/ 207 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY SWInterruptHandlerTable2[3] = 208 { 209 (PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY)(PVOID)KiUnexpectedInterrupt, 210 HalpApcInterrupt2ndEntry, 211 HalpDispatchInterrupt2ndEntry 212 }; 213 214 LONG HalpEisaELCR; 215 216 /* FUNCTIONS ******************************************************************/ 217 218 VOID 219 NTAPI 220 HalpInitializePICs(IN BOOLEAN EnableInterrupts) 221 { 222 ULONG EFlags; 223 EISA_ELCR Elcr; 224 ULONG i, j; 225 BOOLEAN ElcrFound; 226 227 /* Save EFlags and disable interrupts */ 228 EFlags = __readeflags(); 229 _disable(); 230 231 /* Initialize and mask the PIC */ 232 HalpInitializeLegacyPICs(); 233 234 /* Read EISA Edge/Level Register for master and slave */ 235 Elcr.Bits = (__inbyte(EISA_ELCR_SLAVE) << 8) | __inbyte(EISA_ELCR_MASTER); 236 237 #if defined(SARCH_PC98) 238 /* Force defaults when ELCR is not supported */ 239 if (Elcr.Bits == 0xFFFF) 240 { 241 Elcr.Master.Irq0Level = 0; 242 Elcr.Master.Irq1Level = 0; 243 Elcr.Master.Irq7Level = 0; 244 Elcr.Slave.Irq8Level = 0; 245 } 246 ElcrFound = TRUE; 247 #else 248 /* IRQs 0, 1, 2, 8, and 13 are system-reserved and must be edge */ 249 ElcrFound = (!(Elcr.Master.Irq0Level) && !(Elcr.Master.Irq1Level) && !(Elcr.Master.Irq2Level) && 250 !(Elcr.Slave.Irq8Level) && !(Elcr.Slave.Irq13Level)); 251 #endif 252 253 if (ElcrFound) 254 { 255 /* ELCR is as it's supposed to be, save it */ 256 HalpEisaELCR = Elcr.Bits; 257 258 /* Scan for level interrupts */ 259 for (i = 1, j = 0; j < 16; i <<= 1, j++) 260 { 261 if (HalpEisaELCR & i) 262 { 263 /* Switch handler to level */ 264 SWInterruptHandlerTable[j + 4] = HalpHardwareInterruptLevel; 265 266 /* Switch dismiss to level */ 267 HalpSpecialDismissTable[j] = HalpSpecialDismissLevelTable[j]; 268 } 269 } 270 } 271 272 /* Report cascade IRQ usage */ 273 HalpRegisterVector(IDT_INTERNAL, 274 PRIMARY_VECTOR_BASE + PIC_CASCADE_IRQ, 275 PRIMARY_VECTOR_BASE + PIC_CASCADE_IRQ, 276 HIGH_LEVEL); 277 278 /* Restore interrupt state */ 279 if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK; 280 __writeeflags(EFlags); 281 } 282 283 UCHAR 284 FASTCALL 285 HalpIrqToVector(UCHAR Irq) 286 { 287 return (PRIMARY_VECTOR_BASE + Irq); 288 } 289 290 UCHAR 291 FASTCALL 292 HalpVectorToIrq(UCHAR Vector) 293 { 294 return (Vector - PRIMARY_VECTOR_BASE); 295 } 296 297 KIRQL 298 FASTCALL 299 HalpVectorToIrql(UCHAR Vector) 300 { 301 return (PROFILE_LEVEL - (Vector - PRIMARY_VECTOR_BASE)); 302 } 303 304 /* IRQL MANAGEMENT ************************************************************/ 305 306 /* 307 * @implemented 308 */ 309 KIRQL 310 NTAPI 311 KeGetCurrentIrql(VOID) 312 { 313 /* Return the IRQL */ 314 return KeGetPcr()->Irql; 315 } 316 317 /* 318 * @implemented 319 */ 320 KIRQL 321 NTAPI 322 KeRaiseIrqlToDpcLevel(VOID) 323 { 324 PKPCR Pcr = KeGetPcr(); 325 KIRQL CurrentIrql; 326 327 /* Save and update IRQL */ 328 CurrentIrql = Pcr->Irql; 329 Pcr->Irql = DISPATCH_LEVEL; 330 331 #if DBG 332 /* Validate correct raise */ 333 if (CurrentIrql > DISPATCH_LEVEL) KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL); 334 #endif 335 336 /* Return the previous value */ 337 return CurrentIrql; 338 } 339 340 /* 341 * @implemented 342 */ 343 KIRQL 344 NTAPI 345 KeRaiseIrqlToSynchLevel(VOID) 346 { 347 PKPCR Pcr = KeGetPcr(); 348 KIRQL CurrentIrql; 349 350 /* Save and update IRQL */ 351 CurrentIrql = Pcr->Irql; 352 Pcr->Irql = SYNCH_LEVEL; 353 354 #if DBG 355 /* Validate correct raise */ 356 if (CurrentIrql > SYNCH_LEVEL) 357 { 358 /* Crash system */ 359 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL, 360 CurrentIrql, 361 SYNCH_LEVEL, 362 0, 363 1); 364 } 365 #endif 366 367 /* Return the previous value */ 368 return CurrentIrql; 369 } 370 371 /* 372 * @implemented 373 */ 374 KIRQL 375 FASTCALL 376 KfRaiseIrql(IN KIRQL NewIrql) 377 { 378 PKPCR Pcr = KeGetPcr(); 379 KIRQL CurrentIrql; 380 381 /* Read current IRQL */ 382 CurrentIrql = Pcr->Irql; 383 384 #if DBG 385 /* Validate correct raise */ 386 if (CurrentIrql > NewIrql) 387 { 388 /* Crash system */ 389 Pcr->Irql = PASSIVE_LEVEL; 390 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL); 391 } 392 #endif 393 394 /* Set new IRQL */ 395 Pcr->Irql = NewIrql; 396 397 /* Return old IRQL */ 398 return CurrentIrql; 399 } 400 401 402 /* 403 * @implemented 404 */ 405 VOID 406 FASTCALL 407 KfLowerIrql(IN KIRQL OldIrql) 408 { 409 ULONG EFlags; 410 ULONG PendingIrql, PendingIrqlMask; 411 PKPCR Pcr = KeGetPcr(); 412 PIC_MASK Mask; 413 414 #if DBG 415 /* Validate correct lower */ 416 if (OldIrql > Pcr->Irql) 417 { 418 /* Crash system */ 419 Pcr->Irql = HIGH_LEVEL; 420 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); 421 } 422 #endif 423 424 /* Save EFlags and disable interrupts */ 425 EFlags = __readeflags(); 426 _disable(); 427 428 /* Set old IRQL */ 429 Pcr->Irql = OldIrql; 430 431 /* Check for pending software interrupts and compare with current IRQL */ 432 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql]; 433 if (PendingIrqlMask) 434 { 435 /* Check if pending IRQL affects hardware state */ 436 BitScanReverse(&PendingIrql, PendingIrqlMask); 437 if (PendingIrql > DISPATCH_LEVEL) 438 { 439 /* Set new PIC mask */ 440 Mask.Both = Pcr->IDR & 0xFFFF; 441 __outbyte(PIC1_DATA_PORT, Mask.Master); 442 __outbyte(PIC2_DATA_PORT, Mask.Slave); 443 444 /* Clear IRR bit */ 445 Pcr->IRR ^= (1 << PendingIrql); 446 } 447 448 /* Now handle pending interrupt */ 449 SWInterruptHandlerTable[PendingIrql](); 450 } 451 452 /* Restore interrupt state */ 453 __writeeflags(EFlags); 454 } 455 456 /* SOFTWARE INTERRUPTS ********************************************************/ 457 458 /* 459 * @implemented 460 */ 461 VOID 462 FASTCALL 463 HalRequestSoftwareInterrupt(IN KIRQL Irql) 464 { 465 ULONG EFlags; 466 PKPCR Pcr = KeGetPcr(); 467 KIRQL PendingIrql; 468 469 /* Save EFlags and disable interrupts */ 470 EFlags = __readeflags(); 471 _disable(); 472 473 /* Mask out the requested bit */ 474 Pcr->IRR |= (1 << Irql); 475 476 /* Check for pending software interrupts and compare with current IRQL */ 477 PendingIrql = SWInterruptLookUpTable[Pcr->IRR & 3]; 478 if (PendingIrql > Pcr->Irql) SWInterruptHandlerTable[PendingIrql](); 479 480 /* Restore interrupt state */ 481 __writeeflags(EFlags); 482 } 483 484 /* 485 * @implemented 486 */ 487 VOID 488 FASTCALL 489 HalClearSoftwareInterrupt(IN KIRQL Irql) 490 { 491 /* Mask out the requested bit */ 492 KeGetPcr()->IRR &= ~(1 << Irql); 493 } 494 495 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY 496 FASTCALL 497 HalpEndSoftwareInterrupt2(IN KIRQL OldIrql, 498 IN PKTRAP_FRAME TrapFrame) 499 { 500 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask; 501 PKPCR Pcr = KeGetPcr(); 502 PIC_MASK Mask; 503 504 UNREFERENCED_PARAMETER(TrapFrame); 505 506 /* Set old IRQL */ 507 Pcr->Irql = OldIrql; 508 509 /* Loop checking for pending interrupts */ 510 while (TRUE) 511 { 512 /* Check for pending software interrupts and compare with current IRQL */ 513 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql]; 514 if (!PendingIrqlMask) return NULL; 515 516 /* Check for in-service delayed interrupt */ 517 if (Pcr->IrrActive & 0xFFFFFFF0) return NULL; 518 519 /* Check if pending IRQL affects hardware state */ 520 BitScanReverse(&PendingIrql, PendingIrqlMask); 521 if (PendingIrql > DISPATCH_LEVEL) 522 { 523 /* Set new PIC mask */ 524 Mask.Both = Pcr->IDR & 0xFFFF; 525 __outbyte(PIC1_DATA_PORT, Mask.Master); 526 __outbyte(PIC2_DATA_PORT, Mask.Slave); 527 528 /* Set active bit otherwise, and clear it from IRR */ 529 PendingIrqMask = (1 << PendingIrql); 530 Pcr->IrrActive |= PendingIrqMask; 531 Pcr->IRR ^= PendingIrqMask; 532 533 /* Handle delayed hardware interrupt */ 534 SWInterruptHandlerTable[PendingIrql](); 535 536 /* Handling complete */ 537 Pcr->IrrActive ^= PendingIrqMask; 538 } 539 else 540 { 541 /* No need to loop checking for hardware interrupts */ 542 return SWInterruptHandlerTable2[PendingIrql]; 543 } 544 } 545 546 return NULL; 547 } 548 549 /* EDGE INTERRUPT DISMISSAL FUNCTIONS *****************************************/ 550 551 FORCEINLINE 552 BOOLEAN 553 _HalpDismissIrqGeneric(IN KIRQL Irql, 554 IN ULONG Irq, 555 OUT PKIRQL OldIrql) 556 { 557 PIC_MASK Mask; 558 KIRQL CurrentIrql; 559 I8259_OCW2 Ocw2; 560 PKPCR Pcr = KeGetPcr(); 561 562 /* First save current IRQL and compare it to the requested one */ 563 CurrentIrql = Pcr->Irql; 564 565 /* Check if this interrupt is really allowed to happen */ 566 if (Irql > CurrentIrql) 567 { 568 /* Set the new IRQL and return the current one */ 569 Pcr->Irql = Irql; 570 *OldIrql = CurrentIrql; 571 572 /* Prepare OCW2 for EOI */ 573 Ocw2.Bits = 0; 574 Ocw2.EoiMode = SpecificEoi; 575 576 /* Check which PIC needs the EOI */ 577 if (Irq >= 8) 578 { 579 #if defined(SARCH_PC98) 580 I8259_OCW3 Ocw3; 581 I8259_ISR Isr; 582 583 /* Send the EOI for the IRQ */ 584 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF)); 585 586 /* Request the ISR */ 587 Ocw3.Bits = 0; 588 Ocw3.Sbo = 1; 589 Ocw3.ReadRequest = ReadIsr; 590 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits); 591 592 /* Read the ISR */ 593 Isr.Bits = __inbyte(PIC2_CONTROL_PORT); 594 595 /* Check if the interrupt serviced was the only one from the slave PIC */ 596 if (Isr.Bits == 0) 597 { 598 /* If ISR is empty, send the EOI for cascade IRQ on the master PIC */ 599 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ); 600 } 601 #else 602 /* Send the EOI for the IRQ */ 603 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF)); 604 605 /* Send the EOI for cascade IRQ on the master PIC */ 606 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ); 607 #endif 608 } 609 else 610 { 611 /* Send the EOI for the IRQ */ 612 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq & 0xFF)); 613 } 614 615 /* Enable interrupts and return success */ 616 _enable(); 617 return TRUE; 618 } 619 620 /* Update the IRR so that we deliver this interrupt when the IRQL is proper */ 621 Pcr->IRR |= (1 << (Irq + 4)); 622 623 /* Set new PIC mask to real IRQL level, since the optimization is lost now */ 624 Mask.Both = (KiI8259MaskTable[CurrentIrql] | Pcr->IDR) & 0xFFFF; 625 __outbyte(PIC1_DATA_PORT, Mask.Master); 626 __outbyte(PIC2_DATA_PORT, Mask.Slave); 627 628 /* Now lie and say this was spurious */ 629 return FALSE; 630 } 631 632 BOOLEAN 633 NTAPI 634 HalpDismissIrqGeneric(IN KIRQL Irql, 635 IN ULONG Irq, 636 OUT PKIRQL OldIrql) 637 { 638 /* Run the inline code */ 639 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql); 640 } 641 642 BOOLEAN 643 NTAPI 644 HalpDismissIrq15(IN KIRQL Irql, 645 IN ULONG Irq, 646 OUT PKIRQL OldIrql) 647 { 648 I8259_OCW3 Ocw3; 649 I8259_OCW2 Ocw2; 650 I8259_ISR Isr; 651 652 /* Request the ISR */ 653 Ocw3.Bits = 0; 654 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */ 655 Ocw3.ReadRequest = ReadIsr; 656 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits); 657 658 /* Read the ISR */ 659 Isr.Bits = __inbyte(PIC2_CONTROL_PORT); 660 661 /* Is IRQ15 really active (this is IR7) */ 662 if (Isr.Irq7 == FALSE) 663 { 664 /* It isn't, so we have to EOI cascade IRQ */ 665 Ocw2.Bits = 0; 666 Ocw2.EoiMode = SpecificEoi; 667 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ); 668 669 /* And now fail since this was spurious */ 670 return FALSE; 671 } 672 673 /* Do normal interrupt dismiss */ 674 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql); 675 } 676 677 BOOLEAN 678 NTAPI 679 HalpDismissIrq13(IN KIRQL Irql, 680 IN ULONG Irq, 681 OUT PKIRQL OldIrql) 682 { 683 /* Clear the FPU busy latch */ 684 __outbyte(0xF0, 0); 685 686 /* Do normal interrupt dismiss */ 687 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql); 688 } 689 690 #if defined(SARCH_PC98) 691 BOOLEAN 692 NTAPI 693 HalpDismissIrq08( 694 _In_ KIRQL Irql, 695 _In_ ULONG Irq, 696 _Out_ PKIRQL OldIrql) 697 { 698 /* Clear the FPU busy latch */ 699 __outbyte(CPU_IO_o_FPU_BUSY_LATCH, 0); 700 701 /* Do normal interrupt dismiss */ 702 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql); 703 } 704 #endif 705 706 BOOLEAN 707 NTAPI 708 HalpDismissIrq07(IN KIRQL Irql, 709 IN ULONG Irq, 710 OUT PKIRQL OldIrql) 711 { 712 I8259_OCW3 Ocw3; 713 I8259_ISR Isr; 714 715 /* Request the ISR */ 716 Ocw3.Bits = 0; 717 Ocw3.Sbo = 1; 718 Ocw3.ReadRequest = ReadIsr; 719 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits); 720 721 /* Read the ISR */ 722 Isr.Bits = __inbyte(PIC1_CONTROL_PORT); 723 724 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */ 725 if (Isr.Irq7 == FALSE) return FALSE; 726 727 /* Do normal interrupt dismiss */ 728 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql); 729 } 730 731 /* LEVEL INTERRUPT DISMISSAL FUNCTIONS ****************************************/ 732 733 FORCEINLINE 734 BOOLEAN 735 _HalpDismissIrqLevel(IN KIRQL Irql, 736 IN ULONG Irq, 737 OUT PKIRQL OldIrql) 738 { 739 PIC_MASK Mask; 740 KIRQL CurrentIrql; 741 I8259_OCW2 Ocw2; 742 PKPCR Pcr = KeGetPcr(); 743 744 /* Update the PIC */ 745 Mask.Both = (KiI8259MaskTable[Irql] | Pcr->IDR) & 0xFFFF; 746 __outbyte(PIC1_DATA_PORT, Mask.Master); 747 __outbyte(PIC2_DATA_PORT, Mask.Slave); 748 749 /* Update the IRR so that we clear this interrupt when the IRQL is proper */ 750 Pcr->IRR |= (1 << (Irq + 4)); 751 752 /* Save current IRQL */ 753 CurrentIrql = Pcr->Irql; 754 755 /* Prepare OCW2 for EOI */ 756 Ocw2.Bits = 0; 757 Ocw2.EoiMode = SpecificEoi; 758 759 /* Check which PIC needs the EOI */ 760 if (Irq >= 8) 761 { 762 #if defined(SARCH_PC98) 763 I8259_OCW3 Ocw3; 764 I8259_ISR Isr; 765 766 /* Send the EOI for the IRQ */ 767 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF)); 768 769 /* Request the ISR */ 770 Ocw3.Bits = 0; 771 Ocw3.Sbo = 1; 772 Ocw3.ReadRequest = ReadIsr; 773 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits); 774 775 /* Read the ISR */ 776 Isr.Bits = __inbyte(PIC2_CONTROL_PORT); 777 778 /* Check if the interrupt serviced was the only one from the slave PIC */ 779 if (Isr.Bits == 0) 780 { 781 /* If ISR is empty, send the EOI for cascade IRQ on the master PIC */ 782 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ); 783 } 784 #else 785 /* Send the EOI for the IRQ */ 786 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF)); 787 788 /* Send the EOI for cascade IRQ on the master PIC */ 789 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ); 790 #endif 791 } 792 else 793 { 794 /* Send the EOI for the IRQ */ 795 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq & 0xFF)); 796 } 797 798 /* Check if this interrupt should be allowed to happen */ 799 if (Irql > CurrentIrql) 800 { 801 /* Set the new IRQL and return the current one */ 802 Pcr->Irql = Irql; 803 *OldIrql = CurrentIrql; 804 805 /* Enable interrupts and return success */ 806 _enable(); 807 return TRUE; 808 } 809 810 /* Now lie and say this was spurious */ 811 return FALSE; 812 } 813 814 BOOLEAN 815 NTAPI 816 HalpDismissIrqLevel(IN KIRQL Irql, 817 IN ULONG Irq, 818 OUT PKIRQL OldIrql) 819 { 820 /* Run the inline code */ 821 return _HalpDismissIrqLevel(Irql, Irq, OldIrql); 822 } 823 824 BOOLEAN 825 NTAPI 826 HalpDismissIrq15Level(IN KIRQL Irql, 827 IN ULONG Irq, 828 OUT PKIRQL OldIrql) 829 { 830 I8259_OCW3 Ocw3; 831 I8259_OCW2 Ocw2; 832 I8259_ISR Isr; 833 834 /* Request the ISR */ 835 Ocw3.Bits = 0; 836 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */ 837 Ocw3.ReadRequest = ReadIsr; 838 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits); 839 840 /* Read the ISR */ 841 Isr.Bits = __inbyte(PIC2_CONTROL_PORT); 842 843 /* Is IRQ15 really active (this is IR7) */ 844 if (Isr.Irq7 == FALSE) 845 { 846 /* It isn't, so we have to EOI cascade IRQ */ 847 Ocw2.Bits = 0; 848 Ocw2.EoiMode = SpecificEoi; 849 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ); 850 851 /* And now fail since this was spurious */ 852 return FALSE; 853 } 854 855 /* Do normal interrupt dismiss */ 856 return _HalpDismissIrqLevel(Irql, Irq, OldIrql); 857 } 858 859 BOOLEAN 860 NTAPI 861 HalpDismissIrq13Level(IN KIRQL Irql, 862 IN ULONG Irq, 863 OUT PKIRQL OldIrql) 864 { 865 /* Clear the FPU busy latch */ 866 __outbyte(0xF0, 0); 867 868 /* Do normal interrupt dismiss */ 869 return _HalpDismissIrqLevel(Irql, Irq, OldIrql); 870 } 871 872 #if defined(SARCH_PC98) 873 BOOLEAN 874 NTAPI 875 HalpDismissIrq08Level( 876 _In_ KIRQL Irql, 877 _In_ ULONG Irq, 878 _Out_ PKIRQL OldIrql) 879 { 880 /* Clear the FPU busy latch */ 881 __outbyte(CPU_IO_o_FPU_BUSY_LATCH, 0); 882 883 /* Do normal interrupt dismiss */ 884 return _HalpDismissIrqLevel(Irql, Irq, OldIrql); 885 } 886 #endif 887 888 BOOLEAN 889 NTAPI 890 HalpDismissIrq07Level(IN KIRQL Irql, 891 IN ULONG Irq, 892 OUT PKIRQL OldIrql) 893 { 894 I8259_OCW3 Ocw3; 895 I8259_ISR Isr; 896 897 /* Request the ISR */ 898 Ocw3.Bits = 0; 899 Ocw3.Sbo = 1; 900 Ocw3.ReadRequest = ReadIsr; 901 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits); 902 903 /* Read the ISR */ 904 Isr.Bits = __inbyte(PIC1_CONTROL_PORT); 905 906 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */ 907 if (Isr.Irq7 == FALSE) return FALSE; 908 909 /* Do normal interrupt dismiss */ 910 return _HalpDismissIrqLevel(Irql, Irq, OldIrql); 911 } 912 913 PHAL_SW_INTERRUPT_HANDLER 914 __cdecl 915 HalpHardwareInterruptLevel2(VOID) 916 { 917 PKPCR Pcr = KeGetPcr(); 918 ULONG PendingIrqlMask, PendingIrql; 919 920 /* Check for pending software interrupts and compare with current IRQL */ 921 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql]; 922 if (PendingIrqlMask) 923 { 924 /* Check for in-service delayed interrupt */ 925 if (Pcr->IrrActive & 0xFFFFFFF0) return NULL; 926 927 /* Check if pending IRQL affects hardware state */ 928 BitScanReverse(&PendingIrql, PendingIrqlMask); 929 930 /* Clear IRR bit */ 931 Pcr->IRR ^= (1 << PendingIrql); 932 933 /* Now handle pending interrupt */ 934 return SWInterruptHandlerTable[PendingIrql]; 935 } 936 937 return NULL; 938 } 939 940 /* SYSTEM INTERRUPTS **********************************************************/ 941 942 /* 943 * @implemented 944 */ 945 BOOLEAN 946 NTAPI 947 HalEnableSystemInterrupt(IN ULONG Vector, 948 IN KIRQL Irql, 949 IN KINTERRUPT_MODE InterruptMode) 950 { 951 ULONG Irq; 952 PKPCR Pcr = KeGetPcr(); 953 PIC_MASK PicMask; 954 955 /* Validate the IRQ */ 956 Irq = Vector - PRIMARY_VECTOR_BASE; 957 if (Irq >= CLOCK2_LEVEL) return FALSE; 958 959 /* Check for level interrupt */ 960 if (InterruptMode == LevelSensitive) 961 { 962 /* Switch handler to level */ 963 SWInterruptHandlerTable[Irq + 4] = HalpHardwareInterruptLevel; 964 965 /* Switch dismiss to level */ 966 HalpSpecialDismissTable[Irq] = HalpSpecialDismissLevelTable[Irq]; 967 } 968 969 /* Disable interrupts */ 970 _disable(); 971 972 /* Update software IDR */ 973 Pcr->IDR &= ~(1 << Irq); 974 975 /* Set new PIC mask */ 976 PicMask.Both = (KiI8259MaskTable[Pcr->Irql] | Pcr->IDR) & 0xFFFF; 977 __outbyte(PIC1_DATA_PORT, PicMask.Master); 978 __outbyte(PIC2_DATA_PORT, PicMask.Slave); 979 980 /* Enable interrupts and exit */ 981 _enable(); 982 return TRUE; 983 } 984 985 /* 986 * @implemented 987 */ 988 VOID 989 NTAPI 990 HalDisableSystemInterrupt(IN ULONG Vector, 991 IN KIRQL Irql) 992 { 993 ULONG IrqMask; 994 PIC_MASK PicMask; 995 996 /* Compute new combined IRQ mask */ 997 IrqMask = 1 << (Vector - PRIMARY_VECTOR_BASE); 998 999 /* Disable interrupts */ 1000 _disable(); 1001 1002 /* Update software IDR */ 1003 KeGetPcr()->IDR |= IrqMask; 1004 1005 /* Read current interrupt mask */ 1006 PicMask.Master = __inbyte(PIC1_DATA_PORT); 1007 PicMask.Slave = __inbyte(PIC2_DATA_PORT); 1008 1009 /* Add the new disabled interrupt */ 1010 PicMask.Both |= IrqMask; 1011 1012 /* Write new interrupt mask */ 1013 __outbyte(PIC1_DATA_PORT, PicMask.Master); 1014 __outbyte(PIC2_DATA_PORT, PicMask.Slave); 1015 1016 /* Bring interrupts back */ 1017 _enable(); 1018 } 1019 1020 /* 1021 * @implemented 1022 */ 1023 BOOLEAN 1024 NTAPI 1025 HalBeginSystemInterrupt(IN KIRQL Irql, 1026 IN ULONG Vector, 1027 OUT PKIRQL OldIrql) 1028 { 1029 ULONG Irq; 1030 1031 /* Get the IRQ and call the proper routine to handle it */ 1032 Irq = Vector - PRIMARY_VECTOR_BASE; 1033 return HalpSpecialDismissTable[Irq](Irql, Irq, OldIrql); 1034 } 1035 1036 /* 1037 * @implemented 1038 */ 1039 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY 1040 FASTCALL 1041 HalEndSystemInterrupt2(IN KIRQL OldIrql, 1042 IN PKTRAP_FRAME TrapFrame) 1043 { 1044 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask; 1045 PKPCR Pcr = KeGetPcr(); 1046 PIC_MASK Mask; 1047 1048 /* Set old IRQL */ 1049 Pcr->Irql = OldIrql; 1050 1051 /* Check for pending software interrupts and compare with current IRQL */ 1052 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql]; 1053 if (PendingIrqlMask) 1054 { 1055 /* Check for in-service delayed interrupt */ 1056 if (Pcr->IrrActive & 0xFFFFFFF0) return NULL; 1057 1058 /* Loop checking for pending interrupts */ 1059 while (TRUE) 1060 { 1061 /* Check if pending IRQL affects hardware state */ 1062 BitScanReverse(&PendingIrql, PendingIrqlMask); 1063 if (PendingIrql > DISPATCH_LEVEL) 1064 { 1065 /* Set new PIC mask */ 1066 Mask.Both = Pcr->IDR & 0xFFFF; 1067 __outbyte(PIC1_DATA_PORT, Mask.Master); 1068 __outbyte(PIC2_DATA_PORT, Mask.Slave); 1069 1070 /* Now check if this specific interrupt is already in-service */ 1071 PendingIrqMask = (1 << PendingIrql); 1072 if (Pcr->IrrActive & PendingIrqMask) return NULL; 1073 1074 /* Set active bit otherwise, and clear it from IRR */ 1075 Pcr->IrrActive |= PendingIrqMask; 1076 Pcr->IRR ^= PendingIrqMask; 1077 1078 /* Handle delayed hardware interrupt */ 1079 SWInterruptHandlerTable[PendingIrql](); 1080 1081 /* Handling complete */ 1082 Pcr->IrrActive ^= PendingIrqMask; 1083 1084 /* Check if there's still interrupts pending */ 1085 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql]; 1086 if (!PendingIrqlMask) break; 1087 } 1088 else 1089 { 1090 /* Now handle pending software interrupt */ 1091 return SWInterruptHandlerTable2[PendingIrql]; 1092 } 1093 } 1094 } 1095 1096 return NULL; 1097 } 1098 1099 /* SOFTWARE INTERRUPT TRAPS ***************************************************/ 1100 1101 FORCEINLINE 1102 DECLSPEC_NORETURN 1103 VOID 1104 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) 1105 { 1106 KIRQL CurrentIrql; 1107 PKPCR Pcr = KeGetPcr(); 1108 1109 /* Save the current IRQL and update it */ 1110 CurrentIrql = Pcr->Irql; 1111 Pcr->Irql = APC_LEVEL; 1112 1113 /* Remove DPC from IRR */ 1114 Pcr->IRR &= ~(1 << APC_LEVEL); 1115 1116 /* Enable interrupts and call the kernel's APC interrupt handler */ 1117 _enable(); 1118 KiDeliverApc(((KiUserTrap(TrapFrame)) || (TrapFrame->EFlags & EFLAGS_V86_MASK)) ? 1119 UserMode : KernelMode, 1120 NULL, 1121 TrapFrame); 1122 1123 /* Disable interrupts and end the interrupt */ 1124 _disable(); 1125 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame); 1126 1127 /* Exit the interrupt */ 1128 KiEoiHelper(TrapFrame); 1129 } 1130 1131 DECLSPEC_NORETURN 1132 VOID 1133 FASTCALL 1134 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame) 1135 { 1136 /* Do the work */ 1137 _HalpApcInterruptHandler(TrapFrame); 1138 } 1139 1140 DECLSPEC_NORETURN 1141 VOID 1142 FASTCALL 1143 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) 1144 { 1145 /* Set up a fake INT Stack */ 1146 TrapFrame->EFlags = __readeflags(); 1147 TrapFrame->SegCs = KGDT_R0_CODE; 1148 TrapFrame->Eip = TrapFrame->Eax; 1149 1150 /* Build the trap frame */ 1151 KiEnterInterruptTrap(TrapFrame); 1152 1153 /* Do the work */ 1154 _HalpApcInterruptHandler(TrapFrame); 1155 } 1156 1157 FORCEINLINE 1158 KIRQL 1159 _HalpDispatchInterruptHandler(VOID) 1160 { 1161 KIRQL CurrentIrql; 1162 PKPCR Pcr = KeGetPcr(); 1163 1164 /* Save the current IRQL and update it */ 1165 CurrentIrql = Pcr->Irql; 1166 Pcr->Irql = DISPATCH_LEVEL; 1167 1168 /* Remove DPC from IRR */ 1169 Pcr->IRR &= ~(1 << DISPATCH_LEVEL); 1170 1171 /* Enable interrupts and call the kernel's DPC interrupt handler */ 1172 _enable(); 1173 KiDispatchInterrupt(); 1174 _disable(); 1175 1176 /* Return IRQL */ 1177 return CurrentIrql; 1178 } 1179 1180 DECLSPEC_NORETURN 1181 VOID 1182 FASTCALL 1183 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame) 1184 { 1185 KIRQL CurrentIrql; 1186 1187 /* Do the work */ 1188 CurrentIrql = _HalpDispatchInterruptHandler(); 1189 1190 /* End the interrupt */ 1191 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame); 1192 1193 /* Exit the interrupt */ 1194 KiEoiHelper(TrapFrame); 1195 } 1196 1197 PHAL_SW_INTERRUPT_HANDLER 1198 __cdecl 1199 HalpDispatchInterrupt2(VOID) 1200 { 1201 ULONG PendingIrqlMask, PendingIrql; 1202 KIRQL OldIrql; 1203 PIC_MASK Mask; 1204 PKPCR Pcr = KeGetPcr(); 1205 1206 /* Do the work */ 1207 OldIrql = _HalpDispatchInterruptHandler(); 1208 1209 /* Restore IRQL */ 1210 Pcr->Irql = OldIrql; 1211 1212 /* Check for pending software interrupts and compare with current IRQL */ 1213 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql]; 1214 if (PendingIrqlMask) 1215 { 1216 /* Check if pending IRQL affects hardware state */ 1217 BitScanReverse(&PendingIrql, PendingIrqlMask); 1218 if (PendingIrql > DISPATCH_LEVEL) 1219 { 1220 /* Set new PIC mask */ 1221 Mask.Both = Pcr->IDR & 0xFFFF; 1222 __outbyte(PIC1_DATA_PORT, Mask.Master); 1223 __outbyte(PIC2_DATA_PORT, Mask.Slave); 1224 1225 /* Clear IRR bit */ 1226 Pcr->IRR ^= (1 << PendingIrql); 1227 } 1228 1229 /* Now handle pending interrupt */ 1230 return SWInterruptHandlerTable[PendingIrql]; 1231 } 1232 1233 return NULL; 1234 } 1235 1236 ULONG 1237 NTAPI 1238 HalpGetRootInterruptVector(IN ULONG BusInterruptLevel, 1239 IN ULONG BusInterruptVector, 1240 OUT PKIRQL Irql, 1241 OUT PKAFFINITY Affinity) 1242 { 1243 UCHAR SystemVector; 1244 1245 /* Validate the IRQ */ 1246 if (BusInterruptLevel > 23) 1247 { 1248 /* Invalid vector */ 1249 DPRINT1("IRQ %lx is too high!\n", BusInterruptLevel); 1250 return 0; 1251 } 1252 1253 /* Get the system vector */ 1254 SystemVector = HalpIrqToVector((UCHAR)BusInterruptLevel); 1255 1256 /* Return the IRQL and affinity */ 1257 *Irql = HalpVectorToIrql(SystemVector); 1258 *Affinity = HalpDefaultInterruptAffinity; 1259 ASSERT(HalpDefaultInterruptAffinity); 1260 1261 /* Return the vector */ 1262 return SystemVector; 1263 } 1264 1265 #else /* _MINIHAL_ */ 1266 1267 KIRQL 1268 NTAPI 1269 KeGetCurrentIrql(VOID) 1270 { 1271 return PASSIVE_LEVEL; 1272 } 1273 1274 VOID 1275 FASTCALL 1276 KfLowerIrql( 1277 IN KIRQL OldIrql) 1278 { 1279 } 1280 1281 KIRQL 1282 FASTCALL 1283 KfRaiseIrql( 1284 IN KIRQL NewIrql) 1285 { 1286 return NewIrql; 1287 } 1288 1289 #endif /* !_MINIHAL_ */ 1290