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: 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 */ 11 12 /* INCLUDES *******************************************************************/ 13 14 #include <hal.h> 15 #define NDEBUG 16 #include <debug.h> 17 18 #include "apic.h" 19 void __cdecl HackEoi(void); 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 *(volatile UCHAR *)(IOAPIC_BASE + IOAPIC_IOREGSEL) = Register; 98 return *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOWIN); 99 } 100 101 FORCEINLINE 102 VOID 103 IOApicWrite(UCHAR Register, ULONG Value) 104 { 105 /* Select the register, then do the write */ 106 *(volatile UCHAR *)(IOAPIC_BASE + IOAPIC_IOREGSEL) = Register; 107 *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOWIN) = Value; 108 } 109 110 FORCEINLINE 111 VOID 112 ApicWriteIORedirectionEntry( 113 UCHAR Index, 114 IOAPIC_REDIRECTION_REGISTER ReDirReg) 115 { 116 IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0); 117 IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1); 118 } 119 120 FORCEINLINE 121 IOAPIC_REDIRECTION_REGISTER 122 ApicReadIORedirectionEntry( 123 UCHAR Index) 124 { 125 IOAPIC_REDIRECTION_REGISTER ReDirReg; 126 127 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index); 128 ReDirReg.Long1 = IOApicRead(IOAPIC_REDTBL + 2 * Index + 1); 129 130 return ReDirReg; 131 } 132 133 FORCEINLINE 134 VOID 135 ApicRequestInterrupt(IN UCHAR Vector, UCHAR TriggerMode) 136 { 137 APIC_COMMAND_REGISTER CommandRegister; 138 139 /* Setup the command register */ 140 CommandRegister.Long0 = 0; 141 CommandRegister.Vector = Vector; 142 CommandRegister.MessageType = APIC_MT_Fixed; 143 CommandRegister.TriggerMode = TriggerMode; 144 CommandRegister.DestinationShortHand = APIC_DSH_Self; 145 146 /* Write the low dword to send the interrupt */ 147 ApicWrite(APIC_ICR0, CommandRegister.Long0); 148 } 149 150 FORCEINLINE 151 VOID 152 ApicSendEOI(void) 153 { 154 //ApicWrite(APIC_EOI, 0); 155 HackEoi(); 156 } 157 158 FORCEINLINE 159 KIRQL 160 ApicGetProcessorIrql(VOID) 161 { 162 /* Read the TPR and convert it to an IRQL */ 163 return TprToIrql(ApicRead(APIC_PPR)); 164 } 165 166 FORCEINLINE 167 KIRQL 168 ApicGetCurrentIrql(VOID) 169 { 170 #ifdef _M_AMD64 171 return (KIRQL)__readcr8(); 172 #elif defined(APIC_LAZY_IRQL) 173 // HACK: some magic to Sync VBox's APIC registers 174 ApicRead(APIC_VER); 175 176 /* Return the field in the PCR */ 177 return (KIRQL)__readfsbyte(FIELD_OFFSET(KPCR, Irql)); 178 #else 179 // HACK: some magic to Sync VBox's APIC registers 180 ApicRead(APIC_VER); 181 182 /* Read the TPR and convert it to an IRQL */ 183 return TprToIrql(ApicRead(APIC_TPR)); 184 #endif 185 } 186 187 FORCEINLINE 188 VOID 189 ApicSetIrql(KIRQL Irql) 190 { 191 #ifdef _M_AMD64 192 __writecr8(Irql); 193 #elif defined(APIC_LAZY_IRQL) 194 __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); 195 #else 196 /* Convert IRQL and write the TPR */ 197 ApicWrite(APIC_TPR, IrqlToTpr(Irql)); 198 #endif 199 } 200 #define ApicRaiseIrql ApicSetIrql 201 202 #ifdef APIC_LAZY_IRQL 203 FORCEINLINE 204 VOID 205 ApicLowerIrql(KIRQL Irql) 206 { 207 __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); 208 209 /* Is the new Irql lower than set in the TPR? */ 210 if (Irql < KeGetPcr()->IRR) 211 { 212 /* Save the new hard IRQL in the IRR field */ 213 KeGetPcr()->IRR = Irql; 214 215 /* Need to lower it back */ 216 ApicWrite(APIC_TPR, IrqlToTpr(Irql)); 217 } 218 } 219 #else 220 #define ApicLowerIrql ApicSetIrql 221 #endif 222 223 UCHAR 224 FASTCALL 225 HalpIrqToVector(UCHAR Irq) 226 { 227 IOAPIC_REDIRECTION_REGISTER ReDirReg; 228 229 /* Read low dword of the redirection entry */ 230 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Irq); 231 232 /* Return the vector */ 233 return (UCHAR)ReDirReg.Vector; 234 } 235 236 KIRQL 237 FASTCALL 238 HalpVectorToIrql(UCHAR Vector) 239 { 240 return TprToIrql(Vector); 241 } 242 243 UCHAR 244 FASTCALL 245 HalpVectorToIrq(UCHAR Vector) 246 { 247 return HalpVectorToIndex[Vector]; 248 } 249 250 VOID 251 NTAPI 252 HalpSendEOI(VOID) 253 { 254 ApicSendEOI(); 255 } 256 257 VOID 258 NTAPI 259 ApicInitializeLocalApic(ULONG Cpu) 260 { 261 APIC_BASE_ADRESS_REGISTER BaseRegister; 262 APIC_SPURIOUS_INERRUPT_REGISTER SpIntRegister; 263 LVT_REGISTER LvtEntry; 264 265 /* Enable the APIC if it wasn't yet */ 266 BaseRegister.Long = __readmsr(MSR_APIC_BASE); 267 BaseRegister.Enable = 1; 268 BaseRegister.BootStrapCPUCore = (Cpu == 0); 269 __writemsr(MSR_APIC_BASE, BaseRegister.Long); 270 271 /* Set spurious vector and SoftwareEnable to 1 */ 272 SpIntRegister.Long = ApicRead(APIC_SIVR); 273 SpIntRegister.Vector = APIC_SPURIOUS_VECTOR; 274 SpIntRegister.SoftwareEnable = 1; 275 SpIntRegister.FocusCPUCoreChecking = 0; 276 ApicWrite(APIC_SIVR, SpIntRegister.Long); 277 278 /* Read the version and save it globally */ 279 if (Cpu == 0) ApicVersion = ApicRead(APIC_VER); 280 281 /* Set the mode to flat (max 8 CPUs supported!) */ 282 ApicWrite(APIC_DFR, APIC_DF_Flat); 283 284 /* Set logical apic ID */ 285 ApicWrite(APIC_LDR, ApicLogicalId(Cpu) << 24); 286 287 /* Set the spurious ISR */ 288 KeRegisterInterruptHandler(APIC_SPURIOUS_VECTOR, ApicSpuriousService); 289 290 /* Create a template LVT */ 291 LvtEntry.Long = 0; 292 LvtEntry.Vector = 0xFF; 293 LvtEntry.MessageType = APIC_MT_Fixed; 294 LvtEntry.DeliveryStatus = 0; 295 LvtEntry.RemoteIRR = 0; 296 LvtEntry.TriggerMode = APIC_TGM_Edge; 297 LvtEntry.Mask = 1; 298 LvtEntry.TimerMode = 0; 299 300 /* Initialize and mask LVTs */ 301 ApicWrite(APIC_TMRLVTR, LvtEntry.Long); 302 ApicWrite(APIC_THRMLVTR, LvtEntry.Long); 303 ApicWrite(APIC_PCLVTR, LvtEntry.Long); 304 ApicWrite(APIC_EXT0LVTR, LvtEntry.Long); 305 ApicWrite(APIC_EXT1LVTR, LvtEntry.Long); 306 ApicWrite(APIC_EXT2LVTR, LvtEntry.Long); 307 ApicWrite(APIC_EXT3LVTR, LvtEntry.Long); 308 309 /* LINT0 */ 310 LvtEntry.Vector = APIC_SPURIOUS_VECTOR; 311 LvtEntry.MessageType = APIC_MT_ExtInt; 312 ApicWrite(APIC_LINT0, LvtEntry.Long); 313 314 /* Enable LINT1 (NMI) */ 315 LvtEntry.Mask = 0; 316 LvtEntry.Vector = APIC_NMI_VECTOR; 317 LvtEntry.MessageType = APIC_MT_NMI; 318 LvtEntry.TriggerMode = APIC_TGM_Level; 319 ApicWrite(APIC_LINT1, LvtEntry.Long); 320 321 /* Enable error LVTR */ 322 LvtEntry.Vector = APIC_ERROR_VECTOR; 323 LvtEntry.MessageType = APIC_MT_Fixed; 324 ApicWrite(APIC_ERRLVTR, LvtEntry.Long); 325 326 /* Set the IRQL from the PCR */ 327 ApicSetIrql(KeGetPcr()->Irql); 328 #ifdef APIC_LAZY_IRQL 329 /* Save the new hard IRQL in the IRR field */ 330 KeGetPcr()->IRR = KeGetPcr()->Irql; 331 #endif 332 } 333 334 UCHAR 335 NTAPI 336 HalpAllocateSystemInterrupt( 337 IN UCHAR Irq, 338 IN KIRQL Irql) 339 { 340 IOAPIC_REDIRECTION_REGISTER ReDirReg; 341 IN UCHAR Vector; 342 343 /* Start with lowest vector */ 344 Vector = IrqlToTpr(Irql) & 0xF0; 345 346 /* Find an empty vector */ 347 while (HalpVectorToIndex[Vector] != 0xFF) 348 { 349 Vector++; 350 351 /* Check if we went over the edge */ 352 if (TprToIrql(Vector) > Irql) 353 { 354 /* Nothing free, return failure */ 355 return 0; 356 } 357 } 358 359 /* Save irq in the table */ 360 HalpVectorToIndex[Vector] = Irq; 361 362 /* Setup a redirection entry */ 363 ReDirReg.Vector = Vector; 364 ReDirReg.DeliveryMode = APIC_MT_LowestPriority; 365 ReDirReg.DestinationMode = APIC_DM_Logical; 366 ReDirReg.DeliveryStatus = 0; 367 ReDirReg.Polarity = 0; 368 ReDirReg.RemoteIRR = 0; 369 ReDirReg.TriggerMode = APIC_TGM_Edge; 370 ReDirReg.Mask = 1; 371 ReDirReg.Reserved = 0; 372 ReDirReg.Destination = 0; 373 374 /* Initialize entry */ 375 IOApicWrite(IOAPIC_REDTBL + 2 * Irq, ReDirReg.Long0); 376 IOApicWrite(IOAPIC_REDTBL + 2 * Irq + 1, ReDirReg.Long1); 377 378 return Vector; 379 } 380 381 VOID 382 NTAPI 383 ApicInitializeIOApic(VOID) 384 { 385 PHARDWARE_PTE Pte; 386 IOAPIC_REDIRECTION_REGISTER ReDirReg; 387 UCHAR Index; 388 ULONG Vector; 389 390 /* Map the I/O Apic page */ 391 Pte = HalAddressToPte(IOAPIC_BASE); 392 Pte->PageFrameNumber = IOAPIC_PHYS_BASE / PAGE_SIZE; 393 Pte->Valid = 1; 394 Pte->Write = 1; 395 Pte->Owner = 1; 396 Pte->CacheDisable = 1; 397 Pte->Global = 1; 398 _ReadWriteBarrier(); 399 400 /* Setup a redirection entry */ 401 ReDirReg.Vector = 0xFF; 402 ReDirReg.DeliveryMode = APIC_MT_Fixed; 403 ReDirReg.DestinationMode = APIC_DM_Physical; 404 ReDirReg.DeliveryStatus = 0; 405 ReDirReg.Polarity = 0; 406 ReDirReg.RemoteIRR = 0; 407 ReDirReg.TriggerMode = APIC_TGM_Edge; 408 ReDirReg.Mask = 1; 409 ReDirReg.Reserved = 0; 410 ReDirReg.Destination = 0; 411 412 /* Loop all table entries */ 413 for (Index = 0; Index < 24; Index++) 414 { 415 /* Initialize entry */ 416 IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0); 417 IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1); 418 } 419 420 /* Init the vactor to index table */ 421 for (Vector = 0; Vector <= 255; Vector++) 422 { 423 HalpVectorToIndex[Vector] = 0xFF; 424 } 425 426 // HACK: Allocate all IRQs, should rather do that on demand 427 for (Index = 0; Index <= 15; Index++) 428 { 429 /* Map the IRQs to IRQLs like with the PIC */ 430 HalpAllocateSystemInterrupt(Index, 27 - Index); 431 } 432 433 /* Enable the timer interrupt */ 434 ReDirReg.Vector = APIC_CLOCK_VECTOR; 435 ReDirReg.DeliveryMode = APIC_MT_Fixed; 436 ReDirReg.DestinationMode = APIC_DM_Physical; 437 ReDirReg.TriggerMode = APIC_TGM_Edge; 438 ReDirReg.Mask = 0; 439 ReDirReg.Destination = ApicRead(APIC_ID); 440 IOApicWrite(IOAPIC_REDTBL + 2 * APIC_CLOCK_INDEX, ReDirReg.Long0); 441 } 442 443 VOID 444 NTAPI 445 HalpInitializePICs(IN BOOLEAN EnableInterrupts) 446 { 447 ULONG_PTR EFlags; 448 449 /* Save EFlags and disable interrupts */ 450 EFlags = __readeflags(); 451 _disable(); 452 453 /* Initialize and mask the PIC */ 454 HalpInitializeLegacyPICs(); 455 456 /* Initialize the I/O APIC */ 457 ApicInitializeIOApic(); 458 459 /* Manually reserve some vectors */ 460 HalpVectorToIndex[APIC_CLOCK_VECTOR] = 8; 461 HalpVectorToIndex[APC_VECTOR] = 99; 462 HalpVectorToIndex[DISPATCH_VECTOR] = 99; 463 464 /* Set interrupt handlers in the IDT */ 465 KeRegisterInterruptHandler(APIC_CLOCK_VECTOR, HalpClockInterrupt); 466 #ifndef _M_AMD64 467 KeRegisterInterruptHandler(APC_VECTOR, HalpApcInterrupt); 468 KeRegisterInterruptHandler(DISPATCH_VECTOR, HalpDispatchInterrupt); 469 #endif 470 471 /* Register the vectors for APC and dispatch interrupts */ 472 HalpRegisterVector(IDT_INTERNAL, 0, APC_VECTOR, APC_LEVEL); 473 HalpRegisterVector(IDT_INTERNAL, 0, DISPATCH_VECTOR, DISPATCH_LEVEL); 474 475 /* Restore interrupt state */ 476 if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK; 477 __writeeflags(EFlags); 478 } 479 480 481 /* SOFTWARE INTERRUPT TRAPS ***************************************************/ 482 483 #ifndef _M_AMD64 484 VOID 485 DECLSPEC_NORETURN 486 FASTCALL 487 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) 488 { 489 KPROCESSOR_MODE ProcessorMode; 490 KIRQL OldIrql; 491 ASSERT(ApicGetProcessorIrql() == APC_LEVEL); 492 493 /* Enter trap */ 494 KiEnterInterruptTrap(TrapFrame); 495 496 #ifdef APIC_LAZY_IRQL 497 if (!HalBeginSystemInterrupt(APC_LEVEL, APC_VECTOR, &OldIrql)) 498 { 499 /* "Spurious" interrupt, exit the interrupt */ 500 KiEoiHelper(TrapFrame); 501 } 502 #else 503 /* Save the old IRQL */ 504 OldIrql = ApicGetCurrentIrql(); 505 ASSERT(OldIrql < APC_LEVEL); 506 #endif 507 508 /* Raise to APC_LEVEL */ 509 ApicRaiseIrql(APC_LEVEL); 510 511 /* End the interrupt */ 512 ApicSendEOI(); 513 514 /* Kernel or user APC? */ 515 if (KiUserTrap(TrapFrame)) ProcessorMode = UserMode; 516 else if (TrapFrame->EFlags & EFLAGS_V86_MASK) ProcessorMode = UserMode; 517 else ProcessorMode = KernelMode; 518 519 /* Enable interrupts and call the kernel's APC interrupt handler */ 520 _enable(); 521 KiDeliverApc(ProcessorMode, NULL, TrapFrame); 522 523 /* Disable interrupts */ 524 _disable(); 525 526 /* Restore the old IRQL */ 527 ApicLowerIrql(OldIrql); 528 529 /* Exit the interrupt */ 530 KiEoiHelper(TrapFrame); 531 } 532 533 VOID 534 DECLSPEC_NORETURN 535 FASTCALL 536 HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame) 537 { 538 KIRQL OldIrql; 539 ASSERT(ApicGetProcessorIrql() == DISPATCH_LEVEL); 540 541 /* Enter trap */ 542 KiEnterInterruptTrap(TrapFrame); 543 544 #ifdef APIC_LAZY_IRQL 545 if (!HalBeginSystemInterrupt(DISPATCH_LEVEL, DISPATCH_VECTOR, &OldIrql)) 546 { 547 /* "Spurious" interrupt, exit the interrupt */ 548 KiEoiHelper(TrapFrame); 549 } 550 #else 551 /* Get the current IRQL */ 552 OldIrql = ApicGetCurrentIrql(); 553 ASSERT(OldIrql < DISPATCH_LEVEL); 554 #endif 555 556 /* Raise to DISPATCH_LEVEL */ 557 ApicRaiseIrql(DISPATCH_LEVEL); 558 559 /* End the interrupt */ 560 ApicSendEOI(); 561 562 /* Enable interrupts and call the kernel's DPC interrupt handler */ 563 _enable(); 564 KiDispatchInterrupt(); 565 _disable(); 566 567 /* Restore the old IRQL */ 568 ApicLowerIrql(OldIrql); 569 570 /* Exit the interrupt */ 571 KiEoiHelper(TrapFrame); 572 } 573 #endif 574 575 576 /* SOFTWARE INTERRUPTS ********************************************************/ 577 578 579 VOID 580 FASTCALL 581 HalRequestSoftwareInterrupt(IN KIRQL Irql) 582 { 583 /* Convert irql to vector and request an interrupt */ 584 ApicRequestInterrupt(IrqlToSoftVector(Irql), APIC_TGM_Edge); 585 } 586 587 VOID 588 FASTCALL 589 HalClearSoftwareInterrupt( 590 IN KIRQL Irql) 591 { 592 /* Nothing to do */ 593 } 594 595 596 /* SYSTEM INTERRUPTS **********************************************************/ 597 598 BOOLEAN 599 NTAPI 600 HalEnableSystemInterrupt( 601 IN ULONG Vector, 602 IN KIRQL Irql, 603 IN KINTERRUPT_MODE InterruptMode) 604 { 605 IOAPIC_REDIRECTION_REGISTER ReDirReg; 606 PKPRCB Prcb = KeGetCurrentPrcb(); 607 UCHAR Index; 608 ASSERT(Irql <= HIGH_LEVEL); 609 ASSERT((IrqlToTpr(Irql) & 0xF0) == (Vector & 0xF0)); 610 611 /* Get the irq for this vector */ 612 Index = HalpVectorToIndex[Vector]; 613 614 /* Check if its valid */ 615 if (Index == 0xff) 616 { 617 /* Interrupt is not in use */ 618 return FALSE; 619 } 620 621 /* Read the redirection entry */ 622 ReDirReg = ApicReadIORedirectionEntry(Index); 623 624 /* Check if the interrupt was unused */ 625 if (ReDirReg.Vector != Vector) 626 { 627 ReDirReg.Vector = Vector; 628 ReDirReg.DeliveryMode = APIC_MT_LowestPriority; 629 ReDirReg.DestinationMode = APIC_DM_Logical; 630 ReDirReg.Destination = 0; 631 } 632 633 /* Check if the destination is logical */ 634 if (ReDirReg.DestinationMode == APIC_DM_Logical) 635 { 636 /* Set the bit for this cpu */ 637 ReDirReg.Destination |= ApicLogicalId(Prcb->Number); 638 } 639 640 /* Set the trigger mode */ 641 ReDirReg.TriggerMode = 1 - InterruptMode; 642 643 /* Now unmask it */ 644 ReDirReg.Mask = FALSE; 645 646 /* Write back the entry */ 647 ApicWriteIORedirectionEntry(Index, ReDirReg); 648 649 return TRUE; 650 } 651 652 VOID 653 NTAPI 654 HalDisableSystemInterrupt( 655 IN ULONG Vector, 656 IN KIRQL Irql) 657 { 658 IOAPIC_REDIRECTION_REGISTER ReDirReg; 659 UCHAR Index; 660 ASSERT(Irql <= HIGH_LEVEL); 661 ASSERT(Vector < RTL_NUMBER_OF(HalpVectorToIndex)); 662 663 Index = HalpVectorToIndex[Vector]; 664 665 /* Read lower dword of redirection entry */ 666 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index); 667 668 /* Mask it */ 669 ReDirReg.Mask = 1; 670 671 /* Write back lower dword */ 672 IOApicWrite(IOAPIC_REDTBL + 2 * Irql, ReDirReg.Long0); 673 } 674 675 #ifndef _M_AMD64 676 BOOLEAN 677 NTAPI 678 HalBeginSystemInterrupt( 679 IN KIRQL Irql, 680 IN ULONG Vector, 681 OUT PKIRQL OldIrql) 682 { 683 KIRQL CurrentIrql; 684 685 /* Get the current IRQL */ 686 CurrentIrql = ApicGetCurrentIrql(); 687 688 #ifdef APIC_LAZY_IRQL 689 /* Check if this interrupt is allowed */ 690 if (CurrentIrql >= Irql) 691 { 692 IOAPIC_REDIRECTION_REGISTER RedirReg; 693 UCHAR Index; 694 695 /* It is not, set the real Irql in the TPR! */ 696 ApicWrite(APIC_TPR, IrqlToTpr(CurrentIrql)); 697 698 /* Save the new hard IRQL in the IRR field */ 699 KeGetPcr()->IRR = CurrentIrql; 700 701 /* End this interrupt */ 702 ApicSendEOI(); 703 704 /* Get the irq for this vector */ 705 Index = HalpVectorToIndex[Vector]; 706 707 /* Check if its valid */ 708 if (Index != 0xff) 709 { 710 /* Read the I/O redirection entry */ 711 RedirReg = ApicReadIORedirectionEntry(Index); 712 713 /* Re-request the interrupt to be handled later */ 714 ApicRequestInterrupt(Vector, (UCHAR)RedirReg.TriggerMode); 715 } 716 else 717 { 718 /* Re-request the interrupt to be handled later */ 719 ApicRequestInterrupt(Vector, APIC_TGM_Edge); 720 } 721 722 /* Pretend it was a spurious interrupt */ 723 return FALSE; 724 } 725 #endif 726 /* Save the current IRQL */ 727 *OldIrql = CurrentIrql; 728 729 /* Set the new IRQL */ 730 ApicRaiseIrql(Irql); 731 732 /* Turn on interrupts */ 733 _enable(); 734 735 /* Success */ 736 return TRUE; 737 } 738 739 VOID 740 NTAPI 741 HalEndSystemInterrupt( 742 IN KIRQL OldIrql, 743 IN PKTRAP_FRAME TrapFrame) 744 { 745 /* Send an EOI */ 746 ApicSendEOI(); 747 748 /* Restore the old IRQL */ 749 ApicLowerIrql(OldIrql); 750 } 751 752 753 /* IRQL MANAGEMENT ************************************************************/ 754 755 KIRQL 756 NTAPI 757 KeGetCurrentIrql(VOID) 758 { 759 /* Read the current TPR and convert it to an IRQL */ 760 return ApicGetCurrentIrql(); 761 } 762 763 VOID 764 FASTCALL 765 KfLowerIrql( 766 IN KIRQL OldIrql) 767 { 768 #if DBG 769 /* Validate correct lower */ 770 if (OldIrql > ApicGetCurrentIrql()) 771 { 772 /* Crash system */ 773 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); 774 } 775 #endif 776 /* Set the new IRQL */ 777 ApicLowerIrql(OldIrql); 778 } 779 780 KIRQL 781 FASTCALL 782 KfRaiseIrql( 783 IN KIRQL NewIrql) 784 { 785 KIRQL OldIrql; 786 787 /* Read the current IRQL */ 788 OldIrql = ApicGetCurrentIrql(); 789 #if DBG 790 /* Validate correct raise */ 791 if (OldIrql > NewIrql) 792 { 793 /* Crash system */ 794 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL); 795 } 796 #endif 797 /* Convert the new IRQL to a TPR value and write the register */ 798 ApicRaiseIrql(NewIrql); 799 800 /* Return old IRQL */ 801 return OldIrql; 802 } 803 804 KIRQL 805 NTAPI 806 KeRaiseIrqlToDpcLevel(VOID) 807 { 808 return KfRaiseIrql(DISPATCH_LEVEL); 809 } 810 811 KIRQL 812 NTAPI 813 KeRaiseIrqlToSynchLevel(VOID) 814 { 815 return KfRaiseIrql(SYNCH_LEVEL); 816 } 817 818 #endif /* !_M_AMD64 */ 819 820