win-pvdrivers

view xenpci/xenpci_fdo.c @ 622:f905eb3f0545

Shut down threads properly on hibernate.
Added some debug to try and find where the hang happens when the verifier is enabled
Added the suspend event channel to allow triggering a suspend much earlier
author James Harper <james.harper@bendigoit.com.au>
date Wed Aug 05 19:09:55 2009 +1000 (2009-08-05)
parents bddc14051767
children 0b55299418ce
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 static VOID
29 XenPci_MapHalThenPatchKernel(PXENPCI_DEVICE_DATA xpdd)
30 {
31 NTSTATUS status;
32 PAUX_MODULE_EXTENDED_INFO amei;
33 ULONG module_info_buffer_size;
34 ULONG i;
36 FUNCTION_ENTER();
38 status = AuxKlibInitialize();
39 amei = NULL;
40 /* buffer size could change between requesting and allocating - need to loop until we are successful */
41 while ((status = AuxKlibQueryModuleInformation(&module_info_buffer_size, sizeof(AUX_MODULE_EXTENDED_INFO), amei)) == STATUS_BUFFER_TOO_SMALL || amei == NULL)
42 {
43 if (amei != NULL)
44 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
45 amei = ExAllocatePoolWithTag(NonPagedPool, module_info_buffer_size, XENPCI_POOL_TAG);
46 }
48 KdPrint((__DRIVER_NAME " AuxKlibQueryModuleInformation = %d\n", status));
49 for (i = 0; i < module_info_buffer_size / sizeof(AUX_MODULE_EXTENDED_INFO); i++)
50 {
51 if (strcmp((PCHAR)amei[i].FullPathName + amei[i].FileNameOffset, "hal.dll") == 0)
52 {
53 KdPrint((__DRIVER_NAME " hal.dll found at %p - %p\n",
54 amei[i].BasicInfo.ImageBase,
55 ((PUCHAR)amei[i].BasicInfo.ImageBase) + amei[i].ImageSize));
56 XenPci_PatchKernel(xpdd, amei[i].BasicInfo.ImageBase, amei[i].ImageSize);
57 }
58 }
59 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
60 FUNCTION_EXIT();
61 }
63 #if 0
64 PMDL
65 XenPCI_AllocMMIO(WDFDEVICE device, ULONG len)
66 {
67 PMDL mdl = ExAllocatePoolWithTag(NonPagedPool, MmSizeOfMdl(0, len), XENPCI_POOL_TAG);
68 PVOID va = MmAllocateMappingAddress(len, XENPCI_POOL_TAG);
70 for (i = 0; i < ADDRESS_AND_SIZE_TO_SPAN_PAGES(0, len);
72 }
73 #endif
75 /*
76 * Alloc MMIO from the device's MMIO region. There is no corresponding free() fn
77 */
78 PHYSICAL_ADDRESS
79 XenPci_AllocMMIO(PXENPCI_DEVICE_DATA xpdd, ULONG len)
80 {
81 PHYSICAL_ADDRESS addr;
83 len = (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
85 addr = xpdd->platform_mmio_addr;
86 addr.QuadPart += xpdd->platform_mmio_alloc;
87 xpdd->platform_mmio_alloc += len;
89 ASSERT(xpdd->platform_mmio_alloc <= xpdd->platform_mmio_len);
91 return addr;
92 }
94 extern ULONG tpr_patch_requested;
96 NTSTATUS
97 XenPci_EvtDeviceQueryRemove(WDFDEVICE device)
98 {
99 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
100 NTSTATUS status;
102 FUNCTION_ENTER();
103 if (xpdd->removable)
104 status = STATUS_SUCCESS;
105 else
106 status = STATUS_UNSUCCESSFUL;
107 FUNCTION_EXIT();
108 return status;
109 }
111 static NTSTATUS
112 XenPci_Init(PXENPCI_DEVICE_DATA xpdd)
113 {
114 struct xen_add_to_physmap xatp;
115 int ret;
117 FUNCTION_ENTER();
119 hvm_get_stubs(xpdd);
121 if (!xpdd->shared_info_area)
122 {
123 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
124 /* this should be safe as this part will never be called on resume where IRQL == HIGH_LEVEL */
125 xpdd->shared_info_area_unmapped = XenPci_AllocMMIO(xpdd, PAGE_SIZE);
126 xpdd->shared_info_area = MmMapIoSpace(xpdd->shared_info_area_unmapped,
127 PAGE_SIZE, MmNonCached);
128 }
129 KdPrint((__DRIVER_NAME " shared_info_area_unmapped.QuadPart = %lx\n", xpdd->shared_info_area_unmapped.QuadPart));
130 xatp.domid = DOMID_SELF;
131 xatp.idx = 0;
132 xatp.space = XENMAPSPACE_shared_info;
133 xatp.gpfn = (xen_pfn_t)(xpdd->shared_info_area_unmapped.QuadPart >> PAGE_SHIFT);
134 KdPrint((__DRIVER_NAME " gpfn = %x\n", xatp.gpfn));
135 ret = HYPERVISOR_memory_op(xpdd, XENMEM_add_to_physmap, &xatp);
136 KdPrint((__DRIVER_NAME " hypervisor memory op (XENMAPSPACE_shared_info) ret = %d\n", ret));
138 FUNCTION_EXIT();
140 return STATUS_SUCCESS;
141 }
143 static NTSTATUS
144 XenPci_Resume(PXENPCI_DEVICE_DATA xpdd)
145 {
146 return XenPci_Init(xpdd);
147 }
149 static VOID
150 XenPci_SysrqHandler(char *path, PVOID context)
151 {
152 PXENPCI_DEVICE_DATA xpdd = context;
153 char *value;
154 char letter;
155 char *res;
157 UNREFERENCED_PARAMETER(path);
159 FUNCTION_ENTER();
161 XenBus_Read(xpdd, XBT_NIL, SYSRQ_PATH, &value);
163 KdPrint((__DRIVER_NAME " SysRq Value = %s\n", value));
165 if (value != NULL && strlen(value) != 0)
166 {
167 letter = *value;
168 res = XenBus_Write(xpdd, XBT_NIL, SYSRQ_PATH, "");
169 if (res)
170 {
171 KdPrint(("Error writing sysrq path\n"));
172 XenPci_FreeMem(res);
173 return;
174 }
175 }
176 else
177 {
178 letter = 0;
179 }
181 if (value != NULL)
182 {
183 XenPci_FreeMem(value);
184 }
186 switch (letter)
187 {
188 case 0:
189 break;
190 case 'B': /* cause a bug check */
191 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000001, 0x00000000, 0x00000000, 0x00000000);
192 break;
193 default:
194 KdPrint((" Unhandled sysrq letter %c\n", letter));
195 break;
196 }
198 FUNCTION_EXIT();
199 }
201 #if 0
202 static VOID
203 XenPci_PrintPendingInterrupts()
204 {
205 PULONG bitmap = (PULONG)0xFFFE0200;
206 int i;
207 int j;
208 ULONG value;
210 for (i = 0; i < 8; i++)
211 {
212 value = bitmap[(7 - i) * 4];
213 if (value)
214 {
215 for (j = 0; j < 32; j++)
216 {
217 if ((value >> j) & 1)
218 KdPrint((" Interrupt pending on pin %d\n", ((7 - i) << 5) | j));
219 }
220 }
221 }
222 }
223 #endif
225 #define BALLOON_UNIT_PAGES (BALLOON_UNITS >> PAGE_SHIFT)
227 static VOID
228 XenPci_BalloonThreadProc(PVOID StartContext)
229 {
230 PXENPCI_DEVICE_DATA xpdd = StartContext;
231 ULONG new_target = xpdd->current_memory;
232 LARGE_INTEGER timeout;
233 PLARGE_INTEGER ptimeout;
234 PMDL head = NULL;
235 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
236 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
238 FUNCTION_ENTER();
240 for(;;)
241 {
242 if (xpdd->current_memory != new_target)
243 {
244 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
245 ptimeout = &timeout;
246 }
247 else
248 {
249 ptimeout = NULL;
250 }
251 KeWaitForSingleObject(&xpdd->balloon_event, Executive, KernelMode, FALSE, ptimeout);
252 if (xpdd->balloon_shutdown)
253 PsTerminateSystemThread(0);
254 //TODO: initiate shutdown here
255 KdPrint((__DRIVER_NAME " Got balloon event, current = %d, target = %d\n", xpdd->current_memory, xpdd->target_memory));
256 /* not really worried about races here, but cache target so we only read it once */
257 new_target = xpdd->target_memory;
258 // perform some sanity checks on target_memory
259 // make sure target <= initial
260 // make sure target > some % of initial
262 if (xpdd->current_memory == new_target)
263 {
264 KdPrint((__DRIVER_NAME " No change to memory\n"));
265 continue;
266 }
267 else if (xpdd->current_memory < new_target)
268 {
269 PMDL mdl;
270 KdPrint((__DRIVER_NAME " Trying to take %d MB from Xen\n", new_target - xpdd->current_memory));
271 while ((mdl = head) != NULL && xpdd->current_memory < new_target)
272 {
273 head = mdl->Next;
274 mdl->Next = NULL;
275 MmFreePagesFromMdl(mdl);
276 ExFreePool(mdl);
277 xpdd->current_memory++;
278 }
279 }
280 else
281 {
282 KdPrint((__DRIVER_NAME " Trying to give %d MB to Xen\n", xpdd->current_memory - new_target));
283 while (xpdd->current_memory > new_target)
284 {
285 PHYSICAL_ADDRESS alloc_low;
286 PHYSICAL_ADDRESS alloc_high;
287 PHYSICAL_ADDRESS alloc_skip;
288 PMDL mdl;
289 alloc_low.QuadPart = 0;
290 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
291 alloc_skip.QuadPart = 0;
292 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS);
293 if (!mdl)
294 {
295 KdPrint((__DRIVER_NAME " Allocation failed - try again in 1 second\n"));
296 break;
297 }
298 else
299 {
300 if (head)
301 {
302 mdl->Next = head;
303 head = mdl;
304 }
305 else
306 {
307 head = mdl;
308 }
309 xpdd->current_memory--;
310 }
311 }
312 }
313 }
314 //FUNCTION_EXIT();
315 }
317 static VOID
318 XenPci_BalloonHandler(char *Path, PVOID Data)
319 {
320 WDFDEVICE device = Data;
321 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
322 char *value;
323 xenbus_transaction_t xbt;
324 int retry;
326 UNREFERENCED_PARAMETER(Path);
328 FUNCTION_ENTER();
330 XenBus_StartTransaction(xpdd, &xbt);
332 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
334 if (value == NULL)
335 {
336 KdPrint((__DRIVER_NAME " Failed to read value\n"));
337 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
338 FUNCTION_EXIT();
339 return;
340 }
342 if (atoi(value) > 0)
343 xpdd->target_memory = atoi(value) >> 10; /* convert to MB */
345 KdPrint((__DRIVER_NAME " target memory value = %d (%s)\n", xpdd->target_memory, value));
347 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
349 XenPci_FreeMem(value);
351 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
353 // start a thread to allocate memory up to the required amount
355 FUNCTION_EXIT();
356 }
358 static VOID
359 XenPci_Suspend0(PVOID context)
360 {
361 PXENPCI_DEVICE_DATA xpdd = context;
362 ULONG cancelled;
364 FUNCTION_ENTER();
366 GntTbl_Suspend(xpdd);
368 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
369 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
371 if (qemu_filtered_by_qemu)
372 {
373 XenPci_HideQemuDevices();
374 ASSERT(qemu_filtered_by_qemu);
375 }
377 XenPci_Resume(xpdd);
378 GntTbl_Resume(xpdd);
379 EvtChn_Resume(xpdd); /* this enables interrupts again too */
381 FUNCTION_EXIT();
382 }
384 static VOID
385 XenPci_SuspendN(PVOID context)
386 {
387 UNREFERENCED_PARAMETER(context);
389 FUNCTION_ENTER();
390 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
391 FUNCTION_EXIT();
392 }
394 static VOID
395 XenPci_SuspendEvtDpc(PVOID context);
396 static NTSTATUS
397 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
399 /* called at PASSIVE_LEVEL */
400 static NTSTATUS
401 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd)
402 {
403 CHAR path[128];
405 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
406 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
407 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
408 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
409 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device);
411 return STATUS_SUCCESS;
412 }
414 /* Called at PASSIVE_LEVEL */
415 static VOID DDKAPI
416 XenPci_SuspendResume(WDFWORKITEM workitem)
417 {
418 NTSTATUS status;
419 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
420 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
421 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
422 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
423 WDF_CHILD_LIST_ITERATOR child_iterator;
424 WDFDEVICE child_device;
426 FUNCTION_ENTER();
428 if (xpdd->suspend_state == SUSPEND_STATE_NONE)
429 {
430 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
431 KeMemoryBarrier();
433 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
434 WdfChildListBeginIteration(child_list, &child_iterator);
435 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
436 {
437 KdPrint((__DRIVER_NAME " Suspending child\n"));
438 XenPci_Pdo_Suspend(child_device);
439 }
440 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
441 WdfChildListEndIteration(child_list, &child_iterator);
443 XenBus_Suspend(xpdd);
444 EvtChn_Suspend(xpdd);
445 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
447 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
448 XenBus_Resume(xpdd);
450 XenPci_ConnectSuspendEvt(xpdd);
452 WdfChildListBeginIteration(child_list, &child_iterator);
453 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
454 {
455 KdPrint((__DRIVER_NAME " Resuming child\n"));
456 XenPci_Pdo_Resume(child_device);
457 }
458 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
459 WdfChildListEndIteration(child_list, &child_iterator);
461 xpdd->suspend_state = SUSPEND_STATE_NONE;
462 }
463 FUNCTION_EXIT();
464 }
466 /* called at DISPATCH_LEVEL */
467 static VOID
468 XenPci_SuspendEvtDpc(PVOID context)
469 {
470 NTSTATUS status;
471 WDFDEVICE device = context;
472 //KIRQL old_irql;
473 WDF_OBJECT_ATTRIBUTES attributes;
474 WDF_WORKITEM_CONFIG workitem_config;
475 WDFWORKITEM workitem;
477 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
478 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
479 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
480 attributes.ParentObject = device;
481 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
482 // TODO: check status here
483 WdfWorkItemEnqueue(workitem);
484 }
486 static void
487 XenPci_ShutdownHandler(char *path, PVOID context)
488 {
489 NTSTATUS status;
490 WDFDEVICE device = context;
491 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
492 char *res;
493 char *value;
494 //KIRQL old_irql;
495 WDF_OBJECT_ATTRIBUTES attributes;
496 WDF_WORKITEM_CONFIG workitem_config;
497 WDFWORKITEM workitem;
499 UNREFERENCED_PARAMETER(path);
501 FUNCTION_ENTER();
503 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
504 if (res)
505 {
506 KdPrint(("Error reading shutdown path - %s\n", res));
507 XenPci_FreeMem(res);
508 FUNCTION_EXIT();
509 return;
510 }
512 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
514 if (strlen(value) && strcmp(value, "suspend") == 0)
515 {
516 {
517 KdPrint((__DRIVER_NAME " Suspend detected\n"));
518 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
519 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
520 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
521 attributes.ParentObject = device;
522 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
523 // TODO: check status here
524 WdfWorkItemEnqueue(workitem);
525 }
526 }
528 XenPci_FreeMem(value);
530 FUNCTION_EXIT();
531 }
533 static VOID
534 XenPci_DeviceWatchHandler(char *path, PVOID context)
535 {
536 char **bits;
537 int count;
538 char *err;
539 char *value;
540 PXENPCI_DEVICE_DATA xpdd = context;
542 //FUNCTION_ENTER();
544 bits = SplitString(path, '/', 4, &count);
545 if (count == 3)
546 {
547 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
548 if (err)
549 {
550 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
551 XenPci_FreeMem(err);
552 }
553 else
554 {
555 XenPci_FreeMem(value);
556 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
557 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
558 XenPci_EvtChildListScanForChildren(xpdd->child_list);
559 }
560 }
561 FreeSplitString(bits, count);
563 //FUNCTION_EXIT();
564 }
566 NTSTATUS
567 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
568 {
569 NTSTATUS status = STATUS_SUCCESS;
570 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
571 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
572 ULONG i;
574 FUNCTION_ENTER();
576 ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
578 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
579 {
580 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
581 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
582 switch (raw_descriptor->Type) {
583 case CmResourceTypePort:
584 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
585 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
586 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
587 break;
588 case CmResourceTypeMemory:
589 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));
590 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
591 #if 0
592 mmio_freelist_free = 0;
593 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
594 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
595 #endif
596 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
597 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
598 xpdd->platform_mmio_flags = translated_descriptor->Flags;
599 break;
600 case CmResourceTypeInterrupt:
601 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
602 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
603 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
604 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
605 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
606 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
607 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
608 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
609 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
610 switch(translated_descriptor->ShareDisposition)
611 {
612 case CmResourceShareDeviceExclusive:
613 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
614 break;
615 case CmResourceShareDriverExclusive:
616 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
617 break;
618 case CmResourceShareShared:
619 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
620 break;
621 default:
622 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
623 break;
624 }
625 break;
626 case CmResourceTypeDevicePrivate:
627 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]));
628 break;
629 default:
630 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
631 break;
632 }
633 }
635 FUNCTION_EXIT();
637 return status;
638 }
640 NTSTATUS
641 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
642 {
643 NTSTATUS status = STATUS_SUCCESS;
644 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
646 FUNCTION_ENTER();
648 xpdd->hibernated = FALSE;
650 switch (previous_state)
651 {
652 case WdfPowerDeviceD0:
653 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
654 break;
655 case WdfPowerDeviceD1:
656 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
657 break;
658 case WdfPowerDeviceD2:
659 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
660 break;
661 case WdfPowerDeviceD3:
662 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
663 break;
664 case WdfPowerDeviceD3Final:
665 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
666 break;
667 case WdfPowerDevicePrepareForHibernation:
668 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
669 break;
670 default:
671 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
672 break;
673 }
675 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_filtered_by_qemu)
676 {
677 XenPci_HideQemuDevices();
678 ASSERT(qemu_filtered_by_qemu);
679 }
681 XenPci_Init(xpdd);
682 if (tpr_patch_requested && !xpdd->tpr_patched)
683 {
684 XenPci_MapHalThenPatchKernel(xpdd);
685 xpdd->tpr_patched = TRUE;
686 }
687 if (previous_state == WdfPowerDevicePrepareForHibernation)
688 {
689 GntTbl_Resume(xpdd);
690 }
691 else
692 {
693 GntTbl_Init(xpdd);
694 }
695 EvtChn_Init(xpdd);
697 FUNCTION_EXIT();
699 return status;
700 }
702 NTSTATUS
703 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
704 {
705 NTSTATUS status = STATUS_SUCCESS;
706 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
707 PCHAR response;
708 char *value;
709 domid_t domid = DOMID_SELF;
710 ULONG ret;
711 xen_ulong_t *max_ram_page;
712 HANDLE thread_handle;
714 UNREFERENCED_PARAMETER(previous_state);
716 FUNCTION_ENTER();
718 XenBus_Init(xpdd);
720 XenPci_ConnectSuspendEvt(xpdd);
722 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
724 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
726 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
728 ret = HYPERVISOR_memory_op(xpdd, XENMEM_current_reservation, &domid);
729 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
730 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_reservation, &domid);
731 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
732 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_ram_page, &max_ram_page);
733 KdPrint((__DRIVER_NAME " XENMEM_maximum_ram_page = %d\n", ret));
735 if (!xpdd->initial_memory)
736 {
737 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
738 if (atoi(value) > 0)
739 {
740 xpdd->initial_memory = atoi(value) >> 10; /* convert to MB */
741 xpdd->current_memory = xpdd->initial_memory;
742 xpdd->target_memory = xpdd->initial_memory;
743 }
744 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory, value));
745 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
746 xpdd->balloon_shutdown = FALSE;
747 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
748 if (!NT_SUCCESS(status))
749 {
750 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
751 return status;
752 }
753 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
754 ZwClose(thread_handle);
755 }
756 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
758 FUNCTION_EXIT();
760 return status;
761 }
763 NTSTATUS
764 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
765 {
766 NTSTATUS status = STATUS_SUCCESS;
767 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
768 LARGE_INTEGER timeout;
770 FUNCTION_ENTER();
772 switch (target_state)
773 {
774 case WdfPowerDeviceD0:
775 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
776 break;
777 case WdfPowerDeviceD1:
778 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
779 break;
780 case WdfPowerDeviceD2:
781 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
782 break;
783 case WdfPowerDeviceD3:
784 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
785 break;
786 case WdfPowerDeviceD3Final:
787 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
788 break;
789 case WdfPowerDevicePrepareForHibernation:
790 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
791 break;
792 default:
793 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
794 break;
795 }
797 xpdd->balloon_shutdown = TRUE;
798 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
800 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
801 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
802 {
803 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
804 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
805 }
806 ObDereferenceObject(xpdd->balloon_thread);
808 XenBus_Halt(xpdd);
810 FUNCTION_EXIT();
812 return status;
813 }
815 NTSTATUS
816 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
817 {
818 NTSTATUS status = STATUS_SUCCESS;
819 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
821 FUNCTION_ENTER();
823 switch (target_state)
824 {
825 case WdfPowerDeviceD0:
826 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
827 break;
828 case WdfPowerDeviceD1:
829 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
830 break;
831 case WdfPowerDeviceD2:
832 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
833 break;
834 case WdfPowerDeviceD3:
835 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
836 break;
837 case WdfPowerDeviceD3Final:
838 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
839 break;
840 case WdfPowerDevicePrepareForHibernation:
841 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
842 xpdd->hibernated = TRUE;
843 break;
844 default:
845 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
846 break;
847 }
849 if (target_state == WdfPowerDevicePrepareForHibernation)
850 {
851 GntTbl_Suspend(xpdd);
852 }
854 FUNCTION_EXIT();
856 return status;
857 }
859 NTSTATUS
860 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
861 {
862 NTSTATUS status = STATUS_SUCCESS;
864 UNREFERENCED_PARAMETER(device);
865 UNREFERENCED_PARAMETER(resources_translated);
867 FUNCTION_ENTER();
868 FUNCTION_EXIT();
870 return status;
871 }
873 VOID
874 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
875 {
876 NTSTATUS status;
877 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
878 char *msg;
879 char **devices;
880 char **instances;
881 ULONG i, j;
882 CHAR path[128];
883 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
885 FUNCTION_ENTER();
887 WdfChildListBeginScan(child_list);
889 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
890 if (!msg)
891 {
892 for (i = 0; devices[i]; i++)
893 {
894 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
896 for (j = 0; j < WdfCollectionGetCount(xpdd->veto_devices); j++)
897 {
898 WDFOBJECT ws = WdfCollectionGetItem(xpdd->veto_devices, j);
899 UNICODE_STRING val;
900 ANSI_STRING s;
901 WdfStringGetUnicodeString(ws, &val);
902 RtlUnicodeStringToAnsiString(&s, &val, TRUE);
903 if (!strcmp(devices[i], s.Buffer))
904 {
905 RtlFreeAnsiString(&s);
906 break;
907 }
908 RtlFreeAnsiString(&s);
909 }
910 if (j < WdfCollectionGetCount(xpdd->veto_devices))
911 {
912 XenPci_FreeMem(devices[i]);
913 continue;
914 }
916 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
917 if (!msg)
918 {
919 for (j = 0; instances[j]; j++)
920 {
921 /* the device comparison is done as a memory compare so zero-ing the structure is important */
922 RtlZeroMemory(&child_description, sizeof(child_description));
923 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
924 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
925 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
926 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
927 child_description.index = atoi(instances[j]);
928 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
929 if (!NT_SUCCESS(status))
930 {
931 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
932 }
933 XenPci_FreeMem(instances[j]);
934 }
935 XenPci_FreeMem(instances);
936 }
937 else
938 {
939 // wtf do we do here???
940 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
941 }
942 XenPci_FreeMem(devices[i]);
943 }
944 XenPci_FreeMem(devices);
945 }
946 else
947 {
948 // wtf do we do here???
949 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
950 }
952 WdfChildListEndScan(child_list);
954 FUNCTION_EXIT();
955 }