win-pvdrivers

view xenpci/xenpci_fdo.c @ 1022:cd72cd0e1c19

hooking debug doesn't survive hibernate under win8. Remove it.
Remove initial balloon down - doesn't work under xen 4.2 without xenbus being loaded
author James Harper <james.harper@bendigoit.com.au>
date Tue Feb 19 15:11:49 2013 +1100 (2013-02-19)
parents 9e076343bb8e
children 37c0c84a42e8
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 //extern PMDL balloon_mdl_head;
30 /* Not really necessary but keeps PREfast happy */
31 static EVT_WDF_WORKITEM XenPci_SuspendResume;
32 #if (VER_PRODUCTBUILD >= 7600)
33 static KSTART_ROUTINE XenPci_BalloonThreadProc;
34 #endif
36 static VOID
37 XenPci_MapHalThenPatchKernel(PXENPCI_DEVICE_DATA xpdd)
38 {
39 NTSTATUS status;
40 PAUX_MODULE_EXTENDED_INFO amei;
41 ULONG module_info_buffer_size;
42 ULONG i;
44 FUNCTION_ENTER();
46 amei = NULL;
47 /* buffer size could change between requesting and allocating - need to loop until we are successful */
48 while ((status = AuxKlibQueryModuleInformation(&module_info_buffer_size, sizeof(AUX_MODULE_EXTENDED_INFO), amei)) == STATUS_BUFFER_TOO_SMALL || amei == NULL)
49 {
50 if (amei != NULL)
51 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
52 amei = ExAllocatePoolWithTag(NonPagedPool, module_info_buffer_size, XENPCI_POOL_TAG);
53 }
55 KdPrint((__DRIVER_NAME " AuxKlibQueryModuleInformation = %d\n", status));
56 for (i = 0; i < module_info_buffer_size / sizeof(AUX_MODULE_EXTENDED_INFO); i++)
57 {
58 if (strcmp((PCHAR)amei[i].FullPathName + amei[i].FileNameOffset, "hal.dll") == 0)
59 {
60 KdPrint((__DRIVER_NAME " hal.dll found at %p - %p\n",
61 amei[i].BasicInfo.ImageBase,
62 ((PUCHAR)amei[i].BasicInfo.ImageBase) + amei[i].ImageSize));
63 XenPci_PatchKernel(xpdd, amei[i].BasicInfo.ImageBase, amei[i].ImageSize);
64 }
65 }
66 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
67 FUNCTION_EXIT();
68 }
70 /*
71 * Alloc MMIO from the device's MMIO region. There is no corresponding free() fn
72 */
73 PHYSICAL_ADDRESS
74 XenPci_AllocMMIO(PXENPCI_DEVICE_DATA xpdd, ULONG len)
75 {
76 PHYSICAL_ADDRESS addr;
78 len = (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
80 addr = xpdd->platform_mmio_addr;
81 addr.QuadPart += xpdd->platform_mmio_alloc;
82 xpdd->platform_mmio_alloc += len;
84 XN_ASSERT(xpdd->platform_mmio_alloc <= xpdd->platform_mmio_len);
86 return addr;
87 }
89 extern ULONG tpr_patch_requested;
91 NTSTATUS
92 XenPci_EvtDeviceQueryRemove(WDFDEVICE device)
93 {
94 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
95 NTSTATUS status;
97 FUNCTION_ENTER();
98 if (xpdd->removable)
99 status = STATUS_SUCCESS;
100 else
101 status = STATUS_UNSUCCESSFUL;
102 FUNCTION_EXIT();
103 return status;
104 }
106 static NTSTATUS
107 XenPci_Init(PXENPCI_DEVICE_DATA xpdd)
108 {
109 struct xen_add_to_physmap xatp;
110 int ret;
112 FUNCTION_ENTER();
114 if (!xpdd->hypercall_stubs)
115 {
116 XN_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
117 xpdd->hypercall_stubs = hvm_get_hypercall_stubs();
118 }
119 if (!xpdd->hypercall_stubs)
120 return STATUS_UNSUCCESSFUL;
122 if (!xpdd->shared_info_area)
123 {
124 XN_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
125 /* this should be safe as this part will never be called on resume where IRQL == HIGH_LEVEL */
126 xpdd->shared_info_area_unmapped = XenPci_AllocMMIO(xpdd, PAGE_SIZE);
127 xpdd->shared_info_area = MmMapIoSpace(xpdd->shared_info_area_unmapped,
128 PAGE_SIZE, MmNonCached);
129 }
130 KdPrint((__DRIVER_NAME " shared_info_area_unmapped.QuadPart = %lx\n", xpdd->shared_info_area_unmapped.QuadPart));
131 xatp.domid = DOMID_SELF;
132 xatp.idx = 0;
133 xatp.space = XENMAPSPACE_shared_info;
134 xatp.gpfn = (xen_pfn_t)(xpdd->shared_info_area_unmapped.QuadPart >> PAGE_SHIFT);
135 KdPrint((__DRIVER_NAME " gpfn = %x\n", xatp.gpfn));
136 ret = HYPERVISOR_memory_op(xpdd, XENMEM_add_to_physmap, &xatp);
137 KdPrint((__DRIVER_NAME " hypervisor memory op (XENMAPSPACE_shared_info) ret = %d\n", ret));
139 FUNCTION_EXIT();
141 return STATUS_SUCCESS;
142 }
144 static NTSTATUS
145 XenPci_Resume(PXENPCI_DEVICE_DATA xpdd)
146 {
147 return XenPci_Init(xpdd);
148 }
150 static VOID
151 XenPci_SysrqHandler(char *path, PVOID context) {
152 PXENPCI_DEVICE_DATA xpdd = context;
153 char *value;
154 char letter;
155 char *res;
157 UNREFERENCED_PARAMETER(path);
159 FUNCTION_ENTER();
161 XenBus_Read(xpdd, XBT_NIL, SYSRQ_PATH, &value);
163 KdPrint((__DRIVER_NAME " SysRq Value = %s\n", value));
165 if (value != NULL && strlen(value) != 0) {
166 letter = *value;
167 res = XenBus_Write(xpdd, XBT_NIL, SYSRQ_PATH, "");
168 if (res) {
169 KdPrint(("Error writing sysrq path\n"));
170 XenPci_FreeMem(res);
171 return;
172 }
173 } else {
174 letter = 0;
175 }
177 if (value != NULL) {
178 XenPci_FreeMem(value);
179 }
181 switch (letter) {
182 case 0:
183 break;
184 case 'B': /* cause a bug check */
185 #pragma warning(suppress:28159)
186 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000001, 0x00000000, 0x00000000, 0x00000000);
187 break;
188 case 'A': /* cause an assert */
189 #pragma warning(suppress:28138)
190 XN_ASSERT(letter != 'A');
191 break;
192 default:
193 KdPrint((" Unhandled sysrq letter %c\n", letter));
194 break;
195 }
197 FUNCTION_EXIT();
198 }
200 static VOID
201 XenPci_BalloonThreadProc(PVOID StartContext)
202 {
203 PXENPCI_DEVICE_DATA xpdd = StartContext;
204 ULONG new_target_kb = xpdd->current_memory_kb;
205 LARGE_INTEGER timeout;
206 PLARGE_INTEGER ptimeout;
207 PMDL head;
208 PMDL mdl;
209 struct xen_memory_reservation reservation;
210 xen_pfn_t *pfns;
211 int i;
212 ULONG ret;
213 int pfn_count;
214 int timeout_ms = 1000;
215 DECLARE_CONST_UNICODE_STRING(low_mem_name, L"\\KernelObjects\\LowMemoryCondition");
216 PKEVENT low_mem_event;
217 HANDLE low_mem_handle;
218 BOOLEAN hit_initial_target = FALSE;
220 FUNCTION_ENTER();
222 head = NULL;
224 low_mem_event = IoCreateNotificationEvent((PUNICODE_STRING)&low_mem_name, &low_mem_handle);
225 //high_commit_event = IoCreateNotificationEvent((PUNICODE_STRING)&high_commit_name, &high_commit_handle);
226 //max_commit_event = IoCreateNotificationEvent((PUNICODE_STRING)&max_commit_name, &max_commit_handle);
228 for(;;) {
229 /* back off exponentially if we have adjustments to make and we have already hit our initial target, or wait for event if we don't */
230 if (xpdd->current_memory_kb != new_target_kb) {
231 if (!hit_initial_target) {
232 timeout_ms = 0;
233 }
234 timeout.QuadPart = WDF_REL_TIMEOUT_IN_MS(timeout_ms);
235 ptimeout = &timeout;
236 timeout_ms <<= 1;
237 if (timeout_ms > 60000)
238 timeout_ms = 60000;
239 } else {
240 hit_initial_target = TRUE;
241 ptimeout = NULL;
242 timeout_ms = 1000;
243 }
244 KeWaitForSingleObject(&xpdd->balloon_event, Executive, KernelMode, FALSE, ptimeout);
245 if (xpdd->balloon_shutdown)
246 PsTerminateSystemThread(0);
247 KdPrint((__DRIVER_NAME " Got balloon event, current = %d, target = %d\n", xpdd->current_memory_kb, xpdd->target_memory_kb));
248 /* not really worried about races here, but cache target so we only read it once */
249 new_target_kb = xpdd->target_memory_kb;
250 // perform some sanity checks on target_memory
251 // make sure target <= initial
252 // make sure target > some % of initial
254 if (xpdd->current_memory_kb == new_target_kb) {
255 KdPrint((__DRIVER_NAME " No change to memory\n"));
256 continue;
257 } else if (xpdd->current_memory_kb < new_target_kb) {
258 KdPrint((__DRIVER_NAME " Trying to take %d KB from Xen\n", new_target_kb - xpdd->current_memory_kb));
259 while ((mdl = head) != NULL && xpdd->current_memory_kb < new_target_kb) {
260 pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
261 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
262 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
263 for (i = 0; i < pfn_count; i++)
264 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
265 reservation.address_bits = 0;
266 reservation.extent_order = 0;
267 reservation.domid = DOMID_SELF;
268 reservation.nr_extents = pfn_count;
269 #pragma warning(disable: 4127) /* conditional expression is constant */
270 set_xen_guest_handle(reservation.extent_start, pfns);
272 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_populate_physmap) - pfn_count = %d\n", pfn_count));
273 ret = HYPERVISOR_memory_op(xpdd, XENMEM_populate_physmap, &reservation);
274 //KdPrint((__DRIVER_NAME " populated %d pages\n", ret));
275 if (ret < (ULONG)pfn_count) {
276 if (ret > 0) {
277 /* We hit the Xen hard limit: reprobe. */
278 reservation.nr_extents = ret;
279 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
280 KdPrint((__DRIVER_NAME " decreased %d pages (xen is out of pages)\n", ret));
281 }
282 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
283 break;
284 }
285 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
286 head = mdl->Next;
287 mdl->Next = NULL;
288 MmFreePagesFromMdl(mdl);
289 ExFreePool(mdl);
290 xpdd->current_memory_kb += BALLOON_UNITS_KB;
291 }
292 } else {
293 KdPrint((__DRIVER_NAME " Trying to give %d KB to Xen\n", xpdd->current_memory_kb - new_target_kb));
294 while (xpdd->current_memory_kb > new_target_kb) {
295 PHYSICAL_ADDRESS alloc_low;
296 PHYSICAL_ADDRESS alloc_high;
297 PHYSICAL_ADDRESS alloc_skip;
298 alloc_low.QuadPart = 0;
299 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
300 alloc_skip.QuadPart = 0;
302 if (!hit_initial_target && low_mem_event && KeReadStateEvent(low_mem_event)) {
303 KdPrint((__DRIVER_NAME " Low memory condition exists. Waiting.\n"));
304 break;
305 }
307 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
308 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
309 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024, MmCached, 0);
310 #else
311 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024);
312 #endif
313 if (!mdl) {
314 KdPrint((__DRIVER_NAME " Allocation failed - try again soon\n"));
315 break;
316 } else {
317 int i;
318 ULONG ret;
319 int pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
320 if (pfn_count != BALLOON_UNIT_PAGES) {
321 /* we could probably do this better but it will only happen in low memory conditions... */
322 KdPrint((__DRIVER_NAME " wanted %d pages got %d pages\n", BALLOON_UNIT_PAGES, pfn_count));
323 MmFreePagesFromMdl(mdl);
324 ExFreePool(mdl);
325 break;
326 }
327 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
328 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
329 for (i = 0; i < pfn_count; i++)
330 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
331 reservation.address_bits = 0;
332 reservation.extent_order = 0;
333 reservation.domid = DOMID_SELF;
334 reservation.nr_extents = pfn_count;
335 #pragma warning(disable: 4127) /* conditional expression is constant */
336 set_xen_guest_handle(reservation.extent_start, pfns);
338 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
339 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
340 if (head) {
341 mdl->Next = head;
342 head = mdl;
343 } else {
344 head = mdl;
345 }
346 xpdd->current_memory_kb -= BALLOON_UNITS_KB;
347 }
348 }
349 }
350 KdPrint((__DRIVER_NAME " Memory = %d, Balloon Target = %d\n", xpdd->current_memory_kb, new_target_kb));
351 }
352 }
354 static VOID
355 XenPci_BalloonHandler(char *path, PVOID context) {
356 WDFDEVICE device = context;
357 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
358 char *value;
360 UNREFERENCED_PARAMETER(path);
362 FUNCTION_ENTER();
364 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
366 if (value == NULL) {
367 FUNCTION_MSG("Failed to read balloon target value\n");
368 FUNCTION_EXIT();
369 return;
370 }
372 if (atoi(value) > 0)
373 xpdd->target_memory_kb = atoi(value);
375 FUNCTION_MSG("target memory value = %d (%s)\n", xpdd->target_memory_kb, value);
377 XenPci_FreeMem(value);
379 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
381 FUNCTION_EXIT();
382 }
384 static VOID
385 XenPci_Suspend0(PVOID context)
386 {
387 PXENPCI_DEVICE_DATA xpdd = context;
388 ULONG cancelled;
389 ULONGLONG sysenter_cs, sysenter_esp, sysenter_eip;
391 FUNCTION_ENTER();
393 GntTbl_Suspend(xpdd);
395 sysenter_cs = __readmsr(0x174);
396 sysenter_esp = __readmsr(0x175);
397 sysenter_eip = __readmsr(0x176);
399 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
401 /* this code was to fix a bug that existed in Xen for a short time... it is harmless but can probably be removed */
402 if (__readmsr(0x174) != sysenter_cs) {
403 KdPrint((__DRIVER_NAME " sysenter_cs not restored. Fixing.\n"));
404 __writemsr(0x174, sysenter_cs);
405 }
406 if (__readmsr(0x175) != sysenter_esp) {
407 KdPrint((__DRIVER_NAME " sysenter_esp not restored. Fixing.\n"));
408 __writemsr(0x175, sysenter_esp);
409 }
410 if (__readmsr(0x176) != sysenter_eip) {
411 KdPrint((__DRIVER_NAME " sysenter_eip not restored. Fixing.\n"));
412 __writemsr(0x176, sysenter_eip);
413 }
415 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
417 if (qemu_hide_flags_value) {
418 XenPci_HideQemuDevices();
419 }
421 XenPci_Resume(xpdd);
422 GntTbl_Resume(xpdd);
423 EvtChn_Resume(xpdd); /* this enables interrupts again too */
425 FUNCTION_EXIT();
426 }
428 static VOID
429 XenPci_SuspendN(PVOID context)
430 {
431 UNREFERENCED_PARAMETER(context);
433 FUNCTION_ENTER();
434 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
435 FUNCTION_EXIT();
436 }
438 static VOID
439 XenPci_SuspendEvtDpc(PVOID context);
440 static NTSTATUS
441 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
443 /* called at PASSIVE_LEVEL */
444 static NTSTATUS
445 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd) {
446 CHAR path[128];
448 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
449 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
450 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
451 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
452 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device, EVT_ACTION_FLAGS_NO_SUSPEND);
454 return STATUS_SUCCESS;
455 }
457 /* Called at PASSIVE_LEVEL */
458 static VOID
459 XenPci_SuspendResume(WDFWORKITEM workitem) {
460 NTSTATUS status;
461 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
462 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
463 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
464 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
465 WDF_CHILD_LIST_ITERATOR child_iterator;
466 WDFDEVICE child_device;
468 FUNCTION_ENTER();
470 if (xpdd->suspend_state == SUSPEND_STATE_NONE) {
471 ExAcquireFastMutex(&xpdd->suspend_mutex);
472 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
473 KeMemoryBarrier();
475 // how to prevent device addition etc here? is it implied because dom0 initiated the suspend?
476 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
478 WdfChildListBeginIteration(child_list, &child_iterator);
479 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS) {
480 XenPci_SuspendPdo(child_device);
481 }
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 XenPci_ResumePdo(child_device);
496 }
497 WdfChildListEndIteration(child_list, &child_iterator);
499 xpdd->suspend_state = SUSPEND_STATE_NONE;
500 ExReleaseFastMutex(&xpdd->suspend_mutex);
501 }
502 FUNCTION_EXIT();
503 }
505 /* called at DISPATCH_LEVEL */
506 static VOID
507 XenPci_SuspendEvtDpc(PVOID context)
508 {
509 NTSTATUS status;
510 WDFDEVICE device = context;
511 //KIRQL old_irql;
512 WDF_OBJECT_ATTRIBUTES attributes;
513 WDF_WORKITEM_CONFIG workitem_config;
514 WDFWORKITEM workitem;
516 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
517 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
518 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
519 attributes.ParentObject = device;
520 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
521 if (status != STATUS_SUCCESS) {
522 /* how should we fail here */
523 FUNCTION_MSG("WdfWorkItemCreate failed\n");
524 return;
525 }
526 WdfWorkItemEnqueue(workitem);
527 }
529 static void
530 XenPci_ShutdownHandler(char *path, PVOID context)
531 {
532 NTSTATUS status;
533 WDFDEVICE device = context;
534 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
535 char *res;
536 char *value;
537 //KIRQL old_irql;
538 WDF_OBJECT_ATTRIBUTES attributes;
539 WDF_WORKITEM_CONFIG workitem_config;
540 WDFWORKITEM workitem;
542 UNREFERENCED_PARAMETER(path);
544 FUNCTION_ENTER();
546 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
547 if (res)
548 {
549 KdPrint(("Error reading shutdown path - %s\n", res));
550 XenPci_FreeMem(res);
551 FUNCTION_EXIT();
552 return;
553 }
555 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
557 if (strlen(value) && strcmp(value, "suspend") == 0)
558 {
559 {
560 KdPrint((__DRIVER_NAME " Suspend detected\n"));
561 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
562 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
563 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
564 attributes.ParentObject = device;
565 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
566 // TODO: check status here
567 WdfWorkItemEnqueue(workitem);
568 }
569 }
571 XenPci_FreeMem(value);
573 FUNCTION_EXIT();
574 }
576 static VOID
577 XenPci_DeviceWatchHandler(char *path, PVOID context)
578 {
579 char **bits;
580 int count;
581 char *err;
582 char *value;
583 PXENPCI_DEVICE_DATA xpdd = context;
585 FUNCTION_ENTER();
587 bits = SplitString(path, '/', 4, &count);
588 if (count == 3)
589 {
590 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
591 if (err)
592 {
593 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
594 XenPci_FreeMem(err);
595 }
596 else
597 {
598 XenPci_FreeMem(value);
599 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
600 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
601 XenPci_EvtChildListScanForChildren(xpdd->child_list);
602 }
603 }
604 FreeSplitString(bits, count);
606 FUNCTION_EXIT();
607 }
609 NTSTATUS
610 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
611 {
612 NTSTATUS status = STATUS_SUCCESS;
613 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
614 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
615 ULONG i;
617 FUNCTION_ENTER();
619 XN_ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
621 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
622 {
623 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
624 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
625 switch (raw_descriptor->Type) {
626 case CmResourceTypePort:
627 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
628 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
629 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
630 break;
631 case CmResourceTypeMemory:
632 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));
633 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
634 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
635 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
636 xpdd->platform_mmio_flags = translated_descriptor->Flags;
637 break;
638 case CmResourceTypeInterrupt:
639 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
640 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
641 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
642 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
643 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
644 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
645 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
646 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
647 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
648 switch(translated_descriptor->ShareDisposition)
649 {
650 case CmResourceShareDeviceExclusive:
651 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
652 break;
653 case CmResourceShareDriverExclusive:
654 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
655 break;
656 case CmResourceShareShared:
657 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
658 break;
659 default:
660 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
661 break;
662 }
663 break;
664 case CmResourceTypeDevicePrivate:
665 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]));
666 break;
667 default:
668 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
669 break;
670 }
671 }
673 FUNCTION_EXIT();
675 return status;
676 }
678 NTSTATUS
679 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
680 {
681 NTSTATUS status = STATUS_SUCCESS;
682 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
684 FUNCTION_ENTER();
686 xpdd->hibernated = FALSE;
687 switch (previous_state)
688 {
689 case WdfPowerDeviceD0:
690 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
691 break;
692 case WdfPowerDeviceD1:
693 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
694 break;
695 case WdfPowerDeviceD2:
696 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
697 break;
698 case WdfPowerDeviceD3:
699 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
700 break;
701 case WdfPowerDeviceD3Final:
702 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
703 break;
704 case WdfPowerDevicePrepareForHibernation:
705 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
706 break;
707 default:
708 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
709 break;
710 }
712 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value) {
713 XenPci_HideQemuDevices();
714 }
716 if (previous_state == WdfPowerDeviceD3Final) {
717 XenPci_Init(xpdd);
718 if (tpr_patch_requested && !xpdd->tpr_patched) {
719 XenPci_MapHalThenPatchKernel(xpdd);
720 xpdd->tpr_patched = TRUE;
721 xpdd->removable = FALSE;
722 }
723 GntTbl_Init(xpdd);
724 EvtChn_Init(xpdd);
725 } else {
726 XenPci_Resume(xpdd);
727 GntTbl_Resume(xpdd);
728 EvtChn_Resume(xpdd);
729 }
731 FUNCTION_EXIT();
733 return status;
734 }
736 NTSTATUS
737 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
738 {
739 NTSTATUS status = STATUS_SUCCESS;
740 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
741 PCHAR response;
742 HANDLE thread_handle;
744 UNREFERENCED_PARAMETER(previous_state);
746 FUNCTION_ENTER();
748 if (previous_state == WdfPowerDeviceD3Final)
749 {
750 XenBus_Init(xpdd);
752 XenPci_ConnectSuspendEvt(xpdd);
754 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
756 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
758 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
760 /* prime target as current until the watch gets kicked off */
761 xpdd->target_memory_kb = xpdd->current_memory_kb;
762 xpdd->balloon_shutdown = FALSE;
763 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
764 if (!NT_SUCCESS(status)) {
765 FUNCTION_MSG("Could not start balloon thread\n");
766 return status;
767 }
768 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
769 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
770 ZwClose(thread_handle);
771 } else {
772 XenBus_Resume(xpdd);
773 XenPci_ConnectSuspendEvt(xpdd);
774 }
775 FUNCTION_EXIT();
777 return status;
778 }
780 NTSTATUS
781 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
782 {
783 NTSTATUS status = STATUS_SUCCESS;
784 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
785 LARGE_INTEGER timeout;
787 FUNCTION_ENTER();
789 switch (target_state)
790 {
791 case WdfPowerDeviceD0:
792 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
793 break;
794 case WdfPowerDeviceD1:
795 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
796 break;
797 case WdfPowerDeviceD2:
798 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
799 break;
800 case WdfPowerDeviceD3:
801 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
802 break;
803 case WdfPowerDeviceD3Final:
804 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
805 break;
806 case WdfPowerDevicePrepareForHibernation:
807 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
808 break;
809 default:
810 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
811 break;
812 }
814 if (target_state == WdfPowerDeviceD3Final) {
815 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
817 xpdd->balloon_shutdown = TRUE;
818 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
820 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
821 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
822 {
823 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
824 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
825 }
826 ObDereferenceObject(xpdd->balloon_thread);
828 XenBus_Halt(xpdd);
829 }
830 else
831 {
832 XenBus_Suspend(xpdd);
833 }
835 FUNCTION_EXIT();
837 return status;
838 }
840 NTSTATUS
841 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state) {
842 NTSTATUS status = STATUS_SUCCESS;
843 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
845 FUNCTION_ENTER();
847 switch (target_state) {
848 case WdfPowerDeviceD0:
849 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
850 break;
851 case WdfPowerDeviceD1:
852 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
853 break;
854 case WdfPowerDeviceD2:
855 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
856 break;
857 case WdfPowerDeviceD3:
858 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
859 break;
860 case WdfPowerDeviceD3Final:
861 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
862 break;
863 case WdfPowerDevicePrepareForHibernation:
864 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
865 xpdd->hibernated = TRUE;
866 break;
867 default:
868 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
869 break;
870 }
872 if (target_state == WdfPowerDeviceD3Final) {
873 /* we don't really support exit here */
874 } else {
875 EvtChn_Suspend(xpdd);
876 GntTbl_Suspend(xpdd);
877 }
879 FUNCTION_EXIT();
881 return status;
882 }
884 NTSTATUS
885 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
886 {
887 NTSTATUS status = STATUS_SUCCESS;
889 UNREFERENCED_PARAMETER(device);
890 UNREFERENCED_PARAMETER(resources_translated);
892 FUNCTION_ENTER();
893 FUNCTION_EXIT();
895 return status;
896 }
898 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
899 /* Can be called concurrently, but KMDF takes care of concurrent calls to WdfChildListXxx */
900 VOID
901 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
902 {
903 NTSTATUS status;
904 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
905 char *msg;
906 char **devices;
907 char **instances;
908 ULONG i, j;
909 CHAR path[128];
910 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
911 PVOID entry;
912 WDFDEVICE child_device;
913 WDF_CHILD_RETRIEVE_INFO retrieve_info;
915 FUNCTION_ENTER();
917 WdfChildListBeginScan(child_list);
919 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
920 if (!msg)
921 {
922 for (i = 0; devices[i]; i++)
923 {
924 /* make sure the key is not in the veto list */
925 for (entry = xpdd->veto_list.Flink; entry != &xpdd->veto_list; entry = ((PLIST_ENTRY)entry)->Flink)
926 {
927 if (!strcmp(devices[i], (PCHAR)entry + sizeof(LIST_ENTRY)))
928 break;
929 }
930 if (entry != &xpdd->veto_list)
931 {
932 XenPci_FreeMem(devices[i]);
933 continue;
934 }
936 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
937 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
938 if (!msg)
939 {
940 for (j = 0; instances[j]; j++)
941 {
942 /* the device comparison is done as a memory compare so zero-ing the structure is important */
943 RtlZeroMemory(&child_description, sizeof(child_description));
944 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
945 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
946 KdPrint((__DRIVER_NAME " Found path = %s\n", path));
947 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
948 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
949 child_description.index = atoi(instances[j]);
950 WDF_CHILD_RETRIEVE_INFO_INIT(&retrieve_info, &child_description.header);
951 child_device = WdfChildListRetrievePdo(child_list, &retrieve_info);
952 if (child_device)
953 {
954 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(child_device);
955 char *err;
956 char *value;
957 char backend_state_path[128];
959 if (xppdd->do_not_enumerate)
960 {
961 RtlStringCbPrintfA(backend_state_path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
963 err = XenBus_Read(xpdd, XBT_NIL, backend_state_path, &value);
964 if (err)
965 {
966 XenPci_FreeMem(err);
967 xppdd->backend_state = XenbusStateUnknown;
968 }
969 else
970 {
971 xppdd->backend_state = atoi(value);
972 XenPci_FreeMem(value);
973 }
974 if (xppdd->backend_state == XenbusStateClosing || xppdd->backend_state == XenbusStateClosed)
975 {
976 KdPrint((__DRIVER_NAME " Surprise removing %s due to backend initiated remove\n", path));
977 XenPci_FreeMem(instances[j]);
978 continue;
979 }
980 else
981 {
982 /* I guess we are being added again ... */
983 xppdd->backend_initiated_remove = FALSE;
984 xppdd->do_not_enumerate = FALSE;
985 }
986 }
987 }
988 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
989 if (!NT_SUCCESS(status))
990 {
991 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
992 }
993 XenPci_FreeMem(instances[j]);
994 }
995 XenPci_FreeMem(instances);
996 }
997 else
998 {
999 // wtf do we do here???
1000 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
1002 XenPci_FreeMem(devices[i]);
1004 XenPci_FreeMem(devices);
1006 else
1008 // wtf do we do here???
1009 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
1012 WdfChildListEndScan(child_list);
1014 FUNCTION_EXIT();