KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / ke / ipi.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/ipi.c
6 * PURPOSE: IPI Routines (Inter-Processor Interrupts). NT5+
7 *
8 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 * Hartmut Birr
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 KSPIN_LOCK KiIpiLock;
21
22 /* FUNCTIONS *****************************************************************/
23
24 VOID
25 KiIpiSendRequest(ULONG TargetSet, ULONG IpiRequest)
26 {
27 ULONG i;
28 PKPCR Pcr;
29
30 for (i = 0; i < KeNumberProcessors; i++)
31 {
32 if (TargetSet & (1 << i))
33 {
34 Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
35 Ke386TestAndSetBit(IpiRequest, &Pcr->Prcb->IpiFrozen);
36 HalRequestIpi(i);
37 }
38 }
39 }
40
41 /*
42 * @implemented
43 */
44 BOOLEAN
45 STDCALL
46 KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame,
47 IN PKEXCEPTION_FRAME ExceptionFrame)
48 {
49 #ifdef DBG
50 LARGE_INTEGER StartTime, CurrentTime, Frequency;
51 ULONG Count = 5;
52 #endif
53 PKPRCB Prcb;
54
55 ASSERT(KeGetCurrentIrql() == IPI_LEVEL);
56
57 DPRINT("KiIpiServiceRoutine\n");
58
59 Prcb = KeGetCurrentPrcb();
60
61 if (Ke386TestAndClearBit(IPI_REQUEST_APC, &Prcb->IpiFrozen))
62 {
63 HalRequestSoftwareInterrupt(APC_LEVEL);
64 }
65
66 if (Ke386TestAndClearBit(IPI_REQUEST_DPC, &Prcb->IpiFrozen))
67 {
68 Prcb->DpcInterruptRequested = TRUE;
69 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
70 }
71
72 if (Ke386TestAndClearBit(IPI_REQUEST_FUNCTIONCALL, &Prcb->IpiFrozen))
73 {
74 InterlockedDecrementUL(&Prcb->SignalDone->CurrentPacket[1]);
75 if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
76 {
77 #ifdef DBG
78 StartTime = KeQueryPerformanceCounter(&Frequency);
79 #endif
80 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[1], 0, 0))
81 {
82 #ifdef DBG
83 CurrentTime = KeQueryPerformanceCounter(NULL);
84 if (CurrentTime.QuadPart > StartTime.QuadPart + Count * Frequency.QuadPart)
85 {
86 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds to start the ipi routine\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber(), Count);
87 KEBUGCHECK(0);
88 }
89 #endif
90 }
91 }
92 ((VOID STDCALL(*)(PVOID))(Prcb->SignalDone->WorkerRoutine))(Prcb->SignalDone->CurrentPacket[0]);
93 Ke386TestAndClearBit(KeGetCurrentProcessorNumber(), &Prcb->SignalDone->TargetSet);
94 if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
95 {
96 #ifdef DBG
97 StartTime = KeQueryPerformanceCounter(&Frequency);
98 #endif
99 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->TargetSet, 0, 0))
100 {
101 #ifdef DBG
102 CurrentTime = KeQueryPerformanceCounter(NULL);
103 if (CurrentTime.QuadPart > StartTime.QuadPart + Count * Frequency.QuadPart)
104 {
105 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds after executing the ipi routine\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber(), Count);
106 KEBUGCHECK(0);
107 }
108 #endif
109 }
110 }
111 InterlockedExchangePointer(&Prcb->SignalDone, NULL);
112 }
113 DPRINT("KiIpiServiceRoutine done\n");
114 return TRUE;
115 }
116
117 VOID
118 STDCALL
119 KiIpiSendPacket(ULONG TargetSet, VOID STDCALL (*WorkerRoutine)(PVOID), PVOID Argument, ULONG Count, BOOLEAN Synchronize)
120 {
121 ULONG i, Processor, CurrentProcessor;
122 PKPRCB Prcb, CurrentPrcb;
123 KIRQL oldIrql;
124
125
126 ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
127
128 CurrentPrcb = KeGetCurrentPrcb();
129 InterlockedExchangeUL(&CurrentPrcb->TargetSet, TargetSet);
130 InterlockedExchangeUL(&CurrentPrcb->WorkerRoutine, (ULONG_PTR)WorkerRoutine);
131 InterlockedExchangePointer(&CurrentPrcb->CurrentPacket[0], Argument);
132 InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[1], Count);
133 InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[2], Synchronize ? 1 : 0);
134
135 CurrentProcessor = 1 << KeGetCurrentProcessorNumber();
136
137 for (i = 0, Processor = 1; i < KeNumberProcessors; i++, Processor <<= 1)
138 {
139 if (TargetSet & Processor)
140 {
141 Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb;
142 while(0 != InterlockedCompareExchangeUL(&Prcb->SignalDone, (LONG)CurrentPrcb, 0));
143 Ke386TestAndSetBit(IPI_REQUEST_FUNCTIONCALL, &Prcb->IpiFrozen);
144 if (Processor != CurrentProcessor)
145 {
146 HalRequestIpi(i);
147 }
148 }
149 }
150 if (TargetSet & CurrentProcessor)
151 {
152 KeRaiseIrql(IPI_LEVEL, &oldIrql);
153 KiIpiServiceRoutine(NULL, NULL);
154 KeLowerIrql(oldIrql);
155 }
156 }
157
158 VOID
159 KeIpiGenericCall(VOID (STDCALL *Function)(PVOID), PVOID Argument)
160 {
161 KIRQL oldIrql;
162 ULONG TargetSet;
163
164 DPRINT("KeIpiGenericCall on CPU%d\n", KeGetCurrentProcessorNumber());
165
166 KeRaiseIrql(SYNCH_LEVEL, &oldIrql);
167
168 KiAcquireSpinLock(&KiIpiLock);
169
170 TargetSet = (1 << KeNumberProcessors) - 1;
171
172 KiIpiSendPacket(TargetSet, Function, Argument, KeNumberProcessors, TRUE);
173
174 KiReleaseSpinLock(&KiIpiLock);
175
176 KeLowerIrql(oldIrql);
177
178 DPRINT("KeIpiGenericCall on CPU%d done\n", KeGetCurrentProcessorNumber());
179 }
180
181
182 /* EOF */