windows-nt/Source/XPSP1/NT/base/hals/halacpi/amd64/interrupt.c

464 lines
11 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
interrupt.c
Abstract:
HAL routines required to support generic interrupt processing.
Author:
Forrest Foltz (forrestf) 23-Oct-2000
Revision History:
--*/
#include "halcmn.h"
typedef struct _HAL_INTERRUPT_OBJECT *PHAL_INTERRUPT_OBJECT;
typedef struct _HAL_INTERRUPT_OBJECT {
PHAL_INTERRUPT_OBJECT Next;
KSPIN_LOCK SpinLock;
KINTERRUPT InterruptArray[];
} HAL_INTERRUPT_OBJECT;
//
// Global list of hal interrupt objects
//
PHAL_INTERRUPT_OBJECT HalpInterruptObjectList = NULL;
//
// Statically allocated heap of KINTERRUPT objects for use during
// initialization of processor 0.
//
#define HALP_INIT_STATIC_INTERRUPTS 16
KINTERRUPT
HalpKInterruptHeap[ HALP_INIT_STATIC_INTERRUPTS ];
ULONG HalpKInterruptHeapUsed = 0;
PKINTERRUPT
HalpAllocateKInterrupt (
VOID
)
/*++
Routine Description:
This allocates a KINTERRUPT structure from HalpKInterruptHeap[]. If
this array is exhausted then the allocation is satisfied with nonpaged
pool.
Several KINTERRUPT structures are required very early in system init
(before pool is initialized). HalpKInterruptHeap[] must be
sufficiently large to accomodate these early structures.
Arguments:
None.
Return Value:
Returns a pointer to the KINTERRUPT structure if successful, or NULL
if not.
--*/
{
PKINTERRUPT interrupt;
if (HalpKInterruptHeapUsed < HALP_INIT_STATIC_INTERRUPTS) {
//
// Allocate from our private heap of KINTERRUPT objects. If
// this is exhausted, then assume we are at an init stage post pool
// init and allocate from regular heap.
//
interrupt = &HalpKInterruptHeap[HalpKInterruptHeapUsed];
HalpKInterruptHeapUsed += 1;
} else {
//
// The private KINTERRUPT heap has been exhausted. Assume that
// the system heap has been initialized.
//
interrupt = ExAllocatePoolWithTag(NonPagedPool,
sizeof(KINTERRUPT),
HAL_POOL_TAG);
}
return interrupt;
}
NTSTATUS
HalpEnableInterruptHandler (
IN UCHAR ReportFlags,
IN ULONG BusInterruptVector,
IN ULONG SystemInterruptVector,
IN KIRQL SystemIrql,
IN PHAL_INTERRUPT_SERVICE_ROUTINE HalInterruptServiceRoutine,
IN KINTERRUPT_MODE InterruptMode
)
/*++
Routine Description:
This function connects & registers an IDT vectors usage by the HAL.
Arguments:
ReportFlags - Flags passed to HalpRegisterVector indicating how this
interrupt should be reported.
BusInterruptVector - Supplies the interrupt vector from the bus's
perspective.
SystemInterruptVector - Supplies the interrupt vector from the system's
perspective.
SystemIrql - Supplies the IRQL associated with the vector.
HalInterruptServiceRoutine - Supplies the interrupt handler for the
interrupt.
InterruptMode - Supplies the interupt mode.
Return Value:
Returns the final status of the operation.
--*/
{
ULONG size;
ULONG processorCount;
UCHAR processorNumber;
KAFFINITY processorMask;
PKINTERRUPT kernelInterrupt;
PKSPIN_LOCK spinLock;
NTSTATUS status;
#if !defined(ACPI_HAL)
//
// Remember which vector the hal is connecting so it can be reported
// later on
//
// If this is an ACPI HAL, the vectors will be claimed by the BIOS. This
// is done for Win98 compatibility.
//
HalpRegisterVector (ReportFlags,
BusInterruptVector,
SystemInterruptVector,
SystemIrql);
#endif
status = HalpConnectInterrupt (SystemInterruptVector,
SystemIrql,
HalInterruptServiceRoutine,
InterruptMode);
return status;
}
PKINTERRUPT
HalpCreateInterrupt (
IN PKSERVICE_ROUTINE ServiceRoutine,
IN ULONG Vector,
IN KIRQL Irql,
IN KINTERRUPT_MODE InterruptMode,
IN UCHAR ProcessorNumber,
IN UCHAR IstIndex OPTIONAL,
IN PVOID IstStack OPTIONAL
)
/*++
Routine Description:
This function connects an IDT vector to a hal service routine.
Arguments:
ServiceRoutine - Supplies the interrupt handler for the interrupt.
Vector - Supplies the interrupt vector from the system's perspective.
Irql - Supplies the IRQL associated with the interrupt.
Interrupt Mode - Supplies the interrupt mode, Latched or LevelSensitive.
ProcessorNumber - Supplies the processor number.
IstIndex - The Ist index of the stack that this interrupt must run on
if other than the default (which is zero). This is an
optional parameter.
IstStack - Supplies a pointer to the top of the stack to be used for this
interrupt. This is an optional parameter.
Return Value:
Returns a pointer to the allocated interrupt object, or NULL in the
event of failure.
--*/
{
PKINTERRUPT interrupt;
PKPCR pcr;
PKIDTENTRY64 idt;
PKTSS64 tss;
BOOLEAN connected;
//
// Allocate and initialize the kernel interrupt.
//
interrupt = HalpAllocateKInterrupt();
if (interrupt == NULL) {
KeBugCheckEx(HAL_MEMORY_ALLOCATION,
sizeof(KINTERRUPT),
3,
(ULONG_PTR)__FILE__,
__LINE__
);
}
KeInitializeInterrupt(interrupt,
ServiceRoutine,
NULL, // ServiceContext
NULL, // SpinLock
Vector,
Irql, // Irql
Irql, // SynchronizeIrql
InterruptMode,
FALSE, // ShareVector
ProcessorNumber,
FALSE); // FloatingSave
if (IstIndex != 0) {
pcr = KeGetPcr();
idt = &pcr->IdtBase[Vector];
//
// Check that we're not overwriting an existing IST index and store
// the index in the IDT.
//
ASSERT(idt->IstIndex == 0);
idt->IstIndex = IstIndex;
tss = pcr->TssBase;
//
// If a stack was supplied for this IstIndex then store it in the
// TSS.
//
if (ARGUMENT_PRESENT(IstStack)) {
ASSERT(tss->Ist[IstIndex] == 0);
tss->Ist[IstIndex] = (ULONG64)IstStack;
} else {
ASSERT(tss->Ist[IstIndex] != 0);
}
}
KeSetIdtHandlerAddress(Vector, &interrupt->DispatchCode[0]);
return interrupt;
}
VOID
HalpSetHandlerAddressToIDTIrql (
IN ULONG Vector,
IN PHAL_INTERRUPT_SERVICE_ROUTINE ServiceRoutine,
IN PVOID Context,
IN KIRQL Irql
)
{
PKINTERRUPT interrupt;
KIRQL irql;
if (Irql == 0) {
irql = (KIRQL)(Vector / 16);
} else {
irql = (KIRQL)Irql;
}
interrupt = HalpCreateInterrupt(ServiceRoutine,
Vector,
irql,
Latched,
PROCESSOR_CURRENT,
0,
NULL);
}
NTSTATUS
HalpConnectInterrupt (
IN ULONG SystemInterruptVector,
IN KIRQL SystemIrql,
IN PHAL_INTERRUPT_SERVICE_ROUTINE HalInterruptServiceRoutine,
IN KINTERRUPT_MODE InterruptMode
)
/*++
Routine Description:
This function connects & registers an IDT vectors usage by the HAL.
Arguments:
SystemInterruptVector - Supplies the interrupt vector from the system's
perspective.
SystemIrql - Supplies the IRQL associated with the vector.
HalInterruptServiceRoutine - Supplies the interrupt handler for the
interrupt.
InterruptMode - Supplies the interupt mode.
Return Value:
Returns the final status of the operation.
--*/
{
ULONG size;
ULONG processorCount;
UCHAR processorNumber;
KAFFINITY processorMask;
PHAL_INTERRUPT_OBJECT interruptObject;
PKINTERRUPT kernelInterrupt;
PKSPIN_LOCK spinLock;
PHAL_INTERRUPT_OBJECT interruptObjectHead;
PKSERVICE_ROUTINE interruptServiceRoutine;
//
// Count the number of processors in the system
//
processorCount = 0;
processorMask = 1;
processorMask = HalpActiveProcessors;
while (processorMask != 0) {
if ((processorMask & 1) != 0) {
processorCount += 1;
}
processorMask >>= 1;
}
//
// Allocate and initialize the hal interrupt object
//
size = FIELD_OFFSET(HAL_INTERRUPT_OBJECT,InterruptArray) +
sizeof(KINTERRUPT) * processorCount;
interruptObject = ExAllocatePoolWithTag(NonPagedPool,size,HAL_POOL_TAG);
if (interruptObject == NULL) {
return STATUS_NO_MEMORY;
}
spinLock = &interruptObject->SpinLock;
KeInitializeSpinLock(spinLock);
//
// Initialize each of the kernel interrupt objects
//
kernelInterrupt = interruptObject->InterruptArray;
for (processorNumber = 0, processorMask = HalpActiveProcessors;
processorMask != 0;
processorNumber += 1, processorMask >>= 1) {
if ((processorMask & 1) == 0) {
continue;
}
interruptServiceRoutine =
(PKSERVICE_ROUTINE)(HalInterruptServiceRoutine);
KeInitializeInterrupt(kernelInterrupt,
interruptServiceRoutine,
NULL,
spinLock,
SystemInterruptVector,
SystemIrql,
SystemIrql,
InterruptMode,
FALSE,
processorNumber,
FALSE);
kernelInterrupt += 1;
}
//
// Atomically insert the hal interrupt object in our global list
// and return success.
//
do {
interruptObject->Next = HalpInterruptObjectList;
} while (interruptObject->Next !=
InterlockedCompareExchangePointer(&HalpInterruptObjectList,
interruptObject,
interruptObject->Next));
return STATUS_SUCCESS;
}
BOOLEAN
PicSpuriousService37 (
IN struct _KINTERRUPT *Interrupt,
IN PVOID ServiceContext
)
{
return FALSE;
}
BOOLEAN
HalpApicSpuriousService (
IN struct _KINTERRUPT *Interrupt,
IN PVOID ServiceContext
)
{
return FALSE;
}