Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / ntoskrnl / ke / amd64 / interrupt.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/i386/irq.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 }