2001-08-21 20:18:27 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/hal/x86/mpsirql.c
|
|
|
|
* PURPOSE: Implements IRQLs for multiprocessor systems
|
|
|
|
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
|
|
* Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
|
|
* UPDATE HISTORY:
|
|
|
|
* 12/04/2001 CSH Created
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2002-09-08 10:23:54 +00:00
|
|
|
#include <ddk/ntddk.h>
|
|
|
|
#include <internal/ke.h>
|
|
|
|
#include <internal/ps.h>
|
2003-04-06 10:45:16 +00:00
|
|
|
#include <ntos/minmax.h>
|
2002-09-08 10:23:54 +00:00
|
|
|
#include <mps.h>
|
2001-08-21 20:18:27 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <internal/debug.h>
|
|
|
|
|
|
|
|
/* GLOBALS ******************************************************************/;
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
#define IRQ_BASE (0x30)
|
|
|
|
#define NR_VECTORS (0x100 - IRQ_BASE)
|
|
|
|
|
2001-08-21 20:18:27 +00:00
|
|
|
extern IMPORTED ULONG DpcQueueSize;
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
static ULONG HalpPendingInterruptCount[NR_VECTORS];
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
static VOID KeSetCurrentIrql (KIRQL newlvl);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
VOID STDCALL
|
|
|
|
KiInterruptDispatch2 (ULONG Irq, KIRQL old_level);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
#define IRQL2TPR(irql) (FIRST_DEVICE_VECTOR + ((irql - DISPATCH_LEVEL /* 2 */ - 1) * 8))
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
/* FUNCTIONS ****************************************************************/
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
KIRQL STDCALL KeGetCurrentIrql (VOID)
|
2001-08-21 20:18:27 +00:00
|
|
|
/*
|
2003-04-06 10:45:16 +00:00
|
|
|
* PURPOSE: Returns the current irq level
|
|
|
|
* RETURNS: The current irq level
|
2001-08-21 20:18:27 +00:00
|
|
|
*/
|
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
if (KeGetCurrentKPCR ()->Irql > HIGH_LEVEL)
|
|
|
|
{
|
|
|
|
DPRINT1 ("CurrentIrql %x\n", KeGetCurrentKPCR ()->Irql);
|
|
|
|
KeBugCheck (0);
|
|
|
|
for(;;);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(KeGetCurrentKPCR ()->Irql);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
static VOID KeSetCurrentIrql (KIRQL NewIrql)
|
2001-08-21 20:18:27 +00:00
|
|
|
/*
|
2003-04-06 10:45:16 +00:00
|
|
|
* PURPOSE: Sets the current irq level without taking any action
|
2001-08-21 20:18:27 +00:00
|
|
|
*/
|
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
if (NewIrql > HIGH_LEVEL)
|
|
|
|
{
|
|
|
|
DPRINT1 ("NewIrql %x\n", NewIrql);
|
|
|
|
KeBugCheck (0);
|
|
|
|
for(;;);
|
|
|
|
}
|
|
|
|
|
|
|
|
KeGetCurrentKPCR ()->Irql = NewIrql;
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
VOID HalpEndSystemInterrupt (KIRQL Irql)
|
2001-08-21 20:18:27 +00:00
|
|
|
/*
|
2003-04-06 10:45:16 +00:00
|
|
|
* FUNCTION: Enable all irqs with higher priority.
|
2001-08-21 20:18:27 +00:00
|
|
|
*/
|
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
/* Interrupts should be disabled while enabling irqs */
|
|
|
|
__asm__("pushf\n\t");
|
|
|
|
__asm__("cli\n\t");
|
|
|
|
APICWrite (APIC_TPR, IRQL2TPR (Irql) & APIC_TPR_PRI);
|
|
|
|
__asm__("popf\n\t");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID STATIC
|
|
|
|
HalpExecuteIrqs(KIRQL NewIrql)
|
|
|
|
{
|
|
|
|
ULONG VectorLimit, i;
|
|
|
|
|
|
|
|
VectorLimit = min(IRQL2VECTOR (NewIrql), NR_VECTORS);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For each vector if there have been any deferred interrupts then now
|
|
|
|
* dispatch them.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < VectorLimit; i++)
|
|
|
|
{
|
|
|
|
if (HalpPendingInterruptCount[i] > 0)
|
|
|
|
{
|
|
|
|
KeSetCurrentIrql (VECTOR2IRQL (i));
|
|
|
|
|
|
|
|
while (HalpPendingInterruptCount[i] > 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For each deferred interrupt execute all the handlers at DIRQL.
|
|
|
|
*/
|
|
|
|
KiInterruptDispatch2 (i, NewIrql);
|
|
|
|
HalpPendingInterruptCount[i]--;
|
|
|
|
}
|
|
|
|
KeSetCurrentIrql (KeGetCurrentIrql () - 1);
|
|
|
|
HalpEndSystemInterrupt (KeGetCurrentIrql ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
|
|
|
|
VOID STATIC
|
|
|
|
HalpLowerIrql(KIRQL NewIrql)
|
|
|
|
{
|
|
|
|
if (NewIrql >= PROFILE_LEVEL)
|
|
|
|
{
|
|
|
|
KeSetCurrentIrql (NewIrql);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
HalpExecuteIrqs (NewIrql);
|
|
|
|
if (NewIrql >= DISPATCH_LEVEL)
|
|
|
|
{
|
|
|
|
KeSetCurrentIrql (NewIrql);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
KeSetCurrentIrql (DISPATCH_LEVEL);
|
|
|
|
if (DpcQueueSize > 0)
|
|
|
|
{
|
|
|
|
KiDispatchInterrupt ();
|
|
|
|
}
|
|
|
|
KeSetCurrentIrql (APC_LEVEL);
|
|
|
|
if (NewIrql == APC_LEVEL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (KeGetCurrentThread () != NULL &&
|
|
|
|
KeGetCurrentThread ()->ApcState.KernelApcPending)
|
|
|
|
{
|
|
|
|
KiDeliverApc (0, 0, 0);
|
|
|
|
}
|
|
|
|
KeSetCurrentIrql (PASSIVE_LEVEL);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* NAME EXPORTED
|
|
|
|
* KfLowerIrql
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Restores the irq level on the current processor
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
|
|
|
* NewIrql = Irql to lower to
|
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* Uses fastcall convention
|
|
|
|
*/
|
|
|
|
VOID FASTCALL
|
2003-04-06 10:45:16 +00:00
|
|
|
KfLowerIrql (KIRQL NewIrql)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
if (NewIrql > KeGetCurrentIrql ())
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
DPRINT1 ("NewIrql %x CurrentIrql %x\n", NewIrql, KeGetCurrentIrql ());
|
|
|
|
KeBugCheck (0);
|
2001-08-21 20:18:27 +00:00
|
|
|
for(;;);
|
|
|
|
}
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
HalpLowerIrql (NewIrql);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* NAME EXPORTED
|
|
|
|
* KeLowerIrql
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Restores the irq level on the current processor
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
|
|
|
* NewIrql = Irql to lower to
|
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
*/
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
VOID STDCALL
|
|
|
|
KeLowerIrql (KIRQL NewIrql)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
KfLowerIrql (NewIrql);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* NAME EXPORTED
|
|
|
|
* KfRaiseIrql
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Raises the hardware priority (irql)
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
|
|
|
* NewIrql = Irql to raise to
|
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
* previous irq level
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* Uses fastcall convention
|
|
|
|
*/
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
KIRQL FASTCALL
|
|
|
|
KfRaiseIrql (KIRQL NewIrql)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
2003-04-06 10:45:16 +00:00
|
|
|
|
|
|
|
if (NewIrql < KeGetCurrentIrql ())
|
|
|
|
{
|
|
|
|
DPRINT1 ("CurrentIrql %x NewIrql %x\n", KeGetCurrentIrql (), NewIrql);
|
|
|
|
KeBugCheck (0);
|
|
|
|
for(;;);
|
|
|
|
}
|
|
|
|
|
|
|
|
OldIrql = KeGetCurrentIrql ();
|
|
|
|
KeSetCurrentIrql (NewIrql);
|
|
|
|
return OldIrql;
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* NAME EXPORTED
|
|
|
|
* KeRaiseIrql
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Raises the hardware priority (irql)
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
|
|
|
* NewIrql = Irql to raise to
|
|
|
|
* OldIrql (OUT) = Caller supplied storage for the previous irql
|
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* Calls KfRaiseIrql
|
|
|
|
*/
|
2003-04-06 10:45:16 +00:00
|
|
|
VOID STDCALL
|
|
|
|
KeRaiseIrql (KIRQL NewIrql,
|
|
|
|
PKIRQL OldIrql)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
*OldIrql = KfRaiseIrql (NewIrql);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* NAME EXPORTED
|
|
|
|
* KeRaiseIrqlToDpcLevel
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Raises the hardware priority (irql) to DISPATCH level
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
* Previous irq level
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* Calls KfRaiseIrql
|
|
|
|
*/
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
KIRQL STDCALL
|
2001-08-21 20:18:27 +00:00
|
|
|
KeRaiseIrqlToDpcLevel (VOID)
|
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
return KfRaiseIrql (DISPATCH_LEVEL);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* NAME EXPORTED
|
|
|
|
* KeRaiseIrqlToSynchLevel
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Raises the hardware priority (irql) to CLOCK2 level
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
* Previous irq level
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* Calls KfRaiseIrql
|
|
|
|
*/
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
KIRQL STDCALL
|
2001-08-21 20:18:27 +00:00
|
|
|
KeRaiseIrqlToSynchLevel (VOID)
|
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
return KfRaiseIrql (CLOCK2_LEVEL);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
BOOLEAN STDCALL
|
|
|
|
HalBeginSystemInterrupt (ULONG Vector,
|
|
|
|
KIRQL Irql,
|
|
|
|
PKIRQL OldIrql)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
DPRINT("Vector (0x%X) Irql (0x%X)\n", Vector, Irql);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
|
|
|
if (Vector < FIRST_DEVICE_VECTOR ||
|
2003-04-06 10:45:16 +00:00
|
|
|
Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
|
2001-08-21 20:18:27 +00:00
|
|
|
DPRINT("Not a device interrupt\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
HalDisableSystemInterrupt (Vector, 0);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
APICSendEOI();
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
if (KeGetCurrentIrql () >= Irql)
|
|
|
|
{
|
|
|
|
HalpPendingInterruptCount[Vector]++;
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
*OldIrql = KeGetCurrentIrql ();
|
|
|
|
KeSetCurrentIrql (Irql);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
return(TRUE);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
VOID STDCALL
|
|
|
|
HalEndSystemInterrupt (KIRQL Irql,
|
|
|
|
ULONG Unknown2)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Finish a system interrupt and restore the specified irq level.
|
|
|
|
*/
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2003-04-06 10:45:16 +00:00
|
|
|
HalpLowerIrql (Irql);
|
|
|
|
HalpEndSystemInterrupt (Irql);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
2003-04-06 10:45:16 +00:00
|
|
|
|
|
|
|
BOOLEAN STDCALL
|
|
|
|
HalDisableSystemInterrupt (ULONG Vector,
|
|
|
|
ULONG Unknown2)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
|
|
|
ULONG irq;
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
DPRINT ("Vector (0x%X)\n", Vector);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
|
|
|
if (Vector < FIRST_DEVICE_VECTOR ||
|
2003-04-06 10:45:16 +00:00
|
|
|
Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
|
2001-08-21 20:18:27 +00:00
|
|
|
DPRINT("Not a device interrupt\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
irq = VECTOR2IRQ (Vector);
|
|
|
|
IOAPICMaskIrq (ThisCPU (), irq);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
return TRUE;
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
BOOLEAN STDCALL
|
|
|
|
HalEnableSystemInterrupt (ULONG Vector,
|
|
|
|
ULONG Unknown2,
|
|
|
|
ULONG Unknown3)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
|
|
|
ULONG irq;
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
DPRINT ("Vector (0x%X)\n", Vector);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
|
|
|
if (Vector < FIRST_DEVICE_VECTOR ||
|
2003-04-06 10:45:16 +00:00
|
|
|
Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
|
2001-08-21 20:18:27 +00:00
|
|
|
DPRINT("Not a device interrupt\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
irq = VECTOR2IRQ (Vector);
|
|
|
|
IOAPICUnmaskIrq (ThisCPU (), irq);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|