win-pvdrivers

view xenpci/xenpci_fdo.c @ 1096:05efa89a4ef7

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