/* * PROJECT: ReactOS HAL * LICENSE: GNU GPL - See COPYING in the top level directory * FILE: hal/halx86/apic/apic.c * PURPOSE: HAL APIC Management and Control Code * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) * REFERENCES: https://web.archive.org/web/20190407074221/http://www.joseflores.com/docs/ExploringIrql.html * http://www.codeproject.com/KB/system/soviet_kernel_hack.aspx * http://bbs.unixmap.net/thread-2022-1-1.html * https://www.codemachine.com/article_interruptdispatching.html * https://www.osronline.com/article.cfm%5Earticle=211.htm */ /* INCLUDES *******************************************************************/ #include #include "apicp.h" #define NDEBUG #include #ifndef _M_AMD64 #define APIC_LAZY_IRQL #endif /* GLOBALS ********************************************************************/ ULONG ApicVersion; UCHAR HalpVectorToIndex[256]; #ifndef _M_AMD64 const UCHAR HalpIRQLtoTPR[32] = { 0x00, /* 0 PASSIVE_LEVEL */ 0x3d, /* 1 APC_LEVEL */ 0x41, /* 2 DISPATCH_LEVEL */ 0x41, /* 3 \ */ 0x51, /* 4 \ */ 0x61, /* 5 | */ 0x71, /* 6 | */ 0x81, /* 7 | */ 0x91, /* 8 | */ 0xa1, /* 9 | */ 0xb1, /* 10 | */ 0xb1, /* 11 | */ 0xb1, /* 12 | */ 0xb1, /* 13 | */ 0xb1, /* 14 | */ 0xb1, /* 15 DEVICE IRQL */ 0xb1, /* 16 | */ 0xb1, /* 17 | */ 0xb1, /* 18 | */ 0xb1, /* 19 | */ 0xb1, /* 20 | */ 0xb1, /* 21 | */ 0xb1, /* 22 | */ 0xb1, /* 23 | */ 0xb1, /* 24 | */ 0xb1, /* 25 / */ 0xb1, /* 26 / */ 0xc1, /* 27 PROFILE_LEVEL */ 0xd1, /* 28 CLOCK2_LEVEL */ 0xe1, /* 29 IPI_LEVEL */ 0xef, /* 30 POWER_LEVEL */ 0xff, /* 31 HIGH_LEVEL */ }; const KIRQL HalVectorToIRQL[16] = { 0, /* 00 PASSIVE_LEVEL */ 0xff, /* 10 */ 0xff, /* 20 */ 1, /* 3D APC_LEVEL */ 2, /* 41 DISPATCH_LEVEL */ 4, /* 50 \ */ 5, /* 60 \ */ 6, /* 70 | */ 7, /* 80 DEVICE IRQL */ 8, /* 90 | */ 9, /* A0 / */ 10, /* B0 / */ 27, /* C1 PROFILE_LEVEL */ 28, /* D1 CLOCK2_LEVEL */ 29, /* E1 IPI_LEVEL / EF POWER_LEVEL */ 31, /* FF HIGH_LEVEL */ }; #endif /* PRIVATE FUNCTIONS **********************************************************/ FORCEINLINE ULONG IOApicRead(UCHAR Register) { /* Select the register, then do the read */ ASSERT(Register <= 0x3F); WRITE_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOREGSEL), Register); return READ_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOWIN)); } FORCEINLINE VOID IOApicWrite(UCHAR Register, ULONG Value) { /* Select the register, then do the write */ ASSERT(Register <= 0x3F); WRITE_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOREGSEL), Register); WRITE_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOWIN), Value); } FORCEINLINE VOID ApicWriteIORedirectionEntry( UCHAR Index, IOAPIC_REDIRECTION_REGISTER ReDirReg) { ASSERT(Index < APIC_MAX_IRQ); IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0); IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1); } FORCEINLINE IOAPIC_REDIRECTION_REGISTER ApicReadIORedirectionEntry( UCHAR Index) { IOAPIC_REDIRECTION_REGISTER ReDirReg; ASSERT(Index < APIC_MAX_IRQ); ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index); ReDirReg.Long1 = IOApicRead(IOAPIC_REDTBL + 2 * Index + 1); return ReDirReg; } FORCEINLINE VOID ApicRequestSelfInterrupt(IN UCHAR Vector, UCHAR TriggerMode) { ULONG Flags; APIC_INTERRUPT_COMMAND_REGISTER Icr; APIC_INTERRUPT_COMMAND_REGISTER IcrStatus; /* * The IRR registers are spaced 16 bytes apart and hold 32 status bits each. * Pre-compute the register and bit that match our vector. */ ULONG VectorHigh = Vector / 32; ULONG VectorLow = Vector % 32; ULONG Irr = APIC_IRR + 0x10 * VectorHigh; ULONG IrrBit = 1UL << VectorLow; /* Setup the command register */ Icr.Long0 = 0; Icr.Vector = Vector; Icr.MessageType = APIC_MT_Fixed; Icr.TriggerMode = TriggerMode; Icr.DestinationShortHand = APIC_DSH_Self; /* Disable interrupts so that we can change IRR without being interrupted */ Flags = __readeflags(); _disable(); /* Wait for the APIC to be idle */ do { IcrStatus.Long0 = ApicRead(APIC_ICR0); } while (IcrStatus.DeliveryStatus); /* Write the low dword to send the interrupt */ ApicWrite(APIC_ICR0, Icr.Long0); /* Wait until we see the interrupt request. * It will stay in requested state until we re-enable interrupts. */ while (!(ApicRead(Irr) & IrrBit)) { NOTHING; } /* Finally, restore the original interrupt state */ if (Flags & EFLAGS_INTERRUPT_MASK) { _enable(); } } FORCEINLINE VOID ApicSendEOI(void) { ApicWrite(APIC_EOI, 0); } FORCEINLINE KIRQL ApicGetProcessorIrql(VOID) { /* Read the TPR and convert it to an IRQL */ return TprToIrql(ApicRead(APIC_PPR)); } FORCEINLINE KIRQL ApicGetCurrentIrql(VOID) { #ifdef _M_AMD64 return (KIRQL)__readcr8(); #elif defined(APIC_LAZY_IRQL) /* Return the field in the PCR */ return (KIRQL)__readfsbyte(FIELD_OFFSET(KPCR, Irql)); #else /* Read the TPR and convert it to an IRQL */ return TprToIrql(ApicRead(APIC_TPR)); #endif } FORCEINLINE VOID ApicSetIrql(KIRQL Irql) { #ifdef _M_AMD64 __writecr8(Irql); #elif defined(APIC_LAZY_IRQL) __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); #else /* Convert IRQL and write the TPR */ ApicWrite(APIC_TPR, IrqlToTpr(Irql)); #endif } #define ApicRaiseIrql ApicSetIrql #ifdef APIC_LAZY_IRQL FORCEINLINE VOID ApicLowerIrql(KIRQL Irql) { __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); /* Is the new Irql lower than set in the TPR? */ if (Irql < KeGetPcr()->IRR) { /* Save the new hard IRQL in the IRR field */ KeGetPcr()->IRR = Irql; /* Need to lower it back */ ApicWrite(APIC_TPR, IrqlToTpr(Irql)); } } #else #define ApicLowerIrql ApicSetIrql #endif UCHAR FASTCALL HalpIrqToVector(UCHAR Irq) { IOAPIC_REDIRECTION_REGISTER ReDirReg; /* Read low dword of the redirection entry */ ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Irq); /* Return the vector */ return (UCHAR)ReDirReg.Vector; } KIRQL FASTCALL HalpVectorToIrql(UCHAR Vector) { return TprToIrql(Vector); } UCHAR FASTCALL HalpVectorToIrq(UCHAR Vector) { return HalpVectorToIndex[Vector]; } VOID NTAPI HalpSendEOI(VOID) { ApicSendEOI(); } VOID NTAPI ApicInitializeLocalApic(ULONG Cpu) { APIC_BASE_ADRESS_REGISTER BaseRegister; APIC_SPURIOUS_INERRUPT_REGISTER SpIntRegister; LVT_REGISTER LvtEntry; /* Enable the APIC if it wasn't yet */ BaseRegister.LongLong = __readmsr(MSR_APIC_BASE); BaseRegister.Enable = 1; BaseRegister.BootStrapCPUCore = (Cpu == 0); __writemsr(MSR_APIC_BASE, BaseRegister.LongLong); /* Set spurious vector and SoftwareEnable to 1 */ SpIntRegister.Long = ApicRead(APIC_SIVR); SpIntRegister.Vector = APIC_SPURIOUS_VECTOR; SpIntRegister.SoftwareEnable = 1; SpIntRegister.FocusCPUCoreChecking = 0; ApicWrite(APIC_SIVR, SpIntRegister.Long); /* Read the version and save it globally */ if (Cpu == 0) ApicVersion = ApicRead(APIC_VER); /* Set the mode to flat (max 8 CPUs supported!) */ ApicWrite(APIC_DFR, APIC_DF_Flat); /* Set logical apic ID */ ApicWrite(APIC_LDR, ApicLogicalId(Cpu) << 24); /* Set the spurious ISR */ KeRegisterInterruptHandler(APIC_SPURIOUS_VECTOR, ApicSpuriousService); /* Create a template LVT */ LvtEntry.Long = 0; LvtEntry.Vector = APIC_FREE_VECTOR; LvtEntry.MessageType = APIC_MT_Fixed; LvtEntry.DeliveryStatus = 0; LvtEntry.RemoteIRR = 0; LvtEntry.TriggerMode = APIC_TGM_Edge; LvtEntry.Mask = 1; LvtEntry.TimerMode = 0; /* Initialize and mask LVTs */ ApicWrite(APIC_TMRLVTR, LvtEntry.Long); ApicWrite(APIC_THRMLVTR, LvtEntry.Long); ApicWrite(APIC_PCLVTR, LvtEntry.Long); ApicWrite(APIC_EXT0LVTR, LvtEntry.Long); ApicWrite(APIC_EXT1LVTR, LvtEntry.Long); ApicWrite(APIC_EXT2LVTR, LvtEntry.Long); ApicWrite(APIC_EXT3LVTR, LvtEntry.Long); /* LINT0 */ LvtEntry.Vector = APIC_SPURIOUS_VECTOR; LvtEntry.MessageType = APIC_MT_ExtInt; ApicWrite(APIC_LINT0, LvtEntry.Long); /* Enable LINT1 (NMI) */ LvtEntry.Mask = 0; LvtEntry.Vector = APIC_NMI_VECTOR; LvtEntry.MessageType = APIC_MT_NMI; LvtEntry.TriggerMode = APIC_TGM_Level; ApicWrite(APIC_LINT1, LvtEntry.Long); /* Enable error LVTR */ LvtEntry.Vector = APIC_ERROR_VECTOR; LvtEntry.MessageType = APIC_MT_Fixed; ApicWrite(APIC_ERRLVTR, LvtEntry.Long); /* Set the IRQL from the PCR */ ApicSetIrql(KeGetPcr()->Irql); #ifdef APIC_LAZY_IRQL /* Save the new hard IRQL in the IRR field */ KeGetPcr()->IRR = KeGetPcr()->Irql; #endif } UCHAR NTAPI HalpAllocateSystemInterrupt( _In_ UCHAR Irq, _In_ UCHAR Vector) { IOAPIC_REDIRECTION_REGISTER ReDirReg; ASSERT(Irq < APIC_MAX_IRQ); ASSERT(HalpVectorToIndex[Vector] == APIC_FREE_VECTOR); /* Setup a redirection entry */ ReDirReg.Vector = Vector; ReDirReg.DeliveryMode = APIC_MT_LowestPriority; ReDirReg.DestinationMode = APIC_DM_Logical; ReDirReg.DeliveryStatus = 0; ReDirReg.Polarity = 0; ReDirReg.RemoteIRR = 0; ReDirReg.TriggerMode = APIC_TGM_Edge; ReDirReg.Mask = 1; ReDirReg.Reserved = 0; ReDirReg.Destination = 0; /* Initialize entry */ ApicWriteIORedirectionEntry(Irq, ReDirReg); /* Save irq in the table */ HalpVectorToIndex[Vector] = Irq; return Vector; } ULONG NTAPI HalpGetRootInterruptVector( _In_ ULONG BusInterruptLevel, _In_ ULONG BusInterruptVector, _Out_ PKIRQL OutIrql, _Out_ PKAFFINITY OutAffinity) { UCHAR Vector; KIRQL Irql; /* Get the vector currently registered */ Vector = HalpIrqToVector(BusInterruptLevel); /* Check if it's used */ if (Vector != APIC_FREE_VECTOR) { /* Calculate IRQL */ NT_ASSERT(HalpVectorToIndex[Vector] == BusInterruptLevel); *OutIrql = HalpVectorToIrql(Vector); } else { ULONG Offset; /* Outer loop to find alternative slots, when all IRQLs are in use */ for (Offset = 0; Offset < 15; Offset++) { /* Loop allowed IRQL range */ for (Irql = CLOCK_LEVEL - 1; Irql >= CMCI_LEVEL; Irql--) { /* Calculate the vactor */ Vector = IrqlToTpr(Irql) + Offset; /* Check if the vector is free */ if (HalpVectorToIrq(Vector) == APIC_FREE_VECTOR) { /* Found one, allocate the interrupt */ Vector = HalpAllocateSystemInterrupt(BusInterruptLevel, Vector); *OutIrql = Irql; goto Exit; } } } DPRINT1("Failed to get an interrupt vector for IRQ %lu\n", BusInterruptLevel); *OutAffinity = 0; *OutIrql = 0; return 0; } Exit: *OutAffinity = HalpDefaultInterruptAffinity; ASSERT(HalpDefaultInterruptAffinity); return Vector; } VOID NTAPI ApicInitializeIOApic(VOID) { PHARDWARE_PTE Pte; IOAPIC_REDIRECTION_REGISTER ReDirReg; UCHAR Index; ULONG Vector; /* Map the I/O Apic page */ Pte = HalAddressToPte(IOAPIC_BASE); Pte->PageFrameNumber = IOAPIC_PHYS_BASE / PAGE_SIZE; Pte->Valid = 1; Pte->Write = 1; Pte->Owner = 1; Pte->CacheDisable = 1; Pte->Global = 1; _ReadWriteBarrier(); /* Setup a redirection entry */ ReDirReg.Vector = APIC_FREE_VECTOR; ReDirReg.DeliveryMode = APIC_MT_Fixed; ReDirReg.DestinationMode = APIC_DM_Physical; ReDirReg.DeliveryStatus = 0; ReDirReg.Polarity = 0; ReDirReg.RemoteIRR = 0; ReDirReg.TriggerMode = APIC_TGM_Edge; ReDirReg.Mask = 1; ReDirReg.Reserved = 0; ReDirReg.Destination = 0; /* Loop all table entries */ for (Index = 0; Index < APIC_MAX_IRQ; Index++) { /* Initialize entry */ ApicWriteIORedirectionEntry(Index, ReDirReg); } /* Init the vactor to index table */ for (Vector = 0; Vector <= 255; Vector++) { HalpVectorToIndex[Vector] = APIC_FREE_VECTOR; } /* Enable the timer interrupt (but keep it masked) */ ReDirReg.Vector = APIC_CLOCK_VECTOR; ReDirReg.DeliveryMode = APIC_MT_Fixed; ReDirReg.DestinationMode = APIC_DM_Physical; ReDirReg.TriggerMode = APIC_TGM_Edge; ReDirReg.Mask = 1; ReDirReg.Destination = ApicRead(APIC_ID); ApicWriteIORedirectionEntry(APIC_CLOCK_INDEX, ReDirReg); } VOID NTAPI HalpInitializePICs(IN BOOLEAN EnableInterrupts) { ULONG_PTR EFlags; /* Save EFlags and disable interrupts */ EFlags = __readeflags(); _disable(); /* Initialize and mask the PIC */ HalpInitializeLegacyPICs(); /* Initialize the I/O APIC */ ApicInitializeIOApic(); /* Manually reserve some vectors */ HalpVectorToIndex[APC_VECTOR] = APIC_RESERVED_VECTOR; HalpVectorToIndex[DISPATCH_VECTOR] = APIC_RESERVED_VECTOR; HalpVectorToIndex[APIC_CLOCK_VECTOR] = 8; HalpVectorToIndex[APIC_SPURIOUS_VECTOR] = APIC_RESERVED_VECTOR; /* Set interrupt handlers in the IDT */ KeRegisterInterruptHandler(APIC_CLOCK_VECTOR, HalpClockInterrupt); #ifndef _M_AMD64 KeRegisterInterruptHandler(APC_VECTOR, HalpApcInterrupt); KeRegisterInterruptHandler(DISPATCH_VECTOR, HalpDispatchInterrupt); #endif /* Register the vectors for APC and dispatch interrupts */ HalpRegisterVector(IDT_INTERNAL, 0, APC_VECTOR, APC_LEVEL); HalpRegisterVector(IDT_INTERNAL, 0, DISPATCH_VECTOR, DISPATCH_LEVEL); /* Restore interrupt state */ if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK; __writeeflags(EFlags); } /* SOFTWARE INTERRUPT TRAPS ***************************************************/ #ifndef _M_AMD64 VOID DECLSPEC_NORETURN FASTCALL HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) { KPROCESSOR_MODE ProcessorMode; KIRQL OldIrql; ASSERT(ApicGetProcessorIrql() == APC_LEVEL); /* Enter trap */ KiEnterInterruptTrap(TrapFrame); #ifdef APIC_LAZY_IRQL if (!HalBeginSystemInterrupt(APC_LEVEL, APC_VECTOR, &OldIrql)) { /* "Spurious" interrupt, exit the interrupt */ KiEoiHelper(TrapFrame); } #else /* Save the old IRQL */ OldIrql = ApicGetCurrentIrql(); ASSERT(OldIrql < APC_LEVEL); #endif /* Raise to APC_LEVEL */ ApicRaiseIrql(APC_LEVEL); /* End the interrupt */ ApicSendEOI(); /* Kernel or user APC? */ if (KiUserTrap(TrapFrame)) ProcessorMode = UserMode; else if (TrapFrame->EFlags & EFLAGS_V86_MASK) ProcessorMode = UserMode; else ProcessorMode = KernelMode; /* Enable interrupts and call the kernel's APC interrupt handler */ _enable(); KiDeliverApc(ProcessorMode, NULL, TrapFrame); /* Disable interrupts */ _disable(); /* Restore the old IRQL */ ApicLowerIrql(OldIrql); /* Exit the interrupt */ KiEoiHelper(TrapFrame); } VOID DECLSPEC_NORETURN FASTCALL HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame) { KIRQL OldIrql; ASSERT(ApicGetProcessorIrql() == DISPATCH_LEVEL); /* Enter trap */ KiEnterInterruptTrap(TrapFrame); #ifdef APIC_LAZY_IRQL if (!HalBeginSystemInterrupt(DISPATCH_LEVEL, DISPATCH_VECTOR, &OldIrql)) { /* "Spurious" interrupt, exit the interrupt */ KiEoiHelper(TrapFrame); } #else /* Get the current IRQL */ OldIrql = ApicGetCurrentIrql(); ASSERT(OldIrql < DISPATCH_LEVEL); #endif /* Raise to DISPATCH_LEVEL */ ApicRaiseIrql(DISPATCH_LEVEL); /* End the interrupt */ ApicSendEOI(); /* Enable interrupts and call the kernel's DPC interrupt handler */ _enable(); KiDispatchInterrupt(); _disable(); /* Restore the old IRQL */ ApicLowerIrql(OldIrql); /* Exit the interrupt */ KiEoiHelper(TrapFrame); } #endif /* SOFTWARE INTERRUPTS ********************************************************/ VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql) { /* Convert irql to vector and request an interrupt */ ApicRequestSelfInterrupt(IrqlToSoftVector(Irql), APIC_TGM_Edge); } VOID FASTCALL HalClearSoftwareInterrupt( IN KIRQL Irql) { /* Nothing to do */ } /* SYSTEM INTERRUPTS **********************************************************/ BOOLEAN NTAPI HalEnableSystemInterrupt( IN ULONG Vector, IN KIRQL Irql, IN KINTERRUPT_MODE InterruptMode) { IOAPIC_REDIRECTION_REGISTER ReDirReg; PKPRCB Prcb = KeGetCurrentPrcb(); UCHAR Index; ASSERT(Irql <= HIGH_LEVEL); ASSERT((IrqlToTpr(Irql) & 0xF0) == (Vector & 0xF0)); /* Get the irq for this vector */ Index = HalpVectorToIndex[Vector]; /* Check if its valid */ if (Index == APIC_FREE_VECTOR) { /* Interrupt is not in use */ return FALSE; } /* Read the redirection entry */ ReDirReg = ApicReadIORedirectionEntry(Index); /* Check if the interrupt was unused */ if (ReDirReg.Vector != Vector) { ReDirReg.Vector = Vector; ReDirReg.DeliveryMode = APIC_MT_LowestPriority; ReDirReg.DestinationMode = APIC_DM_Logical; ReDirReg.Destination = 0; } /* Check if the destination is logical */ if (ReDirReg.DestinationMode == APIC_DM_Logical) { /* Set the bit for this cpu */ ReDirReg.Destination |= ApicLogicalId(Prcb->Number); } /* Set the trigger mode */ ReDirReg.TriggerMode = 1 - InterruptMode; /* Now unmask it */ ReDirReg.Mask = FALSE; /* Write back the entry */ ApicWriteIORedirectionEntry(Index, ReDirReg); return TRUE; } VOID NTAPI HalDisableSystemInterrupt( IN ULONG Vector, IN KIRQL Irql) { IOAPIC_REDIRECTION_REGISTER ReDirReg; UCHAR Index; ASSERT(Irql <= HIGH_LEVEL); ASSERT(Vector < RTL_NUMBER_OF(HalpVectorToIndex)); Index = HalpVectorToIndex[Vector]; /* Read lower dword of redirection entry */ ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index); /* Mask it */ ReDirReg.Mask = 1; /* Write back lower dword */ IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0); } #ifndef _M_AMD64 BOOLEAN NTAPI HalBeginSystemInterrupt( IN KIRQL Irql, IN ULONG Vector, OUT PKIRQL OldIrql) { KIRQL CurrentIrql; /* Get the current IRQL */ CurrentIrql = ApicGetCurrentIrql(); #ifdef APIC_LAZY_IRQL /* Check if this interrupt is allowed */ if (CurrentIrql >= Irql) { IOAPIC_REDIRECTION_REGISTER RedirReg; UCHAR Index; /* It is not, set the real Irql in the TPR! */ ApicWrite(APIC_TPR, IrqlToTpr(CurrentIrql)); /* Save the new hard IRQL in the IRR field */ KeGetPcr()->IRR = CurrentIrql; /* End this interrupt */ ApicSendEOI(); /* Get the irq for this vector */ Index = HalpVectorToIndex[Vector]; /* Check if it's valid */ if (Index < APIC_MAX_IRQ) { /* Read the I/O redirection entry */ RedirReg = ApicReadIORedirectionEntry(Index); /* Re-request the interrupt to be handled later */ ApicRequestSelfInterrupt(Vector, (UCHAR)RedirReg.TriggerMode); } else { /* This should be a reserved vector! */ ASSERT(Index == APIC_RESERVED_VECTOR); /* Re-request the interrupt to be handled later */ ApicRequestSelfInterrupt(Vector, APIC_TGM_Edge); } /* Pretend it was a spurious interrupt */ return FALSE; } #endif /* Save the current IRQL */ *OldIrql = CurrentIrql; /* Set the new IRQL */ ApicRaiseIrql(Irql); /* Turn on interrupts */ _enable(); /* Success */ return TRUE; } VOID NTAPI HalEndSystemInterrupt( IN KIRQL OldIrql, IN PKTRAP_FRAME TrapFrame) { /* Send an EOI */ ApicSendEOI(); /* Restore the old IRQL */ ApicLowerIrql(OldIrql); } /* IRQL MANAGEMENT ************************************************************/ KIRQL NTAPI KeGetCurrentIrql(VOID) { /* Read the current TPR and convert it to an IRQL */ return ApicGetCurrentIrql(); } VOID FASTCALL KfLowerIrql( IN KIRQL OldIrql) { #if DBG /* Validate correct lower */ if (OldIrql > ApicGetCurrentIrql()) { /* Crash system */ KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); } #endif /* Set the new IRQL */ ApicLowerIrql(OldIrql); } KIRQL FASTCALL KfRaiseIrql( IN KIRQL NewIrql) { KIRQL OldIrql; /* Read the current IRQL */ OldIrql = ApicGetCurrentIrql(); #if DBG /* Validate correct raise */ if (OldIrql > NewIrql) { /* Crash system */ KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL); } #endif /* Convert the new IRQL to a TPR value and write the register */ ApicRaiseIrql(NewIrql); /* Return old IRQL */ return OldIrql; } KIRQL NTAPI KeRaiseIrqlToDpcLevel(VOID) { return KfRaiseIrql(DISPATCH_LEVEL); } KIRQL NTAPI KeRaiseIrqlToSynchLevel(VOID) { return KfRaiseIrql(SYNCH_LEVEL); } #endif /* !_M_AMD64 */