win-pvdrivers

view xenpci/xenpci_highsync.c @ 902:44029b09876a

Flush DPC's before freeing highsync_info memory
author James Harper <james.harper@bendigoit.com.au>
date Fri Apr 01 16:02:17 2011 +1100 (2011-04-01)
parents 70738d39e3cc
children 1ee7940af105
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xenpci.h"
22 /* Not really necessary but keeps PREfast happy */
23 #if (NTDDI_VERSION >= NTDDI_WINXP)
24 static KDEFERRED_ROUTINE XenPci_HighSyncCallFunction0;
25 static KDEFERRED_ROUTINE XenPci_HighSyncCallFunctionN;
26 #endif
28 /*
29 we need these intrinsics as even going to HIGH_LEVEL doesn't ensure that interrupts are completely disabled
30 */
31 #pragma intrinsic(_disable)
32 #pragma intrinsic(_enable)
34 struct {
35 volatile ULONG do_spin;
36 volatile LONG nr_procs_at_dispatch_level;
37 volatile LONG nr_spinning_at_sync_level;
38 KDPC dpcs[MAX_VIRT_CPUS];
39 KEVENT highsync_complete_event;
40 KIRQL sync_level;
41 PXENPCI_HIGHSYNC_FUNCTION function0;
42 PXENPCI_HIGHSYNC_FUNCTION functionN;
43 PVOID context;
44 } typedef highsync_info_t;
46 static VOID
47 XenPci_HighSyncCallFunction0(
48 PRKDPC Dpc,
49 PVOID Context,
50 PVOID SystemArgument1,
51 PVOID SystemArgument2)
52 {
53 highsync_info_t *highsync_info = Context;
54 ULONG ActiveProcessorCount;
55 KIRQL old_irql;
57 UNREFERENCED_PARAMETER(Dpc);
58 UNREFERENCED_PARAMETER(SystemArgument1);
59 UNREFERENCED_PARAMETER(SystemArgument2);
61 FUNCTION_ENTER();
62 #if (NTDDI_VERSION >= NTDDI_WINXP)
63 ActiveProcessorCount = (ULONG)KeNumberProcessors;
64 #else
65 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
66 #endif
67 InterlockedIncrement(&highsync_info->nr_procs_at_dispatch_level);
68 if (highsync_info->sync_level > DISPATCH_LEVEL)
69 {
70 while (highsync_info->nr_procs_at_dispatch_level < (LONG)ActiveProcessorCount)
71 {
72 KeStallExecutionProcessor(1);
73 KeMemoryBarrier();
74 }
75 }
76 _disable(); //__asm cli;
77 KeRaiseIrql(highsync_info->sync_level, &old_irql);
78 while (highsync_info->nr_spinning_at_sync_level < (LONG)ActiveProcessorCount - 1)
79 {
80 KeStallExecutionProcessor(1);
81 KeMemoryBarrier();
82 }
83 highsync_info->function0(highsync_info->context);
84 KeLowerIrql(old_irql);
85 _enable(); //__asm sti;
86 highsync_info->do_spin = FALSE;
87 KeMemoryBarrier();
88 /* wait for all the other processors to complete spinning, just in case it matters */
89 while (highsync_info->nr_spinning_at_sync_level)
90 {
91 KeStallExecutionProcessor(1);
92 KeMemoryBarrier();
93 }
94 InterlockedDecrement(&highsync_info->nr_procs_at_dispatch_level);
95 /* wait until nr_procs_at_dispatch_level drops to 0 indicating that nothing else requires highsync_info */
96 while (highsync_info->nr_procs_at_dispatch_level)
97 {
98 KeStallExecutionProcessor(1);
99 KeMemoryBarrier();
100 }
101 KeSetEvent(&highsync_info->highsync_complete_event, IO_NO_INCREMENT, FALSE);
103 FUNCTION_EXIT();
104 }
106 static VOID
107 XenPci_HighSyncCallFunctionN(
108 PRKDPC Dpc,
109 PVOID Context,
110 PVOID SystemArgument1,
111 PVOID SystemArgument2)
112 {
113 highsync_info_t *highsync_info = Context;
114 ULONG ActiveProcessorCount;
115 KIRQL old_irql;
117 UNREFERENCED_PARAMETER(Dpc);
118 UNREFERENCED_PARAMETER(SystemArgument1);
119 UNREFERENCED_PARAMETER(SystemArgument2);
121 FUNCTION_ENTER();
122 FUNCTION_MSG("(CPU = %d)\n", KeGetCurrentProcessorNumber());
124 KdPrint((__DRIVER_NAME " CPU %d spinning...\n", KeGetCurrentProcessorNumber()));
125 InterlockedIncrement(&highsync_info->nr_procs_at_dispatch_level);
126 if (highsync_info->sync_level > DISPATCH_LEVEL)
127 {
128 #if (NTDDI_VERSION >= NTDDI_WINXP)
129 ActiveProcessorCount = (ULONG)KeNumberProcessors;
130 #else
131 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
132 #endif
133 while (highsync_info->nr_procs_at_dispatch_level < (LONG)ActiveProcessorCount)
134 {
135 KeStallExecutionProcessor(1);
136 KeMemoryBarrier();
137 }
138 }
139 _disable(); //__asm cli;
140 KeRaiseIrql(highsync_info->sync_level, &old_irql);
141 InterlockedIncrement(&highsync_info->nr_spinning_at_sync_level);
142 while(highsync_info->do_spin)
143 {
144 KeStallExecutionProcessor(1);
145 KeMemoryBarrier();
146 }
147 highsync_info->functionN(highsync_info->context);
148 KeLowerIrql(old_irql);
149 _enable(); //__asm sti;
150 InterlockedDecrement(&highsync_info->nr_spinning_at_sync_level);
151 InterlockedDecrement(&highsync_info->nr_procs_at_dispatch_level);
152 FUNCTION_EXIT();
153 return;
154 }
156 VOID
157 XenPci_HighSync(PXENPCI_HIGHSYNC_FUNCTION function0, PXENPCI_HIGHSYNC_FUNCTION functionN, PVOID context)
158 {
159 ULONG ActiveProcessorCount;
160 ULONG i;
161 highsync_info_t *highsync_info;
162 KIRQL old_irql;
164 UNREFERENCED_PARAMETER(context);
165 FUNCTION_ENTER();
167 highsync_info = ExAllocatePoolWithTag(NonPagedPool, sizeof(highsync_info_t), XENPCI_POOL_TAG);
168 RtlZeroMemory(highsync_info, sizeof(highsync_info_t));
169 KeInitializeEvent(&highsync_info->highsync_complete_event, SynchronizationEvent, FALSE);
170 highsync_info->function0 = function0;
171 highsync_info->functionN = functionN;
172 highsync_info->context = context;
173 highsync_info->sync_level = HIGH_LEVEL;
175 #if (NTDDI_VERSION >= NTDDI_WINXP)
176 ActiveProcessorCount = (ULONG)KeNumberProcessors;
177 #else
178 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
179 #endif
181 /* Go to HIGH_LEVEL to prevent any races with Dpc's on the current processor */
182 KeRaiseIrql(highsync_info->sync_level, &old_irql);
184 highsync_info->do_spin = TRUE;
185 for (i = 0; i < ActiveProcessorCount; i++)
186 {
187 if (i == 0)
188 KeInitializeDpc(&highsync_info->dpcs[i], XenPci_HighSyncCallFunction0, highsync_info);
189 else
190 KeInitializeDpc(&highsync_info->dpcs[i], XenPci_HighSyncCallFunctionN, highsync_info);
191 KeSetTargetProcessorDpc(&highsync_info->dpcs[i], (CCHAR)i);
192 KeSetImportanceDpc(&highsync_info->dpcs[i], HighImportance);
193 KdPrint((__DRIVER_NAME " queuing Dpc for CPU %d\n", i));
194 KeInsertQueueDpc(&highsync_info->dpcs[i], NULL, NULL);
195 }
196 KdPrint((__DRIVER_NAME " All Dpc's queued\n"));
198 KeMemoryBarrier();
199 KeLowerIrql(old_irql);
201 KdPrint((__DRIVER_NAME " Waiting for highsync_complete_event\n"));
202 KeWaitForSingleObject(&highsync_info->highsync_complete_event, Executive, KernelMode, FALSE, NULL);
203 #if (NTDDI_VERSION >= NTDDI_WINXP)
204 KeFlushQueuedDpcs();
205 #else
206 {
207 /* just wait 1 second until all DPC's finish - not ideal but it's only for W2K */
208 LARGE_INTEGER interval;
209 interval.QuadPart = -1 * 1000 * 1000 * 10; /* 1 second */
210 KeDelayExecutionThread(KernelMode, FALSE, &interval);
211 }
212 #endif
213 ExFreePoolWithTag(highsync_info, XENPCI_POOL_TAG);
214 FUNCTION_EXIT();
215 }