win-pvdrivers

view xenpci/evtchn.c @ 716:5bdb7251370c

Use WinDDK 7600.16385.0
Update userspace binaries to build for XP not 2K (2K not supported in new DDK)
Fix lots of PREfast errors
Make build and installer less dependant on DDK version
Fix IRQL crash in DpgPrint hooking
author James Harper <james.harper@bendigoit.com.au>
date Tue Dec 22 22:44:07 2009 +1100 (2009-12-22)
parents 8b3dae86a7f6
children 3058ea7a6f59
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 static KDEFERRED_ROUTINE EvtChn_DpcBounce;
25 #if defined(_X86_)
26 #define xchg(p1, p2) InterlockedExchange(p1, p2)
27 #define synch_clear_bit(p1, p2) InterlockedBitTestAndReset(p2, p1)
28 #define synch_set_bit(p1, p2) InterlockedBitTestAndSet(p2, p1)
29 #define bit_scan_forward(p1, p2) _BitScanForward(p1, p2)
30 #else
31 #define xchg(p1, p2) InterlockedExchange64(p1, p2)
32 #define synch_clear_bit(p1, p2) InterlockedBitTestAndReset64(p2, p1)
33 #define synch_set_bit(p1, p2) InterlockedBitTestAndSet64(p2, p1)
34 #define bit_scan_forward(p1, p2) _BitScanForward64(p1, p2)
35 #endif
37 #define BITS_PER_LONG (sizeof(xen_ulong_t) * 8)
38 #define BITS_PER_LONG_SHIFT (5 + (sizeof(xen_ulong_t) >> 3))
40 static DDKAPI VOID
41 EvtChn_DpcBounce(PRKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2)
42 {
43 ev_action_t *action = Context;
45 UNREFERENCED_PARAMETER(Dpc);
46 UNREFERENCED_PARAMETER(SystemArgument1);
47 UNREFERENCED_PARAMETER(SystemArgument2);
49 //FUNCTION_ENTER();
51 if (action->type != EVT_ACTION_TYPE_EMPTY)
52 {
53 action->ServiceRoutine(action->ServiceContext);
54 }
55 //FUNCTION_EXIT();
56 }
58 /* Called at DIRQL */
59 BOOLEAN
60 EvtChn_AckEvent(PVOID context, evtchn_port_t port, BOOLEAN *last_interrupt)
61 {
62 PXENPCI_DEVICE_DATA xpdd = context;
63 ULONG pcpu = KeGetCurrentProcessorNumber() & 0xff;
64 ULONG evt_word;
65 ULONG evt_bit;
66 xen_ulong_t val;
67 int i;
69 evt_bit = port & (BITS_PER_LONG - 1);
70 evt_word = port >> BITS_PER_LONG_SHIFT;
72 val = synch_clear_bit(evt_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[pcpu][evt_word]);
73 *last_interrupt = TRUE;
74 for (i = 0; i < sizeof(xen_ulong_t) * 8; i++)
75 {
76 if (xpdd->evtchn_pending_pvt[pcpu][i])
77 {
78 *last_interrupt = FALSE;
79 break;
80 }
81 }
83 return (BOOLEAN)!!val;
84 }
86 volatile ULONG in_inq = 0;
88 BOOLEAN
89 EvtChn_EvtInterruptIsr(WDFINTERRUPT interrupt, ULONG message_id)
90 {
91 /*
92 For HVM domains, Xen always triggers the event on CPU0. Because the
93 interrupt is delivered via the virtual PCI device it might get delivered
94 to CPU != 0, but we should always use vcpu_info[0]
95 */
96 int vcpu = 0;
97 ULONG pcpu = KeGetCurrentProcessorNumber() & 0xff;
98 vcpu_info_t *vcpu_info;
99 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfInterruptGetDevice(interrupt));
100 shared_info_t *shared_info_area = xpdd->shared_info_area;
101 xen_ulong_t evt_words;
102 unsigned long evt_word;
103 unsigned long evt_bit;
104 unsigned int port;
105 ev_action_t *ev_action;
106 BOOLEAN handled = FALSE;
107 BOOLEAN deferred = FALSE;
108 int i;
110 UNREFERENCED_PARAMETER(message_id);
112 if (xpdd->interrupts_masked)
113 {
114 KdPrint((__DRIVER_NAME " unhandled interrupt\n"));
115 }
117 if (xpdd->hibernated)
118 {
119 KdPrint((__DRIVER_NAME " interrupt while hibernated\n"));
120 }
122 for (i = 0; i < ARRAY_SIZE(xpdd->evtchn_pending_pvt[pcpu]); i++)
123 {
124 if (xpdd->evtchn_pending_pvt[pcpu][i])
125 {
126 KdPrint((__DRIVER_NAME " Unacknowledged event word = %d, val = %p\n", i, xpdd->evtchn_pending_pvt[pcpu][i]));
127 xpdd->evtchn_pending_pvt[pcpu][i] = 0;
128 }
129 }
131 vcpu_info = &shared_info_area->vcpu_info[vcpu];
133 vcpu_info->evtchn_upcall_pending = 0;
135 if (xpdd->interrupts_masked)
136 {
137 return TRUE;
138 }
140 evt_words = (xen_ulong_t)xchg((volatile xen_long_t *)&vcpu_info->evtchn_pending_sel, 0);
142 while (bit_scan_forward(&evt_word, evt_words))
143 {
144 evt_words &= ~(1 << evt_word);
145 while (bit_scan_forward(&evt_bit, shared_info_area->evtchn_pending[evt_word] & ~shared_info_area->evtchn_mask[evt_word]))
146 {
147 synch_clear_bit(evt_bit, (volatile xen_long_t *)&shared_info_area->evtchn_pending[evt_word]);
148 handled = TRUE;
149 port = (evt_word << BITS_PER_LONG_SHIFT) + evt_bit;
150 ev_action = &xpdd->ev_actions[port];
151 ev_action->count++;
152 switch (ev_action->type)
153 {
154 case EVT_ACTION_TYPE_NORMAL:
155 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_NORMAL\n"));
156 ev_action->ServiceRoutine(ev_action->ServiceContext);
157 break;
158 case EVT_ACTION_TYPE_IRQ:
159 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_IRQ\n"));
160 synch_set_bit(evt_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[pcpu][evt_word]);
161 deferred = TRUE;
162 break;
163 case EVT_ACTION_TYPE_DPC:
164 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_DPC\n"));
165 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
166 break;
167 case EVT_ACTION_TYPE_SUSPEND:
168 KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_SUSPEND\n"));
169 for (i = 0; i < ARRAY_SIZE(xpdd->evtchn_pending_pvt[pcpu]); i++)
170 {
171 if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_IRQ)
172 {
173 int suspend_bit = i & (BITS_PER_LONG - 1);
174 int suspend_word = i >> BITS_PER_LONG_SHIFT;
175 synch_set_bit(suspend_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[pcpu][suspend_word]);
176 }
177 else if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_NORMAL && xpdd->ev_actions[i].ServiceRoutine)
178 {
179 xpdd->ev_actions[i].ServiceRoutine(xpdd->ev_actions[i].ServiceContext);
180 }
181 }
182 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
183 deferred = TRUE;
184 break;
185 default:
186 KdPrint((__DRIVER_NAME " Unhandled Event!!!\n"));
187 break;
188 }
189 }
190 }
192 return handled && !deferred;
193 }
195 NTSTATUS
196 EvtChn_EvtInterruptEnable(WDFINTERRUPT interrupt, WDFDEVICE device)
197 {
198 NTSTATUS status = STATUS_SUCCESS;
200 UNREFERENCED_PARAMETER(interrupt);
201 UNREFERENCED_PARAMETER(device);
203 FUNCTION_ENTER();
204 FUNCTION_EXIT();
206 return status;
207 }
209 NTSTATUS
210 EvtChn_EvtInterruptDisable(WDFINTERRUPT interrupt, WDFDEVICE device)
211 {
212 NTSTATUS status = STATUS_SUCCESS;
214 UNREFERENCED_PARAMETER(interrupt);
215 UNREFERENCED_PARAMETER(device);
217 FUNCTION_ENTER();
218 FUNCTION_EXIT();
220 return status;
221 }
223 NTSTATUS
224 EvtChn_Bind(PVOID Context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
225 {
226 PXENPCI_DEVICE_DATA xpdd = Context;
228 FUNCTION_ENTER();
230 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
231 {
232 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
233 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
234 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
235 }
237 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
238 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
239 xpdd->ev_actions[Port].xpdd = xpdd;
240 KeMemoryBarrier();
241 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_NORMAL;
243 EvtChn_Unmask(Context, Port);
245 FUNCTION_EXIT();
247 return STATUS_SUCCESS;
248 }
250 NTSTATUS
251 EvtChn_BindDpc(PVOID Context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
252 {
253 PXENPCI_DEVICE_DATA xpdd = Context;
255 FUNCTION_ENTER();
257 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
258 {
259 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
260 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
261 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
262 }
264 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
265 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
266 xpdd->ev_actions[Port].xpdd = xpdd;
267 KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
268 KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
269 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_DPC;
271 EvtChn_Unmask(Context, Port);
273 FUNCTION_EXIT();
275 return STATUS_SUCCESS;
276 }
278 NTSTATUS
279 EvtChn_BindIrq(PVOID Context, evtchn_port_t Port, ULONG vector, PCHAR description)
280 {
281 PXENPCI_DEVICE_DATA xpdd = Context;
283 FUNCTION_ENTER();
285 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
286 {
287 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
288 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
289 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
290 }
292 xpdd->ev_actions[Port].vector = vector;
293 xpdd->ev_actions[Port].xpdd = xpdd;
294 KeMemoryBarrier();
295 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_IRQ;
296 RtlStringCbCopyA(xpdd->ev_actions[Port].description, 128, description);
298 EvtChn_Unmask(Context, Port);
300 FUNCTION_EXIT();
302 return STATUS_SUCCESS;
303 }
305 NTSTATUS
306 EvtChn_Unbind(PVOID Context, evtchn_port_t Port)
307 {
308 PXENPCI_DEVICE_DATA xpdd = Context;
309 int old_type;
311 EvtChn_Mask(Context, Port);
312 old_type = xpdd->ev_actions[Port].type;
313 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
314 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
315 xpdd->ev_actions[Port].ServiceRoutine = NULL;
316 xpdd->ev_actions[Port].ServiceContext = NULL;
318 if (old_type == EVT_ACTION_TYPE_DPC)
319 {
320 KeRemoveQueueDpc(&xpdd->ev_actions[Port].Dpc);
321 KeFlushQueuedDpcs();
322 }
324 return STATUS_SUCCESS;
325 }
327 NTSTATUS
328 EvtChn_Mask(PVOID Context, evtchn_port_t port)
329 {
330 PXENPCI_DEVICE_DATA xpdd = Context;
332 synch_set_bit(port & (BITS_PER_LONG - 1),
333 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[port >> BITS_PER_LONG_SHIFT]);
334 return STATUS_SUCCESS;
335 }
337 NTSTATUS
338 EvtChn_Unmask(PVOID context, evtchn_port_t port)
339 {
340 PXENPCI_DEVICE_DATA xpdd = context;
342 synch_clear_bit(port & (BITS_PER_LONG - 1),
343 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[port >> BITS_PER_LONG_SHIFT]);
344 return STATUS_SUCCESS;
345 }
347 NTSTATUS
348 EvtChn_Notify(PVOID Context, evtchn_port_t Port)
349 {
350 PXENPCI_DEVICE_DATA xpdd = Context;
351 struct evtchn_send send;
353 send.port = Port;
354 (void)HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_send, &send);
355 return STATUS_SUCCESS;
356 }
358 evtchn_port_t
359 EvtChn_AllocIpi(PVOID context, ULONG vcpu)
360 {
361 PXENPCI_DEVICE_DATA xpdd = context;
362 evtchn_bind_ipi_t op;
364 FUNCTION_ENTER();
365 op.vcpu = vcpu;
366 op.port = 0;
367 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_bind_ipi, &op);
368 FUNCTION_EXIT();
369 return op.port;
370 }
372 evtchn_port_t
373 EvtChn_AllocUnbound(PVOID Context, domid_t Domain)
374 {
375 PXENPCI_DEVICE_DATA xpdd = Context;
376 evtchn_alloc_unbound_t op;
377 op.dom = DOMID_SELF;
378 op.remote_dom = Domain;
379 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_alloc_unbound, &op);
380 return op.port;
381 }
383 VOID
384 EvtChn_Close(PVOID Context, evtchn_port_t port )
385 {
386 PXENPCI_DEVICE_DATA xpdd = Context;
387 evtchn_close_t op;
388 op.port = port;
389 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_close, &op);
390 return;
391 }
393 VOID
394 EvtChn_PdoEventChannelDpc(PVOID context)
395 {
396 PXENPCI_DEVICE_DATA xpdd = context;
398 FUNCTION_ENTER();
399 KeSetEvent(&xpdd->pdo_suspend_event, IO_NO_INCREMENT, FALSE);
400 FUNCTION_EXIT();
401 }
403 NTSTATUS
404 EvtChn_Init(PXENPCI_DEVICE_DATA xpdd)
405 {
406 ULONGLONG result;
407 int i;
409 FUNCTION_ENTER();
411 for (i = 0; i < NR_EVENTS; i++)
412 {
413 EvtChn_Mask(xpdd, i);
414 xpdd->ev_actions[i].type = EVT_ACTION_TYPE_EMPTY;
415 xpdd->ev_actions[i].count = 0;
416 }
418 for (i = 0; i < 8; i++)
419 {
420 xpdd->shared_info_area->evtchn_pending[i] = 0;
421 }
423 for (i = 0; i < MAX_VIRT_CPUS; i++)
424 {
425 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_pending = 0;
426 xpdd->shared_info_area->vcpu_info[i].evtchn_pending_sel = 0;
427 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1; /* apparantly this doesn't do anything */
428 }
430 KeMemoryBarrier();
432 result = hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, xpdd->irq_number);
433 KdPrint((__DRIVER_NAME " hvm_set_parameter(HVM_PARAM_CALLBACK_IRQ, %d) = %d\n", xpdd->irq_number, (ULONG)result));
435 for (i = 0; i < MAX_VIRT_CPUS; i++)
436 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 0;
437 xpdd->interrupts_masked = FALSE;
438 KeMemoryBarrier();
440 KeInitializeEvent(&xpdd->pdo_suspend_event, SynchronizationEvent, FALSE);
441 xpdd->pdo_event_channel = EvtChn_AllocIpi(xpdd, 0);
442 EvtChn_BindDpc(xpdd, xpdd->pdo_event_channel, EvtChn_PdoEventChannelDpc, xpdd);
443 xpdd->ev_actions[xpdd->pdo_event_channel].type = EVT_ACTION_TYPE_SUSPEND; /* override dpc type */
445 KdPrint((__DRIVER_NAME " pdo_event_channel = %d\n", xpdd->pdo_event_channel));
447 FUNCTION_EXIT();
449 return STATUS_SUCCESS;
450 }
452 NTSTATUS
453 EvtChn_Suspend(PXENPCI_DEVICE_DATA xpdd)
454 {
455 int i;
456 // LARGE_INTEGER wait_time;
458 xpdd->interrupts_masked = TRUE;
459 for (i = 0; i < MAX_VIRT_CPUS; i++)
460 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1;
461 KeMemoryBarrier();
462 hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, 0);
464 for (i = 0; i < NR_EVENTS; i++)
465 {
466 if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_DPC)
467 {
468 KeRemoveQueueDpc(&xpdd->ev_actions[i].Dpc);
469 }
470 }
471 KeFlushQueuedDpcs();
473 return STATUS_SUCCESS;
474 }
476 NTSTATUS
477 EvtChn_Resume(PXENPCI_DEVICE_DATA xpdd)
478 {
479 return EvtChn_Init(xpdd);