win-pvdrivers

view xenpci/xenpci_pdo.c @ 692:1fe30f6966eb

Fix bug where changing network adapter properties would not reload the adapter correctly
author James Harper <james.harper@bendigoit.com.au>
date Sun Nov 08 22:24:33 2009 +1100 (2009-11-08)
parents c13ccf5a629b
children 93b98effc8e7
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"
21 #include <stdlib.h>
22 #include <io/ring.h>
24 #pragma warning(disable : 4200) // zero-sized array
25 #pragma warning(disable: 4127) // conditional expression is constant
27 /*
28 Called at PASSIVE_LEVEL(?)
29 Called during restore
30 */
31 static ULONG
32 XenPci_ReadBackendState(PXENPCI_PDO_DEVICE_DATA xppdd)
33 {
34 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
35 char path[128];
36 char *value;
37 char *err;
38 ULONG backend_state;
40 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
41 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
42 if (err)
43 {
44 XenPci_FreeMem(err);
45 return XenbusStateUnknown;
46 }
47 else
48 {
49 backend_state = atoi(value);
50 XenPci_FreeMem(value);
51 return backend_state;
52 }
53 }
55 static NTSTATUS
56 XenPciPdo_ReconfigureCompletionRoutine(
57 PDEVICE_OBJECT device_object,
58 PIRP irp,
59 PVOID context)
60 {
61 UNREFERENCED_PARAMETER(device_object);
63 if (irp->PendingReturned)
64 {
65 KeSetEvent ((PKEVENT)context, IO_NO_INCREMENT, FALSE);
66 }
67 return STATUS_MORE_PROCESSING_REQUIRED;
68 }
70 static VOID
71 XenPci_UpdateBackendState(PVOID context)
72 {
73 WDFDEVICE device = context;
74 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
75 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
76 ULONG new_backend_state;
78 FUNCTION_ENTER();
80 ExAcquireFastMutex(&xppdd->backend_state_mutex);
82 new_backend_state = XenPci_ReadBackendState(xppdd);
83 if (new_backend_state == XenbusStateUnknown)
84 {
85 if (xpdd->suspend_state != SUSPEND_STATE_NONE)
86 {
87 ExReleaseFastMutex(&xppdd->backend_state_mutex);
88 return;
89 }
90 KdPrint(("Failed to read path, assuming closed\n"));
91 new_backend_state = XenbusStateClosed;
92 }
94 if (xppdd->backend_state == new_backend_state)
95 {
96 KdPrint((__DRIVER_NAME " state unchanged\n"));
97 ExReleaseFastMutex(&xppdd->backend_state_mutex);
98 return;
99 }
101 xppdd->backend_state = new_backend_state;
103 switch (xppdd->backend_state)
104 {
105 case XenbusStateUnknown:
106 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
107 break;
109 case XenbusStateInitialising:
110 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
111 break;
113 case XenbusStateInitWait:
114 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
115 break;
117 case XenbusStateInitialised:
118 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
119 break;
121 case XenbusStateConnected:
122 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
123 break;
125 case XenbusStateClosing:
126 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
127 if (xppdd->frontend_state != XenbusStateClosing)
128 {
129 KdPrint((__DRIVER_NAME " Requesting eject\n"));
130 WdfPdoRequestEject(device);
131 }
132 break;
134 case XenbusStateClosed:
135 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
136 break;
138 default:
139 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xppdd->backend_state));
140 break;
141 }
143 KeSetEvent(&xppdd->backend_state_event, 1, FALSE);
145 ExReleaseFastMutex(&xppdd->backend_state_mutex);
146 FUNCTION_EXIT();
148 return;
149 }
151 static VOID
152 XenPci_BackendStateHandler(char *path, PVOID context)
153 {
154 UNREFERENCED_PARAMETER(path);
156 /* check that path == device/id/state */
157 //RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->path);
159 XenPci_UpdateBackendState(context);
160 }
162 static NTSTATUS
163 XenPci_GetBackendAndAddWatch(WDFDEVICE device)
164 {
165 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
166 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
167 char path[128];
168 PCHAR res;
169 PCHAR value;
171 FUNCTION_ENTER();
172 /* Get backend path */
173 RtlStringCbPrintfA(path, ARRAY_SIZE(path),
174 "%s/backend", xppdd->path);
175 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
176 if (res)
177 {
178 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
179 XenPci_FreeMem(res);
180 return STATUS_UNSUCCESSFUL;
181 }
182 RtlStringCbCopyA(xppdd->backend_path, ARRAY_SIZE(xppdd->backend_path), value);
183 XenPci_FreeMem(value);
185 /* Add watch on backend state */
186 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
187 XenBus_AddWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
189 FUNCTION_EXIT();
190 return STATUS_SUCCESS;
191 }
193 static NTSTATUS
194 XenConfig_InitConfigPage(WDFDEVICE device)
195 {
196 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
197 //PXENCONFIG_DEVICE_DATA xcdd = (PXENCONFIG_DEVICE_DATA)device_object->DeviceExtension;
198 //PXENPCI_PDO_DEVICE_DATA xppdd = (PXENPCI_PDO_DEVICE_DATA)device_object->DeviceExtension;
199 //PXENPCI_DEVICE_DATA xpdd = xppdd->bus_fdo->DeviceExtension;
200 PUCHAR ptr;
201 PDEVICE_OBJECT curr, prev;
202 PDRIVER_OBJECT fdo_driver_object;
203 PUCHAR fdo_driver_extension;
205 FUNCTION_ENTER();
207 ptr = MmGetMdlVirtualAddress(xppdd->config_page_mdl);
208 curr = IoGetAttachedDeviceReference(WdfDeviceWdmGetDeviceObject(device));
209 //curr = WdfDeviceWdmGetAttachedDevice(device);
210 while (curr != NULL)
211 {
212 fdo_driver_object = curr->DriverObject;
213 KdPrint((__DRIVER_NAME " fdo_driver_object = %p\n", fdo_driver_object));
214 if (fdo_driver_object)
215 {
216 fdo_driver_extension = IoGetDriverObjectExtension(fdo_driver_object, UlongToPtr(XEN_INIT_DRIVER_EXTENSION_MAGIC));
217 KdPrint((__DRIVER_NAME " fdo_driver_extension = %p\n", fdo_driver_extension));
218 if (fdo_driver_extension)
219 {
220 memcpy(ptr, fdo_driver_extension, PAGE_SIZE);
221 ObDereferenceObject(curr);
222 break;
223 }
224 }
225 prev = curr;
226 curr = IoGetLowerDeviceObject(curr);
227 ObDereferenceObject(prev);
228 }
230 FUNCTION_EXIT();
232 return STATUS_SUCCESS;
233 }
235 static NTSTATUS
236 XenPci_EvtChn_Bind(PVOID context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
237 {
238 WDFDEVICE device = context;
239 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
240 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
242 return EvtChn_Bind(xpdd, Port, ServiceRoutine, ServiceContext);
243 }
245 static NTSTATUS
246 XenPci_EvtChn_BindDpc(PVOID context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
247 {
248 WDFDEVICE device = context;
249 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
250 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
252 return EvtChn_BindDpc(xpdd, Port, ServiceRoutine, ServiceContext);
253 }
255 static NTSTATUS
256 XenPci_EvtChn_Unbind(PVOID context, evtchn_port_t Port)
257 {
258 WDFDEVICE device = context;
259 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
260 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
262 return EvtChn_Unbind(xpdd, Port);
263 }
265 static NTSTATUS
266 XenPci_EvtChn_Mask(PVOID context, evtchn_port_t Port)
267 {
268 WDFDEVICE device = context;
269 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
270 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
272 return EvtChn_Mask(xpdd, Port);
273 }
275 static NTSTATUS
276 XenPci_EvtChn_Unmask(PVOID context, evtchn_port_t Port)
277 {
278 WDFDEVICE device = context;
279 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
280 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
282 return EvtChn_Unmask(xpdd, Port);
283 }
285 static NTSTATUS
286 XenPci_EvtChn_Notify(PVOID context, evtchn_port_t Port)
287 {
288 WDFDEVICE device = context;
289 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
290 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
292 return EvtChn_Notify(xpdd, Port);
293 }
295 static BOOLEAN
296 XenPci_EvtChn_AckEvent(PVOID context, evtchn_port_t port, BOOLEAN *last_interrupt)
297 {
298 WDFDEVICE device = context;
299 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
300 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
302 return EvtChn_AckEvent(xpdd, port, last_interrupt);
303 }
305 typedef struct {
306 PXEN_EVTCHN_SYNC_ROUTINE sync_routine;
307 PVOID sync_context;
308 } sync_context_t;
310 static BOOLEAN
311 XenPci_EvtChn_Sync_Routine(WDFINTERRUPT interrupt, WDFCONTEXT context)
312 {
313 sync_context_t *wdf_sync_context = context;
314 UNREFERENCED_PARAMETER(interrupt);
315 return wdf_sync_context->sync_routine(wdf_sync_context->sync_context);
316 }
318 static BOOLEAN
319 XenPci_EvtChn_Sync(PVOID context, PXEN_EVTCHN_SYNC_ROUTINE sync_routine, PVOID sync_context)
320 {
321 WDFDEVICE device = context;
322 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
323 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
324 sync_context_t wdf_sync_context;
326 wdf_sync_context.sync_routine = sync_routine;
327 wdf_sync_context.sync_context = sync_context;
329 return WdfInterruptSynchronize(xpdd->interrupt, XenPci_EvtChn_Sync_Routine, &wdf_sync_context);
330 }
332 static grant_ref_t
333 XenPci_GntTbl_GrantAccess(PVOID context, domid_t domid, uint32_t frame, int readonly, grant_ref_t ref)
334 {
335 WDFDEVICE device = context;
336 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
337 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
339 return GntTbl_GrantAccess(xpdd, domid, frame, readonly, ref);
340 }
342 static BOOLEAN
343 XenPci_GntTbl_EndAccess(PVOID context, grant_ref_t ref, BOOLEAN keepref)
344 {
345 WDFDEVICE device = context;
346 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
347 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
349 return GntTbl_EndAccess(xpdd, ref, keepref);
350 }
352 static VOID
353 XenPci_GntTbl_PutRef(PVOID context, grant_ref_t ref)
354 {
355 WDFDEVICE device = context;
356 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
357 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
359 GntTbl_PutRef(xpdd, ref);
360 }
362 static grant_ref_t
363 XenPci_GntTbl_GetRef(PVOID context)
364 {
365 WDFDEVICE device = context;
366 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
367 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
369 return GntTbl_GetRef(xpdd);
370 }
372 PCHAR
373 XenPci_XenBus_Read(PVOID context, xenbus_transaction_t xbt, char *path, char **value)
374 {
375 WDFDEVICE device = context;
376 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
377 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
378 return XenBus_Read(xpdd, xbt, path, value);
379 }
381 PCHAR
382 XenPci_XenBus_Write(PVOID context, xenbus_transaction_t xbt, char *path, char *value)
383 {
384 WDFDEVICE device = context;
385 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
386 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
387 return XenBus_Write(xpdd, xbt, path, value);
388 }
390 PCHAR
391 XenPci_XenBus_Printf(PVOID context, xenbus_transaction_t xbt, char *path, char *fmt, ...)
392 {
393 //PXENPCI_PDO_DEVICE_DATA xppdd = Context;
394 //PXENPCI_DEVICE_DATA xpdd = xppdd->bus_fdo->DeviceExtension;
395 //return XenBus_Printf(xpdd, xbt, path, value);
396 UNREFERENCED_PARAMETER(context);
397 UNREFERENCED_PARAMETER(xbt);
398 UNREFERENCED_PARAMETER(path);
399 UNREFERENCED_PARAMETER(fmt);
400 return NULL;
401 }
403 PCHAR
404 XenPci_XenBus_StartTransaction(PVOID context, xenbus_transaction_t *xbt)
405 {
406 WDFDEVICE device = context;
407 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
408 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
409 return XenBus_StartTransaction(xpdd, xbt);
410 }
412 PCHAR
413 XenPci_XenBus_EndTransaction(PVOID context, xenbus_transaction_t xbt, int abort, int *retry)
414 {
415 WDFDEVICE device = context;
416 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
417 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
418 return XenBus_EndTransaction(xpdd, xbt, abort, retry);
419 }
421 PCHAR
422 XenPci_XenBus_List(PVOID context, xenbus_transaction_t xbt, char *prefix, char ***contents)
423 {
424 WDFDEVICE device = context;
425 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
426 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
427 return XenBus_List(xpdd, xbt, prefix, contents);
428 }
430 PCHAR
431 XenPci_XenBus_AddWatch(PVOID context, xenbus_transaction_t xbt, char *path, PXENBUS_WATCH_CALLBACK ServiceRoutine, PVOID ServiceContext)
432 {
433 WDFDEVICE device = context;
434 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
435 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
436 PCHAR retval;
438 FUNCTION_ENTER();
439 retval = XenBus_AddWatch(xpdd, xbt, path, ServiceRoutine, ServiceContext);
440 if (retval == NULL)
441 {
442 KdPrint((__DRIVER_NAME " XenPci_XenBus_AddWatch - %s = NULL\n", path));
443 }
444 else
445 {
446 KdPrint((__DRIVER_NAME " XenPci_XenBus_AddWatch - %s = %s\n", path, retval));
447 }
448 FUNCTION_EXIT();
449 return retval;
450 }
452 PCHAR
453 XenPci_XenBus_RemWatch(PVOID context, xenbus_transaction_t xbt, char *path, PXENBUS_WATCH_CALLBACK ServiceRoutine, PVOID ServiceContext)
454 {
455 WDFDEVICE device = context;
456 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
457 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
458 return XenBus_RemWatch(xpdd, xbt, path, ServiceRoutine, ServiceContext);
459 }
461 /*
462 Called at PASSIVE_LEVEL
463 Called during restore
464 */
466 static NTSTATUS
467 XenPci_ChangeFrontendState(WDFDEVICE device, ULONG frontend_state_set, ULONG backend_state_response, ULONG maximum_wait_ms)
468 {
469 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
470 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
471 LARGE_INTEGER timeout;
472 ULONG remaining;
473 ULONG thiswait;
474 char path[128];
476 FUNCTION_ENTER();
478 xppdd->frontend_state = frontend_state_set;
480 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->path);
481 XenBus_Printf(xpdd, XBT_NIL, path, "%d", frontend_state_set);
483 remaining = maximum_wait_ms;
485 while (xppdd->backend_state != backend_state_response)
486 {
487 thiswait = min((LONG)remaining, 1000); // 1 second or remaining time, whichever is less
488 timeout.QuadPart = (LONGLONG)-1 * thiswait * 1000 * 10;
489 if (KeWaitForSingleObject(&xppdd->backend_state_event, Executive, KernelMode, FALSE, &timeout) == STATUS_TIMEOUT)
490 {
491 /* it's possible that the workitems are blocked because the pagefile isn't available. Lets just re-read the backend value for now */
492 XenPci_UpdateBackendState(device);
493 remaining -= thiswait;
494 if (remaining == 0)
495 {
496 KdPrint((__DRIVER_NAME " Timed out waiting for %d!\n", backend_state_response));
497 return STATUS_UNSUCCESSFUL;
498 }
499 KdPrint((__DRIVER_NAME " Still waiting for %d (currently %d)...\n", backend_state_response, xppdd->backend_state));
500 }
501 }
502 FUNCTION_EXIT();
503 return STATUS_SUCCESS;
504 }
506 static NTSTATUS
507 XenPci_XenConfigDevice(WDFDEVICE device);
509 static NTSTATUS
510 XenPci_XenShutdownDevice(PVOID context)
511 {
512 WDFDEVICE device = context;
513 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
514 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
515 PUCHAR in_ptr;
516 ULONG i;
517 UCHAR type;
518 PVOID setting;
519 PVOID value;
520 PVOID value2;
522 FUNCTION_ENTER();
524 if (xppdd->backend_state == XenbusStateConnected)
525 {
526 XenPci_ChangeFrontendState(device, XenbusStateClosing, XenbusStateClosing, 30000);
527 if (xppdd->backend_state == XenbusStateClosing)
528 XenPci_ChangeFrontendState(device, XenbusStateClosed, XenbusStateClosed, 30000);
529 if (xppdd->backend_state == XenbusStateClosed)
530 XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 30000);
531 }
532 else
533 {
534 if (xppdd->backend_state == XenbusStateClosing)
535 XenPci_ChangeFrontendState(device, XenbusStateClosed, XenbusStateClosed, 30000);
536 }
538 if (xppdd->assigned_resources_start != NULL)
539 {
540 ADD_XEN_INIT_RSP(&xppdd->assigned_resources_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
541 in_ptr = xppdd->assigned_resources_start;
542 while((type = GET_XEN_INIT_RSP(&in_ptr, &setting, &value, &value2)) != XEN_INIT_TYPE_END)
543 {
544 switch (type)
545 {
546 case XEN_INIT_TYPE_RING: /* frontend ring */
547 FreePages(value);
548 break;
549 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
550 case XEN_INIT_TYPE_EVENT_CHANNEL_DPC: /* frontend event channel bound to dpc */
551 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel bound to irq */
552 EvtChn_Unbind(xpdd, PtrToUlong(value));
553 EvtChn_Close(xpdd, PtrToUlong(value));
554 break;
555 case XEN_INIT_TYPE_GRANT_ENTRIES:
556 for (i = 0; i < PtrToUlong(setting); i++)
557 GntTbl_EndAccess(xpdd, ((grant_ref_t *)value)[i], FALSE);
558 break;
559 }
560 }
561 ExFreePoolWithTag(xppdd->assigned_resources_start, XENPCI_POOL_TAG);
562 xppdd->assigned_resources_start = NULL;
563 }
565 FUNCTION_EXIT();
567 return STATUS_SUCCESS;
568 }
570 struct dummy_sring {
571 RING_IDX req_prod, req_event;
572 RING_IDX rsp_prod, rsp_event;
573 uint8_t pad[48];
574 };
576 static NTSTATUS
577 XenPci_XenConfigDeviceSpecifyBuffers(WDFDEVICE device, PUCHAR src, PUCHAR dst)
578 {
579 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
580 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
581 NTSTATUS status = STATUS_SUCCESS;
582 ULONG i;
583 char path[128];
584 PCHAR setting, value;
585 PCHAR res;
586 PVOID address;
587 UCHAR type;
588 PUCHAR in_ptr;
589 PUCHAR out_ptr;
590 XENPCI_VECTORS vectors;
591 ULONG event_channel;
592 ULONG run_type = 0;
593 PMDL ring;
594 grant_ref_t gref;
595 BOOLEAN done_xenbus_init = FALSE;
596 PVOID value2;
597 BOOLEAN active = TRUE;
598 BOOLEAN dont_config = FALSE;
600 FUNCTION_ENTER();
602 in_ptr = src;
603 out_ptr = dst;
605 // always add vectors
606 vectors.magic = XEN_DATA_MAGIC;
607 vectors.length = sizeof(XENPCI_VECTORS);
608 vectors.context = device;
609 vectors.EvtChn_Bind = XenPci_EvtChn_Bind;
610 vectors.EvtChn_BindDpc = XenPci_EvtChn_BindDpc;
611 vectors.EvtChn_Unbind = XenPci_EvtChn_Unbind;
612 vectors.EvtChn_Mask = XenPci_EvtChn_Mask;
613 vectors.EvtChn_Unmask = XenPci_EvtChn_Unmask;
614 vectors.EvtChn_Notify = XenPci_EvtChn_Notify;
615 vectors.EvtChn_AckEvent = XenPci_EvtChn_AckEvent;
616 vectors.EvtChn_Sync = XenPci_EvtChn_Sync;
617 vectors.GntTbl_GetRef = XenPci_GntTbl_GetRef;
618 vectors.GntTbl_PutRef = XenPci_GntTbl_PutRef;
619 vectors.GntTbl_GrantAccess = XenPci_GntTbl_GrantAccess;
620 vectors.GntTbl_EndAccess = XenPci_GntTbl_EndAccess;
621 vectors.XenPci_XenConfigDevice = XenPci_XenConfigDevice;
622 vectors.XenPci_XenShutdownDevice = XenPci_XenShutdownDevice;
623 strncpy(vectors.path, xppdd->path, 128);
624 strncpy(vectors.backend_path, xppdd->backend_path, 128);
625 //vectors.pdo_event_channel = xpdd->pdo_event_channel;
626 vectors.XenBus_Read = XenPci_XenBus_Read;
627 vectors.XenBus_Write = XenPci_XenBus_Write;
628 vectors.XenBus_Printf = XenPci_XenBus_Printf;
629 vectors.XenBus_StartTransaction = XenPci_XenBus_StartTransaction;
630 vectors.XenBus_EndTransaction = XenPci_XenBus_EndTransaction;
631 vectors.XenBus_List = XenPci_XenBus_List;
632 vectors.XenBus_AddWatch = XenPci_XenBus_AddWatch;
633 vectors.XenBus_RemWatch = XenPci_XenBus_RemWatch;
635 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_QEMU_PROTOCOL_VERSION, NULL, UlongToPtr(qemu_protocol_version), NULL);
637 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_VECTORS, NULL, &vectors, NULL);
638 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_STATE_PTR, NULL, &xppdd->device_state, NULL);
640 if (!qemu_filtered)
641 active = FALSE;
643 while((type = GET_XEN_INIT_REQ(&in_ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
644 {
645 BOOLEAN condition;
646 PCHAR xb_value;
647 switch (type)
648 {
649 case XEN_INIT_TYPE_MATCH_FRONT:
650 case XEN_INIT_TYPE_MATCH_BACK:
651 if (type == XEN_INIT_TYPE_MATCH_FRONT)
652 {
653 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
654 }
655 else
656 {
657 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->backend_path, setting);
658 }
659 KdPrint((__DRIVER_NAME " testing path = %s\n", path));
660 res = XenBus_Read(xpdd, XBT_NIL, path, &xb_value);
661 if (res)
662 {
663 KdPrint((__DRIVER_NAME " read failed (%s)\n", res));
664 XenPci_FreeMem(res);
665 }
666 else
667 {
668 KdPrint((__DRIVER_NAME " testing %s vs %s\n", xb_value, value));
669 if (PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_IF_MATCH)
670 condition = (strcmp(xb_value, value) == 0)?TRUE:FALSE;
671 else
672 condition = (strcmp(xb_value, value) != 0)?TRUE:FALSE;
673 KdPrint((__DRIVER_NAME " condition = %d\n", condition));
675 if ((PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_ONLY_IF_QEMU_HIDE) && qemu_protocol_version && condition)
676 condition = FALSE;
678 if (condition)
679 {
680 if (PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_SET_INACTIVE)
681 {
682 active = FALSE;
683 KdPrint((__DRIVER_NAME " set inactive\n"));
684 }
685 if (PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_DONT_CONFIG)
686 {
687 dont_config = TRUE;
688 KdPrint((__DRIVER_NAME " set inactive with dont config\n"));
689 }
690 }
691 XenPci_FreeMem(xb_value);
692 }
693 break;
694 }
695 }
696 if (dont_config)
697 {
698 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
699 FUNCTION_EXIT();
700 return status;
701 }
703 // first pass, possibly before state == Connected
704 in_ptr = src;
705 while((type = GET_XEN_INIT_REQ(&in_ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
706 {
707 if (!done_xenbus_init)
708 {
709 if (XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 2000) != STATUS_SUCCESS)
710 {
711 status = STATUS_UNSUCCESSFUL;
712 goto error;
713 }
714 done_xenbus_init = TRUE;
715 }
717 ADD_XEN_INIT_REQ(&xppdd->requested_resources_ptr, type, setting, value, value2);
719 switch (type)
720 {
721 case XEN_INIT_TYPE_RUN:
722 run_type++;
723 break;
724 case XEN_INIT_TYPE_WRITE_STRING: /* frontend setting = value */
725 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_WRITE_STRING - %s = %s\n", setting, value));
726 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
727 XenBus_Printf(xpdd, XBT_NIL, path, "%s", value);
728 break;
729 case XEN_INIT_TYPE_RING: /* frontend ring */
730 /* we only allocate and do the SHARED_RING_INIT here */
731 if ((ring = AllocatePage()) != 0)
732 {
733 address = MmGetMdlVirtualAddress(ring);
734 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, address));
735 SHARED_RING_INIT((struct dummy_sring *)address);
736 if ((gref = GntTbl_GrantAccess(
737 xpdd, 0, (ULONG)*MmGetMdlPfnArray(ring), FALSE, INVALID_GRANT_REF)) != INVALID_GRANT_REF)
738 {
739 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
740 XenBus_Printf(xpdd, XBT_NIL, path, "%d", gref);
741 ADD_XEN_INIT_RSP(&out_ptr, type, setting, address, NULL);
742 ADD_XEN_INIT_RSP(&xppdd->assigned_resources_ptr, type, setting, ring, NULL);
743 // add the grant entry too so it gets freed automatically
744 __ADD_XEN_INIT_UCHAR(&xppdd->assigned_resources_ptr, XEN_INIT_TYPE_GRANT_ENTRIES);
745 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, 1);
746 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, gref);
747 }
748 else
749 {
750 FreePages(ring);
751 status = STATUS_UNSUCCESSFUL;
752 goto error;
753 }
754 }
755 else
756 {
757 status = STATUS_UNSUCCESSFUL;
758 goto error;
759 }
760 break;
761 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
762 case XEN_INIT_TYPE_EVENT_CHANNEL_DPC: /* frontend event channel bound to dpc */
763 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel bound to irq */
764 if ((event_channel = EvtChn_AllocUnbound(xpdd, 0)) != 0)
765 {
766 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, event_channel));
767 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
768 XenBus_Printf(xpdd, XBT_NIL, path, "%d", event_channel);
769 ADD_XEN_INIT_RSP(&out_ptr, type, setting, UlongToPtr(event_channel), NULL);
770 ADD_XEN_INIT_RSP(&xppdd->assigned_resources_ptr, type, setting, UlongToPtr(event_channel), NULL);
771 if (type == XEN_INIT_TYPE_EVENT_CHANNEL_IRQ)
772 {
773 EvtChn_BindIrq(xpdd, event_channel, xppdd->irq_vector, path);
774 }
775 else if (type == XEN_INIT_TYPE_EVENT_CHANNEL_DPC)
776 {
777 #pragma warning(suppress:4055)
778 EvtChn_BindDpc(xpdd, event_channel, (PXEN_EVTCHN_SERVICE_ROUTINE)value, value2);
779 }
780 else
781 {
782 #pragma warning(suppress:4055)
783 EvtChn_Bind(xpdd, event_channel, (PXEN_EVTCHN_SERVICE_ROUTINE)value, value2);
784 }
785 }
786 else
787 {
788 status = STATUS_UNSUCCESSFUL;
789 goto error;
790 }
791 break;
792 }
793 }
794 if (!NT_SUCCESS(status))
795 {
796 goto error;
797 }
798 // If XEN_INIT_TYPE_RUN was specified more than once then we skip XenbusStateInitialised here and go straight to XenbusStateConnected at the end
799 if (run_type == 1)
800 {
801 if (XenPci_ChangeFrontendState(device, XenbusStateInitialised, XenbusStateConnected, 2000) != STATUS_SUCCESS)
802 {
803 status = STATUS_UNSUCCESSFUL;
804 goto error;
805 }
806 }
808 // second pass, possibly after state == Connected
809 in_ptr = src;
810 while((type = GET_XEN_INIT_REQ(&in_ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
811 {
812 switch(type)
813 {
814 case XEN_INIT_TYPE_READ_STRING_BACK:
815 case XEN_INIT_TYPE_READ_STRING_FRONT:
816 if (type == XEN_INIT_TYPE_READ_STRING_FRONT)
817 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
818 else
819 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->backend_path, setting);
820 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
821 if (res)
822 {
823 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = <failed>\n", setting));
824 XenPci_FreeMem(res);
825 ADD_XEN_INIT_RSP(&out_ptr, type, setting, "", "");
826 }
827 else
828 {
829 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
830 ADD_XEN_INIT_RSP(&out_ptr, type, setting, value, value2);
831 XenPci_FreeMem(value);
832 }
833 break;
834 case XEN_INIT_TYPE_VECTORS:
835 // this is always done so ignore the request
836 break;
837 case XEN_INIT_TYPE_GRANT_ENTRIES:
838 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_GRANT_ENTRIES - %d\n", PtrToUlong(value)));
839 __ADD_XEN_INIT_UCHAR(&out_ptr, type);
840 __ADD_XEN_INIT_UCHAR(&xppdd->assigned_resources_ptr, type);
841 __ADD_XEN_INIT_ULONG(&out_ptr, PtrToUlong(value));
842 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, PtrToUlong(value));
843 for (i = 0; i < PtrToUlong(value); i++)
844 {
845 gref = GntTbl_GetRef(xpdd);
846 __ADD_XEN_INIT_ULONG(&out_ptr, gref);
847 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, gref);
848 }
849 break;
850 }
851 }
852 if (active)
853 {
854 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_ACTIVE, NULL, NULL, NULL);
855 }
856 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
858 if (run_type)
859 {
860 if (XenPci_ChangeFrontendState(device, XenbusStateConnected, XenbusStateConnected, 2000) != STATUS_SUCCESS)
861 {
862 status = STATUS_UNSUCCESSFUL;
863 goto error;
864 }
865 }
866 FUNCTION_EXIT();
867 return status;
869 error:
870 XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 2000);
871 FUNCTION_EXIT_STATUS(status);
872 return status;
873 }
875 static NTSTATUS
876 XenPci_XenConfigDevice(WDFDEVICE device)
877 {
878 NTSTATUS status;
879 PUCHAR src, dst;
880 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
882 src = ExAllocatePoolWithTag(NonPagedPool, xppdd->config_page_length, XENPCI_POOL_TAG);
883 dst = MmMapIoSpace(xppdd->config_page_phys, xppdd->config_page_length, MmNonCached);
884 memcpy(src, dst, xppdd->config_page_length);
886 status = XenPci_XenConfigDeviceSpecifyBuffers(device, src, dst);
888 MmUnmapIoSpace(dst, xppdd->config_page_length);
889 ExFreePoolWithTag(src, XENPCI_POOL_TAG);
891 return status;
892 }
894 static NTSTATUS
895 XenPciPdo_EvtDeviceWdmIrpPreprocess_START_DEVICE(WDFDEVICE device, PIRP irp)
896 {
897 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
898 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
899 PIO_STACK_LOCATION stack;
900 PCM_PARTIAL_RESOURCE_LIST prl;
901 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
902 ULONG i;
903 //char path[128];
904 //PMDL mdl;
906 FUNCTION_ENTER();
907 KdPrint((__DRIVER_NAME " %s\n", xppdd->path));
909 stack = IoGetCurrentIrpStackLocation(irp);
911 prl = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
912 for (i = 0; i < prl->Count; i++)
913 {
914 prd = & prl->PartialDescriptors[i];
915 switch (prd->Type)
916 {
917 case CmResourceTypeMemory:
918 if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart && prd->u.Memory.Length == 0)
919 {
920 prd->u.Memory.Start.QuadPart = MmGetMdlPfnArray(xppdd->config_page_mdl)[0] << PAGE_SHIFT;
921 prd->u.Memory.Length = MmGetMdlByteCount(xppdd->config_page_mdl);
922 }
923 else if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart + 1 && prd->u.Memory.Length == 0)
924 {
925 RtlZeroMemory(prd, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
926 prd->Type = CmResourceTypeInterrupt;
927 prd->ShareDisposition = CmResourceShareShared;
928 prd->Flags = (xpdd->irq_mode == Latched)?CM_RESOURCE_INTERRUPT_LATCHED:CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
929 prd->u.Interrupt.Level = 0; // Set group and level to zero (group = upper word)
930 prd->u.Interrupt.Level = xpdd->irq_number & 0xffff; // Only set the lower word
931 prd->u.Interrupt.Vector = xpdd->irq_number;
932 prd->u.Interrupt.Affinity = KeQueryActiveProcessors();
933 xppdd->irq_number = xpdd->irq_number;
934 }
935 break;
936 }
937 }
939 prl = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
940 for (i = 0; i < prl->Count; i++)
941 {
942 prd = & prl->PartialDescriptors[i];
943 switch (prd->Type)
944 {
945 case CmResourceTypeMemory:
946 KdPrint((__DRIVER_NAME " CmResourceTypeMemory (%d)\n", i));
947 KdPrint((__DRIVER_NAME " Start = %08x, Length = %d\n", prd->u.Memory.Start.LowPart, prd->u.Memory.Length));
948 if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart)
949 {
950 if (prd->u.Memory.Length == 0)
951 {
952 KdPrint((__DRIVER_NAME " pfn[0] = %08x\n", (ULONG)MmGetMdlPfnArray(xppdd->config_page_mdl)[0]));
953 prd->u.Memory.Start.QuadPart = (ULONGLONG)MmGetMdlPfnArray(xppdd->config_page_mdl)[0] << PAGE_SHIFT;
954 prd->u.Memory.Length = MmGetMdlByteCount(xppdd->config_page_mdl);
955 KdPrint((__DRIVER_NAME " New Start = %08x%08x, Length = %d\n", prd->u.Memory.Start.HighPart, prd->u.Memory.Start.LowPart, prd->u.Memory.Length));
956 }
957 xppdd->config_page_phys = prd->u.Memory.Start;
958 xppdd->config_page_length = prd->u.Memory.Length;
959 xppdd->requested_resources_start = xppdd->requested_resources_ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
960 //xppdd->assigned_resources_start = xppdd->assigned_resources_ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
962 #if 0
963 status = XenPci_XenConfigDevice(device);
964 if (!NT_SUCCESS(status))
965 {
966 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
967 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
968 FUNCTION_ERROR_EXIT();
969 return status;
970 }
971 #endif
972 }
973 else if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart + 1 && prd->u.Memory.Length == 0)
974 {
975 RtlZeroMemory(prd, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
976 prd->Type = CmResourceTypeInterrupt;
977 prd->ShareDisposition = CmResourceShareShared;
978 prd->Flags = (xpdd->irq_mode == Latched)?CM_RESOURCE_INTERRUPT_LATCHED:CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
979 prd->u.Interrupt.Level = 0; // Set group and level to zero (group = upper word)
980 prd->u.Interrupt.Level = xpdd->irq_level & 0xffff; // Only set the lower word
981 prd->u.Interrupt.Vector = xpdd->irq_vector;
982 prd->u.Interrupt.Affinity = KeQueryActiveProcessors();
983 xppdd->irq_vector = xpdd->irq_vector;
984 xppdd->irq_level = xpdd->irq_level;
985 }
986 break;
987 }
988 }
990 IoSkipCurrentIrpStackLocation(irp);
992 FUNCTION_EXIT();
994 return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
995 }
997 #if 0
998 static NTSTATUS
999 XenPciPdo_EvtDeviceResourcesQuery(WDFDEVICE device, WDFCMRESLIST resources)
1002 #endif
1004 static NTSTATUS
1005 XenPciPdo_EvtDeviceResourceRequirementsQuery(WDFDEVICE device, WDFIORESREQLIST requirements_list)
1007 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1008 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1009 WDFIORESLIST res_list;
1010 IO_RESOURCE_DESCRIPTOR ird;
1012 //FUNCTION_ENTER();
1014 WdfIoResourceRequirementsListSetInterfaceType(requirements_list, PNPBus);
1016 WdfIoResourceListCreate(requirements_list, WDF_NO_OBJECT_ATTRIBUTES, &res_list);
1017 ird.Option = 0;
1018 ird.Type = CmResourceTypeMemory;
1019 ird.ShareDisposition = CmResourceShareShared;
1020 ird.Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
1021 ird.u.Memory.MinimumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart;
1022 ird.u.Memory.MaximumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart;
1023 ird.u.Memory.Length = 0;
1024 ird.u.Memory.Alignment = 1; //PAGE_SIZE;
1025 WdfIoResourceListAppendDescriptor(res_list, &ird);
1027 ird.Option = 0;
1028 ird.Type = CmResourceTypeMemory;
1029 ird.ShareDisposition = CmResourceShareShared;
1030 ird.Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
1031 ird.u.Memory.MinimumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart + 1;
1032 ird.u.Memory.MaximumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart + 1;
1033 ird.u.Memory.Length = 0;
1034 ird.u.Memory.Alignment = 1; //PAGE_SIZE;
1035 WdfIoResourceListAppendDescriptor(res_list, &ird);
1037 WdfIoResourceRequirementsListAppendIoResList(requirements_list, res_list);
1039 //FUNCTION_EXIT();
1041 return STATUS_SUCCESS;
1044 NTSTATUS
1045 XenPciPdo_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
1047 NTSTATUS status = STATUS_SUCCESS;
1048 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1049 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1050 CHAR path[128];
1052 FUNCTION_ENTER();
1054 switch (previous_state)
1056 case WdfPowerDeviceD0:
1057 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
1058 break;
1059 case WdfPowerDeviceD1:
1060 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
1061 break;
1062 case WdfPowerDeviceD2:
1063 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
1064 break;
1065 case WdfPowerDeviceD3:
1066 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
1067 break;
1068 case WdfPowerDeviceD3Final:
1069 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
1070 break;
1071 case WdfPowerDevicePrepareForHibernation:
1072 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
1073 break;
1074 default:
1075 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
1076 break;
1079 if (previous_state == WdfPowerDevicePrepareForHibernation
1080 || (previous_state == WdfPowerDeviceD3 && xppdd->hiber_usage_kludge))
1082 KdPrint((__DRIVER_NAME " starting up from hibernation\n"));
1084 else
1088 if (previous_state == WdfPowerDevicePrepareForHibernation || previous_state == WdfPowerDeviceD3 || previous_state == WdfPowerDeviceD3Final)
1090 xppdd->requested_resources_ptr = xppdd->requested_resources_start;
1091 xppdd->assigned_resources_start = xppdd->assigned_resources_ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
1094 XenConfig_InitConfigPage(device);
1096 status = XenPci_GetBackendAndAddWatch(device);
1097 if (!NT_SUCCESS(status))
1099 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
1100 FUNCTION_ERROR_EXIT();
1101 return status;
1103 status = XenPci_XenConfigDevice(device);
1104 if (!NT_SUCCESS(status))
1106 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
1107 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
1108 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
1109 FUNCTION_ERROR_EXIT();
1110 return status;
1113 FUNCTION_EXIT();
1115 return status;
1118 NTSTATUS
1119 XenPciPdo_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
1121 NTSTATUS status = STATUS_SUCCESS;
1122 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1123 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1124 char path[128];
1126 UNREFERENCED_PARAMETER(device);
1127 UNREFERENCED_PARAMETER(target_state);
1129 FUNCTION_ENTER();
1131 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
1134 switch (target_state)
1136 case WdfPowerDeviceD0:
1137 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
1138 break;
1139 case WdfPowerDeviceD1:
1140 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
1141 break;
1142 case WdfPowerDeviceD2:
1143 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
1144 break;
1145 case WdfPowerDeviceD3:
1146 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
1147 break;
1148 case WdfPowerDeviceD3Final:
1149 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
1150 break;
1151 case WdfPowerDevicePrepareForHibernation:
1152 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
1153 break;
1154 default:
1155 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
1156 break;
1159 if (target_state == WdfPowerDevicePrepareForHibernation
1160 || (target_state == WdfPowerDeviceD3 && xppdd->hiber_usage_kludge))
1162 KdPrint((__DRIVER_NAME " not powering down as we are hibernating\n"));
1164 else
1166 status = XenPci_XenShutdownDevice(device);
1169 /* Remove watch on backend state */
1170 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
1171 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
1173 FUNCTION_EXIT();
1175 return status;
1178 NTSTATUS
1179 XenPciPdo_EvtDevicePrepareHardware(WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
1181 NTSTATUS status = STATUS_SUCCESS;
1183 UNREFERENCED_PARAMETER(device);
1184 UNREFERENCED_PARAMETER(resources_raw);
1185 UNREFERENCED_PARAMETER(resources_translated);
1187 FUNCTION_ENTER();
1188 FUNCTION_EXIT();
1190 return status;
1193 NTSTATUS
1194 XenPciPdo_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
1196 NTSTATUS status = STATUS_SUCCESS;
1198 UNREFERENCED_PARAMETER(device);
1199 UNREFERENCED_PARAMETER(resources_translated);
1201 FUNCTION_ENTER();
1202 FUNCTION_EXIT();
1204 return status;
1207 static VOID
1208 XenPciPdo_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
1210 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1212 FUNCTION_ENTER();
1214 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
1215 switch (notification_type)
1217 case WdfSpecialFilePaging:
1218 KdPrint((__DRIVER_NAME " notification_type = Paging, flag = %d\n", is_in_notification_path));
1219 break;
1220 case WdfSpecialFileHibernation:
1221 xppdd->hiber_usage_kludge = is_in_notification_path;
1222 KdPrint((__DRIVER_NAME " notification_type = Hibernation, flag = %d\n", is_in_notification_path));
1223 break;
1224 case WdfSpecialFileDump:
1225 KdPrint((__DRIVER_NAME " notification_type = Dump, flag = %d\n", is_in_notification_path));
1226 break;
1227 default:
1228 KdPrint((__DRIVER_NAME " notification_type = %d, flag = %d\n", notification_type, is_in_notification_path));
1229 break;
1232 FUNCTION_EXIT();
1235 NTSTATUS
1236 XenPci_EvtChildListCreateDevice(WDFCHILDLIST child_list,
1237 PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER identification_header,
1238 PWDFDEVICE_INIT child_init)
1240 NTSTATUS status = STATUS_SUCCESS;
1241 WDF_OBJECT_ATTRIBUTES child_attributes;
1242 WDFDEVICE child_device;
1243 PXENPCI_PDO_IDENTIFICATION_DESCRIPTION identification = (PXENPCI_PDO_IDENTIFICATION_DESCRIPTION)identification_header;
1244 WDF_DEVICE_PNP_CAPABILITIES child_pnp_capabilities;
1245 DECLARE_UNICODE_STRING_SIZE(buffer, 512);
1246 DECLARE_CONST_UNICODE_STRING(location, L"Xen Bus");
1247 PXENPCI_PDO_DEVICE_DATA xppdd;
1248 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
1249 WDF_QUERY_INTERFACE_CONFIG interface_config;
1250 BUS_INTERFACE_STANDARD bus_interface;
1251 WDF_PDO_EVENT_CALLBACKS pdo_callbacks;
1252 WDF_PNPPOWER_EVENT_CALLBACKS child_pnp_power_callbacks;
1253 UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
1254 WDF_DEVICE_POWER_CAPABILITIES child_power_capabilities;
1256 FUNCTION_ENTER();
1258 WdfDeviceInitSetDeviceType(child_init, FILE_DEVICE_UNKNOWN);
1260 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&child_pnp_power_callbacks);
1261 child_pnp_power_callbacks.EvtDeviceD0Entry = XenPciPdo_EvtDeviceD0Entry;
1262 //child_pnp_power_callbacks.EvtDeviceD0EntryPostInterruptsEnabled = XenPciPdo_EvtDeviceD0EntryPostInterruptsEnabled;
1263 child_pnp_power_callbacks.EvtDeviceD0Exit = XenPciPdo_EvtDeviceD0Exit;
1264 //child_pnp_power_callbacks.EvtDeviceD0ExitPreInterruptsDisabled = XenPciPdo_EvtDeviceD0ExitPreInterruptsDisabled;
1265 child_pnp_power_callbacks.EvtDevicePrepareHardware = XenPciPdo_EvtDevicePrepareHardware;
1266 child_pnp_power_callbacks.EvtDeviceReleaseHardware = XenPciPdo_EvtDeviceReleaseHardware;
1267 child_pnp_power_callbacks.EvtDeviceUsageNotification = XenPciPdo_EvtDeviceUsageNotification;
1268 WdfDeviceInitSetPnpPowerEventCallbacks(child_init, &child_pnp_power_callbacks);
1270 KdPrint((__DRIVER_NAME " device = '%s', index = '%d', path = '%s'\n",
1271 identification->device, identification->index, identification->path));
1273 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(child_init, XenPciPdo_EvtDeviceWdmIrpPreprocess_START_DEVICE,
1274 IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
1275 if (!NT_SUCCESS(status))
1277 return status;
1280 WDF_PDO_EVENT_CALLBACKS_INIT(&pdo_callbacks);
1281 //pdo_callbacks.EvtDeviceResourcesQuery = XenPciPdo_EvtDeviceResourcesQuery;
1282 pdo_callbacks.EvtDeviceResourceRequirementsQuery = XenPciPdo_EvtDeviceResourceRequirementsQuery;
1283 //pdo_callbacks.EvtDeviceEject = XenPciPdo_EvtDeviceEject;
1284 //pdo_callbacks.EvtDeviceSetLock = XenPciPdo_EvtDeviceSetLock;
1285 WdfPdoInitSetEventCallbacks(child_init, &pdo_callbacks);
1287 RtlUnicodeStringPrintf(&buffer, L"xen\\%S", identification->device);
1288 status = WdfPdoInitAssignDeviceID(child_init, &buffer);
1289 if (!NT_SUCCESS(status))
1291 return status;
1293 status = WdfPdoInitAddHardwareID(child_init, &buffer);
1294 if (!NT_SUCCESS(status))
1296 return status;
1298 status = WdfPdoInitAddCompatibleID(child_init, &buffer);
1299 if (!NT_SUCCESS(status))
1301 return status;
1304 RtlUnicodeStringPrintf(&buffer, L"%02d", identification->index);
1305 status = WdfPdoInitAssignInstanceID(child_init, &buffer);
1306 if (!NT_SUCCESS(status))
1308 return status;
1311 RtlUnicodeStringPrintf(&buffer, L"Xen %S device #%d", identification->device, identification->index);
1312 status = WdfPdoInitAddDeviceText(child_init, &buffer, &location, 0x0409);
1313 if (!NT_SUCCESS(status))
1315 return status;
1317 WdfPdoInitSetDefaultLocale(child_init, 0x0409);
1319 WdfDeviceInitSetPowerNotPageable(child_init);
1321 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&child_attributes, XENPCI_PDO_DEVICE_DATA);
1322 status = WdfDeviceCreate(&child_init, &child_attributes, &child_device);
1323 if (!NT_SUCCESS(status))
1325 return status;
1328 xppdd = GetXppdd(child_device);
1330 xppdd->wdf_device = child_device;
1331 xppdd->wdf_device_bus_fdo = WdfChildListGetDevice(child_list);
1333 xppdd->config_page_mdl = AllocateUncachedPage();
1335 xppdd->device_state.magic = XEN_DEVICE_STATE_MAGIC;
1336 xppdd->device_state.length = sizeof(XENPCI_DEVICE_STATE);
1337 xppdd->device_state.suspend_resume_state_pdo = SR_STATE_RUNNING;
1338 xppdd->device_state.suspend_resume_state_fdo = SR_STATE_RUNNING;
1339 xppdd->device_state.pdo_event_channel = xpdd->pdo_event_channel;
1340 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFilePaging, TRUE);
1341 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileHibernation, TRUE);
1342 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileDump, TRUE);
1344 WDF_DEVICE_PNP_CAPABILITIES_INIT(&child_pnp_capabilities);
1345 child_pnp_capabilities.LockSupported = WdfFalse;
1346 child_pnp_capabilities.EjectSupported = WdfTrue;
1347 child_pnp_capabilities.Removable = WdfTrue;
1348 child_pnp_capabilities.DockDevice = WdfFalse;
1349 child_pnp_capabilities.UniqueID = WdfFalse;
1350 child_pnp_capabilities.SilentInstall = WdfTrue;
1351 child_pnp_capabilities.SurpriseRemovalOK = WdfTrue;
1352 child_pnp_capabilities.HardwareDisabled = WdfFalse;
1353 WdfDeviceSetPnpCapabilities(child_device, &child_pnp_capabilities);
1355 WDF_DEVICE_POWER_CAPABILITIES_INIT(&child_power_capabilities);
1356 child_power_capabilities.DeviceD1 = WdfTrue;
1357 child_power_capabilities.WakeFromD1 = WdfTrue;
1358 child_power_capabilities.DeviceWake = PowerDeviceD1;
1359 child_power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD1;
1360 child_power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
1361 child_power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
1362 child_power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
1363 child_power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
1364 child_power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
1365 WdfDeviceSetPowerCapabilities(child_device, &child_power_capabilities);
1367 bus_interface.Size = sizeof(BUS_INTERFACE_STANDARD);
1368 bus_interface.Version = 1; //BUS_INTERFACE_STANDARD_VERSION;
1369 bus_interface.Context = xppdd;
1370 bus_interface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
1371 bus_interface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
1372 bus_interface.TranslateBusAddress = XenPci_BIS_TranslateBusAddress;
1373 bus_interface.GetDmaAdapter = XenPci_BIS_GetDmaAdapter;
1374 bus_interface.SetBusData = XenPci_BIS_SetBusData;
1375 bus_interface.GetBusData = XenPci_BIS_GetBusData;
1376 WDF_QUERY_INTERFACE_CONFIG_INIT(&interface_config, (PINTERFACE)&bus_interface, &GUID_BUS_INTERFACE_STANDARD, NULL);
1377 status = WdfDeviceAddQueryInterface(child_device, &interface_config);
1378 if (!NT_SUCCESS(status))
1380 return status;
1383 RtlStringCbCopyA(xppdd->path, ARRAY_SIZE(xppdd->path), identification->path);
1384 RtlStringCbCopyA(xppdd->device, ARRAY_SIZE(xppdd->device), identification->device);
1385 xppdd->index = identification->index;
1386 KeInitializeEvent(&xppdd->backend_state_event, SynchronizationEvent, FALSE);
1387 ExInitializeFastMutex(&xppdd->backend_state_mutex);
1388 xppdd->backend_state = XenbusStateUnknown;
1389 xppdd->frontend_state = XenbusStateUnknown;
1390 xppdd->backend_path[0] = '\0';
1392 FUNCTION_EXIT();
1394 return status;
1397 static __forceinline VOID
1398 XenPci_Pdo_ChangeSuspendState(WDFDEVICE device, ULONG new_state)
1400 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1401 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1403 FUNCTION_ENTER();
1404 KdPrint((__DRIVER_NAME " setting pdo state to %d\n", new_state));
1405 xppdd->device_state.suspend_resume_state_pdo = new_state;
1406 KeMemoryBarrier();
1407 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xpdd->pdo_event_channel));
1408 EvtChn_Notify(xpdd, xpdd->pdo_event_channel);
1409 while(xppdd->device_state.suspend_resume_state_fdo != xppdd->device_state.suspend_resume_state_pdo)
1411 KdPrint((__DRIVER_NAME " waiting...\n"));
1412 KeWaitForSingleObject(&xpdd->pdo_suspend_event, Executive, KernelMode, FALSE, NULL);
1414 KdPrint((__DRIVER_NAME " fdo state set to %d\n", new_state));
1415 FUNCTION_EXIT();
1418 /* called at PASSIVE_LEVEL */
1419 NTSTATUS
1420 XenPci_Pdo_Suspend(WDFDEVICE device)
1422 NTSTATUS status = STATUS_SUCCESS;
1423 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1424 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1425 //LARGE_INTEGER wait_time;
1426 char path[128];
1427 PUCHAR in_ptr;
1428 UCHAR type;
1429 PVOID setting;
1430 PVOID value;
1431 PVOID value2;
1433 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ " (%s)\n", xppdd->path));
1435 if (xppdd->backend_state == XenbusStateConnected)
1437 xppdd->restart_on_resume = TRUE;
1438 XenPci_Pdo_ChangeSuspendState(device, SR_STATE_SUSPENDING);
1440 XenPci_ChangeFrontendState(device, XenbusStateClosing, XenbusStateClosing, 30000);
1441 XenPci_ChangeFrontendState(device, XenbusStateClosed, XenbusStateClosed, 30000);
1442 XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 30000);
1444 if (xppdd->assigned_resources_start != NULL)
1446 in_ptr = xppdd->assigned_resources_ptr;
1447 ADD_XEN_INIT_RSP(&in_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
1448 in_ptr = xppdd->assigned_resources_start;
1449 while((type = GET_XEN_INIT_RSP(&in_ptr, &setting, &value, &value2)) != XEN_INIT_TYPE_END)
1451 switch (type)
1453 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
1454 case XEN_INIT_TYPE_EVENT_CHANNEL_DPC: /* frontend event channel bound to dpc */
1455 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel bound to irq */
1456 EvtChn_Unbind(xpdd, PtrToUlong(value));
1457 EvtChn_Close(xpdd, PtrToUlong(value));
1458 break;
1463 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
1464 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, xppdd);
1466 else
1468 xppdd->restart_on_resume = FALSE;
1471 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1473 return status;
1476 NTSTATUS
1477 XenPci_Pdo_Resume(WDFDEVICE device)
1479 NTSTATUS status = STATUS_SUCCESS;
1480 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1481 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1482 ULONG old_backend_state;
1483 PUCHAR src, dst;
1485 FUNCTION_ENTER();
1486 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
1488 xppdd->device_state.pdo_event_channel = xpdd->pdo_event_channel;
1489 old_backend_state = xppdd->backend_state;
1491 if (xppdd->restart_on_resume)
1493 status = XenPci_GetBackendAndAddWatch(device);
1495 if (XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 30000) != STATUS_SUCCESS)
1497 KdPrint((__DRIVER_NAME " Failed to change frontend state to Initialising\n"));
1498 // this is probably an unrecoverable situation...
1499 FUNCTION_ERROR_EXIT();
1500 return STATUS_UNSUCCESSFUL;
1502 if (xppdd->assigned_resources_ptr)
1504 // reset things - feed the 'requested resources' back in
1505 ADD_XEN_INIT_REQ(&xppdd->requested_resources_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
1506 src = xppdd->requested_resources_start;
1507 xppdd->requested_resources_ptr = xppdd->requested_resources_start = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);;
1508 xppdd->assigned_resources_ptr = xppdd->assigned_resources_start;
1510 dst = MmMapIoSpace(xppdd->config_page_phys, xppdd->config_page_length, MmNonCached);
1512 status = XenPci_XenConfigDeviceSpecifyBuffers(device, src, dst);
1514 MmUnmapIoSpace(dst, xppdd->config_page_length);
1515 ExFreePoolWithTag(src, XENPCI_POOL_TAG);
1517 if (XenPci_ChangeFrontendState(device, XenbusStateConnected, XenbusStateConnected, 30000) != STATUS_SUCCESS)
1519 // this is definitely an unrecoverable situation...
1520 KdPrint((__DRIVER_NAME " Failed to change frontend state to connected\n"));
1521 FUNCTION_ERROR_EXIT();
1522 return STATUS_UNSUCCESSFUL;
1524 XenPci_Pdo_ChangeSuspendState(device, SR_STATE_RESUMING);
1525 XenPci_Pdo_ChangeSuspendState(device, SR_STATE_RUNNING);
1528 FUNCTION_EXIT();
1530 return STATUS_SUCCESS;