292 lines
7.8 KiB
C
292 lines
7.8 KiB
C
/*++
|
|
|
|
Copyright (c) 1989-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
intobj.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the kernel interrupt object. Functions are provided
|
|
to initialize, connect, and disconnect interrupt objects.
|
|
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
|
|
//
|
|
// Externs from trap.asm used to compute and set handlers for unexpected
|
|
// hardware interrupts.
|
|
//
|
|
|
|
extern ULONG KiStartUnexpectedRange(VOID);
|
|
extern ULONG KiEndUnexpectedRange(VOID);
|
|
extern ULONG KiUnexpectedEntrySize;
|
|
|
|
VOID
|
|
KeInitializeInterrupt (
|
|
IN PKINTERRUPT Interrupt,
|
|
IN PKSERVICE_ROUTINE ServiceRoutine,
|
|
IN PVOID ServiceContext,
|
|
IN ULONG Vector,
|
|
IN KIRQL Irql,
|
|
IN KINTERRUPT_MODE InterruptMode,
|
|
IN BOOLEAN ShareVector
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes a kernel interrupt object. The service routine,
|
|
service context, spin lock, vector, IRQL, SynchronizeIrql, and floating
|
|
context save flag are initialized.
|
|
|
|
Arguments:
|
|
|
|
Interrupt - Supplies a pointer to a control object of type interrupt.
|
|
|
|
ServiceRoutine - Supplies a pointer to a function that is to be
|
|
executed when an interrupt occurs via the specified interrupt
|
|
vector.
|
|
|
|
ServiceContext - Supplies a pointer to an arbitrary data structure which is
|
|
to be passed to the function specified by the ServiceRoutine parameter.
|
|
|
|
Vector - Supplies the index of the entry in the Interrupt Dispatch Table
|
|
that is to be associated with the ServiceRoutine function.
|
|
|
|
Irql - Supplies the request priority of the interrupting source.
|
|
|
|
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
|
|
|
|
ShareVector - Supplies a boolean value that specifies whether the
|
|
vector can be shared with other interrupt objects or not. If FALSE
|
|
then the vector may not be shared, if TRUE it may be.
|
|
Latched.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PULONG pl;
|
|
PULONG NormalDispatchCode;
|
|
ULONG InterruptDispatch;
|
|
|
|
ASSERT(Irql <= HIGH_LEVEL);
|
|
ASSERT(Vector >= PRIMARY_VECTOR_BASE && Vector < PRIMARY_VECTOR_BASE + 16);
|
|
|
|
//
|
|
// Initialize the address of the service routine,
|
|
// the service context, the address of the spin lock, the vector
|
|
// number, the IRQL of the interrupting source, the Irql used for
|
|
// synchronize execution, abd the interrupt mode.
|
|
//
|
|
|
|
Interrupt->ServiceRoutine = ServiceRoutine;
|
|
Interrupt->ServiceContext = ServiceContext;
|
|
|
|
Interrupt->BusInterruptLevel = Vector - PRIMARY_VECTOR_BASE;
|
|
Interrupt->Irql = (UCHAR)Irql;
|
|
Interrupt->Mode = InterruptMode;
|
|
|
|
//
|
|
// Copy the interrupt dispatch code template into the interrupt object
|
|
// and edit the machine code stored in the structure (please see
|
|
// _KiInterruptTemplate in intsup.asm.)
|
|
//
|
|
|
|
NormalDispatchCode = &(Interrupt->DispatchCode[0]);
|
|
|
|
RtlCopyMemory(NormalDispatchCode, KiInterruptTemplate,
|
|
NORMAL_DISPATCH_LENGTH * sizeof(ULONG));
|
|
|
|
//
|
|
// Fill in the address of the interrupt object.
|
|
//
|
|
|
|
pl = (PULONG)((PUCHAR)NormalDispatchCode + ((PUCHAR)&KiInterruptTemplateObject -
|
|
(PUCHAR)KiInterruptTemplate) -4);
|
|
*pl = (ULONG)Interrupt;
|
|
|
|
//
|
|
// Fill in the address of interrupt dispatch code.
|
|
//
|
|
|
|
pl = (PULONG)((PUCHAR)NormalDispatchCode +
|
|
((PUCHAR)&KiInterruptTemplateDispatch -
|
|
(PUCHAR)KiInterruptTemplate) -4);
|
|
|
|
if (InterruptMode == LevelSensitive) {
|
|
InterruptDispatch = (ULONG)KiLevelInterruptDispatch;
|
|
} else {
|
|
InterruptDispatch = (ULONG)KiInterruptDispatch;
|
|
}
|
|
|
|
*pl = InterruptDispatch-(ULONG)((PUCHAR)pl+4);
|
|
|
|
//
|
|
// Set the connected state of the interrupt object to FALSE.
|
|
//
|
|
|
|
Interrupt->Connected = FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
KeConnectInterrupt (
|
|
IN PKINTERRUPT Interrupt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function connects an interrupt object to the interrupt vector
|
|
specified by the interrupt object. If the interrupt object is already
|
|
connected, or an attempt is made to connect to an interrupt that cannot
|
|
be connected, then a value of FALSE is returned. Else the specified
|
|
interrupt object is connected to the interrupt vector, the connected
|
|
state is set to TRUE, and TRUE is returned as the function value.
|
|
|
|
Arguments:
|
|
|
|
Interrupt - Supplies a pointer to a control object of type interrupt.
|
|
|
|
Return Value:
|
|
|
|
If the interrupt object is already connected or an attempt is made to
|
|
connect to an interrupt vector that cannot be connected, then a value
|
|
of FALSE is returned. Else a value of TRUE is returned.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN Connected;
|
|
ULONG BusInterruptLevel;
|
|
|
|
//
|
|
// Raise IRQL to dispatcher level and lock dispatcher database.
|
|
//
|
|
|
|
KiLockDispatcherDatabase(&OldIrql);
|
|
|
|
//
|
|
// Is interrupt object already connected?
|
|
//
|
|
|
|
Connected = FALSE;
|
|
|
|
if (!Interrupt->Connected) {
|
|
|
|
BusInterruptLevel = Interrupt->BusInterruptLevel;
|
|
|
|
//
|
|
// Is the IDT entry unclaimed?
|
|
//
|
|
|
|
if (KiReturnHandlerAddressFromIDT(BusInterruptLevel + PRIMARY_VECTOR_BASE) ==
|
|
(((ULONG)&KiStartUnexpectedRange) +
|
|
BusInterruptLevel * KiUnexpectedEntrySize)) {
|
|
|
|
//
|
|
// Connect the dispatch code in the interrupt object to the IDT
|
|
// and enable the interrupt.
|
|
//
|
|
|
|
KiSetHandlerAddressToIDT(BusInterruptLevel + PRIMARY_VECTOR_BASE,
|
|
(ULONG)&Interrupt->DispatchCode);
|
|
|
|
HalEnableSystemInterrupt(BusInterruptLevel, Interrupt->Mode);
|
|
|
|
Interrupt->Connected = TRUE;
|
|
Connected = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Unlock dispatcher database and lower IRQL to its previous value.
|
|
//
|
|
|
|
KiUnlockDispatcherDatabase(OldIrql);
|
|
|
|
//
|
|
// Return whether interrupt was connected to the specified vector.
|
|
//
|
|
|
|
return Connected;
|
|
}
|
|
|
|
BOOLEAN
|
|
KeDisconnectInterrupt (
|
|
IN PKINTERRUPT Interrupt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disconnects an interrupt object from the interrupt vector
|
|
specified by the interrupt object. If the interrupt object is not
|
|
connected, then a value of FALSE is returned. Else the specified interrupt
|
|
object is disconnected from the interrupt vector, the connected state is
|
|
set to FALSE, and TRUE is returned as the function value.
|
|
|
|
Arguments:
|
|
|
|
Interrupt - Supplies a pointer to a control object of type interrupt.
|
|
|
|
Return Value:
|
|
|
|
If the interrupt object is not connected, then a value of FALSE is
|
|
returned. Else a value of TRUE is returned.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN Connected;
|
|
ULONG BusInterruptLevel;
|
|
|
|
//
|
|
// Raise IRQL to dispatcher level and lock dispatcher database.
|
|
//
|
|
|
|
KiLockDispatcherDatabase(&OldIrql);
|
|
|
|
//
|
|
// If the interrupt object is connected, then disconnect it from the
|
|
// specified vector.
|
|
//
|
|
|
|
Connected = Interrupt->Connected;
|
|
|
|
if (Connected) {
|
|
|
|
BusInterruptLevel = Interrupt->BusInterruptLevel;
|
|
|
|
//
|
|
// Disable the interrupt and connect the unexpected interrupt code to
|
|
// the IDT.
|
|
//
|
|
|
|
HalDisableSystemInterrupt(BusInterruptLevel);
|
|
|
|
KiSetHandlerAddressToIDT(BusInterruptLevel + PRIMARY_VECTOR_BASE,
|
|
(((ULONG)&KiStartUnexpectedRange) +
|
|
BusInterruptLevel * KiUnexpectedEntrySize));
|
|
|
|
Interrupt->Connected = FALSE;
|
|
}
|
|
|
|
//
|
|
// Unlock dispatcher database and lower IRQL to its previous value.
|
|
//
|
|
|
|
KiUnlockDispatcherDatabase(OldIrql);
|
|
|
|
//
|
|
// Return whether interrupt was disconnected from the specified vector.
|
|
//
|
|
|
|
return Connected;
|
|
}
|