win-pvdrivers

view xenpci/xenpci_fdo.c @ 794:aee3767c191d

Complete implementation of ballooning. Not well tested yet.
author James Harper <james.harper@bendigoit.com.au>
date Thu May 20 15:49:59 2010 +1000 (2010-05-20)
parents 467005e7f509
children 340f4430ab07
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 PMDL mdl;
233 struct xen_memory_reservation reservation;
234 xen_pfn_t *pfns;
235 int i;
236 ULONG ret;
237 int pfn_count;
239 FUNCTION_ENTER();
241 for(;;)
242 {
243 /* wait for 1 second if we have adjustments to make, or forever if we don't */
244 if (xpdd->current_memory != new_target)
245 {
246 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
247 ptimeout = &timeout;
248 }
249 else
250 {
251 ptimeout = NULL;
252 }
253 KeWaitForSingleObject(&xpdd->balloon_event, Executive, KernelMode, FALSE, ptimeout);
254 if (xpdd->balloon_shutdown)
255 PsTerminateSystemThread(0);
256 KdPrint((__DRIVER_NAME " Got balloon event, current = %d, target = %d\n", xpdd->current_memory, xpdd->target_memory));
257 /* not really worried about races here, but cache target so we only read it once */
258 new_target = xpdd->target_memory;
259 // perform some sanity checks on target_memory
260 // make sure target <= initial
261 // make sure target > some % of initial
263 if (xpdd->current_memory == new_target)
264 {
265 KdPrint((__DRIVER_NAME " No change to memory\n"));
266 continue;
267 }
268 else if (xpdd->current_memory < new_target)
269 {
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;
276 pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
277 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
278 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
279 for (i = 0; i < pfn_count; i++)
280 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
281 reservation.address_bits = 0;
282 reservation.extent_order = 0;
283 reservation.domid = DOMID_SELF;
284 reservation.nr_extents = pfn_count;
285 #pragma warning(disable: 4127) /* conditional expression is constant */
286 set_xen_guest_handle(reservation.extent_start, pfns);
288 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_populate_physmap) - pfn_count = %d\n", pfn_count));
289 ret = HYPERVISOR_memory_op(xpdd, XENMEM_populate_physmap, &reservation);
290 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
291 KdPrint((__DRIVER_NAME " populated %d pages\n", ret));
292 /* TODO: what do we do if less than the required number of pages were populated??? */
294 MmFreePagesFromMdl(mdl);
295 ExFreePool(mdl);
296 xpdd->current_memory++;
297 }
298 }
299 else
300 {
301 KdPrint((__DRIVER_NAME " Trying to give %d MB to Xen\n", xpdd->current_memory - new_target));
302 while (xpdd->current_memory > new_target)
303 {
304 PHYSICAL_ADDRESS alloc_low;
305 PHYSICAL_ADDRESS alloc_high;
306 PHYSICAL_ADDRESS alloc_skip;
307 alloc_low.QuadPart = 0;
308 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
309 alloc_skip.QuadPart = 0;
310 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS, MmCached, MM_DONT_ZERO_ALLOCATION);
311 if (!mdl)
312 {
313 KdPrint((__DRIVER_NAME " Allocation failed - try again in 1 second\n"));
314 break;
315 }
316 else
317 {
318 int i;
319 ULONG ret;
320 int pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
321 if (pfn_count != BALLOON_UNIT_PAGES)
322 {
323 /* we could probably do this better but it will only happen in low memory conditions... */
324 KdPrint((__DRIVER_NAME " wanted %d pages got %d pages\n", BALLOON_UNIT_PAGES, pfn_count));
325 MmFreePagesFromMdl(mdl);
326 ExFreePool(mdl);
327 break;
328 }
329 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
330 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
331 for (i = 0; i < pfn_count; i++)
332 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
333 reservation.address_bits = 0;
334 reservation.extent_order = 0;
335 reservation.domid = DOMID_SELF;
336 reservation.nr_extents = pfn_count;
337 #pragma warning(disable: 4127) /* conditional expression is constant */
338 set_xen_guest_handle(reservation.extent_start, pfns);
340 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_decrease_reservation) - pfn_count = %d\n", pfn_count));
341 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
342 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
343 KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
344 if (head)
345 {
346 mdl->Next = head;
347 head = mdl;
348 }
349 else
350 {
351 head = mdl;
352 }
353 xpdd->current_memory--;
354 }
355 }
356 }
357 }
358 //FUNCTION_EXIT();
359 }
361 static VOID
362 XenPci_BalloonHandler(char *Path, PVOID Data)
363 {
364 WDFDEVICE device = Data;
365 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
366 char *value;
367 xenbus_transaction_t xbt;
368 int retry;
370 UNREFERENCED_PARAMETER(Path);
372 FUNCTION_ENTER();
374 XenBus_StartTransaction(xpdd, &xbt);
376 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
378 if (value == NULL)
379 {
380 KdPrint((__DRIVER_NAME " Failed to read value\n"));
381 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
382 FUNCTION_EXIT();
383 return;
384 }
386 if (atoi(value) > 0)
387 xpdd->target_memory = atoi(value) >> 10; /* convert to MB */
389 KdPrint((__DRIVER_NAME " target memory value = %d (%s)\n", xpdd->target_memory, value));
391 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
393 XenPci_FreeMem(value);
395 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
397 FUNCTION_EXIT();
398 }
400 static VOID
401 XenPci_Suspend0(PVOID context)
402 {
403 PXENPCI_DEVICE_DATA xpdd = context;
404 ULONG cancelled;
406 FUNCTION_ENTER();
408 GntTbl_Suspend(xpdd);
410 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
411 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
413 if (qemu_hide_flags_value)
414 {
415 XenPci_HideQemuDevices();
416 }
418 XenPci_Resume(xpdd);
419 GntTbl_Resume(xpdd);
420 EvtChn_Resume(xpdd); /* this enables interrupts again too */
422 FUNCTION_EXIT();
423 }
425 static VOID
426 XenPci_SuspendN(PVOID context)
427 {
428 UNREFERENCED_PARAMETER(context);
430 FUNCTION_ENTER();
431 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
432 FUNCTION_EXIT();
433 }
435 static VOID
436 XenPci_SuspendEvtDpc(PVOID context);
437 static NTSTATUS
438 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
440 /* called at PASSIVE_LEVEL */
441 static NTSTATUS
442 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd)
443 {
444 CHAR path[128];
446 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
447 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
448 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
449 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
450 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device);
452 return STATUS_SUCCESS;
453 }
455 /* Called at PASSIVE_LEVEL */
456 static VOID DDKAPI
457 XenPci_SuspendResume(WDFWORKITEM workitem)
458 {
459 NTSTATUS status;
460 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
461 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
462 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
463 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
464 WDF_CHILD_LIST_ITERATOR child_iterator;
465 WDFDEVICE child_device;
467 FUNCTION_ENTER();
469 if (xpdd->suspend_state == SUSPEND_STATE_NONE)
470 {
471 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
472 KeMemoryBarrier();
474 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
475 WdfChildListBeginIteration(child_list, &child_iterator);
476 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
477 {
478 KdPrint((__DRIVER_NAME " Suspending child\n"));
479 XenPci_Pdo_Suspend(child_device);
480 }
481 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
482 WdfChildListEndIteration(child_list, &child_iterator);
484 XenBus_Suspend(xpdd);
485 EvtChn_Suspend(xpdd);
486 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
488 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
489 XenBus_Resume(xpdd);
491 XenPci_ConnectSuspendEvt(xpdd);
493 WdfChildListBeginIteration(child_list, &child_iterator);
494 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
495 {
496 KdPrint((__DRIVER_NAME " Resuming child\n"));
497 XenPci_Pdo_Resume(child_device);
498 }
499 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
500 WdfChildListEndIteration(child_list, &child_iterator);
502 xpdd->suspend_state = SUSPEND_STATE_NONE;
503 }
504 FUNCTION_EXIT();
505 }
507 /* called at DISPATCH_LEVEL */
508 static VOID
509 XenPci_SuspendEvtDpc(PVOID context)
510 {
511 NTSTATUS status;
512 WDFDEVICE device = context;
513 //KIRQL old_irql;
514 WDF_OBJECT_ATTRIBUTES attributes;
515 WDF_WORKITEM_CONFIG workitem_config;
516 WDFWORKITEM workitem;
518 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
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 }
527 static void
528 XenPci_ShutdownHandler(char *path, PVOID context)
529 {
530 NTSTATUS status;
531 WDFDEVICE device = context;
532 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
533 char *res;
534 char *value;
535 //KIRQL old_irql;
536 WDF_OBJECT_ATTRIBUTES attributes;
537 WDF_WORKITEM_CONFIG workitem_config;
538 WDFWORKITEM workitem;
540 UNREFERENCED_PARAMETER(path);
542 FUNCTION_ENTER();
544 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
545 if (res)
546 {
547 KdPrint(("Error reading shutdown path - %s\n", res));
548 XenPci_FreeMem(res);
549 FUNCTION_EXIT();
550 return;
551 }
553 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
555 if (strlen(value) && strcmp(value, "suspend") == 0)
556 {
557 {
558 KdPrint((__DRIVER_NAME " Suspend detected\n"));
559 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
560 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
561 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
562 attributes.ParentObject = device;
563 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
564 // TODO: check status here
565 WdfWorkItemEnqueue(workitem);
566 }
567 }
569 XenPci_FreeMem(value);
571 FUNCTION_EXIT();
572 }
574 static VOID
575 XenPci_DeviceWatchHandler(char *path, PVOID context)
576 {
577 char **bits;
578 int count;
579 char *err;
580 char *value;
581 PXENPCI_DEVICE_DATA xpdd = context;
583 FUNCTION_ENTER();
585 bits = SplitString(path, '/', 4, &count);
586 if (count == 3)
587 {
588 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
589 if (err)
590 {
591 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
592 XenPci_FreeMem(err);
593 }
594 else
595 {
596 XenPci_FreeMem(value);
597 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
598 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
599 XenPci_EvtChildListScanForChildren(xpdd->child_list);
600 }
601 }
602 FreeSplitString(bits, count);
604 FUNCTION_EXIT();
605 }
607 NTSTATUS
608 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
609 {
610 NTSTATUS status = STATUS_SUCCESS;
611 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
612 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
613 ULONG i;
615 FUNCTION_ENTER();
617 ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
619 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
620 {
621 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
622 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
623 switch (raw_descriptor->Type) {
624 case CmResourceTypePort:
625 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
626 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
627 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
628 break;
629 case CmResourceTypeMemory:
630 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));
631 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
632 #if 0
633 mmio_freelist_free = 0;
634 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
635 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
636 #endif
637 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
638 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
639 xpdd->platform_mmio_flags = translated_descriptor->Flags;
640 break;
641 case CmResourceTypeInterrupt:
642 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
643 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
644 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
645 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
646 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
647 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
648 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
649 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
650 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
651 switch(translated_descriptor->ShareDisposition)
652 {
653 case CmResourceShareDeviceExclusive:
654 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
655 break;
656 case CmResourceShareDriverExclusive:
657 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
658 break;
659 case CmResourceShareShared:
660 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
661 break;
662 default:
663 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
664 break;
665 }
666 break;
667 case CmResourceTypeDevicePrivate:
668 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]));
669 break;
670 default:
671 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
672 break;
673 }
674 }
676 FUNCTION_EXIT();
678 return status;
679 }
681 NTSTATUS
682 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
683 {
684 NTSTATUS status = STATUS_SUCCESS;
685 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
686 ULONG i;
687 ULONG ret;
689 FUNCTION_ENTER();
691 xpdd->hibernated = FALSE;
692 switch (previous_state)
693 {
694 case WdfPowerDeviceD0:
695 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
696 break;
697 case WdfPowerDeviceD1:
698 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
699 break;
700 case WdfPowerDeviceD2:
701 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
702 break;
703 case WdfPowerDeviceD3:
704 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
705 break;
706 case WdfPowerDeviceD3Final:
707 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
708 break;
709 case WdfPowerDevicePrepareForHibernation:
710 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
711 break;
712 default:
713 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
714 break;
715 }
717 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value)
718 {
719 XenPci_HideQemuDevices();
720 }
722 if (previous_state == WdfPowerDeviceD3Final)
723 {
724 XenPci_Init(xpdd);
725 if (tpr_patch_requested && !xpdd->tpr_patched)
726 {
727 XenPci_MapHalThenPatchKernel(xpdd);
728 xpdd->tpr_patched = TRUE;
729 }
730 GntTbl_Init(xpdd);
731 EvtChn_Init(xpdd);
733 for (i = 0; i < NR_GRANT_FRAMES + 1; i++)
734 {
735 struct xen_memory_reservation reservation;
736 xen_pfn_t pfn;
737 PMDL mdl = AllocatePage();
738 pfn = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[0]);
739 reservation.address_bits = 0;
740 reservation.extent_order = 0;
741 reservation.domid = DOMID_SELF;
742 reservation.nr_extents = 1;
743 #pragma warning(disable: 4127) /* conditional expression is constant */
744 set_xen_guest_handle(reservation.extent_start, &pfn);
746 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
747 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
748 //KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
749 }
751 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
752 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
753 }
754 else
755 {
756 XenPci_Resume(xpdd);
757 GntTbl_Resume(xpdd);
758 EvtChn_Resume(xpdd);
759 }
761 FUNCTION_EXIT();
763 return status;
764 }
766 NTSTATUS
767 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
768 {
769 NTSTATUS status = STATUS_SUCCESS;
770 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
771 PCHAR response;
772 char *value;
773 domid_t domid = DOMID_SELF;
774 ULONG ret;
775 xen_ulong_t *max_ram_page;
776 HANDLE thread_handle;
778 UNREFERENCED_PARAMETER(previous_state);
780 FUNCTION_ENTER();
782 if (previous_state == WdfPowerDeviceD3Final)
783 {
784 XenBus_Init(xpdd);
786 XenPci_ConnectSuspendEvt(xpdd);
788 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
790 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
792 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
794 ret = HYPERVISOR_memory_op(xpdd, XENMEM_current_reservation, &domid);
795 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
796 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_reservation, &domid);
797 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
798 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_ram_page, &max_ram_page);
799 KdPrint((__DRIVER_NAME " XENMEM_maximum_ram_page = %d\n", ret));
801 if (!xpdd->initial_memory)
802 {
803 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
804 if (atoi(value) > 0)
805 {
806 xpdd->initial_memory = atoi(value) >> 10; /* convert to MB */
807 xpdd->current_memory = xpdd->initial_memory;
808 xpdd->target_memory = xpdd->initial_memory;
809 }
810 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory, value));
811 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
812 xpdd->balloon_shutdown = FALSE;
813 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
814 if (!NT_SUCCESS(status))
815 {
816 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
817 return status;
818 }
819 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
820 ZwClose(thread_handle);
821 }
822 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
823 }
824 else
825 {
826 XenBus_Resume(xpdd);
827 XenPci_ConnectSuspendEvt(xpdd);
828 }
829 FUNCTION_EXIT();
831 return status;
832 }
834 NTSTATUS
835 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
836 {
837 NTSTATUS status = STATUS_SUCCESS;
838 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
839 LARGE_INTEGER timeout;
841 FUNCTION_ENTER();
843 switch (target_state)
844 {
845 case WdfPowerDeviceD0:
846 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
847 break;
848 case WdfPowerDeviceD1:
849 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
850 break;
851 case WdfPowerDeviceD2:
852 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
853 break;
854 case WdfPowerDeviceD3:
855 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
856 break;
857 case WdfPowerDeviceD3Final:
858 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
859 break;
860 case WdfPowerDevicePrepareForHibernation:
861 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
862 break;
863 default:
864 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
865 break;
866 }
868 if (target_state == WdfPowerDeviceD3Final)
869 {
870 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
872 xpdd->balloon_shutdown = TRUE;
873 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
875 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
876 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
877 {
878 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
879 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
880 }
881 ObDereferenceObject(xpdd->balloon_thread);
883 XenBus_Halt(xpdd);
884 }
885 else
886 {
887 XenBus_Suspend(xpdd);
888 }
890 FUNCTION_EXIT();
892 return status;
893 }
895 NTSTATUS
896 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
897 {
898 NTSTATUS status = STATUS_SUCCESS;
899 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
901 FUNCTION_ENTER();
903 switch (target_state)
904 {
905 case WdfPowerDeviceD0:
906 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
907 break;
908 case WdfPowerDeviceD1:
909 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
910 break;
911 case WdfPowerDeviceD2:
912 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
913 break;
914 case WdfPowerDeviceD3:
915 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
916 break;
917 case WdfPowerDeviceD3Final:
918 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
919 break;
920 case WdfPowerDevicePrepareForHibernation:
921 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
922 xpdd->hibernated = TRUE;
923 break;
924 default:
925 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
926 break;
927 }
929 if (target_state == WdfPowerDeviceD3Final)
930 {
931 /* we don't really support exit here */
932 }
933 else
934 {
935 GntTbl_Suspend(xpdd);
936 }
938 FUNCTION_EXIT();
940 return status;
941 }
943 NTSTATUS
944 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
945 {
946 NTSTATUS status = STATUS_SUCCESS;
948 UNREFERENCED_PARAMETER(device);
949 UNREFERENCED_PARAMETER(resources_translated);
951 FUNCTION_ENTER();
952 FUNCTION_EXIT();
954 return status;
955 }
957 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
958 /* Can be called concurrently, but KMDF takes care of concurrent calls to WdfChildListXxx */
959 VOID
960 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
961 {
962 NTSTATUS status;
963 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
964 char *msg;
965 char **devices;
966 char **instances;
967 ULONG i, j;
968 CHAR path[128];
969 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
970 PVOID entry;
972 FUNCTION_ENTER();
974 WdfChildListBeginScan(child_list);
976 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
977 if (!msg)
978 {
979 for (i = 0; devices[i]; i++)
980 {
981 /* make sure the key is not in the veto list */
982 for (entry = xpdd->veto_list.Flink; entry != &xpdd->veto_list; entry = ((PLIST_ENTRY)entry)->Flink)
983 {
984 if (!strcmp(devices[i], (PCHAR)entry + sizeof(LIST_ENTRY)))
985 break;
986 }
987 if (entry != &xpdd->veto_list)
988 {
989 XenPci_FreeMem(devices[i]);
990 continue;
991 }
993 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
994 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
995 if (!msg)
996 {
997 for (j = 0; instances[j]; j++)
998 {
999 /* the device comparison is done as a memory compare so zero-ing the structure is important */
1000 RtlZeroMemory(&child_description, sizeof(child_description));
1001 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
1002 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
1003 KdPrint((__DRIVER_NAME " Found path = %s\n", path));
1004 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
1005 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
1006 child_description.index = atoi(instances[j]);
1007 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
1008 if (!NT_SUCCESS(status))
1010 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
1012 XenPci_FreeMem(instances[j]);
1014 XenPci_FreeMem(instances);
1016 else
1018 // wtf do we do here???
1019 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
1021 XenPci_FreeMem(devices[i]);
1023 XenPci_FreeMem(devices);
1025 else
1027 // wtf do we do here???
1028 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
1031 WdfChildListEndScan(child_list);
1033 FUNCTION_EXIT();