ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

apic.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.