You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
3.6 KiB
230 lines
3.6 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
Copyright (c) 1998 Intel Corporation
|
|
|
|
Module Name:
|
|
|
|
intsupc.c
|
|
|
|
Abstract:
|
|
|
|
This module implements ruotines for interrupt support.
|
|
|
|
Author:
|
|
|
|
Bernard Lint 5-May-1998
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
|
|
__inline
|
|
VOID
|
|
KiLowerIrqlSpecial(KIRQL NewIrql)
|
|
{
|
|
__setReg( CV_IA64_SaTPR, (NewIrql << TPR_IRQL_SHIFT));
|
|
KeGetPcr()->CurrentIrql = NewIrql;
|
|
}
|
|
|
|
VOID
|
|
KiDispatchSoftwareInterrupt (
|
|
KIRQL Irql
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dispatch pending software interrupt
|
|
|
|
Arguments:
|
|
|
|
Irql (a0) - Software interrupt to dispatch
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
Interrupts disabled on entry/return.
|
|
The function is only called by KiCheckForSoftwareInterrupt that passes an
|
|
Irql value of APC_LEVEL or DISPATCH_LEVEL.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
KiLowerIrqlSpecial(Irql); // set IRQL
|
|
|
|
if (Irql == APC_LEVEL) {
|
|
|
|
PCR->ApcInterrupt = 0;
|
|
|
|
_enable();
|
|
|
|
//
|
|
// Dispatch APC Interrupt via direct call to KiDeliverApc
|
|
//
|
|
|
|
KiDeliverApc(KernelMode,NULL,NULL);
|
|
|
|
_disable();
|
|
|
|
} else {
|
|
|
|
PCR->DispatchInterrupt = 0;
|
|
|
|
_enable();
|
|
|
|
//
|
|
// Dispatch DPC Interrupt
|
|
//
|
|
|
|
KiDispatchInterrupt();
|
|
|
|
_disable();
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
KiCheckForSoftwareInterrupt (
|
|
KIRQL RequestIrql
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check for and dispatch pending software interrupts
|
|
|
|
Arguments:
|
|
|
|
Irql (a0) - New, lower IRQL
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
Caller must check IRQL has dropped below s/w IRQL level
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN InterruptState;
|
|
|
|
InterruptState = KeDisableInterrupts();
|
|
|
|
if (RequestIrql == APC_LEVEL) {
|
|
|
|
//
|
|
// Dispatch only DPC requests
|
|
//
|
|
|
|
while (PCR->DispatchInterrupt) {
|
|
KiDispatchSoftwareInterrupt(DISPATCH_LEVEL);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Dispatch either APC or DPC
|
|
//
|
|
|
|
while (PCR->SoftwareInterruptPending) {
|
|
KIRQL Irql;
|
|
|
|
if (PCR->DispatchInterrupt) {
|
|
Irql = DISPATCH_LEVEL;
|
|
} else {
|
|
Irql = APC_LEVEL;
|
|
}
|
|
KiDispatchSoftwareInterrupt(Irql);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Lower IRQL to the requested level, restore interrupts and
|
|
// return.
|
|
//
|
|
|
|
KiLowerIrqlSpecial(RequestIrql);
|
|
KeEnableInterrupts(InterruptState);
|
|
}
|
|
|
|
VOID
|
|
KiRequestSoftwareInterrupt (
|
|
KIRQL RequestIrql
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function requests a software interrupt at the specified IRQL
|
|
level.
|
|
|
|
Arguments:
|
|
|
|
RequestIrql (a0) - Supplies the request IRQL value.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL Irql;
|
|
|
|
#if DEBUG
|
|
if ((RequestIrql < APC_LEVEL) || (RequestIrql > DISPATCH_LEVEL))
|
|
KeBugCheckEx(INVALID_SOFTWARE_INTERRUPT, RequestIrql, 0, 0, 0);
|
|
#endif
|
|
|
|
((PUCHAR)&PCR->SoftwareInterruptPending)[RequestIrql-APC_LEVEL] = 1;
|
|
|
|
Irql = KeGetCurrentIrql();
|
|
if (Irql < RequestIrql) {
|
|
KeLowerIrql (Irql);
|
|
}
|
|
}
|
|
|
|
#undef KeRaiseIrql
|
|
VOID
|
|
KeRaiseIrql (
|
|
IN KIRQL NewIrql,
|
|
OUT PKIRQL OldIrql
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function raises the current IRQL to the specified value and returns
|
|
the previous IRQL.
|
|
|
|
Arguments:
|
|
|
|
NewIrql - Supplies the new IRQL value.
|
|
|
|
OldIrql - Supplies a pointer to the location where the old IRQL is stored.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
*OldIrql = KfRaiseIrql(NewIrql);
|
|
}
|
|
|