win-pvdrivers

view xenpci/xenpci_fdo.c @ 1004:a5d1d333e0e2

Start of major changes to xenpci interface. Now using xenpci as export driver. storport and xennet6 drivers working but not suspend/resume or dump mode
author James Harper <james.harper@bendigoit.com.au>
date Sun Jan 06 14:08:22 2013 +1100 (2013-01-06)
parents 58899e6ed48f
children 4f7d5a8636bd
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 NT_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 NT_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 NT_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 NT_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 #if 0
558 XenPci_Pdo_Suspend(child_device);
559 #endif
560 }
561 WdfChildListEndIteration(child_list, &child_iterator);
563 XenBus_Suspend(xpdd);
564 EvtChn_Suspend(xpdd);
565 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
567 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
568 XenBus_Resume(xpdd);
570 XenPci_ConnectSuspendEvt(xpdd);
572 WdfChildListBeginIteration(child_list, &child_iterator);
573 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
574 {
575 KdPrint((__DRIVER_NAME " Resuming child\n"));
576 #if 0
577 XenPci_Pdo_Resume(child_device);
578 #endif
579 }
580 WdfChildListEndIteration(child_list, &child_iterator);
582 xpdd->suspend_state = SUSPEND_STATE_NONE;
583 }
584 FUNCTION_EXIT();
585 }
587 /* called at DISPATCH_LEVEL */
588 static VOID
589 XenPci_SuspendEvtDpc(PVOID context)
590 {
591 NTSTATUS status;
592 WDFDEVICE device = context;
593 //KIRQL old_irql;
594 WDF_OBJECT_ATTRIBUTES attributes;
595 WDF_WORKITEM_CONFIG workitem_config;
596 WDFWORKITEM workitem;
598 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
599 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
600 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
601 attributes.ParentObject = device;
602 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
603 if (status != STATUS_SUCCESS) {
604 /* how should we fail here */
605 FUNCTION_MSG("WdfWorkItemCreate failed\n");
606 return;
607 }
608 WdfWorkItemEnqueue(workitem);
609 }
611 static void
612 XenPci_ShutdownHandler(char *path, PVOID context)
613 {
614 NTSTATUS status;
615 WDFDEVICE device = context;
616 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
617 char *res;
618 char *value;
619 //KIRQL old_irql;
620 WDF_OBJECT_ATTRIBUTES attributes;
621 WDF_WORKITEM_CONFIG workitem_config;
622 WDFWORKITEM workitem;
624 UNREFERENCED_PARAMETER(path);
626 FUNCTION_ENTER();
628 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
629 if (res)
630 {
631 KdPrint(("Error reading shutdown path - %s\n", res));
632 XenPci_FreeMem(res);
633 FUNCTION_EXIT();
634 return;
635 }
637 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
639 if (strlen(value) && strcmp(value, "suspend") == 0)
640 {
641 {
642 KdPrint((__DRIVER_NAME " Suspend detected\n"));
643 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
644 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
645 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
646 attributes.ParentObject = device;
647 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
648 // TODO: check status here
649 WdfWorkItemEnqueue(workitem);
650 }
651 }
653 XenPci_FreeMem(value);
655 FUNCTION_EXIT();
656 }
658 static VOID
659 XenPci_DeviceWatchHandler(char *path, PVOID context)
660 {
661 char **bits;
662 int count;
663 char *err;
664 char *value;
665 PXENPCI_DEVICE_DATA xpdd = context;
667 FUNCTION_ENTER();
669 bits = SplitString(path, '/', 4, &count);
670 if (count == 3)
671 {
672 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
673 if (err)
674 {
675 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
676 XenPci_FreeMem(err);
677 }
678 else
679 {
680 XenPci_FreeMem(value);
681 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
682 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
683 XenPci_EvtChildListScanForChildren(xpdd->child_list);
684 }
685 }
686 FreeSplitString(bits, count);
688 FUNCTION_EXIT();
689 }
691 NTSTATUS
692 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
693 {
694 NTSTATUS status = STATUS_SUCCESS;
695 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
696 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
697 ULONG i;
699 FUNCTION_ENTER();
701 NT_ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
703 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
704 {
705 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
706 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
707 switch (raw_descriptor->Type) {
708 case CmResourceTypePort:
709 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
710 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
711 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
712 break;
713 case CmResourceTypeMemory:
714 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));
715 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
716 #if 0
717 mmio_freelist_free = 0;
718 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
719 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
720 #endif
721 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
722 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
723 xpdd->platform_mmio_flags = translated_descriptor->Flags;
724 break;
725 case CmResourceTypeInterrupt:
726 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
727 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
728 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
729 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
730 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
731 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
732 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
733 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
734 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
735 switch(translated_descriptor->ShareDisposition)
736 {
737 case CmResourceShareDeviceExclusive:
738 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
739 break;
740 case CmResourceShareDriverExclusive:
741 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
742 break;
743 case CmResourceShareShared:
744 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
745 break;
746 default:
747 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
748 break;
749 }
750 break;
751 case CmResourceTypeDevicePrivate:
752 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]));
753 break;
754 default:
755 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
756 break;
757 }
758 }
760 FUNCTION_EXIT();
762 return status;
763 }
765 NTSTATUS
766 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
767 {
768 NTSTATUS status = STATUS_SUCCESS;
769 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
771 FUNCTION_ENTER();
773 xpdd->hibernated = FALSE;
774 switch (previous_state)
775 {
776 case WdfPowerDeviceD0:
777 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
778 break;
779 case WdfPowerDeviceD1:
780 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
781 break;
782 case WdfPowerDeviceD2:
783 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
784 break;
785 case WdfPowerDeviceD3:
786 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
787 break;
788 case WdfPowerDeviceD3Final:
789 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
790 break;
791 case WdfPowerDevicePrepareForHibernation:
792 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
793 break;
794 default:
795 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
796 break;
797 }
799 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value)
800 {
801 XenPci_HideQemuDevices();
802 }
804 if (previous_state == WdfPowerDeviceD3Final)
805 {
806 XenPci_Init(xpdd);
807 if (tpr_patch_requested && !xpdd->tpr_patched)
808 {
809 XenPci_MapHalThenPatchKernel(xpdd);
810 xpdd->tpr_patched = TRUE;
811 xpdd->removable = FALSE;
812 }
813 GntTbl_Init(xpdd);
814 EvtChn_Init(xpdd);
816 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
817 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
818 }
819 else
820 {
821 XenPci_Resume(xpdd);
822 GntTbl_Resume(xpdd);
823 EvtChn_Resume(xpdd);
824 }
826 FUNCTION_EXIT();
828 return status;
829 }
831 NTSTATUS
832 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
833 {
834 NTSTATUS status = STATUS_SUCCESS;
835 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
836 PCHAR response;
837 char *value;
838 HANDLE thread_handle;
840 UNREFERENCED_PARAMETER(previous_state);
842 FUNCTION_ENTER();
844 if (previous_state == WdfPowerDeviceD3Final)
845 {
846 XenBus_Init(xpdd);
848 XenPci_ConnectSuspendEvt(xpdd);
850 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
852 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
854 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
856 if (!xpdd->initial_memory_kb)
857 {
858 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
859 if (atoi(value) > 0)
860 {
861 xpdd->initial_memory_kb = atoi(value);
862 xpdd->current_memory_kb = xpdd->initial_memory_kb;
863 xpdd->target_memory_kb = xpdd->initial_memory_kb;
864 }
865 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory_kb, value));
866 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
867 xpdd->balloon_shutdown = FALSE;
868 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
869 if (!NT_SUCCESS(status))
870 {
871 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
872 return status;
873 }
874 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
875 ZwClose(thread_handle);
876 }
877 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
878 }
879 else
880 {
881 XenBus_Resume(xpdd);
882 XenPci_ConnectSuspendEvt(xpdd);
883 }
884 FUNCTION_EXIT();
886 return status;
887 }
889 NTSTATUS
890 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
891 {
892 NTSTATUS status = STATUS_SUCCESS;
893 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
894 LARGE_INTEGER timeout;
896 FUNCTION_ENTER();
898 switch (target_state)
899 {
900 case WdfPowerDeviceD0:
901 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
902 break;
903 case WdfPowerDeviceD1:
904 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
905 break;
906 case WdfPowerDeviceD2:
907 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
908 break;
909 case WdfPowerDeviceD3:
910 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
911 break;
912 case WdfPowerDeviceD3Final:
913 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
914 break;
915 case WdfPowerDevicePrepareForHibernation:
916 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
917 break;
918 default:
919 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
920 break;
921 }
923 if (target_state == WdfPowerDeviceD3Final)
924 {
925 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
927 xpdd->balloon_shutdown = TRUE;
928 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
930 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
931 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
932 {
933 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
934 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
935 }
936 ObDereferenceObject(xpdd->balloon_thread);
938 XenBus_Halt(xpdd);
939 }
940 else
941 {
942 XenBus_Suspend(xpdd);
943 }
945 FUNCTION_EXIT();
947 return status;
948 }
950 NTSTATUS
951 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
952 {
953 NTSTATUS status = STATUS_SUCCESS;
954 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
956 FUNCTION_ENTER();
958 switch (target_state)
959 {
960 case WdfPowerDeviceD0:
961 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
962 break;
963 case WdfPowerDeviceD1:
964 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
965 break;
966 case WdfPowerDeviceD2:
967 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
968 break;
969 case WdfPowerDeviceD3:
970 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
971 break;
972 case WdfPowerDeviceD3Final:
973 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
974 break;
975 case WdfPowerDevicePrepareForHibernation:
976 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
977 xpdd->hibernated = TRUE;
978 break;
979 default:
980 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
981 break;
982 }
984 if (target_state == WdfPowerDeviceD3Final)
985 {
986 /* we don't really support exit here */
987 }
988 else
989 {
990 EvtChn_Suspend(xpdd);
991 GntTbl_Suspend(xpdd);
993 }
995 FUNCTION_EXIT();
997 return status;
998 }
1000 NTSTATUS
1001 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
1003 NTSTATUS status = STATUS_SUCCESS;
1005 UNREFERENCED_PARAMETER(device);
1006 UNREFERENCED_PARAMETER(resources_translated);
1008 FUNCTION_ENTER();
1009 FUNCTION_EXIT();
1011 return status;
1014 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
1015 /* Can be called concurrently, but KMDF takes care of concurrent calls to WdfChildListXxx */
1016 VOID
1017 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
1019 NTSTATUS status;
1020 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
1021 char *msg;
1022 char **devices;
1023 char **instances;
1024 ULONG i, j;
1025 CHAR path[128];
1026 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
1027 PVOID entry;
1028 WDFDEVICE child_device;
1029 WDF_CHILD_RETRIEVE_INFO retrieve_info;
1031 FUNCTION_ENTER();
1033 WdfChildListBeginScan(child_list);
1035 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
1036 if (!msg)
1038 for (i = 0; devices[i]; i++)
1040 /* make sure the key is not in the veto list */
1041 for (entry = xpdd->veto_list.Flink; entry != &xpdd->veto_list; entry = ((PLIST_ENTRY)entry)->Flink)
1043 if (!strcmp(devices[i], (PCHAR)entry + sizeof(LIST_ENTRY)))
1044 break;
1046 if (entry != &xpdd->veto_list)
1048 XenPci_FreeMem(devices[i]);
1049 continue;
1052 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
1053 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
1054 if (!msg)
1056 for (j = 0; instances[j]; j++)
1058 /* the device comparison is done as a memory compare so zero-ing the structure is important */
1059 RtlZeroMemory(&child_description, sizeof(child_description));
1060 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
1061 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
1062 KdPrint((__DRIVER_NAME " Found path = %s\n", path));
1063 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
1064 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
1065 child_description.index = atoi(instances[j]);
1066 WDF_CHILD_RETRIEVE_INFO_INIT(&retrieve_info, &child_description.header);
1067 child_device = WdfChildListRetrievePdo(child_list, &retrieve_info);
1068 if (child_device)
1070 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(child_device);
1071 char *err;
1072 char *value;
1073 char backend_state_path[128];
1075 if (xppdd->do_not_enumerate)
1077 RtlStringCbPrintfA(backend_state_path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
1079 err = XenBus_Read(xpdd, XBT_NIL, backend_state_path, &value);
1080 if (err)
1082 XenPci_FreeMem(err);
1083 xppdd->backend_state = XenbusStateUnknown;
1085 else
1087 xppdd->backend_state = atoi(value);
1088 XenPci_FreeMem(value);
1090 if (xppdd->backend_state == XenbusStateClosing || xppdd->backend_state == XenbusStateClosed)
1092 KdPrint((__DRIVER_NAME " Surprise removing %s due to backend initiated remove\n", path));
1093 XenPci_FreeMem(instances[j]);
1094 continue;
1096 else
1098 /* I guess we are being added again ... */
1099 xppdd->backend_initiated_remove = FALSE;
1100 xppdd->do_not_enumerate = FALSE;
1104 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
1105 if (!NT_SUCCESS(status))
1107 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
1109 XenPci_FreeMem(instances[j]);
1111 XenPci_FreeMem(instances);
1113 else
1115 // wtf do we do here???
1116 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
1118 XenPci_FreeMem(devices[i]);
1120 XenPci_FreeMem(devices);
1122 else
1124 // wtf do we do here???
1125 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
1128 WdfChildListEndScan(child_list);
1130 FUNCTION_EXIT();