/*++ 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; }