win-pvdrivers

view xenpci/xenpci_pdo.c @ 685:c13ccf5a629b

Fixed a bug in the dma routines which was causing memory corruption. In some cases when Windows gave an MDL that was longer than the buffer to be dma'd, the end of the buffer would be overwritten. The only time I am aware of this occuring is on one particular map in Call Of Duty 4.

Split out the dma routines from xenpci_pdo.c into xenpci_dma.c
author James Harper <james.harper@bendigoit.com.au>
date Wed Oct 14 14:46:39 2009 +1100 (2009-10-14)
parents 38fd04771db8
children 1fe30f6966eb
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 KdPrint((__DRIVER_NAME " Requesting eject\n"));
128 WdfPdoRequestEject(device);
129 break;
131 case XenbusStateClosed:
132 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
133 break;
135 default:
136 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xppdd->backend_state));
137 break;
138 }
140 KeSetEvent(&xppdd->backend_state_event, 1, FALSE);
142 ExReleaseFastMutex(&xppdd->backend_state_mutex);
143 FUNCTION_EXIT();
145 return;
146 }
148 static VOID
149 XenPci_BackendStateHandler(char *path, PVOID context)
150 {
151 UNREFERENCED_PARAMETER(path);
153 /* check that path == device/id/state */
154 //RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->path);
156 XenPci_UpdateBackendState(context);
157 }
159 static NTSTATUS
160 XenPci_GetBackendAndAddWatch(WDFDEVICE device)
161 {
162 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
163 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
164 char path[128];
165 PCHAR res;
166 PCHAR value;
168 FUNCTION_ENTER();
169 /* Get backend path */
170 RtlStringCbPrintfA(path, ARRAY_SIZE(path),
171 "%s/backend", xppdd->path);
172 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
173 if (res)
174 {
175 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
176 XenPci_FreeMem(res);
177 return STATUS_UNSUCCESSFUL;
178 }
179 RtlStringCbCopyA(xppdd->backend_path, ARRAY_SIZE(xppdd->backend_path), value);
180 XenPci_FreeMem(value);
182 /* Add watch on backend state */
183 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
184 XenBus_AddWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
186 FUNCTION_EXIT();
187 return STATUS_SUCCESS;
188 }
190 static NTSTATUS
191 XenConfig_InitConfigPage(WDFDEVICE device)
192 {
193 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
194 //PXENCONFIG_DEVICE_DATA xcdd = (PXENCONFIG_DEVICE_DATA)device_object->DeviceExtension;
195 //PXENPCI_PDO_DEVICE_DATA xppdd = (PXENPCI_PDO_DEVICE_DATA)device_object->DeviceExtension;
196 //PXENPCI_DEVICE_DATA xpdd = xppdd->bus_fdo->DeviceExtension;
197 PUCHAR ptr;
198 PDEVICE_OBJECT curr, prev;
199 PDRIVER_OBJECT fdo_driver_object;
200 PUCHAR fdo_driver_extension;
202 FUNCTION_ENTER();
204 ptr = MmGetMdlVirtualAddress(xppdd->config_page_mdl);
205 curr = IoGetAttachedDeviceReference(WdfDeviceWdmGetDeviceObject(device));
206 //curr = WdfDeviceWdmGetAttachedDevice(device);
207 while (curr != NULL)
208 {
209 fdo_driver_object = curr->DriverObject;
210 KdPrint((__DRIVER_NAME " fdo_driver_object = %p\n", fdo_driver_object));
211 if (fdo_driver_object)
212 {
213 fdo_driver_extension = IoGetDriverObjectExtension(fdo_driver_object, UlongToPtr(XEN_INIT_DRIVER_EXTENSION_MAGIC));
214 KdPrint((__DRIVER_NAME " fdo_driver_extension = %p\n", fdo_driver_extension));
215 if (fdo_driver_extension)
216 {
217 memcpy(ptr, fdo_driver_extension, PAGE_SIZE);
218 ObDereferenceObject(curr);
219 break;
220 }
221 }
222 prev = curr;
223 curr = IoGetLowerDeviceObject(curr);
224 ObDereferenceObject(prev);
225 }
227 FUNCTION_EXIT();
229 return STATUS_SUCCESS;
230 }
232 static NTSTATUS
233 XenPci_EvtChn_Bind(PVOID context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
234 {
235 WDFDEVICE device = context;
236 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
237 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
239 return EvtChn_Bind(xpdd, Port, ServiceRoutine, ServiceContext);
240 }
242 static NTSTATUS
243 XenPci_EvtChn_BindDpc(PVOID context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
244 {
245 WDFDEVICE device = context;
246 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
247 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
249 return EvtChn_BindDpc(xpdd, Port, ServiceRoutine, ServiceContext);
250 }
252 static NTSTATUS
253 XenPci_EvtChn_Unbind(PVOID context, evtchn_port_t Port)
254 {
255 WDFDEVICE device = context;
256 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
257 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
259 return EvtChn_Unbind(xpdd, Port);
260 }
262 static NTSTATUS
263 XenPci_EvtChn_Mask(PVOID context, evtchn_port_t Port)
264 {
265 WDFDEVICE device = context;
266 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
267 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
269 return EvtChn_Mask(xpdd, Port);
270 }
272 static NTSTATUS
273 XenPci_EvtChn_Unmask(PVOID context, evtchn_port_t Port)
274 {
275 WDFDEVICE device = context;
276 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
277 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
279 return EvtChn_Unmask(xpdd, Port);
280 }
282 static NTSTATUS
283 XenPci_EvtChn_Notify(PVOID context, evtchn_port_t Port)
284 {
285 WDFDEVICE device = context;
286 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
287 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
289 return EvtChn_Notify(xpdd, Port);
290 }
292 static BOOLEAN
293 XenPci_EvtChn_AckEvent(PVOID context, evtchn_port_t port, BOOLEAN *last_interrupt)
294 {
295 WDFDEVICE device = context;
296 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
297 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
299 return EvtChn_AckEvent(xpdd, port, last_interrupt);
300 }
302 typedef struct {
303 PXEN_EVTCHN_SYNC_ROUTINE sync_routine;
304 PVOID sync_context;
305 } sync_context_t;
307 static BOOLEAN
308 XenPci_EvtChn_Sync_Routine(WDFINTERRUPT interrupt, WDFCONTEXT context)
309 {
310 sync_context_t *wdf_sync_context = context;
311 UNREFERENCED_PARAMETER(interrupt);
312 return wdf_sync_context->sync_routine(wdf_sync_context->sync_context);
313 }
315 static BOOLEAN
316 XenPci_EvtChn_Sync(PVOID context, PXEN_EVTCHN_SYNC_ROUTINE sync_routine, PVOID sync_context)
317 {
318 WDFDEVICE device = context;
319 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
320 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
321 sync_context_t wdf_sync_context;
323 wdf_sync_context.sync_routine = sync_routine;
324 wdf_sync_context.sync_context = sync_context;
326 return WdfInterruptSynchronize(xpdd->interrupt, XenPci_EvtChn_Sync_Routine, &wdf_sync_context);
327 }
329 static grant_ref_t
330 XenPci_GntTbl_GrantAccess(PVOID context, domid_t domid, uint32_t frame, int readonly, grant_ref_t ref)
331 {
332 WDFDEVICE device = context;
333 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
334 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
336 return GntTbl_GrantAccess(xpdd, domid, frame, readonly, ref);
337 }
339 static BOOLEAN
340 XenPci_GntTbl_EndAccess(PVOID context, grant_ref_t ref, BOOLEAN keepref)
341 {
342 WDFDEVICE device = context;
343 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
344 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
346 return GntTbl_EndAccess(xpdd, ref, keepref);
347 }
349 static VOID
350 XenPci_GntTbl_PutRef(PVOID context, grant_ref_t ref)
351 {
352 WDFDEVICE device = context;
353 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
354 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
356 GntTbl_PutRef(xpdd, ref);
357 }
359 static grant_ref_t
360 XenPci_GntTbl_GetRef(PVOID context)
361 {
362 WDFDEVICE device = context;
363 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
364 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
366 return GntTbl_GetRef(xpdd);
367 }
369 PCHAR
370 XenPci_XenBus_Read(PVOID context, xenbus_transaction_t xbt, char *path, char **value)
371 {
372 WDFDEVICE device = context;
373 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
374 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
375 return XenBus_Read(xpdd, xbt, path, value);
376 }
378 PCHAR
379 XenPci_XenBus_Write(PVOID context, xenbus_transaction_t xbt, char *path, char *value)
380 {
381 WDFDEVICE device = context;
382 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
383 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
384 return XenBus_Write(xpdd, xbt, path, value);
385 }
387 PCHAR
388 XenPci_XenBus_Printf(PVOID context, xenbus_transaction_t xbt, char *path, char *fmt, ...)
389 {
390 //PXENPCI_PDO_DEVICE_DATA xppdd = Context;
391 //PXENPCI_DEVICE_DATA xpdd = xppdd->bus_fdo->DeviceExtension;
392 //return XenBus_Printf(xpdd, xbt, path, value);
393 UNREFERENCED_PARAMETER(context);
394 UNREFERENCED_PARAMETER(xbt);
395 UNREFERENCED_PARAMETER(path);
396 UNREFERENCED_PARAMETER(fmt);
397 return NULL;
398 }
400 PCHAR
401 XenPci_XenBus_StartTransaction(PVOID context, xenbus_transaction_t *xbt)
402 {
403 WDFDEVICE device = context;
404 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
405 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
406 return XenBus_StartTransaction(xpdd, xbt);
407 }
409 PCHAR
410 XenPci_XenBus_EndTransaction(PVOID context, xenbus_transaction_t xbt, int abort, int *retry)
411 {
412 WDFDEVICE device = context;
413 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
414 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
415 return XenBus_EndTransaction(xpdd, xbt, abort, retry);
416 }
418 PCHAR
419 XenPci_XenBus_List(PVOID context, xenbus_transaction_t xbt, char *prefix, char ***contents)
420 {
421 WDFDEVICE device = context;
422 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
423 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
424 return XenBus_List(xpdd, xbt, prefix, contents);
425 }
427 PCHAR
428 XenPci_XenBus_AddWatch(PVOID context, xenbus_transaction_t xbt, char *path, PXENBUS_WATCH_CALLBACK ServiceRoutine, PVOID ServiceContext)
429 {
430 WDFDEVICE device = context;
431 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
432 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
433 PCHAR retval;
435 FUNCTION_ENTER();
436 retval = XenBus_AddWatch(xpdd, xbt, path, ServiceRoutine, ServiceContext);
437 if (retval == NULL)
438 {
439 KdPrint((__DRIVER_NAME " XenPci_XenBus_AddWatch - %s = NULL\n", path));
440 }
441 else
442 {
443 KdPrint((__DRIVER_NAME " XenPci_XenBus_AddWatch - %s = %s\n", path, retval));
444 }
445 FUNCTION_EXIT();
446 return retval;
447 }
449 PCHAR
450 XenPci_XenBus_RemWatch(PVOID context, xenbus_transaction_t xbt, char *path, PXENBUS_WATCH_CALLBACK ServiceRoutine, PVOID ServiceContext)
451 {
452 WDFDEVICE device = context;
453 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
454 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
455 return XenBus_RemWatch(xpdd, xbt, path, ServiceRoutine, ServiceContext);
456 }
458 /*
459 Called at PASSIVE_LEVEL
460 Called during restore
461 */
463 static NTSTATUS
464 XenPci_ChangeFrontendState(WDFDEVICE device, ULONG frontend_state_set, ULONG backend_state_response, ULONG maximum_wait_ms)
465 {
466 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
467 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
468 LARGE_INTEGER timeout;
469 ULONG remaining;
470 ULONG thiswait;
471 char path[128];
473 FUNCTION_ENTER();
475 xppdd->frontend_state = frontend_state_set;
477 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->path);
478 XenBus_Printf(xpdd, XBT_NIL, path, "%d", frontend_state_set);
480 remaining = maximum_wait_ms;
482 while (xppdd->backend_state != backend_state_response)
483 {
484 thiswait = min((LONG)remaining, 1000); // 1 second or remaining time, whichever is less
485 timeout.QuadPart = (LONGLONG)-1 * thiswait * 1000 * 10;
486 if (KeWaitForSingleObject(&xppdd->backend_state_event, Executive, KernelMode, FALSE, &timeout) == STATUS_TIMEOUT)
487 {
488 /* it's possible that the workitems are blocked because the pagefile isn't available. Lets just re-read the backend value for now */
489 XenPci_UpdateBackendState(device);
490 remaining -= thiswait;
491 if (remaining == 0)
492 {
493 KdPrint((__DRIVER_NAME " Timed out waiting for %d!\n", backend_state_response));
494 return STATUS_UNSUCCESSFUL;
495 }
496 KdPrint((__DRIVER_NAME " Still waiting for %d (currently %d)...\n", backend_state_response, xppdd->backend_state));
497 }
498 }
499 FUNCTION_EXIT();
500 return STATUS_SUCCESS;
501 }
503 static NTSTATUS
504 XenPci_XenConfigDevice(WDFDEVICE device);
506 static NTSTATUS
507 XenPci_XenShutdownDevice(PVOID context)
508 {
509 WDFDEVICE device = context;
510 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
511 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
512 PUCHAR in_ptr;
513 ULONG i;
514 UCHAR type;
515 PVOID setting;
516 PVOID value;
517 PVOID value2;
519 FUNCTION_ENTER();
521 if (xppdd->backend_state == XenbusStateConnected)
522 {
523 XenPci_ChangeFrontendState(device, XenbusStateClosing, XenbusStateClosing, 30000);
524 if (xppdd->backend_state == XenbusStateClosing)
525 XenPci_ChangeFrontendState(device, XenbusStateClosed, XenbusStateClosed, 30000);
526 if (xppdd->backend_state == XenbusStateClosed)
527 XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 30000);
528 }
529 else
530 {
531 if (xppdd->backend_state == XenbusStateClosing)
532 XenPci_ChangeFrontendState(device, XenbusStateClosed, XenbusStateClosed, 30000);
533 }
535 if (xppdd->assigned_resources_start != NULL)
536 {
537 ADD_XEN_INIT_RSP(&xppdd->assigned_resources_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
538 in_ptr = xppdd->assigned_resources_start;
539 while((type = GET_XEN_INIT_RSP(&in_ptr, &setting, &value, &value2)) != XEN_INIT_TYPE_END)
540 {
541 switch (type)
542 {
543 case XEN_INIT_TYPE_RING: /* frontend ring */
544 FreePages(value);
545 break;
546 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
547 case XEN_INIT_TYPE_EVENT_CHANNEL_DPC: /* frontend event channel bound to dpc */
548 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel bound to irq */
549 EvtChn_Unbind(xpdd, PtrToUlong(value));
550 EvtChn_Close(xpdd, PtrToUlong(value));
551 break;
552 case XEN_INIT_TYPE_GRANT_ENTRIES:
553 for (i = 0; i < PtrToUlong(setting); i++)
554 GntTbl_EndAccess(xpdd, ((grant_ref_t *)value)[i], FALSE);
555 break;
556 }
557 }
558 ExFreePoolWithTag(xppdd->assigned_resources_start, XENPCI_POOL_TAG);
559 xppdd->assigned_resources_start = NULL;
560 }
562 FUNCTION_EXIT();
564 return STATUS_SUCCESS;
565 }
567 struct dummy_sring {
568 RING_IDX req_prod, req_event;
569 RING_IDX rsp_prod, rsp_event;
570 uint8_t pad[48];
571 };
573 static NTSTATUS
574 XenPci_XenConfigDeviceSpecifyBuffers(WDFDEVICE device, PUCHAR src, PUCHAR dst)
575 {
576 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
577 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
578 NTSTATUS status = STATUS_SUCCESS;
579 ULONG i;
580 char path[128];
581 PCHAR setting, value;
582 PCHAR res;
583 PVOID address;
584 UCHAR type;
585 PUCHAR in_ptr;
586 PUCHAR out_ptr;
587 XENPCI_VECTORS vectors;
588 ULONG event_channel;
589 ULONG run_type = 0;
590 PMDL ring;
591 grant_ref_t gref;
592 BOOLEAN done_xenbus_init = FALSE;
593 PVOID value2;
594 BOOLEAN active = TRUE;
595 BOOLEAN dont_config = FALSE;
597 FUNCTION_ENTER();
599 in_ptr = src;
600 out_ptr = dst;
602 // always add vectors
603 vectors.magic = XEN_DATA_MAGIC;
604 vectors.length = sizeof(XENPCI_VECTORS);
605 vectors.context = device;
606 vectors.EvtChn_Bind = XenPci_EvtChn_Bind;
607 vectors.EvtChn_BindDpc = XenPci_EvtChn_BindDpc;
608 vectors.EvtChn_Unbind = XenPci_EvtChn_Unbind;
609 vectors.EvtChn_Mask = XenPci_EvtChn_Mask;
610 vectors.EvtChn_Unmask = XenPci_EvtChn_Unmask;
611 vectors.EvtChn_Notify = XenPci_EvtChn_Notify;
612 vectors.EvtChn_AckEvent = XenPci_EvtChn_AckEvent;
613 vectors.EvtChn_Sync = XenPci_EvtChn_Sync;
614 vectors.GntTbl_GetRef = XenPci_GntTbl_GetRef;
615 vectors.GntTbl_PutRef = XenPci_GntTbl_PutRef;
616 vectors.GntTbl_GrantAccess = XenPci_GntTbl_GrantAccess;
617 vectors.GntTbl_EndAccess = XenPci_GntTbl_EndAccess;
618 vectors.XenPci_XenConfigDevice = XenPci_XenConfigDevice;
619 vectors.XenPci_XenShutdownDevice = XenPci_XenShutdownDevice;
620 strncpy(vectors.path, xppdd->path, 128);
621 strncpy(vectors.backend_path, xppdd->backend_path, 128);
622 //vectors.pdo_event_channel = xpdd->pdo_event_channel;
623 vectors.XenBus_Read = XenPci_XenBus_Read;
624 vectors.XenBus_Write = XenPci_XenBus_Write;
625 vectors.XenBus_Printf = XenPci_XenBus_Printf;
626 vectors.XenBus_StartTransaction = XenPci_XenBus_StartTransaction;
627 vectors.XenBus_EndTransaction = XenPci_XenBus_EndTransaction;
628 vectors.XenBus_List = XenPci_XenBus_List;
629 vectors.XenBus_AddWatch = XenPci_XenBus_AddWatch;
630 vectors.XenBus_RemWatch = XenPci_XenBus_RemWatch;
632 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_QEMU_PROTOCOL_VERSION, NULL, UlongToPtr(qemu_protocol_version), NULL);
634 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_VECTORS, NULL, &vectors, NULL);
635 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_STATE_PTR, NULL, &xppdd->device_state, NULL);
637 if (!qemu_filtered)
638 active = FALSE;
640 while((type = GET_XEN_INIT_REQ(&in_ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
641 {
642 BOOLEAN condition;
643 PCHAR xb_value;
644 switch (type)
645 {
646 case XEN_INIT_TYPE_MATCH_FRONT:
647 case XEN_INIT_TYPE_MATCH_BACK:
648 if (type == XEN_INIT_TYPE_MATCH_FRONT)
649 {
650 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
651 }
652 else
653 {
654 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->backend_path, setting);
655 }
656 KdPrint((__DRIVER_NAME " testing path = %s\n", path));
657 res = XenBus_Read(xpdd, XBT_NIL, path, &xb_value);
658 if (res)
659 {
660 KdPrint((__DRIVER_NAME " read failed (%s)\n", res));
661 XenPci_FreeMem(res);
662 }
663 else
664 {
665 KdPrint((__DRIVER_NAME " testing %s vs %s\n", xb_value, value));
666 if (PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_IF_MATCH)
667 condition = (strcmp(xb_value, value) == 0)?TRUE:FALSE;
668 else
669 condition = (strcmp(xb_value, value) != 0)?TRUE:FALSE;
670 KdPrint((__DRIVER_NAME " condition = %d\n", condition));
672 if ((PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_ONLY_IF_QEMU_HIDE) && qemu_protocol_version && condition)
673 condition = FALSE;
675 if (condition)
676 {
677 if (PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_SET_INACTIVE)
678 {
679 active = FALSE;
680 KdPrint((__DRIVER_NAME " set inactive\n"));
681 }
682 if (PtrToUlong(value2) & XEN_INIT_MATCH_TYPE_DONT_CONFIG)
683 {
684 dont_config = TRUE;
685 KdPrint((__DRIVER_NAME " set inactive with dont config\n"));
686 }
687 }
688 XenPci_FreeMem(xb_value);
689 }
690 break;
691 }
692 }
693 if (dont_config)
694 {
695 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
696 FUNCTION_EXIT();
697 return status;
698 }
700 // first pass, possibly before state == Connected
701 in_ptr = src;
702 while((type = GET_XEN_INIT_REQ(&in_ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
703 {
704 if (!done_xenbus_init)
705 {
706 if (XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 2000) != STATUS_SUCCESS)
707 {
708 status = STATUS_UNSUCCESSFUL;
709 goto error;
710 }
711 done_xenbus_init = TRUE;
712 }
714 ADD_XEN_INIT_REQ(&xppdd->requested_resources_ptr, type, setting, value, value2);
716 switch (type)
717 {
718 case XEN_INIT_TYPE_RUN:
719 run_type++;
720 break;
721 case XEN_INIT_TYPE_WRITE_STRING: /* frontend setting = value */
722 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_WRITE_STRING - %s = %s\n", setting, value));
723 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
724 XenBus_Printf(xpdd, XBT_NIL, path, "%s", value);
725 break;
726 case XEN_INIT_TYPE_RING: /* frontend ring */
727 /* we only allocate and do the SHARED_RING_INIT here */
728 if ((ring = AllocatePage()) != 0)
729 {
730 address = MmGetMdlVirtualAddress(ring);
731 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, address));
732 SHARED_RING_INIT((struct dummy_sring *)address);
733 if ((gref = GntTbl_GrantAccess(
734 xpdd, 0, (ULONG)*MmGetMdlPfnArray(ring), FALSE, INVALID_GRANT_REF)) != INVALID_GRANT_REF)
735 {
736 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
737 XenBus_Printf(xpdd, XBT_NIL, path, "%d", gref);
738 ADD_XEN_INIT_RSP(&out_ptr, type, setting, address, NULL);
739 ADD_XEN_INIT_RSP(&xppdd->assigned_resources_ptr, type, setting, ring, NULL);
740 // add the grant entry too so it gets freed automatically
741 __ADD_XEN_INIT_UCHAR(&xppdd->assigned_resources_ptr, XEN_INIT_TYPE_GRANT_ENTRIES);
742 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, 1);
743 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, gref);
744 }
745 else
746 {
747 FreePages(ring);
748 status = STATUS_UNSUCCESSFUL;
749 goto error;
750 }
751 }
752 else
753 {
754 status = STATUS_UNSUCCESSFUL;
755 goto error;
756 }
757 break;
758 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
759 case XEN_INIT_TYPE_EVENT_CHANNEL_DPC: /* frontend event channel bound to dpc */
760 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel bound to irq */
761 if ((event_channel = EvtChn_AllocUnbound(xpdd, 0)) != 0)
762 {
763 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, event_channel));
764 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
765 XenBus_Printf(xpdd, XBT_NIL, path, "%d", event_channel);
766 ADD_XEN_INIT_RSP(&out_ptr, type, setting, UlongToPtr(event_channel), NULL);
767 ADD_XEN_INIT_RSP(&xppdd->assigned_resources_ptr, type, setting, UlongToPtr(event_channel), NULL);
768 if (type == XEN_INIT_TYPE_EVENT_CHANNEL_IRQ)
769 {
770 EvtChn_BindIrq(xpdd, event_channel, xppdd->irq_vector, path);
771 }
772 else if (type == XEN_INIT_TYPE_EVENT_CHANNEL_DPC)
773 {
774 #pragma warning(suppress:4055)
775 EvtChn_BindDpc(xpdd, event_channel, (PXEN_EVTCHN_SERVICE_ROUTINE)value, value2);
776 }
777 else
778 {
779 #pragma warning(suppress:4055)
780 EvtChn_Bind(xpdd, event_channel, (PXEN_EVTCHN_SERVICE_ROUTINE)value, value2);
781 }
782 }
783 else
784 {
785 status = STATUS_UNSUCCESSFUL;
786 goto error;
787 }
788 break;
789 }
790 }
791 if (!NT_SUCCESS(status))
792 {
793 goto error;
794 }
795 // If XEN_INIT_TYPE_RUN was specified more than once then we skip XenbusStateInitialised here and go straight to XenbusStateConnected at the end
796 if (run_type == 1)
797 {
798 if (XenPci_ChangeFrontendState(device, XenbusStateInitialised, XenbusStateConnected, 2000) != STATUS_SUCCESS)
799 {
800 status = STATUS_UNSUCCESSFUL;
801 goto error;
802 }
803 }
805 // second pass, possibly after state == Connected
806 in_ptr = src;
807 while((type = GET_XEN_INIT_REQ(&in_ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
808 {
809 switch(type)
810 {
811 case XEN_INIT_TYPE_READ_STRING_BACK:
812 case XEN_INIT_TYPE_READ_STRING_FRONT:
813 if (type == XEN_INIT_TYPE_READ_STRING_FRONT)
814 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->path, setting);
815 else
816 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/%s", xppdd->backend_path, setting);
817 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
818 if (res)
819 {
820 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = <failed>\n", setting));
821 XenPci_FreeMem(res);
822 ADD_XEN_INIT_RSP(&out_ptr, type, setting, "", "");
823 }
824 else
825 {
826 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
827 ADD_XEN_INIT_RSP(&out_ptr, type, setting, value, value2);
828 XenPci_FreeMem(value);
829 }
830 break;
831 case XEN_INIT_TYPE_VECTORS:
832 // this is always done so ignore the request
833 break;
834 case XEN_INIT_TYPE_GRANT_ENTRIES:
835 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_GRANT_ENTRIES - %d\n", PtrToUlong(value)));
836 __ADD_XEN_INIT_UCHAR(&out_ptr, type);
837 __ADD_XEN_INIT_UCHAR(&xppdd->assigned_resources_ptr, type);
838 __ADD_XEN_INIT_ULONG(&out_ptr, PtrToUlong(value));
839 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, PtrToUlong(value));
840 for (i = 0; i < PtrToUlong(value); i++)
841 {
842 gref = GntTbl_GetRef(xpdd);
843 __ADD_XEN_INIT_ULONG(&out_ptr, gref);
844 __ADD_XEN_INIT_ULONG(&xppdd->assigned_resources_ptr, gref);
845 }
846 break;
847 }
848 }
849 if (active)
850 {
851 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_ACTIVE, NULL, NULL, NULL);
852 }
853 ADD_XEN_INIT_RSP(&out_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
855 if (run_type)
856 {
857 if (XenPci_ChangeFrontendState(device, XenbusStateConnected, XenbusStateConnected, 2000) != STATUS_SUCCESS)
858 {
859 status = STATUS_UNSUCCESSFUL;
860 goto error;
861 }
862 }
863 FUNCTION_EXIT();
864 return status;
866 error:
867 XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 2000);
868 FUNCTION_EXIT_STATUS(status);
869 return status;
870 }
872 static NTSTATUS
873 XenPci_XenConfigDevice(WDFDEVICE device)
874 {
875 NTSTATUS status;
876 PUCHAR src, dst;
877 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
879 src = ExAllocatePoolWithTag(NonPagedPool, xppdd->config_page_length, XENPCI_POOL_TAG);
880 dst = MmMapIoSpace(xppdd->config_page_phys, xppdd->config_page_length, MmNonCached);
881 memcpy(src, dst, xppdd->config_page_length);
883 status = XenPci_XenConfigDeviceSpecifyBuffers(device, src, dst);
885 MmUnmapIoSpace(dst, xppdd->config_page_length);
886 ExFreePoolWithTag(src, XENPCI_POOL_TAG);
888 return status;
889 }
891 static NTSTATUS
892 XenPciPdo_EvtDeviceWdmIrpPreprocess_START_DEVICE(WDFDEVICE device, PIRP irp)
893 {
894 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
895 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
896 PIO_STACK_LOCATION stack;
897 PCM_PARTIAL_RESOURCE_LIST prl;
898 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
899 ULONG i;
900 //char path[128];
901 //PMDL mdl;
903 FUNCTION_ENTER();
904 KdPrint((__DRIVER_NAME " %s\n", xppdd->path));
906 stack = IoGetCurrentIrpStackLocation(irp);
908 prl = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
909 for (i = 0; i < prl->Count; i++)
910 {
911 prd = & prl->PartialDescriptors[i];
912 switch (prd->Type)
913 {
914 case CmResourceTypeMemory:
915 if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart && prd->u.Memory.Length == 0)
916 {
917 prd->u.Memory.Start.QuadPart = MmGetMdlPfnArray(xppdd->config_page_mdl)[0] << PAGE_SHIFT;
918 prd->u.Memory.Length = MmGetMdlByteCount(xppdd->config_page_mdl);
919 }
920 else if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart + 1 && prd->u.Memory.Length == 0)
921 {
922 RtlZeroMemory(prd, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
923 prd->Type = CmResourceTypeInterrupt;
924 prd->ShareDisposition = CmResourceShareShared;
925 prd->Flags = (xpdd->irq_mode == Latched)?CM_RESOURCE_INTERRUPT_LATCHED:CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
926 prd->u.Interrupt.Level = 0; // Set group and level to zero (group = upper word)
927 prd->u.Interrupt.Level = xpdd->irq_number & 0xffff; // Only set the lower word
928 prd->u.Interrupt.Vector = xpdd->irq_number;
929 prd->u.Interrupt.Affinity = KeQueryActiveProcessors();
930 xppdd->irq_number = xpdd->irq_number;
931 }
932 break;
933 }
934 }
936 prl = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
937 for (i = 0; i < prl->Count; i++)
938 {
939 prd = & prl->PartialDescriptors[i];
940 switch (prd->Type)
941 {
942 case CmResourceTypeMemory:
943 KdPrint((__DRIVER_NAME " CmResourceTypeMemory (%d)\n", i));
944 KdPrint((__DRIVER_NAME " Start = %08x, Length = %d\n", prd->u.Memory.Start.LowPart, prd->u.Memory.Length));
945 if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart)
946 {
947 if (prd->u.Memory.Length == 0)
948 {
949 KdPrint((__DRIVER_NAME " pfn[0] = %08x\n", (ULONG)MmGetMdlPfnArray(xppdd->config_page_mdl)[0]));
950 prd->u.Memory.Start.QuadPart = (ULONGLONG)MmGetMdlPfnArray(xppdd->config_page_mdl)[0] << PAGE_SHIFT;
951 prd->u.Memory.Length = MmGetMdlByteCount(xppdd->config_page_mdl);
952 KdPrint((__DRIVER_NAME " New Start = %08x%08x, Length = %d\n", prd->u.Memory.Start.HighPart, prd->u.Memory.Start.LowPart, prd->u.Memory.Length));
953 }
954 xppdd->config_page_phys = prd->u.Memory.Start;
955 xppdd->config_page_length = prd->u.Memory.Length;
956 xppdd->requested_resources_start = xppdd->requested_resources_ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
957 //xppdd->assigned_resources_start = xppdd->assigned_resources_ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
959 #if 0
960 status = XenPci_XenConfigDevice(device);
961 if (!NT_SUCCESS(status))
962 {
963 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
964 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
965 FUNCTION_ERROR_EXIT();
966 return status;
967 }
968 #endif
969 }
970 else if (prd->u.Memory.Start.QuadPart == xpdd->platform_mmio_addr.QuadPart + 1 && prd->u.Memory.Length == 0)
971 {
972 RtlZeroMemory(prd, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
973 prd->Type = CmResourceTypeInterrupt;
974 prd->ShareDisposition = CmResourceShareShared;
975 prd->Flags = (xpdd->irq_mode == Latched)?CM_RESOURCE_INTERRUPT_LATCHED:CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
976 prd->u.Interrupt.Level = 0; // Set group and level to zero (group = upper word)
977 prd->u.Interrupt.Level = xpdd->irq_level & 0xffff; // Only set the lower word
978 prd->u.Interrupt.Vector = xpdd->irq_vector;
979 prd->u.Interrupt.Affinity = KeQueryActiveProcessors();
980 xppdd->irq_vector = xpdd->irq_vector;
981 xppdd->irq_level = xpdd->irq_level;
982 }
983 break;
984 }
985 }
987 IoSkipCurrentIrpStackLocation(irp);
989 FUNCTION_EXIT();
991 return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
992 }
994 #if 0
995 static NTSTATUS
996 XenPciPdo_EvtDeviceResourcesQuery(WDFDEVICE device, WDFCMRESLIST resources)
997 {
998 }
999 #endif
1001 static NTSTATUS
1002 XenPciPdo_EvtDeviceResourceRequirementsQuery(WDFDEVICE device, WDFIORESREQLIST requirements_list)
1004 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1005 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1006 WDFIORESLIST res_list;
1007 IO_RESOURCE_DESCRIPTOR ird;
1009 //FUNCTION_ENTER();
1011 WdfIoResourceRequirementsListSetInterfaceType(requirements_list, PNPBus);
1013 WdfIoResourceListCreate(requirements_list, WDF_NO_OBJECT_ATTRIBUTES, &res_list);
1014 ird.Option = 0;
1015 ird.Type = CmResourceTypeMemory;
1016 ird.ShareDisposition = CmResourceShareShared;
1017 ird.Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
1018 ird.u.Memory.MinimumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart;
1019 ird.u.Memory.MaximumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart;
1020 ird.u.Memory.Length = 0;
1021 ird.u.Memory.Alignment = 1; //PAGE_SIZE;
1022 WdfIoResourceListAppendDescriptor(res_list, &ird);
1024 ird.Option = 0;
1025 ird.Type = CmResourceTypeMemory;
1026 ird.ShareDisposition = CmResourceShareShared;
1027 ird.Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
1028 ird.u.Memory.MinimumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart + 1;
1029 ird.u.Memory.MaximumAddress.QuadPart = xpdd->platform_mmio_addr.QuadPart + 1;
1030 ird.u.Memory.Length = 0;
1031 ird.u.Memory.Alignment = 1; //PAGE_SIZE;
1032 WdfIoResourceListAppendDescriptor(res_list, &ird);
1034 WdfIoResourceRequirementsListAppendIoResList(requirements_list, res_list);
1036 //FUNCTION_EXIT();
1038 return STATUS_SUCCESS;
1041 NTSTATUS
1042 XenPciPdo_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
1044 NTSTATUS status = STATUS_SUCCESS;
1045 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1046 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1047 CHAR path[128];
1049 FUNCTION_ENTER();
1051 switch (previous_state)
1053 case WdfPowerDeviceD0:
1054 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
1055 break;
1056 case WdfPowerDeviceD1:
1057 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
1058 break;
1059 case WdfPowerDeviceD2:
1060 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
1061 break;
1062 case WdfPowerDeviceD3:
1063 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
1064 break;
1065 case WdfPowerDeviceD3Final:
1066 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
1067 break;
1068 case WdfPowerDevicePrepareForHibernation:
1069 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
1070 break;
1071 default:
1072 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
1073 break;
1076 if (previous_state == WdfPowerDevicePrepareForHibernation
1077 || (previous_state == WdfPowerDeviceD3 && xppdd->hiber_usage_kludge))
1079 KdPrint((__DRIVER_NAME " starting up from hibernation\n"));
1081 else
1085 if (previous_state == WdfPowerDevicePrepareForHibernation || previous_state == WdfPowerDeviceD3 || previous_state == WdfPowerDeviceD3Final)
1087 xppdd->requested_resources_ptr = xppdd->requested_resources_start;
1088 xppdd->assigned_resources_start = xppdd->assigned_resources_ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
1091 XenConfig_InitConfigPage(device);
1093 status = XenPci_GetBackendAndAddWatch(device);
1094 if (!NT_SUCCESS(status))
1096 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
1097 FUNCTION_ERROR_EXIT();
1098 return status;
1100 status = XenPci_XenConfigDevice(device);
1101 if (!NT_SUCCESS(status))
1103 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
1104 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
1105 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
1106 FUNCTION_ERROR_EXIT();
1107 return status;
1110 FUNCTION_EXIT();
1112 return status;
1115 NTSTATUS
1116 XenPciPdo_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
1118 NTSTATUS status = STATUS_SUCCESS;
1119 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1120 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1121 char path[128];
1123 UNREFERENCED_PARAMETER(device);
1124 UNREFERENCED_PARAMETER(target_state);
1126 FUNCTION_ENTER();
1128 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
1131 switch (target_state)
1133 case WdfPowerDeviceD0:
1134 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
1135 break;
1136 case WdfPowerDeviceD1:
1137 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
1138 break;
1139 case WdfPowerDeviceD2:
1140 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
1141 break;
1142 case WdfPowerDeviceD3:
1143 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
1144 break;
1145 case WdfPowerDeviceD3Final:
1146 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
1147 break;
1148 case WdfPowerDevicePrepareForHibernation:
1149 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
1150 break;
1151 default:
1152 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
1153 break;
1156 if (target_state == WdfPowerDevicePrepareForHibernation
1157 || (target_state == WdfPowerDeviceD3 && xppdd->hiber_usage_kludge))
1159 KdPrint((__DRIVER_NAME " not powering down as we are hibernating\n"));
1161 else
1163 status = XenPci_XenShutdownDevice(device);
1166 /* Remove watch on backend state */
1167 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
1168 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
1170 FUNCTION_EXIT();
1172 return status;
1175 NTSTATUS
1176 XenPciPdo_EvtDevicePrepareHardware(WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
1178 NTSTATUS status = STATUS_SUCCESS;
1180 UNREFERENCED_PARAMETER(device);
1181 UNREFERENCED_PARAMETER(resources_raw);
1182 UNREFERENCED_PARAMETER(resources_translated);
1184 FUNCTION_ENTER();
1185 FUNCTION_EXIT();
1187 return status;
1190 NTSTATUS
1191 XenPciPdo_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
1193 NTSTATUS status = STATUS_SUCCESS;
1195 UNREFERENCED_PARAMETER(device);
1196 UNREFERENCED_PARAMETER(resources_translated);
1198 FUNCTION_ENTER();
1199 FUNCTION_EXIT();
1201 return status;
1204 static VOID
1205 XenPciPdo_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
1207 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1209 FUNCTION_ENTER();
1211 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
1212 switch (notification_type)
1214 case WdfSpecialFilePaging:
1215 KdPrint((__DRIVER_NAME " notification_type = Paging, flag = %d\n", is_in_notification_path));
1216 break;
1217 case WdfSpecialFileHibernation:
1218 xppdd->hiber_usage_kludge = is_in_notification_path;
1219 KdPrint((__DRIVER_NAME " notification_type = Hibernation, flag = %d\n", is_in_notification_path));
1220 break;
1221 case WdfSpecialFileDump:
1222 KdPrint((__DRIVER_NAME " notification_type = Dump, flag = %d\n", is_in_notification_path));
1223 break;
1224 default:
1225 KdPrint((__DRIVER_NAME " notification_type = %d, flag = %d\n", notification_type, is_in_notification_path));
1226 break;
1229 FUNCTION_EXIT();
1232 NTSTATUS
1233 XenPci_EvtChildListCreateDevice(WDFCHILDLIST child_list,
1234 PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER identification_header,
1235 PWDFDEVICE_INIT child_init)
1237 NTSTATUS status = STATUS_SUCCESS;
1238 WDF_OBJECT_ATTRIBUTES child_attributes;
1239 WDFDEVICE child_device;
1240 PXENPCI_PDO_IDENTIFICATION_DESCRIPTION identification = (PXENPCI_PDO_IDENTIFICATION_DESCRIPTION)identification_header;
1241 WDF_DEVICE_PNP_CAPABILITIES child_pnp_capabilities;
1242 DECLARE_UNICODE_STRING_SIZE(buffer, 512);
1243 DECLARE_CONST_UNICODE_STRING(location, L"Xen Bus");
1244 PXENPCI_PDO_DEVICE_DATA xppdd;
1245 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
1246 WDF_QUERY_INTERFACE_CONFIG interface_config;
1247 BUS_INTERFACE_STANDARD bus_interface;
1248 WDF_PDO_EVENT_CALLBACKS pdo_callbacks;
1249 WDF_PNPPOWER_EVENT_CALLBACKS child_pnp_power_callbacks;
1250 UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
1251 WDF_DEVICE_POWER_CAPABILITIES child_power_capabilities;
1253 FUNCTION_ENTER();
1255 WdfDeviceInitSetDeviceType(child_init, FILE_DEVICE_UNKNOWN);
1257 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&child_pnp_power_callbacks);
1258 child_pnp_power_callbacks.EvtDeviceD0Entry = XenPciPdo_EvtDeviceD0Entry;
1259 //child_pnp_power_callbacks.EvtDeviceD0EntryPostInterruptsEnabled = XenPciPdo_EvtDeviceD0EntryPostInterruptsEnabled;
1260 child_pnp_power_callbacks.EvtDeviceD0Exit = XenPciPdo_EvtDeviceD0Exit;
1261 //child_pnp_power_callbacks.EvtDeviceD0ExitPreInterruptsDisabled = XenPciPdo_EvtDeviceD0ExitPreInterruptsDisabled;
1262 child_pnp_power_callbacks.EvtDevicePrepareHardware = XenPciPdo_EvtDevicePrepareHardware;
1263 child_pnp_power_callbacks.EvtDeviceReleaseHardware = XenPciPdo_EvtDeviceReleaseHardware;
1264 child_pnp_power_callbacks.EvtDeviceUsageNotification = XenPciPdo_EvtDeviceUsageNotification;
1265 WdfDeviceInitSetPnpPowerEventCallbacks(child_init, &child_pnp_power_callbacks);
1267 KdPrint((__DRIVER_NAME " device = '%s', index = '%d', path = '%s'\n",
1268 identification->device, identification->index, identification->path));
1270 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(child_init, XenPciPdo_EvtDeviceWdmIrpPreprocess_START_DEVICE,
1271 IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
1272 if (!NT_SUCCESS(status))
1274 return status;
1277 WDF_PDO_EVENT_CALLBACKS_INIT(&pdo_callbacks);
1278 //pdo_callbacks.EvtDeviceResourcesQuery = XenPciPdo_EvtDeviceResourcesQuery;
1279 pdo_callbacks.EvtDeviceResourceRequirementsQuery = XenPciPdo_EvtDeviceResourceRequirementsQuery;
1280 //pdo_callbacks.EvtDeviceEject = XenPciPdo_EvtDeviceEject;
1281 //pdo_callbacks.EvtDeviceSetLock = XenPciPdo_EvtDeviceSetLock;
1282 WdfPdoInitSetEventCallbacks(child_init, &pdo_callbacks);
1284 RtlUnicodeStringPrintf(&buffer, L"xen\\%S", identification->device);
1285 status = WdfPdoInitAssignDeviceID(child_init, &buffer);
1286 if (!NT_SUCCESS(status))
1288 return status;
1290 status = WdfPdoInitAddHardwareID(child_init, &buffer);
1291 if (!NT_SUCCESS(status))
1293 return status;
1295 status = WdfPdoInitAddCompatibleID(child_init, &buffer);
1296 if (!NT_SUCCESS(status))
1298 return status;
1301 RtlUnicodeStringPrintf(&buffer, L"%02d", identification->index);
1302 status = WdfPdoInitAssignInstanceID(child_init, &buffer);
1303 if (!NT_SUCCESS(status))
1305 return status;
1308 RtlUnicodeStringPrintf(&buffer, L"Xen %S device #%d", identification->device, identification->index);
1309 status = WdfPdoInitAddDeviceText(child_init, &buffer, &location, 0x0409);
1310 if (!NT_SUCCESS(status))
1312 return status;
1314 WdfPdoInitSetDefaultLocale(child_init, 0x0409);
1316 WdfDeviceInitSetPowerNotPageable(child_init);
1318 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&child_attributes, XENPCI_PDO_DEVICE_DATA);
1319 status = WdfDeviceCreate(&child_init, &child_attributes, &child_device);
1320 if (!NT_SUCCESS(status))
1322 return status;
1325 xppdd = GetXppdd(child_device);
1327 xppdd->wdf_device = child_device;
1328 xppdd->wdf_device_bus_fdo = WdfChildListGetDevice(child_list);
1330 xppdd->config_page_mdl = AllocateUncachedPage();
1332 xppdd->device_state.magic = XEN_DEVICE_STATE_MAGIC;
1333 xppdd->device_state.length = sizeof(XENPCI_DEVICE_STATE);
1334 xppdd->device_state.suspend_resume_state_pdo = SR_STATE_RUNNING;
1335 xppdd->device_state.suspend_resume_state_fdo = SR_STATE_RUNNING;
1336 xppdd->device_state.pdo_event_channel = xpdd->pdo_event_channel;
1337 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFilePaging, TRUE);
1338 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileHibernation, TRUE);
1339 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileDump, TRUE);
1341 WDF_DEVICE_PNP_CAPABILITIES_INIT(&child_pnp_capabilities);
1342 child_pnp_capabilities.LockSupported = WdfFalse;
1343 child_pnp_capabilities.EjectSupported = WdfTrue;
1344 child_pnp_capabilities.Removable = WdfTrue;
1345 child_pnp_capabilities.DockDevice = WdfFalse;
1346 child_pnp_capabilities.UniqueID = WdfFalse;
1347 child_pnp_capabilities.SilentInstall = WdfTrue;
1348 child_pnp_capabilities.SurpriseRemovalOK = WdfTrue;
1349 child_pnp_capabilities.HardwareDisabled = WdfFalse;
1350 WdfDeviceSetPnpCapabilities(child_device, &child_pnp_capabilities);
1352 WDF_DEVICE_POWER_CAPABILITIES_INIT(&child_power_capabilities);
1353 child_power_capabilities.DeviceD1 = WdfTrue;
1354 child_power_capabilities.WakeFromD1 = WdfTrue;
1355 child_power_capabilities.DeviceWake = PowerDeviceD1;
1356 child_power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD1;
1357 child_power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
1358 child_power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
1359 child_power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
1360 child_power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
1361 child_power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
1362 WdfDeviceSetPowerCapabilities(child_device, &child_power_capabilities);
1364 bus_interface.Size = sizeof(BUS_INTERFACE_STANDARD);
1365 bus_interface.Version = 1; //BUS_INTERFACE_STANDARD_VERSION;
1366 bus_interface.Context = xppdd;
1367 bus_interface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
1368 bus_interface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
1369 bus_interface.TranslateBusAddress = XenPci_BIS_TranslateBusAddress;
1370 bus_interface.GetDmaAdapter = XenPci_BIS_GetDmaAdapter;
1371 bus_interface.SetBusData = XenPci_BIS_SetBusData;
1372 bus_interface.GetBusData = XenPci_BIS_GetBusData;
1373 WDF_QUERY_INTERFACE_CONFIG_INIT(&interface_config, (PINTERFACE)&bus_interface, &GUID_BUS_INTERFACE_STANDARD, NULL);
1374 status = WdfDeviceAddQueryInterface(child_device, &interface_config);
1375 if (!NT_SUCCESS(status))
1377 return status;
1380 RtlStringCbCopyA(xppdd->path, ARRAY_SIZE(xppdd->path), identification->path);
1381 RtlStringCbCopyA(xppdd->device, ARRAY_SIZE(xppdd->device), identification->device);
1382 xppdd->index = identification->index;
1383 KeInitializeEvent(&xppdd->backend_state_event, SynchronizationEvent, FALSE);
1384 ExInitializeFastMutex(&xppdd->backend_state_mutex);
1385 xppdd->backend_state = XenbusStateUnknown;
1386 xppdd->frontend_state = XenbusStateUnknown;
1387 xppdd->backend_path[0] = '\0';
1389 FUNCTION_EXIT();
1391 return status;
1394 static __forceinline VOID
1395 XenPci_Pdo_ChangeSuspendState(WDFDEVICE device, ULONG new_state)
1397 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1398 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1400 FUNCTION_ENTER();
1401 KdPrint((__DRIVER_NAME " setting pdo state to %d\n", new_state));
1402 xppdd->device_state.suspend_resume_state_pdo = new_state;
1403 KeMemoryBarrier();
1404 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xpdd->pdo_event_channel));
1405 EvtChn_Notify(xpdd, xpdd->pdo_event_channel);
1406 while(xppdd->device_state.suspend_resume_state_fdo != xppdd->device_state.suspend_resume_state_pdo)
1408 KdPrint((__DRIVER_NAME " waiting...\n"));
1409 KeWaitForSingleObject(&xpdd->pdo_suspend_event, Executive, KernelMode, FALSE, NULL);
1411 KdPrint((__DRIVER_NAME " fdo state set to %d\n", new_state));
1412 FUNCTION_EXIT();
1415 /* called at PASSIVE_LEVEL */
1416 NTSTATUS
1417 XenPci_Pdo_Suspend(WDFDEVICE device)
1419 NTSTATUS status = STATUS_SUCCESS;
1420 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1421 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1422 //LARGE_INTEGER wait_time;
1423 char path[128];
1424 PUCHAR in_ptr;
1425 UCHAR type;
1426 PVOID setting;
1427 PVOID value;
1428 PVOID value2;
1430 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ " (%s)\n", xppdd->path));
1432 if (xppdd->backend_state == XenbusStateConnected)
1434 xppdd->restart_on_resume = TRUE;
1435 XenPci_Pdo_ChangeSuspendState(device, SR_STATE_SUSPENDING);
1437 XenPci_ChangeFrontendState(device, XenbusStateClosing, XenbusStateClosing, 30000);
1438 XenPci_ChangeFrontendState(device, XenbusStateClosed, XenbusStateClosed, 30000);
1439 XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 30000);
1441 if (xppdd->assigned_resources_start != NULL)
1443 in_ptr = xppdd->assigned_resources_ptr;
1444 ADD_XEN_INIT_RSP(&in_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
1445 in_ptr = xppdd->assigned_resources_start;
1446 while((type = GET_XEN_INIT_RSP(&in_ptr, &setting, &value, &value2)) != XEN_INIT_TYPE_END)
1448 switch (type)
1450 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
1451 case XEN_INIT_TYPE_EVENT_CHANNEL_DPC: /* frontend event channel bound to dpc */
1452 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel bound to irq */
1453 EvtChn_Unbind(xpdd, PtrToUlong(value));
1454 EvtChn_Close(xpdd, PtrToUlong(value));
1455 break;
1460 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
1461 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, xppdd);
1463 else
1465 xppdd->restart_on_resume = FALSE;
1468 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1470 return status;
1473 NTSTATUS
1474 XenPci_Pdo_Resume(WDFDEVICE device)
1476 NTSTATUS status = STATUS_SUCCESS;
1477 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
1478 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
1479 ULONG old_backend_state;
1480 PUCHAR src, dst;
1482 FUNCTION_ENTER();
1483 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
1485 xppdd->device_state.pdo_event_channel = xpdd->pdo_event_channel;
1486 old_backend_state = xppdd->backend_state;
1488 if (xppdd->restart_on_resume)
1490 status = XenPci_GetBackendAndAddWatch(device);
1492 if (XenPci_ChangeFrontendState(device, XenbusStateInitialising, XenbusStateInitWait, 30000) != STATUS_SUCCESS)
1494 KdPrint((__DRIVER_NAME " Failed to change frontend state to Initialising\n"));
1495 // this is probably an unrecoverable situation...
1496 FUNCTION_ERROR_EXIT();
1497 return STATUS_UNSUCCESSFUL;
1499 if (xppdd->assigned_resources_ptr)
1501 // reset things - feed the 'requested resources' back in
1502 ADD_XEN_INIT_REQ(&xppdd->requested_resources_ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
1503 src = xppdd->requested_resources_start;
1504 xppdd->requested_resources_ptr = xppdd->requested_resources_start = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);;
1505 xppdd->assigned_resources_ptr = xppdd->assigned_resources_start;
1507 dst = MmMapIoSpace(xppdd->config_page_phys, xppdd->config_page_length, MmNonCached);
1509 status = XenPci_XenConfigDeviceSpecifyBuffers(device, src, dst);
1511 MmUnmapIoSpace(dst, xppdd->config_page_length);
1512 ExFreePoolWithTag(src, XENPCI_POOL_TAG);
1514 if (XenPci_ChangeFrontendState(device, XenbusStateConnected, XenbusStateConnected, 30000) != STATUS_SUCCESS)
1516 // this is definitely an unrecoverable situation...
1517 KdPrint((__DRIVER_NAME " Failed to change frontend state to connected\n"));
1518 FUNCTION_ERROR_EXIT();
1519 return STATUS_UNSUCCESSFUL;
1521 XenPci_Pdo_ChangeSuspendState(device, SR_STATE_RESUMING);
1522 XenPci_Pdo_ChangeSuspendState(device, SR_STATE_RUNNING);
1525 FUNCTION_EXIT();
1527 return STATUS_SUCCESS;