win-pvdrivers

view xenpci/xenpci_fdo.c @ 804:6ea80e94e8cf

Added tag 0.11.0.218 for changeset bbc6c94b9621
author James Harper <james.harper@bendigoit.com.au>
date Sun Jun 27 16:15:21 2010 +1000 (2010-06-27)
parents bbc6c94b9621
children ff77e2f26a3e
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 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
312 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS, MmCached, 0);
313 #else
314 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS);
315 #endif
316 if (!mdl)
317 {
318 KdPrint((__DRIVER_NAME " Allocation failed - try again in 1 second\n"));
319 break;
320 }
321 else
322 {
323 int i;
324 ULONG ret;
325 int pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
326 if (pfn_count != BALLOON_UNIT_PAGES)
327 {
328 /* we could probably do this better but it will only happen in low memory conditions... */
329 KdPrint((__DRIVER_NAME " wanted %d pages got %d pages\n", BALLOON_UNIT_PAGES, pfn_count));
330 MmFreePagesFromMdl(mdl);
331 ExFreePool(mdl);
332 break;
333 }
334 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
335 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
336 for (i = 0; i < pfn_count; i++)
337 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
338 reservation.address_bits = 0;
339 reservation.extent_order = 0;
340 reservation.domid = DOMID_SELF;
341 reservation.nr_extents = pfn_count;
342 #pragma warning(disable: 4127) /* conditional expression is constant */
343 set_xen_guest_handle(reservation.extent_start, pfns);
345 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_decrease_reservation) - pfn_count = %d\n", pfn_count));
346 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
347 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
348 KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
349 if (head)
350 {
351 mdl->Next = head;
352 head = mdl;
353 }
354 else
355 {
356 head = mdl;
357 }
358 xpdd->current_memory--;
359 }
360 }
361 }
362 }
363 //FUNCTION_EXIT();
364 }
366 static VOID
367 XenPci_BalloonHandler(char *Path, PVOID Data)
368 {
369 WDFDEVICE device = Data;
370 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
371 char *value;
372 xenbus_transaction_t xbt;
373 int retry;
375 UNREFERENCED_PARAMETER(Path);
377 FUNCTION_ENTER();
379 XenBus_StartTransaction(xpdd, &xbt);
381 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
383 if (value == NULL)
384 {
385 KdPrint((__DRIVER_NAME " Failed to read value\n"));
386 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
387 FUNCTION_EXIT();
388 return;
389 }
391 if (atoi(value) > 0)
392 xpdd->target_memory = atoi(value) >> 10; /* convert to MB */
394 KdPrint((__DRIVER_NAME " target memory value = %d (%s)\n", xpdd->target_memory, value));
396 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
398 XenPci_FreeMem(value);
400 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
402 FUNCTION_EXIT();
403 }
405 static VOID
406 XenPci_Suspend0(PVOID context)
407 {
408 PXENPCI_DEVICE_DATA xpdd = context;
409 ULONG cancelled;
411 FUNCTION_ENTER();
413 GntTbl_Suspend(xpdd);
415 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
416 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
418 if (qemu_hide_flags_value)
419 {
420 XenPci_HideQemuDevices();
421 }
423 XenPci_Resume(xpdd);
424 GntTbl_Resume(xpdd);
425 EvtChn_Resume(xpdd); /* this enables interrupts again too */
427 FUNCTION_EXIT();
428 }
430 static VOID
431 XenPci_SuspendN(PVOID context)
432 {
433 UNREFERENCED_PARAMETER(context);
435 FUNCTION_ENTER();
436 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
437 FUNCTION_EXIT();
438 }
440 static VOID
441 XenPci_SuspendEvtDpc(PVOID context);
442 static NTSTATUS
443 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
445 /* called at PASSIVE_LEVEL */
446 static NTSTATUS
447 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd)
448 {
449 CHAR path[128];
451 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
452 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
453 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
454 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
455 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device);
457 return STATUS_SUCCESS;
458 }
460 /* Called at PASSIVE_LEVEL */
461 static VOID DDKAPI
462 XenPci_SuspendResume(WDFWORKITEM workitem)
463 {
464 NTSTATUS status;
465 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
466 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
467 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
468 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
469 WDF_CHILD_LIST_ITERATOR child_iterator;
470 WDFDEVICE child_device;
472 FUNCTION_ENTER();
474 if (xpdd->suspend_state == SUSPEND_STATE_NONE)
475 {
476 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
477 KeMemoryBarrier();
479 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
480 WdfChildListBeginIteration(child_list, &child_iterator);
481 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
482 {
483 KdPrint((__DRIVER_NAME " Suspending child\n"));
484 XenPci_Pdo_Suspend(child_device);
485 }
486 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
487 WdfChildListEndIteration(child_list, &child_iterator);
489 XenBus_Suspend(xpdd);
490 EvtChn_Suspend(xpdd);
491 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
493 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
494 XenBus_Resume(xpdd);
496 XenPci_ConnectSuspendEvt(xpdd);
498 WdfChildListBeginIteration(child_list, &child_iterator);
499 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
500 {
501 KdPrint((__DRIVER_NAME " Resuming child\n"));
502 XenPci_Pdo_Resume(child_device);
503 }
504 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
505 WdfChildListEndIteration(child_list, &child_iterator);
507 xpdd->suspend_state = SUSPEND_STATE_NONE;
508 }
509 FUNCTION_EXIT();
510 }
512 /* called at DISPATCH_LEVEL */
513 static VOID
514 XenPci_SuspendEvtDpc(PVOID context)
515 {
516 NTSTATUS status;
517 WDFDEVICE device = context;
518 //KIRQL old_irql;
519 WDF_OBJECT_ATTRIBUTES attributes;
520 WDF_WORKITEM_CONFIG workitem_config;
521 WDFWORKITEM workitem;
523 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
524 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
525 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
526 attributes.ParentObject = device;
527 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
528 // TODO: check status here
529 WdfWorkItemEnqueue(workitem);
530 }
532 static void
533 XenPci_ShutdownHandler(char *path, PVOID context)
534 {
535 NTSTATUS status;
536 WDFDEVICE device = context;
537 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
538 char *res;
539 char *value;
540 //KIRQL old_irql;
541 WDF_OBJECT_ATTRIBUTES attributes;
542 WDF_WORKITEM_CONFIG workitem_config;
543 WDFWORKITEM workitem;
545 UNREFERENCED_PARAMETER(path);
547 FUNCTION_ENTER();
549 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
550 if (res)
551 {
552 KdPrint(("Error reading shutdown path - %s\n", res));
553 XenPci_FreeMem(res);
554 FUNCTION_EXIT();
555 return;
556 }
558 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
560 if (strlen(value) && strcmp(value, "suspend") == 0)
561 {
562 {
563 KdPrint((__DRIVER_NAME " Suspend detected\n"));
564 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
565 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
566 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
567 attributes.ParentObject = device;
568 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
569 // TODO: check status here
570 WdfWorkItemEnqueue(workitem);
571 }
572 }
574 XenPci_FreeMem(value);
576 FUNCTION_EXIT();
577 }
579 static VOID
580 XenPci_DeviceWatchHandler(char *path, PVOID context)
581 {
582 char **bits;
583 int count;
584 char *err;
585 char *value;
586 PXENPCI_DEVICE_DATA xpdd = context;
588 FUNCTION_ENTER();
590 bits = SplitString(path, '/', 4, &count);
591 if (count == 3)
592 {
593 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
594 if (err)
595 {
596 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
597 XenPci_FreeMem(err);
598 }
599 else
600 {
601 XenPci_FreeMem(value);
602 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
603 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
604 XenPci_EvtChildListScanForChildren(xpdd->child_list);
605 }
606 }
607 FreeSplitString(bits, count);
609 FUNCTION_EXIT();
610 }
612 NTSTATUS
613 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
614 {
615 NTSTATUS status = STATUS_SUCCESS;
616 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
617 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
618 ULONG i;
620 FUNCTION_ENTER();
622 ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
624 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
625 {
626 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
627 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
628 switch (raw_descriptor->Type) {
629 case CmResourceTypePort:
630 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
631 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
632 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
633 break;
634 case CmResourceTypeMemory:
635 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));
636 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
637 #if 0
638 mmio_freelist_free = 0;
639 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
640 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
641 #endif
642 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
643 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
644 xpdd->platform_mmio_flags = translated_descriptor->Flags;
645 break;
646 case CmResourceTypeInterrupt:
647 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
648 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
649 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
650 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
651 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
652 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
653 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
654 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
655 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
656 switch(translated_descriptor->ShareDisposition)
657 {
658 case CmResourceShareDeviceExclusive:
659 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
660 break;
661 case CmResourceShareDriverExclusive:
662 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
663 break;
664 case CmResourceShareShared:
665 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
666 break;
667 default:
668 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
669 break;
670 }
671 break;
672 case CmResourceTypeDevicePrivate:
673 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]));
674 break;
675 default:
676 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
677 break;
678 }
679 }
681 FUNCTION_EXIT();
683 return status;
684 }
686 NTSTATUS
687 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
688 {
689 NTSTATUS status = STATUS_SUCCESS;
690 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
691 ULONG i;
692 ULONG ret;
694 FUNCTION_ENTER();
696 xpdd->hibernated = FALSE;
697 switch (previous_state)
698 {
699 case WdfPowerDeviceD0:
700 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
701 break;
702 case WdfPowerDeviceD1:
703 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
704 break;
705 case WdfPowerDeviceD2:
706 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
707 break;
708 case WdfPowerDeviceD3:
709 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
710 break;
711 case WdfPowerDeviceD3Final:
712 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
713 break;
714 case WdfPowerDevicePrepareForHibernation:
715 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
716 break;
717 default:
718 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
719 break;
720 }
722 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value)
723 {
724 XenPci_HideQemuDevices();
725 }
727 if (previous_state == WdfPowerDeviceD3Final)
728 {
729 XenPci_Init(xpdd);
730 if (tpr_patch_requested && !xpdd->tpr_patched)
731 {
732 XenPci_MapHalThenPatchKernel(xpdd);
733 xpdd->tpr_patched = TRUE;
734 }
735 GntTbl_Init(xpdd);
736 EvtChn_Init(xpdd);
738 for (i = 0; i < NR_GRANT_FRAMES + 1; i++)
739 {
740 struct xen_memory_reservation reservation;
741 xen_pfn_t pfn;
742 PMDL mdl = AllocatePage();
743 pfn = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[0]);
744 reservation.address_bits = 0;
745 reservation.extent_order = 0;
746 reservation.domid = DOMID_SELF;
747 reservation.nr_extents = 1;
748 #pragma warning(disable: 4127) /* conditional expression is constant */
749 set_xen_guest_handle(reservation.extent_start, &pfn);
751 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
752 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
753 //KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
754 }
756 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
757 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
758 }
759 else
760 {
761 XenPci_Resume(xpdd);
762 GntTbl_Resume(xpdd);
763 EvtChn_Resume(xpdd);
764 }
766 FUNCTION_EXIT();
768 return status;
769 }
771 NTSTATUS
772 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
773 {
774 NTSTATUS status = STATUS_SUCCESS;
775 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
776 PCHAR response;
777 char *value;
778 domid_t domid = DOMID_SELF;
779 ULONG ret;
780 xen_ulong_t *max_ram_page;
781 HANDLE thread_handle;
783 UNREFERENCED_PARAMETER(previous_state);
785 FUNCTION_ENTER();
787 if (previous_state == WdfPowerDeviceD3Final)
788 {
789 XenBus_Init(xpdd);
791 XenPci_ConnectSuspendEvt(xpdd);
793 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
795 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
797 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
799 ret = HYPERVISOR_memory_op(xpdd, XENMEM_current_reservation, &domid);
800 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
801 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_reservation, &domid);
802 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
803 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_ram_page, &max_ram_page);
804 KdPrint((__DRIVER_NAME " XENMEM_maximum_ram_page = %d\n", ret));
806 if (!xpdd->initial_memory)
807 {
808 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
809 if (atoi(value) > 0)
810 {
811 xpdd->initial_memory = atoi(value) >> 10; /* convert to MB */
812 xpdd->current_memory = xpdd->initial_memory;
813 xpdd->target_memory = xpdd->initial_memory;
814 }
815 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory, value));
816 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
817 xpdd->balloon_shutdown = FALSE;
818 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
819 if (!NT_SUCCESS(status))
820 {
821 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
822 return status;
823 }
824 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
825 ZwClose(thread_handle);
826 }
827 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
828 }
829 else
830 {
831 XenBus_Resume(xpdd);
832 XenPci_ConnectSuspendEvt(xpdd);
833 }
834 FUNCTION_EXIT();
836 return status;
837 }
839 NTSTATUS
840 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
841 {
842 NTSTATUS status = STATUS_SUCCESS;
843 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
844 LARGE_INTEGER timeout;
846 FUNCTION_ENTER();
848 switch (target_state)
849 {
850 case WdfPowerDeviceD0:
851 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
852 break;
853 case WdfPowerDeviceD1:
854 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
855 break;
856 case WdfPowerDeviceD2:
857 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
858 break;
859 case WdfPowerDeviceD3:
860 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
861 break;
862 case WdfPowerDeviceD3Final:
863 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
864 break;
865 case WdfPowerDevicePrepareForHibernation:
866 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
867 break;
868 default:
869 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
870 break;
871 }
873 if (target_state == WdfPowerDeviceD3Final)
874 {
875 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
877 xpdd->balloon_shutdown = TRUE;
878 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
880 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
881 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
882 {
883 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
884 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
885 }
886 ObDereferenceObject(xpdd->balloon_thread);
888 XenBus_Halt(xpdd);
889 }
890 else
891 {
892 XenBus_Suspend(xpdd);
893 }
895 FUNCTION_EXIT();
897 return status;
898 }
900 NTSTATUS
901 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
902 {
903 NTSTATUS status = STATUS_SUCCESS;
904 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
906 FUNCTION_ENTER();
908 switch (target_state)
909 {
910 case WdfPowerDeviceD0:
911 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
912 break;
913 case WdfPowerDeviceD1:
914 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
915 break;
916 case WdfPowerDeviceD2:
917 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
918 break;
919 case WdfPowerDeviceD3:
920 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
921 break;
922 case WdfPowerDeviceD3Final:
923 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
924 break;
925 case WdfPowerDevicePrepareForHibernation:
926 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
927 xpdd->hibernated = TRUE;
928 break;
929 default:
930 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
931 break;
932 }
934 if (target_state == WdfPowerDeviceD3Final)
935 {
936 /* we don't really support exit here */
937 }
938 else
939 {
940 GntTbl_Suspend(xpdd);
941 }
943 FUNCTION_EXIT();
945 return status;
946 }
948 NTSTATUS
949 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
950 {
951 NTSTATUS status = STATUS_SUCCESS;
953 UNREFERENCED_PARAMETER(device);
954 UNREFERENCED_PARAMETER(resources_translated);
956 FUNCTION_ENTER();
957 FUNCTION_EXIT();
959 return status;
960 }
962 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
963 /* Can be called concurrently, but KMDF takes care of concurrent calls to WdfChildListXxx */
964 VOID
965 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
966 {
967 NTSTATUS status;
968 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
969 char *msg;
970 char **devices;
971 char **instances;
972 ULONG i, j;
973 CHAR path[128];
974 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
975 PVOID entry;
976 WDFDEVICE child_device;
977 WDF_CHILD_RETRIEVE_INFO retrieve_info;
979 FUNCTION_ENTER();
981 WdfChildListBeginScan(child_list);
983 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
984 if (!msg)
985 {
986 for (i = 0; devices[i]; i++)
987 {
988 /* make sure the key is not in the veto list */
989 for (entry = xpdd->veto_list.Flink; entry != &xpdd->veto_list; entry = ((PLIST_ENTRY)entry)->Flink)
990 {
991 if (!strcmp(devices[i], (PCHAR)entry + sizeof(LIST_ENTRY)))
992 break;
993 }
994 if (entry != &xpdd->veto_list)
995 {
996 XenPci_FreeMem(devices[i]);
997 continue;
998 }
1000 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
1001 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
1002 if (!msg)
1004 for (j = 0; instances[j]; j++)
1006 /* the device comparison is done as a memory compare so zero-ing the structure is important */
1007 RtlZeroMemory(&child_description, sizeof(child_description));
1008 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
1009 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
1010 KdPrint((__DRIVER_NAME " Found path = %s\n", path));
1011 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
1012 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
1013 child_description.index = atoi(instances[j]);
1014 WDF_CHILD_RETRIEVE_INFO_INIT(&retrieve_info, &child_description.header);
1015 child_device = WdfChildListRetrievePdo(child_list, &retrieve_info);
1016 if (child_device)
1018 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(child_device);
1019 char *err;
1020 char *value;
1021 char backend_state_path[128];
1023 if (xppdd->do_not_enumerate)
1025 RtlStringCbPrintfA(backend_state_path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
1027 err = XenBus_Read(xpdd, XBT_NIL, backend_state_path, &value);
1028 if (err)
1030 XenPci_FreeMem(err);
1031 xppdd->backend_state = XenbusStateUnknown;
1033 else
1035 xppdd->backend_state = atoi(value);
1036 XenPci_FreeMem(value);
1038 if (xppdd->backend_state == XenbusStateClosing || xppdd->backend_state == XenbusStateClosed)
1040 KdPrint((__DRIVER_NAME " Surprise removing %s due to backend initiated remove\n", path));
1041 XenPci_FreeMem(instances[j]);
1042 continue;
1044 else
1046 /* I guess we are being added again ... */
1047 xppdd->backend_initiated_remove = FALSE;
1048 xppdd->do_not_enumerate = FALSE;
1052 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
1053 if (!NT_SUCCESS(status))
1055 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
1057 XenPci_FreeMem(instances[j]);
1059 XenPci_FreeMem(instances);
1061 else
1063 // wtf do we do here???
1064 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
1066 XenPci_FreeMem(devices[i]);
1068 XenPci_FreeMem(devices);
1070 else
1072 // wtf do we do here???
1073 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
1076 WdfChildListEndScan(child_list);
1078 FUNCTION_EXIT();