1 /* 2 * PROJECT: ReactOS HAL 3 * LICENSE: GNU GPL - See COPYING in the top level directory 4 * FILE: hal/halx86/apic/apic.c 5 * PURPOSE: HAL APIC Management and Control Code 6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) 7 * REFERENCES: https://web.archive.org/web/20190407074221/http://www.joseflores.com/docs/ExploringIrql.html 8 * http://www.codeproject.com/KB/system/soviet_kernel_hack.aspx 9 * http://bbs.unixmap.net/thread-2022-1-1.html 10 * https://www.codemachine.com/article_interruptdispatching.html 11 * https://www.osronline.com/article.cfm%5Earticle=211.htm 12 */ 13 14 /* INCLUDES *******************************************************************/ 15 16 #include <hal.h> 17 #include "apicp.h" 18 #define NDEBUG 19 #include <debug.h> 20 21 #ifndef _M_AMD64 22 #define APIC_LAZY_IRQL 23 #endif 24 25 /* GLOBALS ********************************************************************/ 26 27 ULONG ApicVersion; 28 UCHAR HalpVectorToIndex[256]; 29 30 #ifndef _M_AMD64 31 const UCHAR 32 HalpIRQLtoTPR[32] = 33 { 34 0x00, /* 0 PASSIVE_LEVEL */ 35 0x3d, /* 1 APC_LEVEL */ 36 0x41, /* 2 DISPATCH_LEVEL */ 37 0x41, /* 3 \ */ 38 0x51, /* 4 \ */ 39 0x61, /* 5 | */ 40 0x71, /* 6 | */ 41 0x81, /* 7 | */ 42 0x91, /* 8 | */ 43 0xa1, /* 9 | */ 44 0xb1, /* 10 | */ 45 0xb1, /* 11 | */ 46 0xb1, /* 12 | */ 47 0xb1, /* 13 | */ 48 0xb1, /* 14 | */ 49 0xb1, /* 15 DEVICE IRQL */ 50 0xb1, /* 16 | */ 51 0xb1, /* 17 | */ 52 0xb1, /* 18 | */ 53 0xb1, /* 19 | */ 54 0xb1, /* 20 | */ 55 0xb1, /* 21 | */ 56 0xb1, /* 22 | */ 57 0xb1, /* 23 | */ 58 0xb1, /* 24 | */ 59 0xb1, /* 25 / */ 60 0xb1, /* 26 / */ 61 0xc1, /* 27 PROFILE_LEVEL */ 62 0xd1, /* 28 CLOCK2_LEVEL */ 63 0xe1, /* 29 IPI_LEVEL */ 64 0xef, /* 30 POWER_LEVEL */ 65 0xff, /* 31 HIGH_LEVEL */ 66 }; 67 68 const KIRQL 69 HalVectorToIRQL[16] = 70 { 71 0, /* 00 PASSIVE_LEVEL */ 72 0xff, /* 10 */ 73 0xff, /* 20 */ 74 1, /* 3D APC_LEVEL */ 75 2, /* 41 DISPATCH_LEVEL */ 76 4, /* 50 \ */ 77 5, /* 60 \ */ 78 6, /* 70 | */ 79 7, /* 80 DEVICE IRQL */ 80 8, /* 90 | */ 81 9, /* A0 / */ 82 10, /* B0 / */ 83 27, /* C1 PROFILE_LEVEL */ 84 28, /* D1 CLOCK2_LEVEL */ 85 29, /* E1 IPI_LEVEL / EF POWER_LEVEL */ 86 31, /* FF HIGH_LEVEL */ 87 }; 88 #endif 89 90 /* PRIVATE FUNCTIONS **********************************************************/ 91 92 FORCEINLINE 93 ULONG 94 IOApicRead(UCHAR Register) 95 { 96 /* Select the register, then do the read */ 97 ASSERT(Register <= 0x3F); 98 WRITE_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOREGSEL), Register); 99 return READ_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOWIN)); 100 } 101 102 FORCEINLINE 103 VOID 104 IOApicWrite(UCHAR Register, ULONG Value) 105 { 106 /* Select the register, then do the write */ 107 ASSERT(Register <= 0x3F); 108 WRITE_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOREGSEL), Register); 109 WRITE_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOWIN), Value); 110 } 111 112 FORCEINLINE 113 VOID 114 ApicWriteIORedirectionEntry( 115 UCHAR Index, 116 IOAPIC_REDIRECTION_REGISTER ReDirReg) 117 { 118 ASSERT(Index < APIC_MAX_IRQ); 119 IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0); 120 IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1); 121 } 122 123 FORCEINLINE 124 IOAPIC_REDIRECTION_REGISTER 125 ApicReadIORedirectionEntry( 126 UCHAR Index) 127 { 128 IOAPIC_REDIRECTION_REGISTER ReDirReg; 129 130 ASSERT(Index < APIC_MAX_IRQ); 131 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index); 132 ReDirReg.Long1 = IOApicRead(IOAPIC_REDTBL + 2 * Index + 1); 133 134 return ReDirReg; 135 } 136 137 FORCEINLINE 138 VOID 139 ApicRequestSelfInterrupt(IN UCHAR Vector, UCHAR TriggerMode) 140 { 141 ULONG Flags; 142 APIC_INTERRUPT_COMMAND_REGISTER Icr; 143 APIC_INTERRUPT_COMMAND_REGISTER IcrStatus; 144 145 /* 146 * The IRR registers are spaced 16 bytes apart and hold 32 status bits each. 147 * Pre-compute the register and bit that match our vector. 148 */ 149 ULONG VectorHigh = Vector / 32; 150 ULONG VectorLow = Vector % 32; 151 ULONG Irr = APIC_IRR + 0x10 * VectorHigh; 152 ULONG IrrBit = 1UL << VectorLow; 153 154 /* Setup the command register */ 155 Icr.Long0 = 0; 156 Icr.Vector = Vector; 157 Icr.MessageType = APIC_MT_Fixed; 158 Icr.TriggerMode = TriggerMode; 159 Icr.DestinationShortHand = APIC_DSH_Self; 160 161 /* Disable interrupts so that we can change IRR without being interrupted */ 162 Flags = __readeflags(); 163 _disable(); 164 165 /* Wait for the APIC to be idle */ 166 do 167 { 168 IcrStatus.Long0 = ApicRead(APIC_ICR0); 169 } while (IcrStatus.DeliveryStatus); 170 171 /* Write the low dword to send the interrupt */ 172 ApicWrite(APIC_ICR0, Icr.Long0); 173 174 /* Wait until we see the interrupt request. 175 * It will stay in requested state until we re-enable interrupts. 176 */ 177 while (!(ApicRead(Irr) & IrrBit)) 178 { 179 NOTHING; 180 } 181 182 /* Finally, restore the original interrupt state */ 183 if (Flags & EFLAGS_INTERRUPT_MASK) 184 { 185 _enable(); 186 } 187 } 188 189 FORCEINLINE 190 VOID 191 ApicSendEOI(void) 192 { 193 ApicWrite(APIC_EOI, 0); 194 } 195 196 FORCEINLINE 197 KIRQL 198 ApicGetProcessorIrql(VOID) 199 { 200 /* Read the TPR and convert it to an IRQL */ 201 return TprToIrql(ApicRead(APIC_PPR)); 202 } 203 204 FORCEINLINE 205 KIRQL 206 ApicGetCurrentIrql(VOID) 207 { 208 #ifdef _M_AMD64 209 return (KIRQL)__readcr8(); 210 #elif defined(APIC_LAZY_IRQL) 211 /* Return the field in the PCR */ 212 return (KIRQL)__readfsbyte(FIELD_OFFSET(KPCR, Irql)); 213 #else 214 /* Read the TPR and convert it to an IRQL */ 215 return TprToIrql(ApicRead(APIC_TPR)); 216 #endif 217 } 218 219 FORCEINLINE 220 VOID 221 ApicSetIrql(KIRQL Irql) 222 { 223 #ifdef _M_AMD64 224 __writecr8(Irql); 225 #elif defined(APIC_LAZY_IRQL) 226 __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); 227 #else 228 /* Convert IRQL and write the TPR */ 229 ApicWrite(APIC_TPR, IrqlToTpr(Irql)); 230 #endif 231 } 232 #define ApicRaiseIrql ApicSetIrql 233 234 #ifdef APIC_LAZY_IRQL 235 FORCEINLINE 236 VOID 237 ApicLowerIrql(KIRQL Irql) 238 { 239 __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); 240 241 /* Is the new Irql lower than set in the TPR? */ 242 if (Irql < KeGetPcr()->IRR) 243 { 244 /* Save the new hard IRQL in the IRR field */ 245 KeGetPcr()->IRR = Irql; 246 247 /* Need to lower it back */ 248 ApicWrite(APIC_TPR, IrqlToTpr(Irql)); 249 } 250 } 251 #else 252 #define ApicLowerIrql ApicSetIrql 253 #endif 254 255 UCHAR 256 FASTCALL 257 HalpIrqToVector(UCHAR Irq) 258 { 259 IOAPIC_REDIRECTION_REGISTER ReDirReg; 260 261 /* Read low dword of the redirection entry */ 262 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Irq); 263 264 /* Return the vector */ 265 return (UCHAR)ReDirReg.Vector; 266 } 267 268 KIRQL 269 FASTCALL 270 HalpVectorToIrql(UCHAR Vector) 271 { 272 return TprToIrql(Vector); 273 } 274 275 UCHAR 276 FASTCALL 277 HalpVectorToIrq(UCHAR Vector) 278 { 279 return HalpVectorToIndex[Vector]; 280 } 281 282 VOID 283 NTAPI 284 HalpSendEOI(VOID) 285 { 286 ApicSendEOI(); 287 } 288 289 VOID 290 NTAPI 291 ApicInitializeLocalApic(ULONG Cpu) 292 { 293 APIC_BASE_ADDRESS_REGISTER BaseRegister; 294 APIC_SPURIOUS_INERRUPT_REGISTER SpIntRegister; 295 LVT_REGISTER LvtEntry; 296 297 /* Enable the APIC if it wasn't yet */ 298 BaseRegister.LongLong = __readmsr(MSR_APIC_BASE); 299 BaseRegister.Enable = 1; 300 BaseRegister.BootStrapCPUCore = (Cpu == 0); 301 __writemsr(MSR_APIC_BASE, BaseRegister.LongLong); 302 303 /* Set spurious vector and SoftwareEnable to 1 */ 304 SpIntRegister.Long = ApicRead(APIC_SIVR); 305 SpIntRegister.Vector = APIC_SPURIOUS_VECTOR; 306 SpIntRegister.SoftwareEnable = 1; 307 SpIntRegister.FocusCPUCoreChecking = 0; 308 ApicWrite(APIC_SIVR, SpIntRegister.Long); 309 310 /* Read the version and save it globally */ 311 if (Cpu == 0) ApicVersion = ApicRead(APIC_VER); 312 313 /* Set the mode to flat (max 8 CPUs supported!) */ 314 ApicWrite(APIC_DFR, APIC_DF_Flat); 315 316 /* Set logical apic ID */ 317 ApicWrite(APIC_LDR, ApicLogicalId(Cpu) << 24); 318 319 /* Set the spurious ISR */ 320 KeRegisterInterruptHandler(APIC_SPURIOUS_VECTOR, ApicSpuriousService); 321 322 /* Create a template LVT */ 323 LvtEntry.Long = 0; 324 LvtEntry.Vector = APIC_FREE_VECTOR; 325 LvtEntry.MessageType = APIC_MT_Fixed; 326 LvtEntry.DeliveryStatus = 0; 327 LvtEntry.RemoteIRR = 0; 328 LvtEntry.TriggerMode = APIC_TGM_Edge; 329 LvtEntry.Mask = 1; 330 LvtEntry.TimerMode = 0; 331 332 /* Initialize and mask LVTs */ 333 ApicWrite(APIC_TMRLVTR, LvtEntry.Long); 334 ApicWrite(APIC_THRMLVTR, LvtEntry.Long); 335 ApicWrite(APIC_PCLVTR, LvtEntry.Long); 336 ApicWrite(APIC_EXT0LVTR, LvtEntry.Long); 337 ApicWrite(APIC_EXT1LVTR, LvtEntry.Long); 338 ApicWrite(APIC_EXT2LVTR, LvtEntry.Long); 339 ApicWrite(APIC_EXT3LVTR, LvtEntry.Long); 340 341 /* LINT0 */ 342 LvtEntry.Vector = APIC_SPURIOUS_VECTOR; 343 LvtEntry.MessageType = APIC_MT_ExtInt; 344 ApicWrite(APIC_LINT0, LvtEntry.Long); 345 346 /* Enable LINT1 (NMI) */ 347 LvtEntry.Mask = 0; 348 LvtEntry.Vector = APIC_NMI_VECTOR; 349 LvtEntry.MessageType = APIC_MT_NMI; 350 LvtEntry.TriggerMode = APIC_TGM_Level; 351 ApicWrite(APIC_LINT1, LvtEntry.Long); 352 353 /* Enable error LVTR */ 354 LvtEntry.Vector = APIC_ERROR_VECTOR; 355 LvtEntry.MessageType = APIC_MT_Fixed; 356 ApicWrite(APIC_ERRLVTR, LvtEntry.Long); 357 358 /* Set the IRQL from the PCR */ 359 ApicSetIrql(KeGetPcr()->Irql); 360 #ifdef APIC_LAZY_IRQL 361 /* Save the new hard IRQL in the IRR field */ 362 KeGetPcr()->IRR = KeGetPcr()->Irql; 363 #endif 364 } 365 366 UCHAR 367 NTAPI 368 HalpAllocateSystemInterrupt( 369 _In_ UCHAR Irq, 370 _In_ UCHAR Vector) 371 { 372 IOAPIC_REDIRECTION_REGISTER ReDirReg; 373 374 ASSERT(Irq < APIC_MAX_IRQ); 375 ASSERT(HalpVectorToIndex[Vector] == APIC_FREE_VECTOR); 376 377 /* Setup a redirection entry */ 378 ReDirReg.Vector = Vector; 379 ReDirReg.DeliveryMode = APIC_MT_LowestPriority; 380 ReDirReg.DestinationMode = APIC_DM_Logical; 381 ReDirReg.DeliveryStatus = 0; 382 ReDirReg.Polarity = 0; 383 ReDirReg.RemoteIRR = 0; 384 ReDirReg.TriggerMode = APIC_TGM_Edge; 385 ReDirReg.Mask = 1; 386 ReDirReg.Reserved = 0; 387 ReDirReg.Destination = 0; 388 389 /* Initialize entry */ 390 ApicWriteIORedirectionEntry(Irq, ReDirReg); 391 392 /* Save irq in the table */ 393 HalpVectorToIndex[Vector] = Irq; 394 395 return Vector; 396 } 397 398 ULONG 399 NTAPI 400 HalpGetRootInterruptVector( 401 _In_ ULONG BusInterruptLevel, 402 _In_ ULONG BusInterruptVector, 403 _Out_ PKIRQL OutIrql, 404 _Out_ PKAFFINITY OutAffinity) 405 { 406 UCHAR Vector; 407 KIRQL Irql; 408 409 /* Get the vector currently registered */ 410 Vector = HalpIrqToVector(BusInterruptLevel); 411 412 /* Check if it's used */ 413 if (Vector != APIC_FREE_VECTOR) 414 { 415 /* Calculate IRQL */ 416 NT_ASSERT(HalpVectorToIndex[Vector] == BusInterruptLevel); 417 *OutIrql = HalpVectorToIrql(Vector); 418 } 419 else 420 { 421 ULONG Offset; 422 423 /* Outer loop to find alternative slots, when all IRQLs are in use */ 424 for (Offset = 0; Offset < 15; Offset++) 425 { 426 /* Loop allowed IRQL range */ 427 for (Irql = CLOCK_LEVEL - 1; Irql >= CMCI_LEVEL; Irql--) 428 { 429 /* Calculate the vactor */ 430 Vector = IrqlToTpr(Irql) + Offset; 431 432 /* Check if the vector is free */ 433 if (HalpVectorToIrq(Vector) == APIC_FREE_VECTOR) 434 { 435 /* Found one, allocate the interrupt */ 436 Vector = HalpAllocateSystemInterrupt(BusInterruptLevel, Vector); 437 *OutIrql = Irql; 438 goto Exit; 439 } 440 } 441 } 442 443 DPRINT1("Failed to get an interrupt vector for IRQ %lu\n", BusInterruptLevel); 444 *OutAffinity = 0; 445 *OutIrql = 0; 446 return 0; 447 } 448 449 Exit: 450 451 *OutAffinity = HalpDefaultInterruptAffinity; 452 ASSERT(HalpDefaultInterruptAffinity); 453 454 return Vector; 455 } 456 457 VOID 458 NTAPI 459 ApicInitializeIOApic(VOID) 460 { 461 PHARDWARE_PTE Pte; 462 IOAPIC_REDIRECTION_REGISTER ReDirReg; 463 UCHAR Index; 464 ULONG Vector; 465 466 /* Map the I/O Apic page */ 467 Pte = HalAddressToPte(IOAPIC_BASE); 468 Pte->PageFrameNumber = IOAPIC_PHYS_BASE / PAGE_SIZE; 469 Pte->Valid = 1; 470 Pte->Write = 1; 471 Pte->Owner = 1; 472 Pte->CacheDisable = 1; 473 Pte->Global = 1; 474 _ReadWriteBarrier(); 475 476 /* Setup a redirection entry */ 477 ReDirReg.Vector = APIC_FREE_VECTOR; 478 ReDirReg.DeliveryMode = APIC_MT_Fixed; 479 ReDirReg.DestinationMode = APIC_DM_Physical; 480 ReDirReg.DeliveryStatus = 0; 481 ReDirReg.Polarity = 0; 482 ReDirReg.RemoteIRR = 0; 483 ReDirReg.TriggerMode = APIC_TGM_Edge; 484 ReDirReg.Mask = 1; 485 ReDirReg.Reserved = 0; 486 ReDirReg.Destination = 0; 487 488 /* Loop all table entries */ 489 for (Index = 0; Index < APIC_MAX_IRQ; Index++) 490 { 491 /* Initialize entry */ 492 ApicWriteIORedirectionEntry(Index, ReDirReg); 493 } 494 495 /* Init the vactor to index table */ 496 for (Vector = 0; Vector <= 255; Vector++) 497 { 498 HalpVectorToIndex[Vector] = APIC_FREE_VECTOR; 499 } 500 501 /* Enable the timer interrupt (but keep it masked) */ 502 ReDirReg.Vector = APIC_CLOCK_VECTOR; 503 ReDirReg.DeliveryMode = APIC_MT_Fixed; 504 ReDirReg.DestinationMode = APIC_DM_Physical; 505 ReDirReg.TriggerMode = APIC_TGM_Edge; 506 ReDirReg.Mask = 1; 507 ReDirReg.Destination = ApicRead(APIC_ID); 508 ApicWriteIORedirectionEntry(APIC_CLOCK_INDEX, ReDirReg); 509 } 510 511 VOID 512 NTAPI 513 HalpInitializePICs(IN BOOLEAN EnableInterrupts) 514 { 515 ULONG_PTR EFlags; 516 517 /* Save EFlags and disable interrupts */ 518 EFlags = __readeflags(); 519 _disable(); 520 521 /* Initialize and mask the PIC */ 522 HalpInitializeLegacyPICs(); 523 524 /* Initialize the I/O APIC */ 525 ApicInitializeIOApic(); 526 527 /* Manually reserve some vectors */ 528 HalpVectorToIndex[APC_VECTOR] = APIC_RESERVED_VECTOR; 529 HalpVectorToIndex[DISPATCH_VECTOR] = APIC_RESERVED_VECTOR; 530 HalpVectorToIndex[APIC_CLOCK_VECTOR] = 8; 531 HalpVectorToIndex[APIC_SPURIOUS_VECTOR] = APIC_RESERVED_VECTOR; 532 533 /* Set interrupt handlers in the IDT */ 534 KeRegisterInterruptHandler(APIC_CLOCK_VECTOR, HalpClockInterrupt); 535 #ifndef _M_AMD64 536 KeRegisterInterruptHandler(APC_VECTOR, HalpApcInterrupt); 537 KeRegisterInterruptHandler(DISPATCH_VECTOR, HalpDispatchInterrupt); 538 #endif 539 540 /* Register the vectors for APC and dispatch interrupts */ 541 HalpRegisterVector(IDT_INTERNAL, 0, APC_VECTOR, APC_LEVEL); 542 HalpRegisterVector(IDT_INTERNAL, 0, DISPATCH_VECTOR, DISPATCH_LEVEL); 543 544 /* Restore interrupt state */ 545 if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK; 546 __writeeflags(EFlags); 547 } 548 549 550 /* SOFTWARE INTERRUPT TRAPS ***************************************************/ 551 552 #ifndef _M_AMD64 553 VOID 554 DECLSPEC_NORETURN 555 FASTCALL 556 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) 557 { 558 KPROCESSOR_MODE ProcessorMode; 559 KIRQL OldIrql; 560 ASSERT(ApicGetProcessorIrql() == APC_LEVEL); 561 562 /* Enter trap */ 563 KiEnterInterruptTrap(TrapFrame); 564 565 #ifdef APIC_LAZY_IRQL 566 if (!HalBeginSystemInterrupt(APC_LEVEL, APC_VECTOR, &OldIrql)) 567 { 568 /* "Spurious" interrupt, exit the interrupt */ 569 KiEoiHelper(TrapFrame); 570 } 571 #else 572 /* Save the old IRQL */ 573 OldIrql = ApicGetCurrentIrql(); 574 ASSERT(OldIrql < APC_LEVEL); 575 #endif 576 577 /* Raise to APC_LEVEL */ 578 ApicRaiseIrql(APC_LEVEL); 579 580 /* End the interrupt */ 581 ApicSendEOI(); 582 583 /* Kernel or user APC? */ 584 if (KiUserTrap(TrapFrame)) ProcessorMode = UserMode; 585 else if (TrapFrame->EFlags & EFLAGS_V86_MASK) ProcessorMode = UserMode; 586 else ProcessorMode = KernelMode; 587 588 /* Enable interrupts and call the kernel's APC interrupt handler */ 589 _enable(); 590 KiDeliverApc(ProcessorMode, NULL, TrapFrame); 591 592 /* Disable interrupts */ 593 _disable(); 594 595 /* Restore the old IRQL */ 596 ApicLowerIrql(OldIrql); 597 598 /* Exit the interrupt */ 599 KiEoiHelper(TrapFrame); 600 } 601 602 VOID 603 DECLSPEC_NORETURN 604 FASTCALL 605 HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame) 606 { 607 KIRQL OldIrql; 608 ASSERT(ApicGetProcessorIrql() == DISPATCH_LEVEL); 609 610 /* Enter trap */ 611 KiEnterInterruptTrap(TrapFrame); 612 613 #ifdef APIC_LAZY_IRQL 614 if (!HalBeginSystemInterrupt(DISPATCH_LEVEL, DISPATCH_VECTOR, &OldIrql)) 615 { 616 /* "Spurious" interrupt, exit the interrupt */ 617 KiEoiHelper(TrapFrame); 618 } 619 #else 620 /* Get the current IRQL */ 621 OldIrql = ApicGetCurrentIrql(); 622 ASSERT(OldIrql < DISPATCH_LEVEL); 623 #endif 624 625 /* Raise to DISPATCH_LEVEL */ 626 ApicRaiseIrql(DISPATCH_LEVEL); 627 628 /* End the interrupt */ 629 ApicSendEOI(); 630 631 /* Enable interrupts and call the kernel's DPC interrupt handler */ 632 _enable(); 633 KiDispatchInterrupt(); 634 _disable(); 635 636 /* Restore the old IRQL */ 637 ApicLowerIrql(OldIrql); 638 639 /* Exit the interrupt */ 640 KiEoiHelper(TrapFrame); 641 } 642 #endif 643 644 645 /* SOFTWARE INTERRUPTS ********************************************************/ 646 647 648 VOID 649 FASTCALL 650 HalRequestSoftwareInterrupt(IN KIRQL Irql) 651 { 652 /* Convert irql to vector and request an interrupt */ 653 ApicRequestSelfInterrupt(IrqlToSoftVector(Irql), APIC_TGM_Edge); 654 } 655 656 VOID 657 FASTCALL 658 HalClearSoftwareInterrupt( 659 IN KIRQL Irql) 660 { 661 /* Nothing to do */ 662 } 663 664 665 /* SYSTEM INTERRUPTS **********************************************************/ 666 667 BOOLEAN 668 NTAPI 669 HalEnableSystemInterrupt( 670 IN ULONG Vector, 671 IN KIRQL Irql, 672 IN KINTERRUPT_MODE InterruptMode) 673 { 674 IOAPIC_REDIRECTION_REGISTER ReDirReg; 675 PKPRCB Prcb = KeGetCurrentPrcb(); 676 UCHAR Index; 677 ASSERT(Irql <= HIGH_LEVEL); 678 ASSERT((IrqlToTpr(Irql) & 0xF0) == (Vector & 0xF0)); 679 680 /* Get the irq for this vector */ 681 Index = HalpVectorToIndex[Vector]; 682 683 /* Check if its valid */ 684 if (Index == APIC_FREE_VECTOR) 685 { 686 /* Interrupt is not in use */ 687 return FALSE; 688 } 689 690 /* Read the redirection entry */ 691 ReDirReg = ApicReadIORedirectionEntry(Index); 692 693 /* Check if the interrupt was unused */ 694 if (ReDirReg.Vector != Vector) 695 { 696 ReDirReg.Vector = Vector; 697 ReDirReg.DeliveryMode = APIC_MT_LowestPriority; 698 ReDirReg.DestinationMode = APIC_DM_Logical; 699 ReDirReg.Destination = 0; 700 } 701 702 /* Check if the destination is logical */ 703 if (ReDirReg.DestinationMode == APIC_DM_Logical) 704 { 705 /* Set the bit for this cpu */ 706 ReDirReg.Destination |= ApicLogicalId(Prcb->Number); 707 } 708 709 /* Set the trigger mode */ 710 ReDirReg.TriggerMode = 1 - InterruptMode; 711 712 /* Now unmask it */ 713 ReDirReg.Mask = FALSE; 714 715 /* Write back the entry */ 716 ApicWriteIORedirectionEntry(Index, ReDirReg); 717 718 return TRUE; 719 } 720 721 VOID 722 NTAPI 723 HalDisableSystemInterrupt( 724 IN ULONG Vector, 725 IN KIRQL Irql) 726 { 727 IOAPIC_REDIRECTION_REGISTER ReDirReg; 728 UCHAR Index; 729 ASSERT(Irql <= HIGH_LEVEL); 730 ASSERT(Vector < RTL_NUMBER_OF(HalpVectorToIndex)); 731 732 Index = HalpVectorToIndex[Vector]; 733 734 /* Read lower dword of redirection entry */ 735 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index); 736 737 /* Mask it */ 738 ReDirReg.Mask = 1; 739 740 /* Write back lower dword */ 741 IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0); 742 } 743 744 #ifndef _M_AMD64 745 BOOLEAN 746 NTAPI 747 HalBeginSystemInterrupt( 748 IN KIRQL Irql, 749 IN ULONG Vector, 750 OUT PKIRQL OldIrql) 751 { 752 KIRQL CurrentIrql; 753 754 /* Get the current IRQL */ 755 CurrentIrql = ApicGetCurrentIrql(); 756 757 #ifdef APIC_LAZY_IRQL 758 /* Check if this interrupt is allowed */ 759 if (CurrentIrql >= Irql) 760 { 761 IOAPIC_REDIRECTION_REGISTER RedirReg; 762 UCHAR Index; 763 764 /* It is not, set the real Irql in the TPR! */ 765 ApicWrite(APIC_TPR, IrqlToTpr(CurrentIrql)); 766 767 /* Save the new hard IRQL in the IRR field */ 768 KeGetPcr()->IRR = CurrentIrql; 769 770 /* End this interrupt */ 771 ApicSendEOI(); 772 773 /* Get the irq for this vector */ 774 Index = HalpVectorToIndex[Vector]; 775 776 /* Check if it's valid */ 777 if (Index < APIC_MAX_IRQ) 778 { 779 /* Read the I/O redirection entry */ 780 RedirReg = ApicReadIORedirectionEntry(Index); 781 782 /* Re-request the interrupt to be handled later */ 783 ApicRequestSelfInterrupt(Vector, (UCHAR)RedirReg.TriggerMode); 784 } 785 else 786 { 787 /* This should be a reserved vector! */ 788 ASSERT(Index == APIC_RESERVED_VECTOR); 789 790 /* Re-request the interrupt to be handled later */ 791 ApicRequestSelfInterrupt(Vector, APIC_TGM_Edge); 792 } 793 794 /* Pretend it was a spurious interrupt */ 795 return FALSE; 796 } 797 #endif 798 /* Save the current IRQL */ 799 *OldIrql = CurrentIrql; 800 801 /* Set the new IRQL */ 802 ApicRaiseIrql(Irql); 803 804 /* Turn on interrupts */ 805 _enable(); 806 807 /* Success */ 808 return TRUE; 809 } 810 811 VOID 812 NTAPI 813 HalEndSystemInterrupt( 814 IN KIRQL OldIrql, 815 IN PKTRAP_FRAME TrapFrame) 816 { 817 /* Send an EOI */ 818 ApicSendEOI(); 819 820 /* Restore the old IRQL */ 821 ApicLowerIrql(OldIrql); 822 } 823 824 825 /* IRQL MANAGEMENT ************************************************************/ 826 827 KIRQL 828 NTAPI 829 KeGetCurrentIrql(VOID) 830 { 831 /* Read the current TPR and convert it to an IRQL */ 832 return ApicGetCurrentIrql(); 833 } 834 835 VOID 836 FASTCALL 837 KfLowerIrql( 838 IN KIRQL OldIrql) 839 { 840 #if DBG 841 /* Validate correct lower */ 842 if (OldIrql > ApicGetCurrentIrql()) 843 { 844 /* Crash system */ 845 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); 846 } 847 #endif 848 /* Set the new IRQL */ 849 ApicLowerIrql(OldIrql); 850 } 851 852 KIRQL 853 FASTCALL 854 KfRaiseIrql( 855 IN KIRQL NewIrql) 856 { 857 KIRQL OldIrql; 858 859 /* Read the current IRQL */ 860 OldIrql = ApicGetCurrentIrql(); 861 #if DBG 862 /* Validate correct raise */ 863 if (OldIrql > NewIrql) 864 { 865 /* Crash system */ 866 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL); 867 } 868 #endif 869 /* Convert the new IRQL to a TPR value and write the register */ 870 ApicRaiseIrql(NewIrql); 871 872 /* Return old IRQL */ 873 return OldIrql; 874 } 875 876 KIRQL 877 NTAPI 878 KeRaiseIrqlToDpcLevel(VOID) 879 { 880 return KfRaiseIrql(DISPATCH_LEVEL); 881 } 882 883 KIRQL 884 NTAPI 885 KeRaiseIrqlToSynchLevel(VOID) 886 { 887 return KfRaiseIrql(SYNCH_LEVEL); 888 } 889 890 #endif /* !_M_AMD64 */ 891 892