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 *****************************************************************/
|
|
|
|
|
|
|
|
#define NDEBUG
|
2005-06-18 14:28:28 +00:00
|
|
|
#include <hal.h>
|
2001-08-21 20:18:27 +00:00
|
|
|
|
|
|
|
/* GLOBALS ******************************************************************/;
|
|
|
|
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
/* FUNCTIONS ****************************************************************/
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2005-04-15 10:52:29 +00:00
|
|
|
#undef KeGetCurrentIrql
|
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
|
|
|
*/
|
|
|
|
{
|
2004-11-01 19:01:25 +00:00
|
|
|
KIRQL irql;
|
|
|
|
ULONG Flags;
|
|
|
|
|
|
|
|
Ki386SaveFlags(Flags);
|
|
|
|
Ki386DisableInterrupts();
|
|
|
|
|
2005-06-18 14:28:28 +00:00
|
|
|
irql = Ki386ReadFsByte(FIELD_OFFSET(KPCR, Irql));
|
2004-11-01 19:01:25 +00:00
|
|
|
if (irql > HIGH_LEVEL)
|
2003-04-06 10:45:16 +00:00
|
|
|
{
|
2004-11-01 19:01:25 +00:00
|
|
|
DPRINT1 ("CurrentIrql %x\n", irql);
|
2003-07-21 21:53:53 +00:00
|
|
|
KEBUGCHECK (0);
|
2004-11-28 01:30:02 +00:00
|
|
|
}
|
|
|
|
if (Flags & X86_EFLAGS_IF)
|
|
|
|
{
|
|
|
|
Ki386EnableInterrupts();
|
2003-04-06 10:45:16 +00:00
|
|
|
}
|
2004-11-01 19:01:25 +00:00
|
|
|
return irql;
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-15 10:52:29 +00:00
|
|
|
#undef KeSetCurrentIrql
|
2004-11-01 19:01:25 +00:00
|
|
|
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
|
|
|
*/
|
|
|
|
{
|
2004-11-01 19:01:25 +00:00
|
|
|
ULONG Flags;
|
2003-04-06 10:45:16 +00:00
|
|
|
if (NewIrql > HIGH_LEVEL)
|
2004-11-28 01:30:02 +00:00
|
|
|
{
|
|
|
|
DPRINT1 ("NewIrql %x\n", NewIrql);
|
|
|
|
KEBUGCHECK (0);
|
|
|
|
}
|
2004-11-01 19:01:25 +00:00
|
|
|
Ki386SaveFlags(Flags);
|
2004-07-20 21:25:36 +00:00
|
|
|
Ki386DisableInterrupts();
|
2005-06-18 14:28:28 +00:00
|
|
|
Ki386WriteFsByte(FIELD_OFFSET(KPCR, Irql), NewIrql);
|
2004-11-28 01:30:02 +00:00
|
|
|
if (Flags & X86_EFLAGS_IF)
|
|
|
|
{
|
|
|
|
Ki386EnableInterrupts();
|
|
|
|
}
|
2003-04-06 10:45:16 +00:00
|
|
|
}
|
|
|
|
|
2004-11-01 19:01:25 +00:00
|
|
|
VOID
|
2004-11-28 01:30:02 +00:00
|
|
|
HalpLowerIrql(KIRQL NewIrql, BOOL FromHalEndSystemInterrupt)
|
2003-04-06 10:45:16 +00:00
|
|
|
{
|
2004-11-28 01:30:02 +00:00
|
|
|
ULONG Flags;
|
2003-04-06 10:45:16 +00:00
|
|
|
if (NewIrql >= DISPATCH_LEVEL)
|
|
|
|
{
|
|
|
|
KeSetCurrentIrql (NewIrql);
|
2004-11-01 19:01:25 +00:00
|
|
|
APICWrite(APIC_TPR, IRQL2TPR (NewIrql) & APIC_TPR_PRI);
|
2003-04-06 10:45:16 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-11-28 01:30:02 +00:00
|
|
|
Ki386SaveFlags(Flags);
|
2004-11-01 19:01:25 +00:00
|
|
|
if (KeGetCurrentIrql() > APC_LEVEL)
|
2003-04-06 10:45:16 +00:00
|
|
|
{
|
2004-11-28 01:30:02 +00:00
|
|
|
KeSetCurrentIrql (DISPATCH_LEVEL);
|
|
|
|
APICWrite(APIC_TPR, IRQL2TPR (DISPATCH_LEVEL) & APIC_TPR_PRI);
|
2005-06-18 14:28:28 +00:00
|
|
|
if (FromHalEndSystemInterrupt || Ki386ReadFsByte(FIELD_OFFSET(KIPCR, HalReserved[HAL_DPC_REQUEST])))
|
2004-11-28 01:30:02 +00:00
|
|
|
{
|
2005-06-18 14:28:28 +00:00
|
|
|
Ki386WriteFsByte(FIELD_OFFSET(KIPCR, HalReserved[HAL_DPC_REQUEST]), 0);
|
2004-11-28 01:30:02 +00:00
|
|
|
Ki386EnableInterrupts();
|
|
|
|
KiDispatchInterrupt();
|
|
|
|
if (!(Flags & X86_EFLAGS_IF))
|
|
|
|
{
|
|
|
|
Ki386DisableInterrupts();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
KeSetCurrentIrql (APC_LEVEL);
|
2003-04-06 10:45:16 +00:00
|
|
|
}
|
|
|
|
if (NewIrql == APC_LEVEL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (KeGetCurrentThread () != NULL &&
|
|
|
|
KeGetCurrentThread ()->ApcState.KernelApcPending)
|
|
|
|
{
|
2004-11-28 01:30:02 +00:00
|
|
|
Ki386EnableInterrupts();
|
|
|
|
KiDeliverApc(KernelMode, NULL, NULL);
|
|
|
|
if (!(Flags & X86_EFLAGS_IF))
|
|
|
|
{
|
|
|
|
Ki386DisableInterrupts();
|
|
|
|
}
|
2003-04-06 10:45:16 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
{
|
2004-11-01 19:01:25 +00:00
|
|
|
KIRQL oldIrql = KeGetCurrentIrql();
|
|
|
|
if (NewIrql > oldIrql)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2004-11-01 19:01:25 +00:00
|
|
|
DPRINT1 ("NewIrql %x CurrentIrql %x\n", NewIrql, oldIrql);
|
2003-07-21 21:53:53 +00:00
|
|
|
KEBUGCHECK (0);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
2004-11-28 01:30:02 +00:00
|
|
|
HalpLowerIrql (NewIrql, FALSE);
|
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
|
|
|
|
*/
|
2005-06-18 14:28:28 +00:00
|
|
|
#undef KeLowerIrql
|
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;
|
2004-11-01 19:01:25 +00:00
|
|
|
ULONG Flags;
|
2004-11-28 01:30:02 +00:00
|
|
|
|
|
|
|
Ki386SaveFlags(Flags);
|
|
|
|
Ki386DisableInterrupts();
|
|
|
|
|
|
|
|
OldIrql = KeGetCurrentIrql ();
|
|
|
|
|
|
|
|
if (NewIrql < OldIrql)
|
2003-04-06 10:45:16 +00:00
|
|
|
{
|
|
|
|
DPRINT1 ("CurrentIrql %x NewIrql %x\n", KeGetCurrentIrql (), NewIrql);
|
2003-07-21 21:53:53 +00:00
|
|
|
KEBUGCHECK (0);
|
2003-04-06 10:45:16 +00:00
|
|
|
}
|
2004-11-28 01:30:02 +00:00
|
|
|
|
|
|
|
|
2004-11-01 19:01:25 +00:00
|
|
|
if (NewIrql > DISPATCH_LEVEL)
|
|
|
|
{
|
2004-11-28 01:30:02 +00:00
|
|
|
APICWrite (APIC_TPR, IRQL2TPR(NewIrql) & APIC_TPR_PRI);
|
2004-11-01 19:01:25 +00:00
|
|
|
}
|
2003-04-06 10:45:16 +00:00
|
|
|
KeSetCurrentIrql (NewIrql);
|
2004-11-28 01:30:02 +00:00
|
|
|
if (Flags & X86_EFLAGS_IF)
|
|
|
|
{
|
|
|
|
Ki386EnableInterrupts();
|
|
|
|
}
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
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
|
|
|
|
*/
|
2005-06-18 14:28:28 +00:00
|
|
|
#undef KeRaiseIrql
|
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,
|
2004-11-01 19:01:25 +00:00
|
|
|
KIRQL Irql,
|
|
|
|
PKIRQL OldIrql)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2004-11-01 19:01:25 +00:00
|
|
|
ULONG Flags;
|
2003-04-06 10:45:16 +00:00
|
|
|
DPRINT("Vector (0x%X) Irql (0x%X)\n", Vector, Irql);
|
2004-11-28 01:30:02 +00:00
|
|
|
|
2004-11-01 19:01:25 +00:00
|
|
|
if (KeGetCurrentIrql () >= Irql)
|
|
|
|
{
|
2004-11-28 01:30:02 +00:00
|
|
|
DPRINT1("current irql %d, new irql %d\n", KeGetCurrentIrql(), Irql);
|
|
|
|
KEBUGCHECK(0);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
2004-11-01 19:01:25 +00:00
|
|
|
Ki386SaveFlags(Flags);
|
2004-11-28 01:30:02 +00:00
|
|
|
if (Flags & X86_EFLAGS_IF)
|
|
|
|
{
|
|
|
|
DPRINT1("HalBeginSystemInterrupt was called with interrupt's enabled\n");
|
|
|
|
KEBUGCHECK(0);
|
|
|
|
}
|
2004-11-01 19:01:25 +00:00
|
|
|
APICWrite (APIC_TPR, IRQL2TPR (Irql) & APIC_TPR_PRI);
|
2003-04-06 10:45:16 +00:00
|
|
|
*OldIrql = KeGetCurrentIrql ();
|
|
|
|
KeSetCurrentIrql (Irql);
|
|
|
|
return(TRUE);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
VOID STDCALL
|
|
|
|
HalEndSystemInterrupt (KIRQL Irql,
|
2004-11-28 01:30:02 +00:00
|
|
|
ULONG Unknown2)
|
2003-04-06 10:45:16 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Finish a system interrupt and restore the specified irq level.
|
|
|
|
*/
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2004-11-28 01:30:02 +00:00
|
|
|
ULONG Flags;
|
|
|
|
Ki386SaveFlags(Flags);
|
|
|
|
|
|
|
|
if (Flags & X86_EFLAGS_IF)
|
|
|
|
{
|
|
|
|
DPRINT1("HalEndSystemInterrupt was called with interrupt's enabled\n");
|
|
|
|
KEBUGCHECK(0);
|
|
|
|
}
|
|
|
|
APICSendEOI();
|
|
|
|
HalpLowerIrql (Irql, TRUE);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
2003-04-06 10:45:16 +00:00
|
|
|
|
|
|
|
BOOLEAN STDCALL
|
|
|
|
HalDisableSystemInterrupt (ULONG Vector,
|
2004-11-01 19:01:25 +00:00
|
|
|
KIRQL Irql)
|
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 ||
|
2004-11-01 19:01:25 +00:00
|
|
|
Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS)
|
|
|
|
{
|
|
|
|
DPRINT1("Not a device interrupt, vector=%x\n", Vector);
|
|
|
|
return FALSE;
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
irq = VECTOR2IRQ (Vector);
|
2004-11-01 19:01:25 +00:00
|
|
|
IOAPICMaskIrq (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,
|
2004-11-01 19:01:25 +00:00
|
|
|
KIRQL Irql,
|
|
|
|
KINTERRUPT_MODE InterruptMode)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
|
|
|
ULONG irq;
|
|
|
|
|
|
|
|
if (Vector < FIRST_DEVICE_VECTOR ||
|
2004-11-01 19:01:25 +00:00
|
|
|
Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS)
|
|
|
|
{
|
2001-08-21 20:18:27 +00:00
|
|
|
DPRINT("Not a device interrupt\n");
|
2004-11-01 19:01:25 +00:00
|
|
|
return FALSE;
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
|
|
|
|
2005-01-01 11:31:43 +00:00
|
|
|
/* FIXME: We must check if the requested and the assigned interrupt mode is the same */
|
|
|
|
|
2003-04-06 10:45:16 +00:00
|
|
|
irq = VECTOR2IRQ (Vector);
|
2004-11-01 19:01:25 +00:00
|
|
|
IOAPICUnmaskIrq (irq);
|
2001-08-21 20:18:27 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2004-07-10 21:58:35 +00:00
|
|
|
|
|
|
|
VOID FASTCALL
|
2004-11-01 19:01:25 +00:00
|
|
|
HalRequestSoftwareInterrupt(IN KIRQL Request)
|
2004-07-10 21:58:35 +00:00
|
|
|
{
|
|
|
|
switch (Request)
|
|
|
|
{
|
|
|
|
case APC_LEVEL:
|
2005-06-18 14:28:28 +00:00
|
|
|
Ki386WriteFsByte(FIELD_OFFSET(KIPCR, HalReserved[HAL_APC_REQUEST]), 1);
|
2004-07-10 21:58:35 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DISPATCH_LEVEL:
|
2005-06-18 14:28:28 +00:00
|
|
|
Ki386WriteFsByte(FIELD_OFFSET(KIPCR, HalReserved[HAL_DPC_REQUEST]), 1);
|
2004-07-10 21:58:35 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
KEBUGCHECK(0);
|
|
|
|
}
|
|
|
|
}
|