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 85 ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR); 86 ASSERT(Interrupt->Number < KeNumberProcessors); 87 ASSERT(Interrupt->Irql <= HIGH_LEVEL); 88 89 /* Check if its already connected */ 90 if (Interrupt->Connected) return TRUE; 91 92 /* Query the current handler */ 93 CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector); 94 95 /* Check if the vector is already unused */ 96 if ((CurrentHandler >= (PVOID)KiUnexpectedRange) && 97 (CurrentHandler <= (PVOID)KiUnexpectedRangeEnd)) 98 { 99 /* Initialize the list for chained interrupts */ 100 InitializeListHead(&Interrupt->InterruptListEntry); 101 102 /* Set normal dispatch address */ 103 Interrupt->DispatchAddress = KiInterruptDispatch; 104 105 /* Set the new handler */ 106 KeRegisterInterruptHandler(Interrupt->Vector, 107 Interrupt->DispatchCode); 108 109 if (!HalEnableSystemInterrupt(Interrupt->Vector, 110 Interrupt->Irql, 111 Interrupt->Mode)) 112 { 113 /* Didn't work, restore old handler */ 114 DPRINT1("HalEnableSystemInterrupt failed\n"); 115 KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler); 116 return FALSE; 117 } 118 119 /* Mark as connected */ 120 Interrupt->Connected = TRUE; 121 } 122 else 123 { 124 // later 125 __debugbreak(); 126 } 127 128 return TRUE; 129 } 130 131 BOOLEAN 132 NTAPI 133 KeDisconnectInterrupt(IN PKINTERRUPT Interrupt) 134 { 135 UNIMPLEMENTED; 136 __debugbreak(); 137 return FALSE; 138 } 139 140 BOOLEAN 141 NTAPI 142 KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt, 143 IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, 144 IN PVOID SynchronizeContext OPTIONAL) 145 { 146 BOOLEAN Success; 147 KIRQL OldIrql; 148 149 /* Raise IRQL */ 150 OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql); 151 152 /* Acquire interrupt spinlock */ 153 KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock); 154 155 /* Call the routine */ 156 Success = SynchronizeRoutine(SynchronizeContext); 157 158 /* Release lock */ 159 KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock); 160 161 /* Lower IRQL */ 162 KeLowerIrql(OldIrql); 163 164 /* Return status */ 165 return Success; 166 } 167