win-pvdrivers

view xenpci/xenpci_fdo.c @ 747:f43c89df09b2

Big changes to the way the device hiding works. Should fix the way Vista and above need a reboot into safe mode after install.
author James Harper <james.harper@bendigoit.com.au>
date Sun Jan 10 10:07:32 2010 +1100 (2010-01-10)
parents 5bdb7251370c
children 467005e7f509
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;
33 static VOID
34 XenPci_MapHalThenPatchKernel(PXENPCI_DEVICE_DATA xpdd)
35 {
36 NTSTATUS status;
37 PAUX_MODULE_EXTENDED_INFO amei;
38 ULONG module_info_buffer_size;
39 ULONG i;
41 FUNCTION_ENTER();
43 amei = NULL;
44 /* buffer size could change between requesting and allocating - need to loop until we are successful */
45 while ((status = AuxKlibQueryModuleInformation(&module_info_buffer_size, sizeof(AUX_MODULE_EXTENDED_INFO), amei)) == STATUS_BUFFER_TOO_SMALL || amei == NULL)
46 {
47 if (amei != NULL)
48 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
49 amei = ExAllocatePoolWithTag(NonPagedPool, module_info_buffer_size, XENPCI_POOL_TAG);
50 }
52 KdPrint((__DRIVER_NAME " AuxKlibQueryModuleInformation = %d\n", status));
53 for (i = 0; i < module_info_buffer_size / sizeof(AUX_MODULE_EXTENDED_INFO); i++)
54 {
55 if (strcmp((PCHAR)amei[i].FullPathName + amei[i].FileNameOffset, "hal.dll") == 0)
56 {
57 KdPrint((__DRIVER_NAME " hal.dll found at %p - %p\n",
58 amei[i].BasicInfo.ImageBase,
59 ((PUCHAR)amei[i].BasicInfo.ImageBase) + amei[i].ImageSize));
60 XenPci_PatchKernel(xpdd, amei[i].BasicInfo.ImageBase, amei[i].ImageSize);
61 }
62 }
63 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
64 FUNCTION_EXIT();
65 }
67 /*
68 * Alloc MMIO from the device's MMIO region. There is no corresponding free() fn
69 */
70 PHYSICAL_ADDRESS
71 XenPci_AllocMMIO(PXENPCI_DEVICE_DATA xpdd, ULONG len)
72 {
73 PHYSICAL_ADDRESS addr;
75 len = (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
77 addr = xpdd->platform_mmio_addr;
78 addr.QuadPart += xpdd->platform_mmio_alloc;
79 xpdd->platform_mmio_alloc += len;
81 ASSERT(xpdd->platform_mmio_alloc <= xpdd->platform_mmio_len);
83 return addr;
84 }
86 extern ULONG tpr_patch_requested;
88 NTSTATUS
89 XenPci_EvtDeviceQueryRemove(WDFDEVICE device)
90 {
91 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
92 NTSTATUS status;
94 FUNCTION_ENTER();
95 if (xpdd->removable)
96 status = STATUS_SUCCESS;
97 else
98 status = STATUS_UNSUCCESSFUL;
99 FUNCTION_EXIT();
100 return status;
101 }
103 static NTSTATUS
104 XenPci_Init(PXENPCI_DEVICE_DATA xpdd)
105 {
106 NTSTATUS status;
107 struct xen_add_to_physmap xatp;
108 int ret;
110 FUNCTION_ENTER();
112 status = hvm_get_stubs(xpdd);
113 if (!NT_SUCCESS(status))
114 return status;
116 if (!xpdd->shared_info_area)
117 {
118 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
119 /* this should be safe as this part will never be called on resume where IRQL == HIGH_LEVEL */
120 xpdd->shared_info_area_unmapped = XenPci_AllocMMIO(xpdd, PAGE_SIZE);
121 xpdd->shared_info_area = MmMapIoSpace(xpdd->shared_info_area_unmapped,
122 PAGE_SIZE, MmNonCached);
123 }
124 KdPrint((__DRIVER_NAME " shared_info_area_unmapped.QuadPart = %lx\n", xpdd->shared_info_area_unmapped.QuadPart));
125 xatp.domid = DOMID_SELF;
126 xatp.idx = 0;
127 xatp.space = XENMAPSPACE_shared_info;
128 xatp.gpfn = (xen_pfn_t)(xpdd->shared_info_area_unmapped.QuadPart >> PAGE_SHIFT);
129 KdPrint((__DRIVER_NAME " gpfn = %x\n", xatp.gpfn));
130 ret = HYPERVISOR_memory_op(xpdd, XENMEM_add_to_physmap, &xatp);
131 KdPrint((__DRIVER_NAME " hypervisor memory op (XENMAPSPACE_shared_info) ret = %d\n", ret));
133 FUNCTION_EXIT();
135 return STATUS_SUCCESS;
136 }
138 static NTSTATUS
139 XenPci_Resume(PXENPCI_DEVICE_DATA xpdd)
140 {
141 return XenPci_Init(xpdd);
142 }
144 static VOID
145 XenPci_SysrqHandler(char *path, PVOID context)
146 {
147 PXENPCI_DEVICE_DATA xpdd = context;
148 char *value;
149 char letter;
150 char *res;
152 UNREFERENCED_PARAMETER(path);
154 FUNCTION_ENTER();
156 XenBus_Read(xpdd, XBT_NIL, SYSRQ_PATH, &value);
158 KdPrint((__DRIVER_NAME " SysRq Value = %s\n", value));
160 if (value != NULL && strlen(value) != 0)
161 {
162 letter = *value;
163 res = XenBus_Write(xpdd, XBT_NIL, SYSRQ_PATH, "");
164 if (res)
165 {
166 KdPrint(("Error writing sysrq path\n"));
167 XenPci_FreeMem(res);
168 return;
169 }
170 }
171 else
172 {
173 letter = 0;
174 }
176 if (value != NULL)
177 {
178 XenPci_FreeMem(value);
179 }
181 switch (letter)
182 {
183 case 0:
184 break;
185 case 'B': /* cause a bug check */
186 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000001, 0x00000000, 0x00000000, 0x00000000);
187 break;
188 case 'A': /* cause an assert */
189 ASSERT(1 == 0);
190 break;
191 default:
192 KdPrint((" Unhandled sysrq letter %c\n", letter));
193 break;
194 }
196 FUNCTION_EXIT();
197 }
199 #if 0
200 static VOID
201 XenPci_PrintPendingInterrupts()
202 {
203 PULONG bitmap = (PULONG)0xFFFE0200;
204 int i;
205 int j;
206 ULONG value;
208 for (i = 0; i < 8; i++)
209 {
210 value = bitmap[(7 - i) * 4];
211 if (value)
212 {
213 for (j = 0; j < 32; j++)
214 {
215 if ((value >> j) & 1)
216 KdPrint((" Interrupt pending on pin %d\n", ((7 - i) << 5) | j));
217 }
218 }
219 }
220 }
221 #endif
223 #define BALLOON_UNIT_PAGES (BALLOON_UNITS >> PAGE_SHIFT)
225 static VOID
226 XenPci_BalloonThreadProc(PVOID StartContext)
227 {
228 PXENPCI_DEVICE_DATA xpdd = StartContext;
229 ULONG new_target = xpdd->current_memory;
230 LARGE_INTEGER timeout;
231 PLARGE_INTEGER ptimeout;
232 PMDL head = NULL;
233 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
234 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
236 FUNCTION_ENTER();
238 for(;;)
239 {
240 if (xpdd->current_memory != new_target)
241 {
242 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
243 ptimeout = &timeout;
244 }
245 else
246 {
247 ptimeout = NULL;
248 }
249 KeWaitForSingleObject(&xpdd->balloon_event, Executive, KernelMode, FALSE, ptimeout);
250 if (xpdd->balloon_shutdown)
251 PsTerminateSystemThread(0);
252 KdPrint((__DRIVER_NAME " Got balloon event, current = %d, target = %d\n", xpdd->current_memory, xpdd->target_memory));
253 /* not really worried about races here, but cache target so we only read it once */
254 new_target = xpdd->target_memory;
255 // perform some sanity checks on target_memory
256 // make sure target <= initial
257 // make sure target > some % of initial
259 if (xpdd->current_memory == new_target)
260 {
261 KdPrint((__DRIVER_NAME " No change to memory\n"));
262 continue;
263 }
264 else if (xpdd->current_memory < new_target)
265 {
266 PMDL mdl;
267 KdPrint((__DRIVER_NAME " Trying to take %d MB from Xen\n", new_target - xpdd->current_memory));
268 while ((mdl = head) != NULL && xpdd->current_memory < new_target)
269 {
270 head = mdl->Next;
271 mdl->Next = NULL;
272 MmFreePagesFromMdl(mdl);
273 ExFreePool(mdl);
274 xpdd->current_memory++;
275 }
276 }
277 else
278 {
279 KdPrint((__DRIVER_NAME " Trying to give %d MB to Xen\n", xpdd->current_memory - new_target));
280 while (xpdd->current_memory > new_target)
281 {
282 PHYSICAL_ADDRESS alloc_low;
283 PHYSICAL_ADDRESS alloc_high;
284 PHYSICAL_ADDRESS alloc_skip;
285 PMDL mdl;
286 alloc_low.QuadPart = 0;
287 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
288 alloc_skip.QuadPart = 0;
289 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS);
290 if (!mdl)
291 {
292 KdPrint((__DRIVER_NAME " Allocation failed - try again in 1 second\n"));
293 break;
294 }
295 else
296 {
297 if (head)
298 {
299 mdl->Next = head;
300 head = mdl;
301 }
302 else
303 {
304 head = mdl;
305 }
306 xpdd->current_memory--;
307 }
308 }
309 }
310 }
311 //FUNCTION_EXIT();
312 }
314 static VOID
315 XenPci_BalloonHandler(char *Path, PVOID Data)
316 {
317 WDFDEVICE device = Data;
318 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
319 char *value;
320 xenbus_transaction_t xbt;
321 int retry;
323 UNREFERENCED_PARAMETER(Path);
325 FUNCTION_ENTER();
327 XenBus_StartTransaction(xpdd, &xbt);
329 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
331 if (value == NULL)
332 {
333 KdPrint((__DRIVER_NAME " Failed to read value\n"));
334 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
335 FUNCTION_EXIT();
336 return;
337 }
339 if (atoi(value) > 0)
340 xpdd->target_memory = atoi(value) >> 10; /* convert to MB */
342 KdPrint((__DRIVER_NAME " target memory value = %d (%s)\n", xpdd->target_memory, value));
344 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
346 XenPci_FreeMem(value);
348 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
350 FUNCTION_EXIT();
351 }
353 static VOID
354 XenPci_Suspend0(PVOID context)
355 {
356 PXENPCI_DEVICE_DATA xpdd = context;
357 ULONG cancelled;
359 FUNCTION_ENTER();
361 GntTbl_Suspend(xpdd);
363 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
364 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
366 if (qemu_hide_flags_value)
367 {
368 XenPci_HideQemuDevices();
369 }
371 XenPci_Resume(xpdd);
372 GntTbl_Resume(xpdd);
373 EvtChn_Resume(xpdd); /* this enables interrupts again too */
375 FUNCTION_EXIT();
376 }
378 static VOID
379 XenPci_SuspendN(PVOID context)
380 {
381 UNREFERENCED_PARAMETER(context);
383 FUNCTION_ENTER();
384 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
385 FUNCTION_EXIT();
386 }
388 static VOID
389 XenPci_SuspendEvtDpc(PVOID context);
390 static NTSTATUS
391 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
393 /* called at PASSIVE_LEVEL */
394 static NTSTATUS
395 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd)
396 {
397 CHAR path[128];
399 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
400 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
401 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
402 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
403 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device);
405 return STATUS_SUCCESS;
406 }
408 /* Called at PASSIVE_LEVEL */
409 static VOID DDKAPI
410 XenPci_SuspendResume(WDFWORKITEM workitem)
411 {
412 NTSTATUS status;
413 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
414 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
415 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
416 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
417 WDF_CHILD_LIST_ITERATOR child_iterator;
418 WDFDEVICE child_device;
420 FUNCTION_ENTER();
422 if (xpdd->suspend_state == SUSPEND_STATE_NONE)
423 {
424 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
425 KeMemoryBarrier();
427 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
428 WdfChildListBeginIteration(child_list, &child_iterator);
429 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
430 {
431 KdPrint((__DRIVER_NAME " Suspending child\n"));
432 XenPci_Pdo_Suspend(child_device);
433 }
434 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
435 WdfChildListEndIteration(child_list, &child_iterator);
437 XenBus_Suspend(xpdd);
438 EvtChn_Suspend(xpdd);
439 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
441 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
442 XenBus_Resume(xpdd);
444 XenPci_ConnectSuspendEvt(xpdd);
446 WdfChildListBeginIteration(child_list, &child_iterator);
447 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
448 {
449 KdPrint((__DRIVER_NAME " Resuming child\n"));
450 XenPci_Pdo_Resume(child_device);
451 }
452 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
453 WdfChildListEndIteration(child_list, &child_iterator);
455 xpdd->suspend_state = SUSPEND_STATE_NONE;
456 }
457 FUNCTION_EXIT();
458 }
460 /* called at DISPATCH_LEVEL */
461 static VOID
462 XenPci_SuspendEvtDpc(PVOID context)
463 {
464 NTSTATUS status;
465 WDFDEVICE device = context;
466 //KIRQL old_irql;
467 WDF_OBJECT_ATTRIBUTES attributes;
468 WDF_WORKITEM_CONFIG workitem_config;
469 WDFWORKITEM workitem;
471 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
472 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
473 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
474 attributes.ParentObject = device;
475 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
476 // TODO: check status here
477 WdfWorkItemEnqueue(workitem);
478 }
480 static void
481 XenPci_ShutdownHandler(char *path, PVOID context)
482 {
483 NTSTATUS status;
484 WDFDEVICE device = context;
485 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
486 char *res;
487 char *value;
488 //KIRQL old_irql;
489 WDF_OBJECT_ATTRIBUTES attributes;
490 WDF_WORKITEM_CONFIG workitem_config;
491 WDFWORKITEM workitem;
493 UNREFERENCED_PARAMETER(path);
495 FUNCTION_ENTER();
497 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
498 if (res)
499 {
500 KdPrint(("Error reading shutdown path - %s\n", res));
501 XenPci_FreeMem(res);
502 FUNCTION_EXIT();
503 return;
504 }
506 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
508 if (strlen(value) && strcmp(value, "suspend") == 0)
509 {
510 {
511 KdPrint((__DRIVER_NAME " Suspend detected\n"));
512 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
513 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
514 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
515 attributes.ParentObject = device;
516 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
517 // TODO: check status here
518 WdfWorkItemEnqueue(workitem);
519 }
520 }
522 XenPci_FreeMem(value);
524 FUNCTION_EXIT();
525 }
527 static VOID
528 XenPci_DeviceWatchHandler(char *path, PVOID context)
529 {
530 char **bits;
531 int count;
532 char *err;
533 char *value;
534 PXENPCI_DEVICE_DATA xpdd = context;
536 FUNCTION_ENTER();
538 bits = SplitString(path, '/', 4, &count);
539 if (count == 3)
540 {
541 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
542 if (err)
543 {
544 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
545 XenPci_FreeMem(err);
546 }
547 else
548 {
549 XenPci_FreeMem(value);
550 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
551 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
552 XenPci_EvtChildListScanForChildren(xpdd->child_list);
553 }
554 }
555 FreeSplitString(bits, count);
557 FUNCTION_EXIT();
558 }
560 NTSTATUS
561 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
562 {
563 NTSTATUS status = STATUS_SUCCESS;
564 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
565 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
566 ULONG i;
568 FUNCTION_ENTER();
570 ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
572 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
573 {
574 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
575 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
576 switch (raw_descriptor->Type) {
577 case CmResourceTypePort:
578 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
579 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
580 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
581 break;
582 case CmResourceTypeMemory:
583 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));
584 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
585 #if 0
586 mmio_freelist_free = 0;
587 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
588 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
589 #endif
590 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
591 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
592 xpdd->platform_mmio_flags = translated_descriptor->Flags;
593 break;
594 case CmResourceTypeInterrupt:
595 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
596 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
597 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
598 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
599 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
600 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
601 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
602 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
603 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
604 switch(translated_descriptor->ShareDisposition)
605 {
606 case CmResourceShareDeviceExclusive:
607 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
608 break;
609 case CmResourceShareDriverExclusive:
610 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
611 break;
612 case CmResourceShareShared:
613 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
614 break;
615 default:
616 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
617 break;
618 }
619 break;
620 case CmResourceTypeDevicePrivate:
621 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]));
622 break;
623 default:
624 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
625 break;
626 }
627 }
629 FUNCTION_EXIT();
631 return status;
632 }
634 NTSTATUS
635 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
636 {
637 NTSTATUS status = STATUS_SUCCESS;
638 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
639 ULONG i;
640 ULONG ret;
642 FUNCTION_ENTER();
644 xpdd->hibernated = FALSE;
645 switch (previous_state)
646 {
647 case WdfPowerDeviceD0:
648 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
649 break;
650 case WdfPowerDeviceD1:
651 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
652 break;
653 case WdfPowerDeviceD2:
654 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
655 break;
656 case WdfPowerDeviceD3:
657 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
658 break;
659 case WdfPowerDeviceD3Final:
660 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
661 break;
662 case WdfPowerDevicePrepareForHibernation:
663 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
664 break;
665 default:
666 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
667 break;
668 }
670 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value)
671 {
672 XenPci_HideQemuDevices();
673 }
675 if (previous_state == WdfPowerDeviceD3Final)
676 {
677 XenPci_Init(xpdd);
678 if (tpr_patch_requested && !xpdd->tpr_patched)
679 {
680 XenPci_MapHalThenPatchKernel(xpdd);
681 xpdd->tpr_patched = TRUE;
682 }
683 GntTbl_Init(xpdd);
684 EvtChn_Init(xpdd);
686 for (i = 0; i < NR_GRANT_FRAMES + 1; i++)
687 {
688 struct xen_memory_reservation reservation;
689 xen_pfn_t pfn;
690 PMDL mdl = AllocatePage();
691 pfn = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[0]);
692 reservation.address_bits = 0;
693 reservation.extent_order = 0;
694 reservation.domid = DOMID_SELF;
695 reservation.nr_extents = 1;
696 #pragma warning(disable: 4127) /* conditional expression is constant */
697 set_xen_guest_handle(reservation.extent_start, &pfn);
699 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
700 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
701 //KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
702 }
704 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
705 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
706 }
707 else
708 {
709 XenPci_Resume(xpdd);
710 GntTbl_Resume(xpdd);
711 EvtChn_Resume(xpdd);
712 }
714 FUNCTION_EXIT();
716 return status;
717 }
719 NTSTATUS
720 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
721 {
722 NTSTATUS status = STATUS_SUCCESS;
723 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
724 PCHAR response;
725 char *value;
726 domid_t domid = DOMID_SELF;
727 ULONG ret;
728 xen_ulong_t *max_ram_page;
729 HANDLE thread_handle;
731 UNREFERENCED_PARAMETER(previous_state);
733 FUNCTION_ENTER();
735 if (previous_state == WdfPowerDeviceD3Final)
736 {
737 XenBus_Init(xpdd);
739 XenPci_ConnectSuspendEvt(xpdd);
741 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
743 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
745 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
747 ret = HYPERVISOR_memory_op(xpdd, XENMEM_current_reservation, &domid);
748 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
749 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_reservation, &domid);
750 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
751 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_ram_page, &max_ram_page);
752 KdPrint((__DRIVER_NAME " XENMEM_maximum_ram_page = %d\n", ret));
754 if (!xpdd->initial_memory)
755 {
756 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
757 if (atoi(value) > 0)
758 {
759 xpdd->initial_memory = atoi(value) >> 10; /* convert to MB */
760 xpdd->current_memory = xpdd->initial_memory;
761 xpdd->target_memory = xpdd->initial_memory;
762 }
763 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory, value));
764 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
765 xpdd->balloon_shutdown = FALSE;
766 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
767 if (!NT_SUCCESS(status))
768 {
769 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
770 return status;
771 }
772 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
773 ZwClose(thread_handle);
774 }
775 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
776 }
777 else
778 {
779 XenBus_Resume(xpdd);
780 XenPci_ConnectSuspendEvt(xpdd);
781 }
782 FUNCTION_EXIT();
784 return status;
785 }
787 NTSTATUS
788 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
789 {
790 NTSTATUS status = STATUS_SUCCESS;
791 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
792 LARGE_INTEGER timeout;
794 FUNCTION_ENTER();
796 switch (target_state)
797 {
798 case WdfPowerDeviceD0:
799 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
800 break;
801 case WdfPowerDeviceD1:
802 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
803 break;
804 case WdfPowerDeviceD2:
805 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
806 break;
807 case WdfPowerDeviceD3:
808 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
809 break;
810 case WdfPowerDeviceD3Final:
811 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
812 break;
813 case WdfPowerDevicePrepareForHibernation:
814 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
815 break;
816 default:
817 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
818 break;
819 }
821 if (target_state == WdfPowerDeviceD3Final)
822 {
823 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
825 xpdd->balloon_shutdown = TRUE;
826 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
828 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
829 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
830 {
831 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
832 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
833 }
834 ObDereferenceObject(xpdd->balloon_thread);
836 XenBus_Halt(xpdd);
837 }
838 else
839 {
840 XenBus_Suspend(xpdd);
841 }
843 FUNCTION_EXIT();
845 return status;
846 }
848 NTSTATUS
849 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
850 {
851 NTSTATUS status = STATUS_SUCCESS;
852 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
854 FUNCTION_ENTER();
856 switch (target_state)
857 {
858 case WdfPowerDeviceD0:
859 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
860 break;
861 case WdfPowerDeviceD1:
862 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
863 break;
864 case WdfPowerDeviceD2:
865 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
866 break;
867 case WdfPowerDeviceD3:
868 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
869 break;
870 case WdfPowerDeviceD3Final:
871 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
872 break;
873 case WdfPowerDevicePrepareForHibernation:
874 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
875 xpdd->hibernated = TRUE;
876 break;
877 default:
878 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
879 break;
880 }
882 if (target_state == WdfPowerDeviceD3Final)
883 {
884 /* we don't really support exit here */
885 }
886 else
887 {
888 GntTbl_Suspend(xpdd);
889 }
891 FUNCTION_EXIT();
893 return status;
894 }
896 NTSTATUS
897 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
898 {
899 NTSTATUS status = STATUS_SUCCESS;
901 UNREFERENCED_PARAMETER(device);
902 UNREFERENCED_PARAMETER(resources_translated);
904 FUNCTION_ENTER();
905 FUNCTION_EXIT();
907 return status;
908 }
910 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
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 }