1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/amd64/interrupt.c 5 * PURPOSE: Manages the Kernel's IRQ support for external drivers, 6 * for the purpopses of connecting, disconnecting and setting 7 * up ISRs for drivers. The backend behind the Io* Interrupt 8 * routines. 9 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) 10 * Alex Ionescu (alex.ionescu@reactos.org) 11 */ 12 13 /* INCLUDES *****************************************************************/ 14 15 #include <ntoskrnl.h> 16 #define NDEBUG 17 #include <debug.h> 18 19 extern UCHAR KiInterruptDispatchTemplate[16]; 20 extern UCHAR KiUnexpectedRange[]; 21 extern UCHAR KiUnexpectedRangeEnd[]; 22 void KiInterruptDispatch(void); 23 24 25 /* FUNCTIONS ****************************************************************/ 26 27 VOID 28 NTAPI 29 KeInitializeInterrupt( 30 IN PKINTERRUPT Interrupt, 31 IN PKSERVICE_ROUTINE ServiceRoutine, 32 IN PVOID ServiceContext, 33 IN PKSPIN_LOCK SpinLock, 34 IN ULONG Vector, 35 IN KIRQL Irql, 36 IN KIRQL SynchronizeIrql, 37 IN KINTERRUPT_MODE InterruptMode, 38 IN BOOLEAN ShareVector, 39 IN CHAR ProcessorNumber, 40 IN BOOLEAN FloatingSave) 41 { 42 43 /* Initialize the header */ 44 Interrupt->Type = InterruptObject; 45 Interrupt->Size = sizeof(KINTERRUPT); 46 47 /* If no Spinlock is given, use the internal */ 48 if (!SpinLock) SpinLock = &Interrupt->SpinLock; 49 KeInitializeSpinLock(&Interrupt->SpinLock); 50 51 /* Set the given parameters */ 52 Interrupt->ServiceRoutine = ServiceRoutine; 53 Interrupt->ServiceContext = ServiceContext; 54 Interrupt->ActualLock = SpinLock; 55 Interrupt->Vector = Vector; 56 Interrupt->Irql = Irql; 57 Interrupt->SynchronizeIrql = SynchronizeIrql; 58 Interrupt->Mode = InterruptMode; 59 Interrupt->ShareVector = ShareVector; 60 Interrupt->Number = ProcessorNumber; 61 Interrupt->FloatingSave = FloatingSave; 62 63 /* Set initial values */ 64 Interrupt->TickCount = 0; 65 Interrupt->Connected = FALSE; 66 Interrupt->ServiceCount = 0; 67 Interrupt->DispatchCount = 0; 68 Interrupt->TrapFrame = NULL; 69 Interrupt->Reserved = 0; 70 71 /* Copy the dispatch code (its location independent, no need to patch it) */ 72 RtlCopyMemory(Interrupt->DispatchCode, 73 KiInterruptDispatchTemplate, 74 sizeof(Interrupt->DispatchCode)); 75 76 Interrupt->DispatchAddress = 0; 77 } 78 79 BOOLEAN 80 NTAPI 81 KeConnectInterrupt(IN PKINTERRUPT Interrupt) 82 { 83 PVOID CurrentHandler; 84 PKINTERRUPT ConnectedInterrupt; 85 86 ASSERT(Interrupt->Vector >= PRIMARY_VECTOR_BASE); 87 ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR); 88 ASSERT(Interrupt->Number < KeNumberProcessors); 89 ASSERT(Interrupt->Irql <= HIGH_LEVEL); 90 ASSERT(Interrupt->SynchronizeIrql >= Interrupt->Irql); 91 ASSERT(Interrupt->Irql == (Interrupt->Vector >> 4)); 92 93 /* Check if its already connected */ 94 if (Interrupt->Connected) return TRUE; 95 96 /* Query the current handler */ 97 CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector); 98 99 /* Check if the vector is unused */ 100 if ((CurrentHandler >= (PVOID)KiUnexpectedRange) && 101 (CurrentHandler <= (PVOID)KiUnexpectedRangeEnd)) 102 { 103 /* Initialize the list for chained interrupts */ 104 InitializeListHead(&Interrupt->InterruptListEntry); 105 106 /* Set normal dispatch address */ 107 Interrupt->DispatchAddress = KiInterruptDispatch; 108 109 /* Set the new handler */ 110 KeRegisterInterruptHandler(Interrupt->Vector, 111 Interrupt->DispatchCode); 112 113 /* Enable the interrupt */ 114 if (!HalEnableSystemInterrupt(Interrupt->Vector, 115 Interrupt->Irql, 116 Interrupt->Mode)) 117 { 118 /* Didn't work, restore old handler */ 119 DPRINT1("HalEnableSystemInterrupt failed\n"); 120 KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler); 121 return FALSE; 122 } 123 } 124 else 125 { 126 /* Get the connected interrupt */ 127 ConnectedInterrupt = CONTAINING_RECORD(CurrentHandler, KINTERRUPT, DispatchCode); 128 129 /* Check if sharing is ok */ 130 if ((Interrupt->ShareVector == 0) || 131 (ConnectedInterrupt->ShareVector == 0) || 132 (Interrupt->Mode != ConnectedInterrupt->Mode)) 133 { 134 return FALSE; 135 } 136 137 /* Insert the new interrupt into the connected interrupt's list */ 138 InsertTailList(&ConnectedInterrupt->InterruptListEntry, 139 &Interrupt->InterruptListEntry); 140 } 141 142 /* Mark as connected */ 143 Interrupt->Connected = TRUE; 144 145 return TRUE; 146 } 147 148 BOOLEAN 149 NTAPI 150 KeDisconnectInterrupt(IN PKINTERRUPT Interrupt) 151 { 152 /* If the interrupt wasn't connected, there's nothing to do */ 153 if (!Interrupt->Connected) 154 { 155 return FALSE; 156 } 157 158 UNIMPLEMENTED; 159 __debugbreak(); 160 return TRUE; 161 } 162 163 BOOLEAN 164 NTAPI 165 KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt, 166 IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, 167 IN PVOID SynchronizeContext OPTIONAL) 168 { 169 BOOLEAN Success; 170 KIRQL OldIrql; 171 172 /* Raise IRQL */ 173 OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql); 174 175 /* Acquire interrupt spinlock */ 176 KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock); 177 178 /* Call the routine */ 179 Success = SynchronizeRoutine(SynchronizeContext); 180 181 /* Release lock */ 182 KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock); 183 184 /* Lower IRQL */ 185 KeLowerIrql(OldIrql); 186 187 /* Return status */ 188 return Success; 189 } 190