win-pvdrivers

view xenpci/xenpci_fdo.c @ 641:4bb8c4fc6fa5

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