win-pvdrivers

view xenpci/xenpci_fdo.c @ 795:340f4430ab07

Fix compile error - XP doesn't support MmAllocatePagesForMdlEx
author James Harper <james.harper@bendigoit.com.au>
date Thu May 20 16:03:45 2010 +1000 (2010-05-20)
parents aee3767c191d
children 0be989e514c0
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??? can this happen??? */
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 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
311 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS, MmCached, MM_DONT_ZERO_ALLOCATION);
312 #else
313 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS);
314 #endif
315 if (!mdl)
316 {
317 KdPrint((__DRIVER_NAME " Allocation failed - try again in 1 second\n"));
318 break;
319 }
320 else
321 {
322 int i;
323 ULONG ret;
324 int pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
325 if (pfn_count != BALLOON_UNIT_PAGES)
326 {
327 /* we could probably do this better but it will only happen in low memory conditions... */
328 KdPrint((__DRIVER_NAME " wanted %d pages got %d pages\n", BALLOON_UNIT_PAGES, pfn_count));
329 MmFreePagesFromMdl(mdl);
330 ExFreePool(mdl);
331 break;
332 }
333 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
334 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
335 for (i = 0; i < pfn_count; i++)
336 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
337 reservation.address_bits = 0;
338 reservation.extent_order = 0;
339 reservation.domid = DOMID_SELF;
340 reservation.nr_extents = pfn_count;
341 #pragma warning(disable: 4127) /* conditional expression is constant */
342 set_xen_guest_handle(reservation.extent_start, pfns);
344 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_decrease_reservation) - pfn_count = %d\n", pfn_count));
345 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
346 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
347 KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
348 if (head)
349 {
350 mdl->Next = head;
351 head = mdl;
352 }
353 else
354 {
355 head = mdl;
356 }
357 xpdd->current_memory--;
358 }
359 }
360 }
361 }
362 //FUNCTION_EXIT();
363 }
365 static VOID
366 XenPci_BalloonHandler(char *Path, PVOID Data)
367 {
368 WDFDEVICE device = Data;
369 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
370 char *value;
371 xenbus_transaction_t xbt;
372 int retry;
374 UNREFERENCED_PARAMETER(Path);
376 FUNCTION_ENTER();
378 XenBus_StartTransaction(xpdd, &xbt);
380 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
382 if (value == NULL)
383 {
384 KdPrint((__DRIVER_NAME " Failed to read value\n"));
385 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
386 FUNCTION_EXIT();
387 return;
388 }
390 if (atoi(value) > 0)
391 xpdd->target_memory = atoi(value) >> 10; /* convert to MB */
393 KdPrint((__DRIVER_NAME " target memory value = %d (%s)\n", xpdd->target_memory, value));
395 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
397 XenPci_FreeMem(value);
399 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
401 FUNCTION_EXIT();
402 }
404 static VOID
405 XenPci_Suspend0(PVOID context)
406 {
407 PXENPCI_DEVICE_DATA xpdd = context;
408 ULONG cancelled;
410 FUNCTION_ENTER();
412 GntTbl_Suspend(xpdd);
414 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
415 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
417 if (qemu_hide_flags_value)
418 {
419 XenPci_HideQemuDevices();
420 }
422 XenPci_Resume(xpdd);
423 GntTbl_Resume(xpdd);
424 EvtChn_Resume(xpdd); /* this enables interrupts again too */
426 FUNCTION_EXIT();
427 }
429 static VOID
430 XenPci_SuspendN(PVOID context)
431 {
432 UNREFERENCED_PARAMETER(context);
434 FUNCTION_ENTER();
435 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
436 FUNCTION_EXIT();
437 }
439 static VOID
440 XenPci_SuspendEvtDpc(PVOID context);
441 static NTSTATUS
442 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
444 /* called at PASSIVE_LEVEL */
445 static NTSTATUS
446 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd)
447 {
448 CHAR path[128];
450 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
451 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
452 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
453 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
454 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device);
456 return STATUS_SUCCESS;
457 }
459 /* Called at PASSIVE_LEVEL */
460 static VOID DDKAPI
461 XenPci_SuspendResume(WDFWORKITEM workitem)
462 {
463 NTSTATUS status;
464 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
465 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
466 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
467 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
468 WDF_CHILD_LIST_ITERATOR child_iterator;
469 WDFDEVICE child_device;
471 FUNCTION_ENTER();
473 if (xpdd->suspend_state == SUSPEND_STATE_NONE)
474 {
475 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
476 KeMemoryBarrier();
478 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
479 WdfChildListBeginIteration(child_list, &child_iterator);
480 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
481 {
482 KdPrint((__DRIVER_NAME " Suspending child\n"));
483 XenPci_Pdo_Suspend(child_device);
484 }
485 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
486 WdfChildListEndIteration(child_list, &child_iterator);
488 XenBus_Suspend(xpdd);
489 EvtChn_Suspend(xpdd);
490 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
492 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
493 XenBus_Resume(xpdd);
495 XenPci_ConnectSuspendEvt(xpdd);
497 WdfChildListBeginIteration(child_list, &child_iterator);
498 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
499 {
500 KdPrint((__DRIVER_NAME " Resuming child\n"));
501 XenPci_Pdo_Resume(child_device);
502 }
503 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
504 WdfChildListEndIteration(child_list, &child_iterator);
506 xpdd->suspend_state = SUSPEND_STATE_NONE;
507 }
508 FUNCTION_EXIT();
509 }
511 /* called at DISPATCH_LEVEL */
512 static VOID
513 XenPci_SuspendEvtDpc(PVOID context)
514 {
515 NTSTATUS status;
516 WDFDEVICE device = context;
517 //KIRQL old_irql;
518 WDF_OBJECT_ATTRIBUTES attributes;
519 WDF_WORKITEM_CONFIG workitem_config;
520 WDFWORKITEM workitem;
522 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
523 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
524 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
525 attributes.ParentObject = device;
526 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
527 // TODO: check status here
528 WdfWorkItemEnqueue(workitem);
529 }
531 static void
532 XenPci_ShutdownHandler(char *path, PVOID context)
533 {
534 NTSTATUS status;
535 WDFDEVICE device = context;
536 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
537 char *res;
538 char *value;
539 //KIRQL old_irql;
540 WDF_OBJECT_ATTRIBUTES attributes;
541 WDF_WORKITEM_CONFIG workitem_config;
542 WDFWORKITEM workitem;
544 UNREFERENCED_PARAMETER(path);
546 FUNCTION_ENTER();
548 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
549 if (res)
550 {
551 KdPrint(("Error reading shutdown path - %s\n", res));
552 XenPci_FreeMem(res);
553 FUNCTION_EXIT();
554 return;
555 }
557 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
559 if (strlen(value) && strcmp(value, "suspend") == 0)
560 {
561 {
562 KdPrint((__DRIVER_NAME " Suspend detected\n"));
563 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
564 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
565 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
566 attributes.ParentObject = device;
567 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
568 // TODO: check status here
569 WdfWorkItemEnqueue(workitem);
570 }
571 }
573 XenPci_FreeMem(value);
575 FUNCTION_EXIT();
576 }
578 static VOID
579 XenPci_DeviceWatchHandler(char *path, PVOID context)
580 {
581 char **bits;
582 int count;
583 char *err;
584 char *value;
585 PXENPCI_DEVICE_DATA xpdd = context;
587 FUNCTION_ENTER();
589 bits = SplitString(path, '/', 4, &count);
590 if (count == 3)
591 {
592 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
593 if (err)
594 {
595 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
596 XenPci_FreeMem(err);
597 }
598 else
599 {
600 XenPci_FreeMem(value);
601 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
602 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
603 XenPci_EvtChildListScanForChildren(xpdd->child_list);
604 }
605 }
606 FreeSplitString(bits, count);
608 FUNCTION_EXIT();
609 }
611 NTSTATUS
612 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
613 {
614 NTSTATUS status = STATUS_SUCCESS;
615 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
616 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
617 ULONG i;
619 FUNCTION_ENTER();
621 ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
623 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
624 {
625 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
626 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
627 switch (raw_descriptor->Type) {
628 case CmResourceTypePort:
629 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
630 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
631 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
632 break;
633 case CmResourceTypeMemory:
634 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));
635 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
636 #if 0
637 mmio_freelist_free = 0;
638 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
639 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
640 #endif
641 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
642 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
643 xpdd->platform_mmio_flags = translated_descriptor->Flags;
644 break;
645 case CmResourceTypeInterrupt:
646 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
647 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
648 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
649 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
650 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
651 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
652 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
653 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
654 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
655 switch(translated_descriptor->ShareDisposition)
656 {
657 case CmResourceShareDeviceExclusive:
658 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
659 break;
660 case CmResourceShareDriverExclusive:
661 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
662 break;
663 case CmResourceShareShared:
664 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
665 break;
666 default:
667 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
668 break;
669 }
670 break;
671 case CmResourceTypeDevicePrivate:
672 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]));
673 break;
674 default:
675 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
676 break;
677 }
678 }
680 FUNCTION_EXIT();
682 return status;
683 }
685 NTSTATUS
686 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
687 {
688 NTSTATUS status = STATUS_SUCCESS;
689 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
690 ULONG i;
691 ULONG ret;
693 FUNCTION_ENTER();
695 xpdd->hibernated = FALSE;
696 switch (previous_state)
697 {
698 case WdfPowerDeviceD0:
699 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
700 break;
701 case WdfPowerDeviceD1:
702 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
703 break;
704 case WdfPowerDeviceD2:
705 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
706 break;
707 case WdfPowerDeviceD3:
708 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
709 break;
710 case WdfPowerDeviceD3Final:
711 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
712 break;
713 case WdfPowerDevicePrepareForHibernation:
714 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
715 break;
716 default:
717 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
718 break;
719 }
721 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value)
722 {
723 XenPci_HideQemuDevices();
724 }
726 if (previous_state == WdfPowerDeviceD3Final)
727 {
728 XenPci_Init(xpdd);
729 if (tpr_patch_requested && !xpdd->tpr_patched)
730 {
731 XenPci_MapHalThenPatchKernel(xpdd);
732 xpdd->tpr_patched = TRUE;
733 }
734 GntTbl_Init(xpdd);
735 EvtChn_Init(xpdd);
737 for (i = 0; i < NR_GRANT_FRAMES + 1; i++)
738 {
739 struct xen_memory_reservation reservation;
740 xen_pfn_t pfn;
741 PMDL mdl = AllocatePage();
742 pfn = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[0]);
743 reservation.address_bits = 0;
744 reservation.extent_order = 0;
745 reservation.domid = DOMID_SELF;
746 reservation.nr_extents = 1;
747 #pragma warning(disable: 4127) /* conditional expression is constant */
748 set_xen_guest_handle(reservation.extent_start, &pfn);
750 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
751 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
752 //KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
753 }
755 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
756 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
757 }
758 else
759 {
760 XenPci_Resume(xpdd);
761 GntTbl_Resume(xpdd);
762 EvtChn_Resume(xpdd);
763 }
765 FUNCTION_EXIT();
767 return status;
768 }
770 NTSTATUS
771 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
772 {
773 NTSTATUS status = STATUS_SUCCESS;
774 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
775 PCHAR response;
776 char *value;
777 domid_t domid = DOMID_SELF;
778 ULONG ret;
779 xen_ulong_t *max_ram_page;
780 HANDLE thread_handle;
782 UNREFERENCED_PARAMETER(previous_state);
784 FUNCTION_ENTER();
786 if (previous_state == WdfPowerDeviceD3Final)
787 {
788 XenBus_Init(xpdd);
790 XenPci_ConnectSuspendEvt(xpdd);
792 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
794 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
796 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
798 ret = HYPERVISOR_memory_op(xpdd, XENMEM_current_reservation, &domid);
799 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
800 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_reservation, &domid);
801 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
802 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_ram_page, &max_ram_page);
803 KdPrint((__DRIVER_NAME " XENMEM_maximum_ram_page = %d\n", ret));
805 if (!xpdd->initial_memory)
806 {
807 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
808 if (atoi(value) > 0)
809 {
810 xpdd->initial_memory = atoi(value) >> 10; /* convert to MB */
811 xpdd->current_memory = xpdd->initial_memory;
812 xpdd->target_memory = xpdd->initial_memory;
813 }
814 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory, value));
815 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
816 xpdd->balloon_shutdown = FALSE;
817 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
818 if (!NT_SUCCESS(status))
819 {
820 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
821 return status;
822 }
823 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
824 ZwClose(thread_handle);
825 }
826 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
827 }
828 else
829 {
830 XenBus_Resume(xpdd);
831 XenPci_ConnectSuspendEvt(xpdd);
832 }
833 FUNCTION_EXIT();
835 return status;
836 }
838 NTSTATUS
839 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
840 {
841 NTSTATUS status = STATUS_SUCCESS;
842 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
843 LARGE_INTEGER timeout;
845 FUNCTION_ENTER();
847 switch (target_state)
848 {
849 case WdfPowerDeviceD0:
850 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
851 break;
852 case WdfPowerDeviceD1:
853 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
854 break;
855 case WdfPowerDeviceD2:
856 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
857 break;
858 case WdfPowerDeviceD3:
859 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
860 break;
861 case WdfPowerDeviceD3Final:
862 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
863 break;
864 case WdfPowerDevicePrepareForHibernation:
865 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
866 break;
867 default:
868 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
869 break;
870 }
872 if (target_state == WdfPowerDeviceD3Final)
873 {
874 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
876 xpdd->balloon_shutdown = TRUE;
877 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
879 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
880 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
881 {
882 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
883 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
884 }
885 ObDereferenceObject(xpdd->balloon_thread);
887 XenBus_Halt(xpdd);
888 }
889 else
890 {
891 XenBus_Suspend(xpdd);
892 }
894 FUNCTION_EXIT();
896 return status;
897 }
899 NTSTATUS
900 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
901 {
902 NTSTATUS status = STATUS_SUCCESS;
903 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
905 FUNCTION_ENTER();
907 switch (target_state)
908 {
909 case WdfPowerDeviceD0:
910 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
911 break;
912 case WdfPowerDeviceD1:
913 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
914 break;
915 case WdfPowerDeviceD2:
916 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
917 break;
918 case WdfPowerDeviceD3:
919 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
920 break;
921 case WdfPowerDeviceD3Final:
922 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
923 break;
924 case WdfPowerDevicePrepareForHibernation:
925 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
926 xpdd->hibernated = TRUE;
927 break;
928 default:
929 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
930 break;
931 }
933 if (target_state == WdfPowerDeviceD3Final)
934 {
935 /* we don't really support exit here */
936 }
937 else
938 {
939 GntTbl_Suspend(xpdd);
940 }
942 FUNCTION_EXIT();
944 return status;
945 }
947 NTSTATUS
948 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
949 {
950 NTSTATUS status = STATUS_SUCCESS;
952 UNREFERENCED_PARAMETER(device);
953 UNREFERENCED_PARAMETER(resources_translated);
955 FUNCTION_ENTER();
956 FUNCTION_EXIT();
958 return status;
959 }
961 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
962 /* Can be called concurrently, but KMDF takes care of concurrent calls to WdfChildListXxx */
963 VOID
964 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
965 {
966 NTSTATUS status;
967 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
968 char *msg;
969 char **devices;
970 char **instances;
971 ULONG i, j;
972 CHAR path[128];
973 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
974 PVOID entry;
976 FUNCTION_ENTER();
978 WdfChildListBeginScan(child_list);
980 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
981 if (!msg)
982 {
983 for (i = 0; devices[i]; i++)
984 {
985 /* make sure the key is not in the veto list */
986 for (entry = xpdd->veto_list.Flink; entry != &xpdd->veto_list; entry = ((PLIST_ENTRY)entry)->Flink)
987 {
988 if (!strcmp(devices[i], (PCHAR)entry + sizeof(LIST_ENTRY)))
989 break;
990 }
991 if (entry != &xpdd->veto_list)
992 {
993 XenPci_FreeMem(devices[i]);
994 continue;
995 }
997 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
998 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
999 if (!msg)
1001 for (j = 0; instances[j]; j++)
1003 /* the device comparison is done as a memory compare so zero-ing the structure is important */
1004 RtlZeroMemory(&child_description, sizeof(child_description));
1005 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
1006 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
1007 KdPrint((__DRIVER_NAME " Found path = %s\n", path));
1008 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
1009 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
1010 child_description.index = atoi(instances[j]);
1011 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
1012 if (!NT_SUCCESS(status))
1014 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
1016 XenPci_FreeMem(instances[j]);
1018 XenPci_FreeMem(instances);
1020 else
1022 // wtf do we do here???
1023 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
1025 XenPci_FreeMem(devices[i]);
1027 XenPci_FreeMem(devices);
1029 else
1031 // wtf do we do here???
1032 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
1035 WdfChildListEndScan(child_list);
1037 FUNCTION_EXIT();