win-pvdrivers

view xenpci/xenpci_fdo.c @ 924:35ec9d4ebf94

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