win-pvdrivers

view xenpci/xenpci_fdo.c @ 790:467005e7f509

Big messy changes. Add grant ref tagging to better track when things go wrong (debug build only).
Fix a race in xennet that causes crashes under heavy traffic conditions on driver shutdown.
author James Harper <james.harper@bendigoit.com.au>
date Fri Mar 12 09:38:42 2010 +1100 (2010-03-12)
parents f43c89df09b2
children aee3767c191d
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 <aux_klib.h>
24 #define SYSRQ_PATH "control/sysrq"
25 #define SHUTDOWN_PATH "control/shutdown"
26 #define BALLOON_PATH "memory/target"
28 /* Not really necessary but keeps PREfast happy */
29 static EVT_WDF_WORKITEM XenPci_SuspendResume;
30 static KSTART_ROUTINE XenPci_BalloonThreadProc;
32 static VOID
33 XenPci_MapHalThenPatchKernel(PXENPCI_DEVICE_DATA xpdd)
34 {
35 NTSTATUS status;
36 PAUX_MODULE_EXTENDED_INFO amei;
37 ULONG module_info_buffer_size;
38 ULONG i;
40 FUNCTION_ENTER();
42 amei = NULL;
43 /* buffer size could change between requesting and allocating - need to loop until we are successful */
44 while ((status = AuxKlibQueryModuleInformation(&module_info_buffer_size, sizeof(AUX_MODULE_EXTENDED_INFO), amei)) == STATUS_BUFFER_TOO_SMALL || amei == NULL)
45 {
46 if (amei != NULL)
47 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
48 amei = ExAllocatePoolWithTag(NonPagedPool, module_info_buffer_size, XENPCI_POOL_TAG);
49 }
51 KdPrint((__DRIVER_NAME " AuxKlibQueryModuleInformation = %d\n", status));
52 for (i = 0; i < module_info_buffer_size / sizeof(AUX_MODULE_EXTENDED_INFO); i++)
53 {
54 if (strcmp((PCHAR)amei[i].FullPathName + amei[i].FileNameOffset, "hal.dll") == 0)
55 {
56 KdPrint((__DRIVER_NAME " hal.dll found at %p - %p\n",
57 amei[i].BasicInfo.ImageBase,
58 ((PUCHAR)amei[i].BasicInfo.ImageBase) + amei[i].ImageSize));
59 XenPci_PatchKernel(xpdd, amei[i].BasicInfo.ImageBase, amei[i].ImageSize);
60 }
61 }
62 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
63 FUNCTION_EXIT();
64 }
66 /*
67 * Alloc MMIO from the device's MMIO region. There is no corresponding free() fn
68 */
69 PHYSICAL_ADDRESS
70 XenPci_AllocMMIO(PXENPCI_DEVICE_DATA xpdd, ULONG len)
71 {
72 PHYSICAL_ADDRESS addr;
74 len = (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
76 addr = xpdd->platform_mmio_addr;
77 addr.QuadPart += xpdd->platform_mmio_alloc;
78 xpdd->platform_mmio_alloc += len;
80 ASSERT(xpdd->platform_mmio_alloc <= xpdd->platform_mmio_len);
82 return addr;
83 }
85 extern ULONG tpr_patch_requested;
87 NTSTATUS
88 XenPci_EvtDeviceQueryRemove(WDFDEVICE device)
89 {
90 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
91 NTSTATUS status;
93 FUNCTION_ENTER();
94 if (xpdd->removable)
95 status = STATUS_SUCCESS;
96 else
97 status = STATUS_UNSUCCESSFUL;
98 FUNCTION_EXIT();
99 return status;
100 }
102 static NTSTATUS
103 XenPci_Init(PXENPCI_DEVICE_DATA xpdd)
104 {
105 NTSTATUS status;
106 struct xen_add_to_physmap xatp;
107 int ret;
109 FUNCTION_ENTER();
111 status = hvm_get_stubs(xpdd);
112 if (!NT_SUCCESS(status))
113 return status;
115 if (!xpdd->shared_info_area)
116 {
117 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
118 /* this should be safe as this part will never be called on resume where IRQL == HIGH_LEVEL */
119 xpdd->shared_info_area_unmapped = XenPci_AllocMMIO(xpdd, PAGE_SIZE);
120 xpdd->shared_info_area = MmMapIoSpace(xpdd->shared_info_area_unmapped,
121 PAGE_SIZE, MmNonCached);
122 }
123 KdPrint((__DRIVER_NAME " shared_info_area_unmapped.QuadPart = %lx\n", xpdd->shared_info_area_unmapped.QuadPart));
124 xatp.domid = DOMID_SELF;
125 xatp.idx = 0;
126 xatp.space = XENMAPSPACE_shared_info;
127 xatp.gpfn = (xen_pfn_t)(xpdd->shared_info_area_unmapped.QuadPart >> PAGE_SHIFT);
128 KdPrint((__DRIVER_NAME " gpfn = %x\n", xatp.gpfn));
129 ret = HYPERVISOR_memory_op(xpdd, XENMEM_add_to_physmap, &xatp);
130 KdPrint((__DRIVER_NAME " hypervisor memory op (XENMAPSPACE_shared_info) ret = %d\n", ret));
132 FUNCTION_EXIT();
134 return STATUS_SUCCESS;
135 }
137 static NTSTATUS
138 XenPci_Resume(PXENPCI_DEVICE_DATA xpdd)
139 {
140 return XenPci_Init(xpdd);
141 }
143 static VOID
144 XenPci_SysrqHandler(char *path, PVOID context)
145 {
146 PXENPCI_DEVICE_DATA xpdd = context;
147 char *value;
148 char letter;
149 char *res;
151 UNREFERENCED_PARAMETER(path);
153 FUNCTION_ENTER();
155 XenBus_Read(xpdd, XBT_NIL, SYSRQ_PATH, &value);
157 KdPrint((__DRIVER_NAME " SysRq Value = %s\n", value));
159 if (value != NULL && strlen(value) != 0)
160 {
161 letter = *value;
162 res = XenBus_Write(xpdd, XBT_NIL, SYSRQ_PATH, "");
163 if (res)
164 {
165 KdPrint(("Error writing sysrq path\n"));
166 XenPci_FreeMem(res);
167 return;
168 }
169 }
170 else
171 {
172 letter = 0;
173 }
175 if (value != NULL)
176 {
177 XenPci_FreeMem(value);
178 }
180 switch (letter)
181 {
182 case 0:
183 break;
184 case 'B': /* cause a bug check */
185 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000001, 0x00000000, 0x00000000, 0x00000000);
186 break;
187 case 'A': /* cause an assert */
188 ASSERT(1 == 0);
189 break;
190 default:
191 KdPrint((" Unhandled sysrq letter %c\n", letter));
192 break;
193 }
195 FUNCTION_EXIT();
196 }
198 #if 0
199 static VOID
200 XenPci_PrintPendingInterrupts()
201 {
202 PULONG bitmap = (PULONG)0xFFFE0200;
203 int i;
204 int j;
205 ULONG value;
207 for (i = 0; i < 8; i++)
208 {
209 value = bitmap[(7 - i) * 4];
210 if (value)
211 {
212 for (j = 0; j < 32; j++)
213 {
214 if ((value >> j) & 1)
215 KdPrint((" Interrupt pending on pin %d\n", ((7 - i) << 5) | j));
216 }
217 }
218 }
219 }
220 #endif
222 #define BALLOON_UNIT_PAGES (BALLOON_UNITS >> PAGE_SHIFT)
224 static VOID
225 XenPci_BalloonThreadProc(PVOID StartContext)
226 {
227 PXENPCI_DEVICE_DATA xpdd = StartContext;
228 ULONG new_target = xpdd->current_memory;
229 LARGE_INTEGER timeout;
230 PLARGE_INTEGER ptimeout;
231 PMDL head = NULL;
232 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
233 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
235 FUNCTION_ENTER();
237 for(;;)
238 {
239 if (xpdd->current_memory != new_target)
240 {
241 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
242 ptimeout = &timeout;
243 }
244 else
245 {
246 ptimeout = NULL;
247 }
248 KeWaitForSingleObject(&xpdd->balloon_event, Executive, KernelMode, FALSE, ptimeout);
249 if (xpdd->balloon_shutdown)
250 PsTerminateSystemThread(0);
251 KdPrint((__DRIVER_NAME " Got balloon event, current = %d, target = %d\n", xpdd->current_memory, xpdd->target_memory));
252 /* not really worried about races here, but cache target so we only read it once */
253 new_target = xpdd->target_memory;
254 // perform some sanity checks on target_memory
255 // make sure target <= initial
256 // make sure target > some % of initial
258 if (xpdd->current_memory == new_target)
259 {
260 KdPrint((__DRIVER_NAME " No change to memory\n"));
261 continue;
262 }
263 else if (xpdd->current_memory < new_target)
264 {
265 PMDL mdl;
266 KdPrint((__DRIVER_NAME " Trying to take %d MB from Xen\n", new_target - xpdd->current_memory));
267 while ((mdl = head) != NULL && xpdd->current_memory < new_target)
268 {
269 head = mdl->Next;
270 mdl->Next = NULL;
271 MmFreePagesFromMdl(mdl);
272 ExFreePool(mdl);
273 xpdd->current_memory++;
274 }
275 }
276 else
277 {
278 KdPrint((__DRIVER_NAME " Trying to give %d MB to Xen\n", xpdd->current_memory - new_target));
279 while (xpdd->current_memory > new_target)
280 {
281 PHYSICAL_ADDRESS alloc_low;
282 PHYSICAL_ADDRESS alloc_high;
283 PHYSICAL_ADDRESS alloc_skip;
284 PMDL mdl;
285 alloc_low.QuadPart = 0;
286 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
287 alloc_skip.QuadPart = 0;
288 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS);
289 if (!mdl)
290 {
291 KdPrint((__DRIVER_NAME " Allocation failed - try again in 1 second\n"));
292 break;
293 }
294 else
295 {
296 if (head)
297 {
298 mdl->Next = head;
299 head = mdl;
300 }
301 else
302 {
303 head = mdl;
304 }
305 xpdd->current_memory--;
306 }
307 }
308 }
309 }
310 //FUNCTION_EXIT();
311 }
313 static VOID
314 XenPci_BalloonHandler(char *Path, PVOID Data)
315 {
316 WDFDEVICE device = Data;
317 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
318 char *value;
319 xenbus_transaction_t xbt;
320 int retry;
322 UNREFERENCED_PARAMETER(Path);
324 FUNCTION_ENTER();
326 XenBus_StartTransaction(xpdd, &xbt);
328 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
330 if (value == NULL)
331 {
332 KdPrint((__DRIVER_NAME " Failed to read value\n"));
333 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
334 FUNCTION_EXIT();
335 return;
336 }
338 if (atoi(value) > 0)
339 xpdd->target_memory = atoi(value) >> 10; /* convert to MB */
341 KdPrint((__DRIVER_NAME " target memory value = %d (%s)\n", xpdd->target_memory, value));
343 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
345 XenPci_FreeMem(value);
347 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
349 FUNCTION_EXIT();
350 }
352 static VOID
353 XenPci_Suspend0(PVOID context)
354 {
355 PXENPCI_DEVICE_DATA xpdd = context;
356 ULONG cancelled;
358 FUNCTION_ENTER();
360 GntTbl_Suspend(xpdd);
362 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
363 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
365 if (qemu_hide_flags_value)
366 {
367 XenPci_HideQemuDevices();
368 }
370 XenPci_Resume(xpdd);
371 GntTbl_Resume(xpdd);
372 EvtChn_Resume(xpdd); /* this enables interrupts again too */
374 FUNCTION_EXIT();
375 }
377 static VOID
378 XenPci_SuspendN(PVOID context)
379 {
380 UNREFERENCED_PARAMETER(context);
382 FUNCTION_ENTER();
383 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
384 FUNCTION_EXIT();
385 }
387 static VOID
388 XenPci_SuspendEvtDpc(PVOID context);
389 static NTSTATUS
390 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
392 /* called at PASSIVE_LEVEL */
393 static NTSTATUS
394 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd)
395 {
396 CHAR path[128];
398 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
399 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
400 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
401 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
402 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device);
404 return STATUS_SUCCESS;
405 }
407 /* Called at PASSIVE_LEVEL */
408 static VOID DDKAPI
409 XenPci_SuspendResume(WDFWORKITEM workitem)
410 {
411 NTSTATUS status;
412 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
413 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
414 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
415 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
416 WDF_CHILD_LIST_ITERATOR child_iterator;
417 WDFDEVICE child_device;
419 FUNCTION_ENTER();
421 if (xpdd->suspend_state == SUSPEND_STATE_NONE)
422 {
423 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
424 KeMemoryBarrier();
426 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
427 WdfChildListBeginIteration(child_list, &child_iterator);
428 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
429 {
430 KdPrint((__DRIVER_NAME " Suspending child\n"));
431 XenPci_Pdo_Suspend(child_device);
432 }
433 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
434 WdfChildListEndIteration(child_list, &child_iterator);
436 XenBus_Suspend(xpdd);
437 EvtChn_Suspend(xpdd);
438 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
440 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
441 XenBus_Resume(xpdd);
443 XenPci_ConnectSuspendEvt(xpdd);
445 WdfChildListBeginIteration(child_list, &child_iterator);
446 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
447 {
448 KdPrint((__DRIVER_NAME " Resuming child\n"));
449 XenPci_Pdo_Resume(child_device);
450 }
451 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
452 WdfChildListEndIteration(child_list, &child_iterator);
454 xpdd->suspend_state = SUSPEND_STATE_NONE;
455 }
456 FUNCTION_EXIT();
457 }
459 /* called at DISPATCH_LEVEL */
460 static VOID
461 XenPci_SuspendEvtDpc(PVOID context)
462 {
463 NTSTATUS status;
464 WDFDEVICE device = context;
465 //KIRQL old_irql;
466 WDF_OBJECT_ATTRIBUTES attributes;
467 WDF_WORKITEM_CONFIG workitem_config;
468 WDFWORKITEM workitem;
470 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
471 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
472 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
473 attributes.ParentObject = device;
474 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
475 // TODO: check status here
476 WdfWorkItemEnqueue(workitem);
477 }
479 static void
480 XenPci_ShutdownHandler(char *path, PVOID context)
481 {
482 NTSTATUS status;
483 WDFDEVICE device = context;
484 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
485 char *res;
486 char *value;
487 //KIRQL old_irql;
488 WDF_OBJECT_ATTRIBUTES attributes;
489 WDF_WORKITEM_CONFIG workitem_config;
490 WDFWORKITEM workitem;
492 UNREFERENCED_PARAMETER(path);
494 FUNCTION_ENTER();
496 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
497 if (res)
498 {
499 KdPrint(("Error reading shutdown path - %s\n", res));
500 XenPci_FreeMem(res);
501 FUNCTION_EXIT();
502 return;
503 }
505 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
507 if (strlen(value) && strcmp(value, "suspend") == 0)
508 {
509 {
510 KdPrint((__DRIVER_NAME " Suspend detected\n"));
511 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
512 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
513 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
514 attributes.ParentObject = device;
515 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
516 // TODO: check status here
517 WdfWorkItemEnqueue(workitem);
518 }
519 }
521 XenPci_FreeMem(value);
523 FUNCTION_EXIT();
524 }
526 static VOID
527 XenPci_DeviceWatchHandler(char *path, PVOID context)
528 {
529 char **bits;
530 int count;
531 char *err;
532 char *value;
533 PXENPCI_DEVICE_DATA xpdd = context;
535 FUNCTION_ENTER();
537 bits = SplitString(path, '/', 4, &count);
538 if (count == 3)
539 {
540 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
541 if (err)
542 {
543 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
544 XenPci_FreeMem(err);
545 }
546 else
547 {
548 XenPci_FreeMem(value);
549 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
550 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
551 XenPci_EvtChildListScanForChildren(xpdd->child_list);
552 }
553 }
554 FreeSplitString(bits, count);
556 FUNCTION_EXIT();
557 }
559 NTSTATUS
560 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
561 {
562 NTSTATUS status = STATUS_SUCCESS;
563 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
564 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
565 ULONG i;
567 FUNCTION_ENTER();
569 ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
571 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
572 {
573 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
574 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
575 switch (raw_descriptor->Type) {
576 case CmResourceTypePort:
577 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
578 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
579 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
580 break;
581 case CmResourceTypeMemory:
582 KdPrint((__DRIVER_NAME " Memory mapped CSR:(%x:%x) Length:(%d)\n", translated_descriptor->u.Memory.Start.LowPart, translated_descriptor->u.Memory.Start.HighPart, translated_descriptor->u.Memory.Length));
583 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
584 #if 0
585 mmio_freelist_free = 0;
586 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
587 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
588 #endif
589 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
590 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
591 xpdd->platform_mmio_flags = translated_descriptor->Flags;
592 break;
593 case CmResourceTypeInterrupt:
594 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
595 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
596 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
597 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
598 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
599 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
600 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
601 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
602 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
603 switch(translated_descriptor->ShareDisposition)
604 {
605 case CmResourceShareDeviceExclusive:
606 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
607 break;
608 case CmResourceShareDriverExclusive:
609 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
610 break;
611 case CmResourceShareShared:
612 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
613 break;
614 default:
615 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
616 break;
617 }
618 break;
619 case CmResourceTypeDevicePrivate:
620 KdPrint((__DRIVER_NAME " Private Data: 0x%02x 0x%02x 0x%02x\n", translated_descriptor->u.DevicePrivate.Data[0], translated_descriptor->u.DevicePrivate.Data[1], translated_descriptor->u.DevicePrivate.Data[2]));
621 break;
622 default:
623 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
624 break;
625 }
626 }
628 FUNCTION_EXIT();
630 return status;
631 }
633 NTSTATUS
634 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
635 {
636 NTSTATUS status = STATUS_SUCCESS;
637 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
638 ULONG i;
639 ULONG ret;
641 FUNCTION_ENTER();
643 xpdd->hibernated = FALSE;
644 switch (previous_state)
645 {
646 case WdfPowerDeviceD0:
647 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
648 break;
649 case WdfPowerDeviceD1:
650 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
651 break;
652 case WdfPowerDeviceD2:
653 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
654 break;
655 case WdfPowerDeviceD3:
656 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
657 break;
658 case WdfPowerDeviceD3Final:
659 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
660 break;
661 case WdfPowerDevicePrepareForHibernation:
662 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
663 break;
664 default:
665 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
666 break;
667 }
669 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value)
670 {
671 XenPci_HideQemuDevices();
672 }
674 if (previous_state == WdfPowerDeviceD3Final)
675 {
676 XenPci_Init(xpdd);
677 if (tpr_patch_requested && !xpdd->tpr_patched)
678 {
679 XenPci_MapHalThenPatchKernel(xpdd);
680 xpdd->tpr_patched = TRUE;
681 }
682 GntTbl_Init(xpdd);
683 EvtChn_Init(xpdd);
685 for (i = 0; i < NR_GRANT_FRAMES + 1; i++)
686 {
687 struct xen_memory_reservation reservation;
688 xen_pfn_t pfn;
689 PMDL mdl = AllocatePage();
690 pfn = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[0]);
691 reservation.address_bits = 0;
692 reservation.extent_order = 0;
693 reservation.domid = DOMID_SELF;
694 reservation.nr_extents = 1;
695 #pragma warning(disable: 4127) /* conditional expression is constant */
696 set_xen_guest_handle(reservation.extent_start, &pfn);
698 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
699 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
700 //KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
701 }
703 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
704 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
705 }
706 else
707 {
708 XenPci_Resume(xpdd);
709 GntTbl_Resume(xpdd);
710 EvtChn_Resume(xpdd);
711 }
713 FUNCTION_EXIT();
715 return status;
716 }
718 NTSTATUS
719 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
720 {
721 NTSTATUS status = STATUS_SUCCESS;
722 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
723 PCHAR response;
724 char *value;
725 domid_t domid = DOMID_SELF;
726 ULONG ret;
727 xen_ulong_t *max_ram_page;
728 HANDLE thread_handle;
730 UNREFERENCED_PARAMETER(previous_state);
732 FUNCTION_ENTER();
734 if (previous_state == WdfPowerDeviceD3Final)
735 {
736 XenBus_Init(xpdd);
738 XenPci_ConnectSuspendEvt(xpdd);
740 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
742 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
744 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
746 ret = HYPERVISOR_memory_op(xpdd, XENMEM_current_reservation, &domid);
747 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
748 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_reservation, &domid);
749 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
750 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_ram_page, &max_ram_page);
751 KdPrint((__DRIVER_NAME " XENMEM_maximum_ram_page = %d\n", ret));
753 if (!xpdd->initial_memory)
754 {
755 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
756 if (atoi(value) > 0)
757 {
758 xpdd->initial_memory = atoi(value) >> 10; /* convert to MB */
759 xpdd->current_memory = xpdd->initial_memory;
760 xpdd->target_memory = xpdd->initial_memory;
761 }
762 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory, value));
763 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
764 xpdd->balloon_shutdown = FALSE;
765 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
766 if (!NT_SUCCESS(status))
767 {
768 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
769 return status;
770 }
771 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
772 ZwClose(thread_handle);
773 }
774 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
775 }
776 else
777 {
778 XenBus_Resume(xpdd);
779 XenPci_ConnectSuspendEvt(xpdd);
780 }
781 FUNCTION_EXIT();
783 return status;
784 }
786 NTSTATUS
787 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
788 {
789 NTSTATUS status = STATUS_SUCCESS;
790 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
791 LARGE_INTEGER timeout;
793 FUNCTION_ENTER();
795 switch (target_state)
796 {
797 case WdfPowerDeviceD0:
798 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
799 break;
800 case WdfPowerDeviceD1:
801 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
802 break;
803 case WdfPowerDeviceD2:
804 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
805 break;
806 case WdfPowerDeviceD3:
807 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
808 break;
809 case WdfPowerDeviceD3Final:
810 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
811 break;
812 case WdfPowerDevicePrepareForHibernation:
813 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
814 break;
815 default:
816 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
817 break;
818 }
820 if (target_state == WdfPowerDeviceD3Final)
821 {
822 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
824 xpdd->balloon_shutdown = TRUE;
825 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
827 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
828 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
829 {
830 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
831 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
832 }
833 ObDereferenceObject(xpdd->balloon_thread);
835 XenBus_Halt(xpdd);
836 }
837 else
838 {
839 XenBus_Suspend(xpdd);
840 }
842 FUNCTION_EXIT();
844 return status;
845 }
847 NTSTATUS
848 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
849 {
850 NTSTATUS status = STATUS_SUCCESS;
851 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
853 FUNCTION_ENTER();
855 switch (target_state)
856 {
857 case WdfPowerDeviceD0:
858 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
859 break;
860 case WdfPowerDeviceD1:
861 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
862 break;
863 case WdfPowerDeviceD2:
864 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
865 break;
866 case WdfPowerDeviceD3:
867 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
868 break;
869 case WdfPowerDeviceD3Final:
870 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
871 break;
872 case WdfPowerDevicePrepareForHibernation:
873 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
874 xpdd->hibernated = TRUE;
875 break;
876 default:
877 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
878 break;
879 }
881 if (target_state == WdfPowerDeviceD3Final)
882 {
883 /* we don't really support exit here */
884 }
885 else
886 {
887 GntTbl_Suspend(xpdd);
888 }
890 FUNCTION_EXIT();
892 return status;
893 }
895 NTSTATUS
896 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
897 {
898 NTSTATUS status = STATUS_SUCCESS;
900 UNREFERENCED_PARAMETER(device);
901 UNREFERENCED_PARAMETER(resources_translated);
903 FUNCTION_ENTER();
904 FUNCTION_EXIT();
906 return status;
907 }
909 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
910 /* Can be called concurrently, but KMDF takes care of concurrent calls to WdfChildListXxx */
911 VOID
912 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
913 {
914 NTSTATUS status;
915 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
916 char *msg;
917 char **devices;
918 char **instances;
919 ULONG i, j;
920 CHAR path[128];
921 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
922 PVOID entry;
924 FUNCTION_ENTER();
926 WdfChildListBeginScan(child_list);
928 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
929 if (!msg)
930 {
931 for (i = 0; devices[i]; i++)
932 {
933 /* make sure the key is not in the veto list */
934 for (entry = xpdd->veto_list.Flink; entry != &xpdd->veto_list; entry = ((PLIST_ENTRY)entry)->Flink)
935 {
936 if (!strcmp(devices[i], (PCHAR)entry + sizeof(LIST_ENTRY)))
937 break;
938 }
939 if (entry != &xpdd->veto_list)
940 {
941 XenPci_FreeMem(devices[i]);
942 continue;
943 }
945 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
946 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
947 if (!msg)
948 {
949 for (j = 0; instances[j]; j++)
950 {
951 /* the device comparison is done as a memory compare so zero-ing the structure is important */
952 RtlZeroMemory(&child_description, sizeof(child_description));
953 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
954 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
955 KdPrint((__DRIVER_NAME " Found path = %s\n", path));
956 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
957 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
958 child_description.index = atoi(instances[j]);
959 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
960 if (!NT_SUCCESS(status))
961 {
962 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
963 }
964 XenPci_FreeMem(instances[j]);
965 }
966 XenPci_FreeMem(instances);
967 }
968 else
969 {
970 // wtf do we do here???
971 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
972 }
973 XenPci_FreeMem(devices[i]);
974 }
975 XenPci_FreeMem(devices);
976 }
977 else
978 {
979 // wtf do we do here???
980 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
981 }
983 WdfChildListEndScan(child_list);
985 FUNCTION_EXIT();
986 }