Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenapic.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS HAL 00003 * LICENSE: GNU GPL - See COPYING in the top level directory 00004 * FILE: hal/halx86/generic/apic.c 00005 * PURPOSE: HAL APIC Management and Control Code 00006 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) 00007 * REFERENCES: http://www.joseflores.com/docs/ExploringIrql.html 00008 * http://www.codeproject.com/KB/system/soviet_kernel_hack.aspx 00009 * http://bbs.unixmap.net/thread-2022-1-1.html 00010 */ 00011 00012 /* INCLUDES *******************************************************************/ 00013 00014 #include <hal.h> 00015 #define NDEBUG 00016 #include <debug.h> 00017 00018 #include "apic.h" 00019 void HackEoi(void); 00020 00021 #ifndef _M_AMD64 00022 #define APIC_LAZY_IRQL 00023 #endif 00024 00025 /* GLOBALS ********************************************************************/ 00026 00027 ULONG ApicVersion; 00028 UCHAR HalpVectorToIndex[256]; 00029 00030 #ifndef _M_AMD64 00031 const UCHAR 00032 HalpIRQLtoTPR[32] = 00033 { 00034 0x00, /* 0 PASSIVE_LEVEL */ 00035 0x3d, /* 1 APC_LEVEL */ 00036 0x41, /* 2 DISPATCH_LEVEL */ 00037 0x41, /* 3 \ */ 00038 0x51, /* 4 \ */ 00039 0x61, /* 5 | */ 00040 0x71, /* 6 | */ 00041 0x81, /* 7 | */ 00042 0x91, /* 8 | */ 00043 0xa1, /* 9 | */ 00044 0xb1, /* 10 | */ 00045 0xb1, /* 11 | */ 00046 0xb1, /* 12 | */ 00047 0xb1, /* 13 | */ 00048 0xb1, /* 14 | */ 00049 0xb1, /* 15 DEVICE IRQL */ 00050 0xb1, /* 16 | */ 00051 0xb1, /* 17 | */ 00052 0xb1, /* 18 | */ 00053 0xb1, /* 19 | */ 00054 0xb1, /* 20 | */ 00055 0xb1, /* 21 | */ 00056 0xb1, /* 22 | */ 00057 0xb1, /* 23 | */ 00058 0xb1, /* 24 | */ 00059 0xb1, /* 25 / */ 00060 0xb1, /* 26 / */ 00061 0xc1, /* 27 PROFILE_LEVEL */ 00062 0xd1, /* 28 CLOCK2_LEVEL */ 00063 0xe1, /* 29 IPI_LEVEL */ 00064 0xef, /* 30 POWER_LEVEL */ 00065 0xff, /* 31 HIGH_LEVEL */ 00066 }; 00067 00068 const KIRQL 00069 HalVectorToIRQL[16] = 00070 { 00071 0, /* 00 PASSIVE_LEVEL */ 00072 0xff, /* 10 */ 00073 0xff, /* 20 */ 00074 1, /* 3D APC_LEVEL */ 00075 2, /* 41 DISPATCH_LEVEL */ 00076 4, /* 50 \ */ 00077 5, /* 60 \ */ 00078 6, /* 70 | */ 00079 7, /* 80 DEVICE IRQL */ 00080 8, /* 90 | */ 00081 9, /* A0 / */ 00082 10, /* B0 / */ 00083 27, /* C1 PROFILE_LEVEL */ 00084 28, /* D1 CLOCK2_LEVEL */ 00085 29, /* E1 IPI_LEVEL / EF POWER_LEVEL */ 00086 31, /* FF HIGH_LEVEL */ 00087 }; 00088 #endif 00089 00090 /* PRIVATE FUNCTIONS **********************************************************/ 00091 00092 ULONG 00093 FORCEINLINE 00094 IOApicRead(UCHAR Register) 00095 { 00096 /* Select the register, then do the read */ 00097 *(volatile UCHAR *)(IOAPIC_BASE + IOAPIC_IOREGSEL) = Register; 00098 return *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOWIN); 00099 } 00100 00101 VOID 00102 FORCEINLINE 00103 IOApicWrite(UCHAR Register, ULONG Value) 00104 { 00105 /* Select the register, then do the write */ 00106 *(volatile UCHAR *)(IOAPIC_BASE + IOAPIC_IOREGSEL) = Register; 00107 *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOWIN) = Value; 00108 } 00109 00110 VOID 00111 FORCEINLINE 00112 ApicWriteIORedirectionEntry( 00113 UCHAR Index, 00114 IOAPIC_REDIRECTION_REGISTER ReDirReg) 00115 { 00116 IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0); 00117 IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1); 00118 } 00119 00120 IOAPIC_REDIRECTION_REGISTER 00121 FORCEINLINE 00122 ApicReadIORedirectionEntry( 00123 UCHAR Index) 00124 { 00125 IOAPIC_REDIRECTION_REGISTER ReDirReg; 00126 00127 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index); 00128 ReDirReg.Long1 = IOApicRead(IOAPIC_REDTBL + 2 * Index + 1); 00129 00130 return ReDirReg; 00131 } 00132 00133 VOID 00134 FORCEINLINE 00135 ApicRequestInterrupt(IN UCHAR Vector, UCHAR TriggerMode) 00136 { 00137 APIC_COMMAND_REGISTER CommandRegister; 00138 00139 /* Setup the command register */ 00140 CommandRegister.Long0 = 0; 00141 CommandRegister.Vector = Vector; 00142 CommandRegister.MessageType = APIC_MT_Fixed; 00143 CommandRegister.TriggerMode = TriggerMode; 00144 CommandRegister.DestinationShortHand = APIC_DSH_Self; 00145 00146 /* Write the low dword to send the interrupt */ 00147 ApicWrite(APIC_ICR0, CommandRegister.Long0); 00148 } 00149 00150 VOID 00151 FORCEINLINE 00152 ApicSendEOI(void) 00153 { 00154 //ApicWrite(APIC_EOI, 0); 00155 HackEoi(); 00156 } 00157 00158 KIRQL 00159 FORCEINLINE 00160 ApicGetProcessorIrql(VOID) 00161 { 00162 /* Read the TPR and convert it to an IRQL */ 00163 return TprToIrql(ApicRead(APIC_PPR)); 00164 } 00165 00166 KIRQL 00167 FORCEINLINE 00168 ApicGetCurrentIrql(VOID) 00169 { 00170 #ifdef _M_AMD64 00171 return (KIRQL)__readcr8(); 00172 #elif defined(APIC_LAZY_IRQL) 00173 // HACK: some magic to Sync VBox's APIC registers 00174 ApicRead(APIC_VER); 00175 00176 /* Return the field in the PCR */ 00177 return (KIRQL)__readfsbyte(FIELD_OFFSET(KPCR, Irql)); 00178 #else 00179 // HACK: some magic to Sync VBox's APIC registers 00180 ApicRead(APIC_VER); 00181 00182 /* Read the TPR and convert it to an IRQL */ 00183 return TprToIrql(ApicRead(APIC_TPR)); 00184 #endif 00185 } 00186 00187 VOID 00188 FORCEINLINE 00189 ApicSetIrql(KIRQL Irql) 00190 { 00191 #ifdef _M_AMD64 00192 __writecr8(Irql); 00193 #elif defined(APIC_LAZY_IRQL) 00194 __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); 00195 #else 00196 /* Convert IRQL and write the TPR */ 00197 ApicWrite(APIC_TPR, IrqlToTpr(Irql)); 00198 #endif 00199 } 00200 #define ApicRaiseIrql ApicSetIrql 00201 00202 #ifdef APIC_LAZY_IRQL 00203 VOID 00204 FORCEINLINE 00205 ApicLowerIrql(KIRQL Irql) 00206 { 00207 __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); 00208 00209 /* Is the new Irql lower than set in the TPR? */ 00210 if (Irql < KeGetPcr()->IRR) 00211 { 00212 /* Save the new hard IRQL in the IRR field */ 00213 KeGetPcr()->IRR = Irql; 00214 00215 /* Need to lower it back */ 00216 ApicWrite(APIC_TPR, IrqlToTpr(Irql)); 00217 } 00218 } 00219 #else 00220 #define ApicLowerIrql ApicSetIrql 00221 #endif 00222 00223 UCHAR 00224 FASTCALL 00225 HalpIrqToVector(UCHAR Irq) 00226 { 00227 IOAPIC_REDIRECTION_REGISTER ReDirReg; 00228 00229 /* Read low dword of the redirection entry */ 00230 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Irq); 00231 00232 /* Return the vector */ 00233 return (UCHAR)ReDirReg.Vector; 00234 } 00235 00236 KIRQL 00237 FASTCALL 00238 HalpVectorToIrql(UCHAR Vector) 00239 { 00240 return TprToIrql(Vector); 00241 } 00242 00243 UCHAR 00244 FASTCALL 00245 HalpVectorToIrq(UCHAR Vector) 00246 { 00247 return HalpVectorToIndex[Vector]; 00248 } 00249 00250 VOID 00251 NTAPI 00252 HalpSendEOI(VOID) 00253 { 00254 ApicSendEOI(); 00255 } 00256 00257 VOID 00258 NTAPI 00259 HalpInitializeLegacyPIC(VOID) 00260 { 00261 I8259_ICW1 Icw1; 00262 I8259_ICW2 Icw2; 00263 I8259_ICW3 Icw3; 00264 I8259_ICW4 Icw4; 00265 00266 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */ 00267 Icw1.NeedIcw4 = TRUE; 00268 Icw1.OperatingMode = Cascade; 00269 Icw1.Interval = Interval8; 00270 Icw1.InterruptMode = EdgeTriggered; 00271 Icw1.Init = TRUE; 00272 Icw1.InterruptVectorAddress = 0; 00273 __outbyte(PIC1_CONTROL_PORT, Icw1.Bits); 00274 00275 /* ICW2 - interrupt vector offset */ 00276 Icw2.Bits = PRIMARY_VECTOR_BASE; 00277 __outbyte(PIC1_DATA_PORT, Icw2.Bits); 00278 00279 /* Connect slave to IRQ 2 */ 00280 Icw3.Bits = 0; 00281 Icw3.SlaveIrq2 = TRUE; 00282 __outbyte(PIC1_DATA_PORT, Icw3.Bits); 00283 00284 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */ 00285 Icw4.SystemMode = New8086Mode; 00286 Icw4.EoiMode = NormalEoi; 00287 Icw4.BufferedMode = NonBuffered; 00288 Icw4.SpecialFullyNestedMode = FALSE; 00289 Icw4.Reserved = 0; 00290 __outbyte(PIC1_DATA_PORT, Icw4.Bits); 00291 00292 /* Mask all interrupts */ 00293 __outbyte(PIC1_DATA_PORT, 0xFF); 00294 00295 /* Initialize ICW1 for slave, interval 8, edge-triggered mode with ICW4 */ 00296 Icw1.NeedIcw4 = TRUE; 00297 Icw1.InterruptMode = EdgeTriggered; 00298 Icw1.OperatingMode = Cascade; 00299 Icw1.Interval = Interval8; 00300 Icw1.Init = TRUE; 00301 Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */ 00302 __outbyte(PIC2_CONTROL_PORT, Icw1.Bits); 00303 00304 /* Set interrupt vector base */ 00305 Icw2.Bits = PRIMARY_VECTOR_BASE + 8; 00306 __outbyte(PIC2_DATA_PORT, Icw2.Bits); 00307 00308 /* Slave ID */ 00309 Icw3.Bits = 0; 00310 Icw3.SlaveId = 2; 00311 __outbyte(PIC2_DATA_PORT, Icw3.Bits); 00312 00313 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */ 00314 Icw4.SystemMode = New8086Mode; 00315 Icw4.EoiMode = NormalEoi; 00316 Icw4.BufferedMode = NonBuffered; 00317 Icw4.SpecialFullyNestedMode = FALSE; 00318 Icw4.Reserved = 0; 00319 __outbyte(PIC2_DATA_PORT, Icw4.Bits); 00320 00321 /* Mask all interrupts */ 00322 __outbyte(PIC2_DATA_PORT, 0xFF); 00323 } 00324 00325 VOID 00326 NTAPI 00327 ApicInitializeLocalApic(ULONG Cpu) 00328 { 00329 APIC_BASE_ADRESS_REGISTER BaseRegister; 00330 APIC_SPURIOUS_INERRUPT_REGISTER SpIntRegister; 00331 LVT_REGISTER LvtEntry; 00332 00333 /* Enable the APIC if it wasn't yet */ 00334 BaseRegister.Long = __readmsr(MSR_APIC_BASE); 00335 BaseRegister.Enable = 1; 00336 BaseRegister.BootStrapCPUCore = (Cpu == 0); 00337 __writemsr(MSR_APIC_BASE, BaseRegister.Long); 00338 00339 /* Set spurious vector and SoftwareEnable to 1 */ 00340 SpIntRegister.Long = ApicRead(APIC_SIVR); 00341 SpIntRegister.Vector = APIC_SPURIOUS_VECTOR; 00342 SpIntRegister.SoftwareEnable = 1; 00343 SpIntRegister.FocusCPUCoreChecking = 0; 00344 ApicWrite(APIC_SIVR, SpIntRegister.Long); 00345 00346 /* Read the version and save it globally */ 00347 if (Cpu == 0) ApicVersion = ApicRead(APIC_VER); 00348 00349 /* Set the mode to flat (max 8 CPUs supported!) */ 00350 ApicWrite(APIC_DFR, APIC_DF_Flat); 00351 00352 /* Set logical apic ID */ 00353 ApicWrite(APIC_LDR, ApicLogicalId(Cpu) << 24); 00354 00355 /* Set the spurious ISR */ 00356 KeRegisterInterruptHandler(APIC_SPURIOUS_VECTOR, ApicSpuriousService); 00357 00358 /* Create a template LVT */ 00359 LvtEntry.Long = 0; 00360 LvtEntry.Vector = 0xFF; 00361 LvtEntry.MessageType = APIC_MT_Fixed; 00362 LvtEntry.DeliveryStatus = 0; 00363 LvtEntry.RemoteIRR = 0; 00364 LvtEntry.TriggerMode = APIC_TGM_Edge; 00365 LvtEntry.Mask = 1; 00366 LvtEntry.TimerMode = 0; 00367 00368 /* Initalize and mask LVTs */ 00369 ApicWrite(APIC_TMRLVTR, LvtEntry.Long); 00370 ApicWrite(APIC_THRMLVTR, LvtEntry.Long); 00371 ApicWrite(APIC_PCLVTR, LvtEntry.Long); 00372 ApicWrite(APIC_EXT0LVTR, LvtEntry.Long); 00373 ApicWrite(APIC_EXT1LVTR, LvtEntry.Long); 00374 ApicWrite(APIC_EXT2LVTR, LvtEntry.Long); 00375 ApicWrite(APIC_EXT3LVTR, LvtEntry.Long); 00376 00377 /* LINT0 */ 00378 LvtEntry.Vector = APIC_SPURIOUS_VECTOR; 00379 LvtEntry.MessageType = APIC_MT_ExtInt; 00380 ApicWrite(APIC_LINT0, LvtEntry.Long); 00381 00382 /* Enable LINT1 (NMI) */ 00383 LvtEntry.Mask = 0; 00384 LvtEntry.Vector = APIC_NMI_VECTOR; 00385 LvtEntry.MessageType = APIC_MT_NMI; 00386 LvtEntry.TriggerMode = APIC_TGM_Level; 00387 ApicWrite(APIC_LINT1, LvtEntry.Long); 00388 00389 /* Enable error LVTR */ 00390 LvtEntry.Vector = APIC_ERROR_VECTOR; 00391 LvtEntry.MessageType = APIC_MT_Fixed; 00392 ApicWrite(APIC_ERRLVTR, LvtEntry.Long); 00393 00394 /* Set the IRQL from the PCR */ 00395 ApicSetIrql(KeGetPcr()->Irql); 00396 #ifdef APIC_LAZY_IRQL 00397 /* Save the new hard IRQL in the IRR field */ 00398 KeGetPcr()->IRR = KeGetPcr()->Irql; 00399 #endif 00400 } 00401 00402 UCHAR 00403 NTAPI 00404 HalpAllocateSystemInterrupt( 00405 IN UCHAR Irq, 00406 IN KIRQL Irql) 00407 { 00408 IOAPIC_REDIRECTION_REGISTER ReDirReg; 00409 IN UCHAR Vector; 00410 00411 /* Start with lowest vector */ 00412 Vector = IrqlToTpr(Irql) & 0xF0; 00413 00414 /* Find an empty vector */ 00415 while (HalpVectorToIndex[Vector] != 0xFF) 00416 { 00417 Vector++; 00418 00419 /* Check if we went over the edge */ 00420 if (TprToIrql(Vector) > Irql) 00421 { 00422 /* Nothing free, return failure */ 00423 return 0; 00424 } 00425 } 00426 00427 /* Save irq in the table */ 00428 HalpVectorToIndex[Vector] = Irq; 00429 00430 /* Setup a redirection entry */ 00431 ReDirReg.Vector = Vector; 00432 ReDirReg.DeliveryMode = APIC_MT_LowestPriority; 00433 ReDirReg.DestinationMode = APIC_DM_Logical; 00434 ReDirReg.DeliveryStatus = 0; 00435 ReDirReg.Polarity = 0; 00436 ReDirReg.RemoteIRR = 0; 00437 ReDirReg.TriggerMode = APIC_TGM_Edge; 00438 ReDirReg.Mask = 1; 00439 ReDirReg.Reserved = 0; 00440 ReDirReg.Destination = 0; 00441 00442 /* Initialize entry */ 00443 IOApicWrite(IOAPIC_REDTBL + 2 * Irq, ReDirReg.Long0); 00444 IOApicWrite(IOAPIC_REDTBL + 2 * Irq + 1, ReDirReg.Long1); 00445 00446 return Vector; 00447 } 00448 00449 VOID 00450 NTAPI 00451 ApicInitializeIOApic(VOID) 00452 { 00453 PHARDWARE_PTE Pte; 00454 IOAPIC_REDIRECTION_REGISTER ReDirReg; 00455 UCHAR Index; 00456 ULONG Vector; 00457 00458 /* Map the I/O Apic page */ 00459 Pte = HalAddressToPte(IOAPIC_BASE); 00460 Pte->PageFrameNumber = IOAPIC_PHYS_BASE / PAGE_SIZE; 00461 Pte->Valid = 1; 00462 Pte->Write = 1; 00463 Pte->Owner = 1; 00464 Pte->CacheDisable = 1; 00465 Pte->Global = 1; 00466 _ReadWriteBarrier(); 00467 00468 /* Setup a redirection entry */ 00469 ReDirReg.Vector = 0xFF; 00470 ReDirReg.DeliveryMode = APIC_MT_Fixed; 00471 ReDirReg.DestinationMode = APIC_DM_Physical; 00472 ReDirReg.DeliveryStatus = 0; 00473 ReDirReg.Polarity = 0; 00474 ReDirReg.RemoteIRR = 0; 00475 ReDirReg.TriggerMode = APIC_TGM_Edge; 00476 ReDirReg.Mask = 1; 00477 ReDirReg.Reserved = 0; 00478 ReDirReg.Destination = 0; 00479 00480 /* Loop all table entries */ 00481 for (Index = 0; Index < 24; Index++) 00482 { 00483 /* Initialize entry */ 00484 IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0); 00485 IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1); 00486 } 00487 00488 /* Init the vactor to index table */ 00489 for (Vector = 0; Vector <= 255; Vector++) 00490 { 00491 HalpVectorToIndex[Vector] = 0xFF; 00492 } 00493 00494 // HACK: Allocate all IRQs, should rather do that on demand 00495 for (Index = 0; Index <= 15; Index++) 00496 { 00497 /* Map the IRQs to IRQLs like with the PIC */ 00498 HalpAllocateSystemInterrupt(Index, 27 - Index); 00499 } 00500 00501 /* Enable the timer interrupt */ 00502 ReDirReg.Vector = APIC_CLOCK_VECTOR; 00503 ReDirReg.DeliveryMode = APIC_MT_Fixed; 00504 ReDirReg.DestinationMode = APIC_DM_Physical; 00505 ReDirReg.TriggerMode = APIC_TGM_Edge; 00506 ReDirReg.Mask = 0; 00507 ReDirReg.Destination = ApicRead(APIC_ID); 00508 IOApicWrite(IOAPIC_REDTBL + 2 * APIC_CLOCK_INDEX, ReDirReg.Long0); 00509 00510 ApicSendEOI(); 00511 } 00512 00513 VOID 00514 NTAPI 00515 HalpInitializePICs(IN BOOLEAN EnableInterrupts) 00516 { 00517 ULONG_PTR EFlags; 00518 00519 /* Save EFlags and disable interrupts */ 00520 EFlags = __readeflags(); 00521 _disable(); 00522 00523 /* Initialize and mask the PIC */ 00524 HalpInitializeLegacyPIC(); 00525 00526 /* Initialize the I/O APIC */ 00527 ApicInitializeIOApic(); 00528 00529 /* Manually reserve some vectors */ 00530 HalpVectorToIndex[APIC_CLOCK_VECTOR] = 8; 00531 HalpVectorToIndex[APC_VECTOR] = 99; 00532 HalpVectorToIndex[DISPATCH_VECTOR] = 99; 00533 00534 /* Set interrupt handlers in the IDT */ 00535 KeRegisterInterruptHandler(APIC_CLOCK_VECTOR, HalpClockInterrupt); 00536 #ifndef _M_AMD64 00537 KeRegisterInterruptHandler(APC_VECTOR, HalpApcInterrupt); 00538 KeRegisterInterruptHandler(DISPATCH_VECTOR, HalpDispatchInterrupt); 00539 #endif 00540 00541 /* Register the vectors for APC and dispatch interrupts */ 00542 HalpRegisterVector(IDT_INTERNAL, 0, APC_VECTOR, APC_LEVEL); 00543 HalpRegisterVector(IDT_INTERNAL, 0, DISPATCH_VECTOR, DISPATCH_LEVEL); 00544 00545 /* Restore interrupt state */ 00546 if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK; 00547 __writeeflags(EFlags); 00548 } 00549 00550 00551 /* SOFTWARE INTERRUPT TRAPS ***************************************************/ 00552 00553 #ifndef _M_AMD64 00554 VOID 00555 DECLSPEC_NORETURN 00556 FASTCALL 00557 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) 00558 { 00559 KPROCESSOR_MODE ProcessorMode; 00560 KIRQL OldIrql; 00561 ASSERT(ApicGetProcessorIrql() == APC_LEVEL); 00562 00563 /* Enter trap */ 00564 KiEnterInterruptTrap(TrapFrame); 00565 00566 #ifdef APIC_LAZY_IRQL 00567 if (!HalBeginSystemInterrupt(APC_LEVEL, APC_VECTOR, &OldIrql)) 00568 { 00569 /* "Spurious" interrupt, exit the interrupt */ 00570 KiEoiHelper(TrapFrame); 00571 } 00572 #else 00573 /* Save the old IRQL */ 00574 OldIrql = ApicGetCurrentIrql(); 00575 ASSERT(OldIrql < APC_LEVEL); 00576 #endif 00577 00578 /* Raise to APC_LEVEL */ 00579 ApicRaiseIrql(APC_LEVEL); 00580 00581 /* End the interrupt */ 00582 ApicSendEOI(); 00583 00584 /* Kernel or user APC? */ 00585 if (KiUserTrap(TrapFrame)) ProcessorMode = UserMode; 00586 else if (TrapFrame->EFlags & EFLAGS_V86_MASK) ProcessorMode = UserMode; 00587 else ProcessorMode = KernelMode; 00588 00589 /* Enable interrupts and call the kernel's APC interrupt handler */ 00590 _enable(); 00591 KiDeliverApc(ProcessorMode, NULL, TrapFrame); 00592 00593 /* Disable interrupts */ 00594 _disable(); 00595 00596 /* Restore the old IRQL */ 00597 ApicLowerIrql(OldIrql); 00598 00599 /* Exit the interrupt */ 00600 KiEoiHelper(TrapFrame); 00601 } 00602 00603 VOID 00604 DECLSPEC_NORETURN 00605 FASTCALL 00606 HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame) 00607 { 00608 KIRQL OldIrql; 00609 ASSERT(ApicGetProcessorIrql() == DISPATCH_LEVEL); 00610 00611 /* Enter trap */ 00612 KiEnterInterruptTrap(TrapFrame); 00613 00614 #ifdef APIC_LAZY_IRQL 00615 if (!HalBeginSystemInterrupt(DISPATCH_LEVEL, DISPATCH_VECTOR, &OldIrql)) 00616 { 00617 /* "Spurious" interrupt, exit the interrupt */ 00618 KiEoiHelper(TrapFrame); 00619 } 00620 #else 00621 /* Get the current IRQL */ 00622 OldIrql = ApicGetCurrentIrql(); 00623 ASSERT(OldIrql < DISPATCH_LEVEL); 00624 #endif 00625 00626 /* Raise to DISPATCH_LEVEL */ 00627 ApicRaiseIrql(DISPATCH_LEVEL); 00628 00629 /* End the interrupt */ 00630 ApicSendEOI(); 00631 00632 /* Enable interrupts and call the kernel's DPC interrupt handler */ 00633 _enable(); 00634 KiDispatchInterrupt(); 00635 _disable(); 00636 00637 /* Restore the old IRQL */ 00638 ApicLowerIrql(OldIrql); 00639 00640 /* Exit the interrupt */ 00641 KiEoiHelper(TrapFrame); 00642 } 00643 #endif 00644 00645 00646 /* SOFTWARE INTERRUPTS ********************************************************/ 00647 00648 00649 VOID 00650 FASTCALL 00651 HalRequestSoftwareInterrupt(IN KIRQL Irql) 00652 { 00653 /* Convert irql to vector and request an interrupt */ 00654 ApicRequestInterrupt(IrqlToSoftVector(Irql), APIC_TGM_Edge); 00655 } 00656 00657 VOID 00658 FASTCALL 00659 HalClearSoftwareInterrupt( 00660 IN KIRQL Irql) 00661 { 00662 /* Nothing to do */ 00663 } 00664 00665 00666 /* SYSTEM INTERRUPTS **********************************************************/ 00667 00668 BOOLEAN 00669 NTAPI 00670 HalEnableSystemInterrupt( 00671 IN ULONG Vector, 00672 IN KIRQL Irql, 00673 IN KINTERRUPT_MODE InterruptMode) 00674 { 00675 IOAPIC_REDIRECTION_REGISTER ReDirReg; 00676 PKPRCB Prcb = KeGetCurrentPrcb(); 00677 UCHAR Index; 00678 ASSERT(Irql <= HIGH_LEVEL); 00679 ASSERT((IrqlToTpr(Irql) & 0xF0) == (Vector & 0xF0)); 00680 00681 /* Get the irq for this vector */ 00682 Index = HalpVectorToIndex[Vector]; 00683 00684 /* Check if its valid */ 00685 if (Index == 0xff) 00686 { 00687 /* Interrupt is not in use */ 00688 return FALSE; 00689 } 00690 00691 /* Read the redirection entry */ 00692 ReDirReg = ApicReadIORedirectionEntry(Index); 00693 00694 /* Check if the interrupt was unused */ 00695 if (ReDirReg.Vector != Vector) 00696 { 00697 ReDirReg.Vector = Vector; 00698 ReDirReg.DeliveryMode = APIC_MT_LowestPriority; 00699 ReDirReg.DestinationMode = APIC_DM_Logical; 00700 ReDirReg.Destination = 0; 00701 } 00702 00703 /* Check if the destination is logical */ 00704 if (ReDirReg.DestinationMode == APIC_DM_Logical) 00705 { 00706 /* Set the bit for this cpu */ 00707 ReDirReg.Destination |= ApicLogicalId(Prcb->Number); 00708 } 00709 00710 /* Set the trigger mode */ 00711 ReDirReg.TriggerMode = 1 - InterruptMode; 00712 00713 /* Now unmask it */ 00714 ReDirReg.Mask = FALSE; 00715 00716 /* Write back the entry */ 00717 ApicWriteIORedirectionEntry(Index, ReDirReg); 00718 00719 return TRUE; 00720 } 00721 00722 VOID 00723 NTAPI 00724 HalDisableSystemInterrupt( 00725 IN ULONG Vector, 00726 IN KIRQL Irql) 00727 { 00728 IOAPIC_REDIRECTION_REGISTER ReDirReg; 00729 UCHAR Index; 00730 ASSERT(Irql <= HIGH_LEVEL); 00731 ASSERT(Vector < RTL_NUMBER_OF(HalpVectorToIndex)); 00732 00733 Index = HalpVectorToIndex[Vector]; 00734 00735 /* Read lower dword of redirection entry */ 00736 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index); 00737 00738 /* Mask it */ 00739 ReDirReg.Mask = 1; 00740 00741 /* Write back lower dword */ 00742 IOApicWrite(IOAPIC_REDTBL + 2 * Irql, ReDirReg.Long0); 00743 } 00744 00745 #ifndef _M_AMD64 00746 BOOLEAN 00747 NTAPI 00748 HalBeginSystemInterrupt( 00749 IN KIRQL Irql, 00750 IN ULONG Vector, 00751 OUT PKIRQL OldIrql) 00752 { 00753 KIRQL CurrentIrql; 00754 00755 /* Get the current IRQL */ 00756 CurrentIrql = ApicGetCurrentIrql(); 00757 00758 #ifdef APIC_LAZY_IRQL 00759 /* Check if this interrupt is allowed */ 00760 if (CurrentIrql >= Irql) 00761 { 00762 IOAPIC_REDIRECTION_REGISTER RedirReg; 00763 UCHAR Index; 00764 00765 /* It is not, set the real Irql in the TPR! */ 00766 ApicWrite(APIC_TPR, IrqlToTpr(CurrentIrql)); 00767 00768 /* Save the new hard IRQL in the IRR field */ 00769 KeGetPcr()->IRR = CurrentIrql; 00770 00771 /* End this interrupt */ 00772 ApicSendEOI(); 00773 00774 /* Get the irq for this vector */ 00775 Index = HalpVectorToIndex[Vector]; 00776 00777 /* Check if its valid */ 00778 if (Index != 0xff) 00779 { 00780 /* Read the I/O redirection entry */ 00781 RedirReg = ApicReadIORedirectionEntry(Index); 00782 00783 /* Re-request the interrupt to be handled later */ 00784 ApicRequestInterrupt(Vector, (UCHAR)RedirReg.TriggerMode); 00785 } 00786 else 00787 { 00788 /* Re-request the interrupt to be handled later */ 00789 ApicRequestInterrupt(Vector, APIC_TGM_Edge); 00790 } 00791 00792 /* Pretend it was a spurious interrupt */ 00793 return FALSE; 00794 } 00795 #endif 00796 /* Save the current IRQL */ 00797 *OldIrql = CurrentIrql; 00798 00799 /* Set the new IRQL */ 00800 ApicRaiseIrql(Irql); 00801 00802 /* Turn on interrupts */ 00803 _enable(); 00804 00805 /* Success */ 00806 return TRUE; 00807 } 00808 00809 VOID 00810 NTAPI 00811 HalEndSystemInterrupt( 00812 IN KIRQL OldIrql, 00813 IN PKTRAP_FRAME TrapFrame) 00814 { 00815 /* Send an EOI */ 00816 ApicSendEOI(); 00817 00818 /* Restore the old IRQL */ 00819 ApicLowerIrql(OldIrql); 00820 } 00821 00822 00823 /* IRQL MANAGEMENT ************************************************************/ 00824 00825 KIRQL 00826 NTAPI 00827 KeGetCurrentIrql(VOID) 00828 { 00829 /* Read the current TPR and convert it to an IRQL */ 00830 return ApicGetCurrentIrql(); 00831 } 00832 00833 VOID 00834 FASTCALL 00835 KfLowerIrql( 00836 IN KIRQL OldIrql) 00837 { 00838 #if DBG 00839 /* Validate correct lower */ 00840 if (OldIrql > ApicGetCurrentIrql()) 00841 { 00842 /* Crash system */ 00843 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); 00844 } 00845 #endif 00846 /* Set the new IRQL */ 00847 ApicLowerIrql(OldIrql); 00848 } 00849 00850 KIRQL 00851 FASTCALL 00852 KfRaiseIrql( 00853 IN KIRQL NewIrql) 00854 { 00855 KIRQL OldIrql; 00856 00857 /* Read the current IRQL */ 00858 OldIrql = ApicGetCurrentIrql(); 00859 #if DBG 00860 /* Validate correct raise */ 00861 if (OldIrql > NewIrql) 00862 { 00863 /* Crash system */ 00864 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL); 00865 } 00866 #endif 00867 /* Convert the new IRQL to a TPR value and write the register */ 00868 ApicRaiseIrql(NewIrql); 00869 00870 /* Return old IRQL */ 00871 return OldIrql; 00872 } 00873 00874 KIRQL 00875 NTAPI 00876 KeRaiseIrqlToDpcLevel(VOID) 00877 { 00878 return KfRaiseIrql(DISPATCH_LEVEL); 00879 } 00880 00881 KIRQL 00882 NTAPI 00883 KeRaiseIrqlToSynchLevel(VOID) 00884 { 00885 return KfRaiseIrql(SYNCH_LEVEL); 00886 } 00887 00888 #endif /* !_M_AMD64 */ 00889 Generated on Sat May 26 2012 04:27:22 for ReactOS by
1.7.6.1
|