win-pvdrivers

view xenpci/xenpci_fdo.c @ 979:8f483a2b2991

Fix up PREfast warnings
author James Harper <james.harper@bendigoit.com.au>
date Sun Apr 15 19:47:10 2012 +1000 (2012-04-15)
parents 35ec9d4ebf94
children e9011a1ba5bb 58899e6ed48f
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 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 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 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 {
153 PXENPCI_DEVICE_DATA xpdd = context;
154 char *value;
155 char letter;
156 char *res;
158 UNREFERENCED_PARAMETER(path);
160 FUNCTION_ENTER();
162 XenBus_Read(xpdd, XBT_NIL, SYSRQ_PATH, &value);
164 KdPrint((__DRIVER_NAME " SysRq Value = %s\n", value));
166 if (value != NULL && strlen(value) != 0)
167 {
168 letter = *value;
169 res = XenBus_Write(xpdd, XBT_NIL, SYSRQ_PATH, "");
170 if (res)
171 {
172 KdPrint(("Error writing sysrq path\n"));
173 XenPci_FreeMem(res);
174 return;
175 }
176 }
177 else
178 {
179 letter = 0;
180 }
182 if (value != NULL)
183 {
184 XenPci_FreeMem(value);
185 }
187 switch (letter)
188 {
189 case 0:
190 break;
191 case 'B': /* cause a bug check */
192 #pragma warning(suppress:28159)
193 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000001, 0x00000000, 0x00000000, 0x00000000);
194 break;
195 case 'A': /* cause an assert */
196 ASSERT(1 == 0);
197 break;
198 default:
199 KdPrint((" Unhandled sysrq letter %c\n", letter));
200 break;
201 }
203 FUNCTION_EXIT();
204 }
206 #if 0
207 static VOID
208 XenPci_PrintPendingInterrupts()
209 {
210 PULONG bitmap = (PULONG)0xFFFE0200;
211 int i;
212 int j;
213 ULONG value;
215 for (i = 0; i < 8; i++)
216 {
217 value = bitmap[(7 - i) * 4];
218 if (value)
219 {
220 for (j = 0; j < 32; j++)
221 {
222 if ((value >> j) & 1)
223 KdPrint((" Interrupt pending on pin %d\n", ((7 - i) << 5) | j));
224 }
225 }
226 }
227 }
228 #endif
230 static VOID
231 XenPci_BalloonThreadProc(PVOID StartContext)
232 {
233 PXENPCI_DEVICE_DATA xpdd = StartContext;
234 ULONG new_target_kb = xpdd->current_memory_kb;
235 LARGE_INTEGER timeout;
236 PLARGE_INTEGER ptimeout;
237 PMDL head;
238 PMDL mdl;
239 struct xen_memory_reservation reservation;
240 xen_pfn_t *pfns;
241 int i;
242 ULONG ret;
243 int pfn_count;
244 int timeout_ms = 1000;
245 DECLARE_CONST_UNICODE_STRING(low_mem_name, L"\\KernelObjects\\LowMemoryCondition");
246 //DECLARE_CONST_UNICODE_STRING(high_commit_name, L"\\KernelObjects\\HighCommitCondition");
247 //DECLARE_CONST_UNICODE_STRING(max_commit_name, L"\\KernelObjects\\MaximumCommitCondition");
248 PKEVENT low_mem_event;
249 //PKEVENT high_commit_event;
250 //PKEVENT max_commit_event;
251 HANDLE low_mem_handle;
252 //HANDLE high_commit_handle;
253 //HANDLE max_commit_handle;
255 FUNCTION_ENTER();
257 head = balloon_mdl_head;
258 balloon_mdl_head = NULL;
260 low_mem_event = IoCreateNotificationEvent((PUNICODE_STRING)&low_mem_name, &low_mem_handle);
261 //high_commit_event = IoCreateNotificationEvent((PUNICODE_STRING)&high_commit_name, &high_commit_handle);
262 //max_commit_event = IoCreateNotificationEvent((PUNICODE_STRING)&max_commit_name, &max_commit_handle);
264 KdPrint((__DRIVER_NAME " low_mem_event = %p, state = %d\n", low_mem_event, low_mem_event?KeReadStateEvent(low_mem_event):(ULONG)-1));
265 //KdPrint((__DRIVER_NAME " high_commit_event = %p, state = %d\n", high_commit_event, high_commit_event?KeReadStateEvent(high_commit_event):(ULONG)-1));
266 //KdPrint((__DRIVER_NAME " max_commit_event = %p, state = %d\n", max_commit_event, max_commit_event?KeReadStateEvent(max_commit_event):(ULONG)-1));
268 for(;;)
269 {
270 /* back off exponentially if we have adjustments to make, or wait for event if we don't */
271 if (xpdd->current_memory_kb != new_target_kb)
272 {
273 timeout.QuadPart = WDF_REL_TIMEOUT_IN_MS(timeout_ms);
274 ptimeout = &timeout;
275 timeout_ms <<= 1;
276 if (timeout_ms > 60000)
277 timeout_ms = 60000;
278 }
279 else
280 {
281 ptimeout = NULL;
282 timeout_ms = 1000;
283 }
284 KeWaitForSingleObject(&xpdd->balloon_event, Executive, KernelMode, FALSE, ptimeout);
285 if (xpdd->balloon_shutdown)
286 PsTerminateSystemThread(0);
287 KdPrint((__DRIVER_NAME " Got balloon event, current = %d, target = %d\n", xpdd->current_memory_kb, xpdd->target_memory_kb));
288 /* not really worried about races here, but cache target so we only read it once */
289 new_target_kb = xpdd->target_memory_kb;
290 // perform some sanity checks on target_memory
291 // make sure target <= initial
292 // make sure target > some % of initial
294 if (xpdd->current_memory_kb == new_target_kb)
295 {
296 KdPrint((__DRIVER_NAME " No change to memory\n"));
297 continue;
298 }
299 else if (xpdd->current_memory_kb < new_target_kb)
300 {
301 KdPrint((__DRIVER_NAME " Trying to take %d MB from Xen\n", new_target_kb - xpdd->current_memory_kb));
302 while ((mdl = head) != NULL && xpdd->current_memory_kb < new_target_kb)
303 {
304 pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
305 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
306 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
307 for (i = 0; i < pfn_count; i++)
308 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
309 reservation.address_bits = 0;
310 reservation.extent_order = 0;
311 reservation.domid = DOMID_SELF;
312 reservation.nr_extents = pfn_count;
313 #pragma warning(disable: 4127) /* conditional expression is constant */
314 set_xen_guest_handle(reservation.extent_start, pfns);
316 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_populate_physmap) - pfn_count = %d\n", pfn_count));
317 ret = HYPERVISOR_memory_op(xpdd, XENMEM_populate_physmap, &reservation);
318 //KdPrint((__DRIVER_NAME " populated %d pages\n", ret));
319 if (ret < (ULONG)pfn_count)
320 {
321 if (ret > 0)
322 {
323 /* We hit the Xen hard limit: reprobe. */
324 reservation.nr_extents = ret;
325 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
326 KdPrint((__DRIVER_NAME " decreased %d pages (xen is out of pages)\n", ret));
327 }
328 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
329 break;
330 }
331 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
332 head = mdl->Next;
333 mdl->Next = NULL;
334 MmFreePagesFromMdl(mdl);
335 ExFreePool(mdl);
336 xpdd->current_memory_kb += BALLOON_UNITS_KB;
337 }
338 }
339 else
340 {
341 KdPrint((__DRIVER_NAME " Trying to give %d MB to Xen\n", xpdd->current_memory_kb - new_target_kb));
342 while (xpdd->current_memory_kb > new_target_kb)
343 {
344 PHYSICAL_ADDRESS alloc_low;
345 PHYSICAL_ADDRESS alloc_high;
346 PHYSICAL_ADDRESS alloc_skip;
347 alloc_low.QuadPart = 0;
348 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
349 alloc_skip.QuadPart = 0;
351 if (low_mem_event && KeReadStateEvent(low_mem_event))
352 {
353 KdPrint((__DRIVER_NAME " Low memory condition exists. Waiting.\n"));
354 //KdPrint((__DRIVER_NAME " low_mem_event = %p, state = %d\n", low_mem_event, low_mem_event?KeReadStateEvent(low_mem_event):(ULONG)-1));
355 //KdPrint((__DRIVER_NAME " high_commit_event = %p, state = %d\n", high_commit_event, high_commit_event?KeReadStateEvent(high_commit_event):(ULONG)-1));
356 //KdPrint((__DRIVER_NAME " max_commit_event = %p, state = %d\n", max_commit_event, max_commit_event?KeReadStateEvent(max_commit_event):(ULONG)-1));
357 break;
358 }
360 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
361 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
362 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024, MmCached, 0);
363 #else
364 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024);
365 #endif
366 if (!mdl)
367 {
368 KdPrint((__DRIVER_NAME " Allocation failed - try again soon\n"));
369 break;
370 }
371 else
372 {
373 int i;
374 ULONG ret;
375 int pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
376 if (pfn_count != BALLOON_UNIT_PAGES)
377 {
378 /* we could probably do this better but it will only happen in low memory conditions... */
379 KdPrint((__DRIVER_NAME " wanted %d pages got %d pages\n", BALLOON_UNIT_PAGES, pfn_count));
380 MmFreePagesFromMdl(mdl);
381 ExFreePool(mdl);
382 break;
383 }
384 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
385 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
386 for (i = 0; i < pfn_count; i++)
387 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
388 reservation.address_bits = 0;
389 reservation.extent_order = 0;
390 reservation.domid = DOMID_SELF;
391 reservation.nr_extents = pfn_count;
392 #pragma warning(disable: 4127) /* conditional expression is constant */
393 set_xen_guest_handle(reservation.extent_start, pfns);
395 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_decrease_reservation) - pfn_count = %d\n", pfn_count));
396 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
397 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
398 //KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
399 if (head)
400 {
401 mdl->Next = head;
402 head = mdl;
403 }
404 else
405 {
406 head = mdl;
407 }
408 xpdd->current_memory_kb -= BALLOON_UNITS_KB;
409 }
410 }
411 }
412 KdPrint((__DRIVER_NAME " Memory = %d, Balloon Target = %d\n", xpdd->current_memory_kb, new_target_kb));
413 }
414 //FUNCTION_EXIT();
415 }
417 static VOID
418 XenPci_BalloonHandler(char *Path, PVOID Data)
419 {
420 WDFDEVICE device = Data;
421 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
422 char *value;
423 xenbus_transaction_t xbt;
424 int retry;
426 UNREFERENCED_PARAMETER(Path);
428 FUNCTION_ENTER();
430 XenBus_StartTransaction(xpdd, &xbt);
432 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
434 if (value == NULL)
435 {
436 KdPrint((__DRIVER_NAME " Failed to read value\n"));
437 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
438 FUNCTION_EXIT();
439 return;
440 }
442 if (atoi(value) > 0)
443 xpdd->target_memory_kb = atoi(value);
445 KdPrint((__DRIVER_NAME " target memory value = %d (%s)\n", xpdd->target_memory_kb, value));
447 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
449 XenPci_FreeMem(value);
451 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
453 FUNCTION_EXIT();
454 }
456 static VOID
457 XenPci_Suspend0(PVOID context)
458 {
459 PXENPCI_DEVICE_DATA xpdd = context;
460 ULONG cancelled;
461 ULONGLONG sysenter_cs, sysenter_esp, sysenter_eip;
463 FUNCTION_ENTER();
465 GntTbl_Suspend(xpdd);
467 sysenter_cs = __readmsr(0x174);
468 sysenter_esp = __readmsr(0x175);
469 sysenter_eip = __readmsr(0x176);
471 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
473 if (__readmsr(0x174) != sysenter_cs)
474 {
475 KdPrint((__DRIVER_NAME " sysenter_cs not restored. Fixing.\n"));
476 __writemsr(0x174, sysenter_cs);
477 }
478 if (__readmsr(0x175) != sysenter_esp)
479 {
480 KdPrint((__DRIVER_NAME " sysenter_esp not restored. Fixing.\n"));
481 __writemsr(0x175, sysenter_esp);
482 }
483 if (__readmsr(0x176) != sysenter_eip)
484 {
485 KdPrint((__DRIVER_NAME " sysenter_eip not restored. Fixing.\n"));
486 __writemsr(0x176, sysenter_eip);
487 }
489 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
491 if (qemu_hide_flags_value)
492 {
493 XenPci_HideQemuDevices();
494 }
496 XenPci_Resume(xpdd);
497 GntTbl_Resume(xpdd);
498 EvtChn_Resume(xpdd); /* this enables interrupts again too */
500 FUNCTION_EXIT();
501 }
503 static VOID
504 XenPci_SuspendN(PVOID context)
505 {
506 UNREFERENCED_PARAMETER(context);
508 FUNCTION_ENTER();
509 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
510 FUNCTION_EXIT();
511 }
513 static VOID
514 XenPci_SuspendEvtDpc(PVOID context);
515 static NTSTATUS
516 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
518 /* called at PASSIVE_LEVEL */
519 static NTSTATUS
520 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd)
521 {
522 CHAR path[128];
524 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
525 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
526 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
527 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
528 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device, EVT_ACTION_FLAGS_NO_SUSPEND);
530 return STATUS_SUCCESS;
531 }
533 /* Called at PASSIVE_LEVEL */
534 static VOID
535 XenPci_SuspendResume(WDFWORKITEM workitem)
536 {
537 NTSTATUS status;
538 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
539 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
540 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
541 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
542 WDF_CHILD_LIST_ITERATOR child_iterator;
543 WDFDEVICE child_device;
545 FUNCTION_ENTER();
547 if (xpdd->suspend_state == SUSPEND_STATE_NONE)
548 {
549 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
550 KeMemoryBarrier();
552 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
553 WdfChildListBeginIteration(child_list, &child_iterator);
554 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
555 {
556 KdPrint((__DRIVER_NAME " Suspending child\n"));
557 XenPci_Pdo_Suspend(child_device);
558 }
559 WdfChildListEndIteration(child_list, &child_iterator);
561 XenBus_Suspend(xpdd);
562 EvtChn_Suspend(xpdd);
563 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
565 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
566 XenBus_Resume(xpdd);
568 XenPci_ConnectSuspendEvt(xpdd);
570 WdfChildListBeginIteration(child_list, &child_iterator);
571 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
572 {
573 KdPrint((__DRIVER_NAME " Resuming child\n"));
574 XenPci_Pdo_Resume(child_device);
575 }
576 WdfChildListEndIteration(child_list, &child_iterator);
578 xpdd->suspend_state = SUSPEND_STATE_NONE;
579 }
580 FUNCTION_EXIT();
581 }
583 /* called at DISPATCH_LEVEL */
584 static VOID
585 XenPci_SuspendEvtDpc(PVOID context)
586 {
587 NTSTATUS status;
588 WDFDEVICE device = context;
589 //KIRQL old_irql;
590 WDF_OBJECT_ATTRIBUTES attributes;
591 WDF_WORKITEM_CONFIG workitem_config;
592 WDFWORKITEM workitem;
594 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
595 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
596 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
597 attributes.ParentObject = device;
598 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
599 if (status != STATUS_SUCCESS) {
600 /* how should we fail here */
601 FUNCTION_MSG("WdfWorkItemCreate failed\n");
602 return;
603 }
604 WdfWorkItemEnqueue(workitem);
605 }
607 static void
608 XenPci_ShutdownHandler(char *path, PVOID context)
609 {
610 NTSTATUS status;
611 WDFDEVICE device = context;
612 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
613 char *res;
614 char *value;
615 //KIRQL old_irql;
616 WDF_OBJECT_ATTRIBUTES attributes;
617 WDF_WORKITEM_CONFIG workitem_config;
618 WDFWORKITEM workitem;
620 UNREFERENCED_PARAMETER(path);
622 FUNCTION_ENTER();
624 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
625 if (res)
626 {
627 KdPrint(("Error reading shutdown path - %s\n", res));
628 XenPci_FreeMem(res);
629 FUNCTION_EXIT();
630 return;
631 }
633 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
635 if (strlen(value) && strcmp(value, "suspend") == 0)
636 {
637 {
638 KdPrint((__DRIVER_NAME " Suspend detected\n"));
639 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
640 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
641 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
642 attributes.ParentObject = device;
643 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
644 // TODO: check status here
645 WdfWorkItemEnqueue(workitem);
646 }
647 }
649 XenPci_FreeMem(value);
651 FUNCTION_EXIT();
652 }
654 static VOID
655 XenPci_DeviceWatchHandler(char *path, PVOID context)
656 {
657 char **bits;
658 int count;
659 char *err;
660 char *value;
661 PXENPCI_DEVICE_DATA xpdd = context;
663 FUNCTION_ENTER();
665 bits = SplitString(path, '/', 4, &count);
666 if (count == 3)
667 {
668 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
669 if (err)
670 {
671 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
672 XenPci_FreeMem(err);
673 }
674 else
675 {
676 XenPci_FreeMem(value);
677 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
678 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
679 XenPci_EvtChildListScanForChildren(xpdd->child_list);
680 }
681 }
682 FreeSplitString(bits, count);
684 FUNCTION_EXIT();
685 }
687 NTSTATUS
688 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
689 {
690 NTSTATUS status = STATUS_SUCCESS;
691 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
692 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
693 ULONG i;
695 FUNCTION_ENTER();
697 ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
699 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
700 {
701 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
702 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
703 switch (raw_descriptor->Type) {
704 case CmResourceTypePort:
705 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
706 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
707 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
708 break;
709 case CmResourceTypeMemory:
710 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));
711 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
712 #if 0
713 mmio_freelist_free = 0;
714 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
715 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
716 #endif
717 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
718 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
719 xpdd->platform_mmio_flags = translated_descriptor->Flags;
720 break;
721 case CmResourceTypeInterrupt:
722 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
723 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
724 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
725 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
726 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
727 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
728 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
729 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
730 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
731 switch(translated_descriptor->ShareDisposition)
732 {
733 case CmResourceShareDeviceExclusive:
734 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
735 break;
736 case CmResourceShareDriverExclusive:
737 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
738 break;
739 case CmResourceShareShared:
740 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
741 break;
742 default:
743 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
744 break;
745 }
746 break;
747 case CmResourceTypeDevicePrivate:
748 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]));
749 break;
750 default:
751 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
752 break;
753 }
754 }
756 FUNCTION_EXIT();
758 return status;
759 }
761 NTSTATUS
762 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
763 {
764 NTSTATUS status = STATUS_SUCCESS;
765 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
767 FUNCTION_ENTER();
769 xpdd->hibernated = FALSE;
770 switch (previous_state)
771 {
772 case WdfPowerDeviceD0:
773 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
774 break;
775 case WdfPowerDeviceD1:
776 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
777 break;
778 case WdfPowerDeviceD2:
779 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
780 break;
781 case WdfPowerDeviceD3:
782 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
783 break;
784 case WdfPowerDeviceD3Final:
785 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
786 break;
787 case WdfPowerDevicePrepareForHibernation:
788 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
789 break;
790 default:
791 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
792 break;
793 }
795 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value)
796 {
797 XenPci_HideQemuDevices();
798 }
800 if (previous_state == WdfPowerDeviceD3Final)
801 {
802 XenPci_Init(xpdd);
803 if (tpr_patch_requested && !xpdd->tpr_patched)
804 {
805 XenPci_MapHalThenPatchKernel(xpdd);
806 xpdd->tpr_patched = TRUE;
807 xpdd->removable = FALSE;
808 }
809 GntTbl_Init(xpdd);
810 EvtChn_Init(xpdd);
812 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
813 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
814 }
815 else
816 {
817 XenPci_Resume(xpdd);
818 GntTbl_Resume(xpdd);
819 EvtChn_Resume(xpdd);
820 }
822 FUNCTION_EXIT();
824 return status;
825 }
827 NTSTATUS
828 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
829 {
830 NTSTATUS status = STATUS_SUCCESS;
831 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
832 PCHAR response;
833 char *value;
834 HANDLE thread_handle;
836 UNREFERENCED_PARAMETER(previous_state);
838 FUNCTION_ENTER();
840 if (previous_state == WdfPowerDeviceD3Final)
841 {
842 XenBus_Init(xpdd);
844 XenPci_ConnectSuspendEvt(xpdd);
846 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
848 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
850 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
852 if (!xpdd->initial_memory_kb)
853 {
854 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
855 if (atoi(value) > 0)
856 {
857 xpdd->initial_memory_kb = atoi(value);
858 xpdd->current_memory_kb = xpdd->initial_memory_kb;
859 xpdd->target_memory_kb = xpdd->initial_memory_kb;
860 }
861 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory_kb, value));
862 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
863 xpdd->balloon_shutdown = FALSE;
864 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
865 if (!NT_SUCCESS(status))
866 {
867 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
868 return status;
869 }
870 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
871 ZwClose(thread_handle);
872 }
873 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
874 }
875 else
876 {
877 XenBus_Resume(xpdd);
878 XenPci_ConnectSuspendEvt(xpdd);
879 }
880 FUNCTION_EXIT();
882 return status;
883 }
885 NTSTATUS
886 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
887 {
888 NTSTATUS status = STATUS_SUCCESS;
889 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
890 LARGE_INTEGER timeout;
892 FUNCTION_ENTER();
894 switch (target_state)
895 {
896 case WdfPowerDeviceD0:
897 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
898 break;
899 case WdfPowerDeviceD1:
900 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
901 break;
902 case WdfPowerDeviceD2:
903 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
904 break;
905 case WdfPowerDeviceD3:
906 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
907 break;
908 case WdfPowerDeviceD3Final:
909 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
910 break;
911 case WdfPowerDevicePrepareForHibernation:
912 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
913 break;
914 default:
915 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
916 break;
917 }
919 if (target_state == WdfPowerDeviceD3Final)
920 {
921 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
923 xpdd->balloon_shutdown = TRUE;
924 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
926 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
927 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
928 {
929 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
930 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
931 }
932 ObDereferenceObject(xpdd->balloon_thread);
934 XenBus_Halt(xpdd);
935 }
936 else
937 {
938 XenBus_Suspend(xpdd);
939 }
941 FUNCTION_EXIT();
943 return status;
944 }
946 NTSTATUS
947 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
948 {
949 NTSTATUS status = STATUS_SUCCESS;
950 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
952 FUNCTION_ENTER();
954 switch (target_state)
955 {
956 case WdfPowerDeviceD0:
957 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
958 break;
959 case WdfPowerDeviceD1:
960 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
961 break;
962 case WdfPowerDeviceD2:
963 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
964 break;
965 case WdfPowerDeviceD3:
966 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
967 break;
968 case WdfPowerDeviceD3Final:
969 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
970 break;
971 case WdfPowerDevicePrepareForHibernation:
972 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
973 xpdd->hibernated = TRUE;
974 break;
975 default:
976 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
977 break;
978 }
980 if (target_state == WdfPowerDeviceD3Final)
981 {
982 /* we don't really support exit here */
983 }
984 else
985 {
986 EvtChn_Suspend(xpdd);
987 GntTbl_Suspend(xpdd);
989 }
991 FUNCTION_EXIT();
993 return status;
994 }
996 NTSTATUS
997 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
998 {
999 NTSTATUS status = STATUS_SUCCESS;
1001 UNREFERENCED_PARAMETER(device);
1002 UNREFERENCED_PARAMETER(resources_translated);
1004 FUNCTION_ENTER();
1005 FUNCTION_EXIT();
1007 return status;
1010 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
1011 /* Can be called concurrently, but KMDF takes care of concurrent calls to WdfChildListXxx */
1012 VOID
1013 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
1015 NTSTATUS status;
1016 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
1017 char *msg;
1018 char **devices;
1019 char **instances;
1020 ULONG i, j;
1021 CHAR path[128];
1022 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
1023 PVOID entry;
1024 WDFDEVICE child_device;
1025 WDF_CHILD_RETRIEVE_INFO retrieve_info;
1027 FUNCTION_ENTER();
1029 WdfChildListBeginScan(child_list);
1031 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
1032 if (!msg)
1034 for (i = 0; devices[i]; i++)
1036 /* make sure the key is not in the veto list */
1037 for (entry = xpdd->veto_list.Flink; entry != &xpdd->veto_list; entry = ((PLIST_ENTRY)entry)->Flink)
1039 if (!strcmp(devices[i], (PCHAR)entry + sizeof(LIST_ENTRY)))
1040 break;
1042 if (entry != &xpdd->veto_list)
1044 XenPci_FreeMem(devices[i]);
1045 continue;
1048 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
1049 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
1050 if (!msg)
1052 for (j = 0; instances[j]; j++)
1054 /* the device comparison is done as a memory compare so zero-ing the structure is important */
1055 RtlZeroMemory(&child_description, sizeof(child_description));
1056 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
1057 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
1058 KdPrint((__DRIVER_NAME " Found path = %s\n", path));
1059 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
1060 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
1061 child_description.index = atoi(instances[j]);
1062 WDF_CHILD_RETRIEVE_INFO_INIT(&retrieve_info, &child_description.header);
1063 child_device = WdfChildListRetrievePdo(child_list, &retrieve_info);
1064 if (child_device)
1066 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(child_device);
1067 char *err;
1068 char *value;
1069 char backend_state_path[128];
1071 if (xppdd->do_not_enumerate)
1073 RtlStringCbPrintfA(backend_state_path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
1075 err = XenBus_Read(xpdd, XBT_NIL, backend_state_path, &value);
1076 if (err)
1078 XenPci_FreeMem(err);
1079 xppdd->backend_state = XenbusStateUnknown;
1081 else
1083 xppdd->backend_state = atoi(value);
1084 XenPci_FreeMem(value);
1086 if (xppdd->backend_state == XenbusStateClosing || xppdd->backend_state == XenbusStateClosed)
1088 KdPrint((__DRIVER_NAME " Surprise removing %s due to backend initiated remove\n", path));
1089 XenPci_FreeMem(instances[j]);
1090 continue;
1092 else
1094 /* I guess we are being added again ... */
1095 xppdd->backend_initiated_remove = FALSE;
1096 xppdd->do_not_enumerate = FALSE;
1100 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
1101 if (!NT_SUCCESS(status))
1103 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
1105 XenPci_FreeMem(instances[j]);
1107 XenPci_FreeMem(instances);
1109 else
1111 // wtf do we do here???
1112 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
1114 XenPci_FreeMem(devices[i]);
1116 XenPci_FreeMem(devices);
1118 else
1120 // wtf do we do here???
1121 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
1124 WdfChildListEndScan(child_list);
1126 FUNCTION_EXIT();