win-pvdrivers

annotate xenpci/xenpci_fdo.c @ 910:1ee7940af105

Fix compilation under older DDK
author James Harper <james.harper@bendigoit.com.au>
date Fri Apr 29 23:56:03 2011 +1000 (2011-04-29)
parents e315b8490131
children 35ec9d4ebf94
rev   line source
james@259 1 /*
james@259 2 PV Drivers for Windows Xen HVM Domains
james@259 3 Copyright (C) 2007 James Harper
james@259 4
james@259 5 This program is free software; you can redistribute it and/or
james@259 6 modify it under the terms of the GNU General Public License
james@259 7 as published by the Free Software Foundation; either version 2
james@259 8 of the License, or (at your option) any later version.
james@259 9
james@259 10 This program is distributed in the hope that it will be useful,
james@259 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@259 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@259 13 GNU General Public License for more details.
james@259 14
james@259 15 You should have received a copy of the GNU General Public License
james@259 16 along with this program; if not, write to the Free Software
james@259 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@259 18 */
james@259 19
james@259 20 #include "xenpci.h"
james@259 21 #include <stdlib.h>
james@529 22 #include <aux_klib.h>
james@259 23
james@259 24 #define SYSRQ_PATH "control/sysrq"
james@259 25 #define SHUTDOWN_PATH "control/shutdown"
james@259 26 #define BALLOON_PATH "memory/target"
james@259 27
james@861 28 extern PMDL balloon_mdl_head;
james@861 29
james@716 30 /* Not really necessary but keeps PREfast happy */
james@716 31 static EVT_WDF_WORKITEM XenPci_SuspendResume;
james@910 32 #if (VER_PRODUCTBUILD >= 7600)
james@716 33 static KSTART_ROUTINE XenPci_BalloonThreadProc;
james@818 34 #endif
james@716 35
james@536 36 static VOID
james@536 37 XenPci_MapHalThenPatchKernel(PXENPCI_DEVICE_DATA xpdd)
james@536 38 {
james@536 39 NTSTATUS status;
james@536 40 PAUX_MODULE_EXTENDED_INFO amei;
james@536 41 ULONG module_info_buffer_size;
james@536 42 ULONG i;
james@536 43
james@536 44 FUNCTION_ENTER();
james@536 45
james@536 46 amei = NULL;
james@536 47 /* buffer size could change between requesting and allocating - need to loop until we are successful */
james@536 48 while ((status = AuxKlibQueryModuleInformation(&module_info_buffer_size, sizeof(AUX_MODULE_EXTENDED_INFO), amei)) == STATUS_BUFFER_TOO_SMALL || amei == NULL)
james@536 49 {
james@536 50 if (amei != NULL)
james@536 51 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
james@536 52 amei = ExAllocatePoolWithTag(NonPagedPool, module_info_buffer_size, XENPCI_POOL_TAG);
james@536 53 }
james@536 54
james@536 55 KdPrint((__DRIVER_NAME " AuxKlibQueryModuleInformation = %d\n", status));
james@536 56 for (i = 0; i < module_info_buffer_size / sizeof(AUX_MODULE_EXTENDED_INFO); i++)
james@536 57 {
james@536 58 if (strcmp((PCHAR)amei[i].FullPathName + amei[i].FileNameOffset, "hal.dll") == 0)
james@536 59 {
james@536 60 KdPrint((__DRIVER_NAME " hal.dll found at %p - %p\n",
james@536 61 amei[i].BasicInfo.ImageBase,
james@536 62 ((PUCHAR)amei[i].BasicInfo.ImageBase) + amei[i].ImageSize));
james@536 63 XenPci_PatchKernel(xpdd, amei[i].BasicInfo.ImageBase, amei[i].ImageSize);
james@536 64 }
james@536 65 }
james@536 66 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
james@536 67 FUNCTION_EXIT();
james@536 68 }
james@536 69
james@536 70 /*
james@536 71 * Alloc MMIO from the device's MMIO region. There is no corresponding free() fn
james@536 72 */
james@536 73 PHYSICAL_ADDRESS
james@536 74 XenPci_AllocMMIO(PXENPCI_DEVICE_DATA xpdd, ULONG len)
james@536 75 {
james@536 76 PHYSICAL_ADDRESS addr;
james@536 77
james@536 78 len = (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
james@536 79
james@536 80 addr = xpdd->platform_mmio_addr;
james@536 81 addr.QuadPart += xpdd->platform_mmio_alloc;
james@536 82 xpdd->platform_mmio_alloc += len;
james@536 83
james@536 84 ASSERT(xpdd->platform_mmio_alloc <= xpdd->platform_mmio_len);
james@536 85
james@536 86 return addr;
james@536 87 }
james@536 88
james@536 89 extern ULONG tpr_patch_requested;
james@536 90
james@537 91 NTSTATUS
james@537 92 XenPci_EvtDeviceQueryRemove(WDFDEVICE device)
james@537 93 {
james@537 94 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@537 95 NTSTATUS status;
james@537 96
james@537 97 FUNCTION_ENTER();
james@537 98 if (xpdd->removable)
james@537 99 status = STATUS_SUCCESS;
james@537 100 else
james@537 101 status = STATUS_UNSUCCESSFUL;
james@537 102 FUNCTION_EXIT();
james@537 103 return status;
james@537 104 }
james@537 105
james@536 106 static NTSTATUS
james@536 107 XenPci_Init(PXENPCI_DEVICE_DATA xpdd)
james@536 108 {
james@536 109 struct xen_add_to_physmap xatp;
james@536 110 int ret;
james@536 111
james@536 112 FUNCTION_ENTER();
james@536 113
james@860 114 if (!xpdd->hypercall_stubs)
james@860 115 {
james@860 116 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
james@860 117 xpdd->hypercall_stubs = hvm_get_hypercall_stubs();
james@860 118 }
james@860 119 if (!xpdd->hypercall_stubs)
james@860 120 return STATUS_UNSUCCESSFUL;
james@536 121
james@536 122 if (!xpdd->shared_info_area)
james@536 123 {
james@536 124 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
james@536 125 /* this should be safe as this part will never be called on resume where IRQL == HIGH_LEVEL */
james@536 126 xpdd->shared_info_area_unmapped = XenPci_AllocMMIO(xpdd, PAGE_SIZE);
james@536 127 xpdd->shared_info_area = MmMapIoSpace(xpdd->shared_info_area_unmapped,
james@536 128 PAGE_SIZE, MmNonCached);
james@536 129 }
james@536 130 KdPrint((__DRIVER_NAME " shared_info_area_unmapped.QuadPart = %lx\n", xpdd->shared_info_area_unmapped.QuadPart));
james@536 131 xatp.domid = DOMID_SELF;
james@536 132 xatp.idx = 0;
james@536 133 xatp.space = XENMAPSPACE_shared_info;
james@536 134 xatp.gpfn = (xen_pfn_t)(xpdd->shared_info_area_unmapped.QuadPart >> PAGE_SHIFT);
james@536 135 KdPrint((__DRIVER_NAME " gpfn = %x\n", xatp.gpfn));
james@536 136 ret = HYPERVISOR_memory_op(xpdd, XENMEM_add_to_physmap, &xatp);
james@536 137 KdPrint((__DRIVER_NAME " hypervisor memory op (XENMAPSPACE_shared_info) ret = %d\n", ret));
james@622 138
james@536 139 FUNCTION_EXIT();
james@536 140
james@536 141 return STATUS_SUCCESS;
james@536 142 }
james@536 143
james@536 144 static NTSTATUS
james@536 145 XenPci_Resume(PXENPCI_DEVICE_DATA xpdd)
james@536 146 {
james@536 147 return XenPci_Init(xpdd);
james@536 148 }
james@536 149
james@536 150 static VOID
james@536 151 XenPci_SysrqHandler(char *path, PVOID context)
james@536 152 {
james@536 153 PXENPCI_DEVICE_DATA xpdd = context;
james@536 154 char *value;
james@536 155 char letter;
james@536 156 char *res;
james@536 157
james@536 158 UNREFERENCED_PARAMETER(path);
james@536 159
james@536 160 FUNCTION_ENTER();
james@536 161
james@536 162 XenBus_Read(xpdd, XBT_NIL, SYSRQ_PATH, &value);
james@536 163
james@536 164 KdPrint((__DRIVER_NAME " SysRq Value = %s\n", value));
james@536 165
james@536 166 if (value != NULL && strlen(value) != 0)
james@536 167 {
james@536 168 letter = *value;
james@536 169 res = XenBus_Write(xpdd, XBT_NIL, SYSRQ_PATH, "");
james@536 170 if (res)
james@536 171 {
james@536 172 KdPrint(("Error writing sysrq path\n"));
james@536 173 XenPci_FreeMem(res);
james@536 174 return;
james@536 175 }
james@536 176 }
james@536 177 else
james@536 178 {
james@536 179 letter = 0;
james@536 180 }
james@536 181
james@536 182 if (value != NULL)
james@536 183 {
james@536 184 XenPci_FreeMem(value);
james@536 185 }
james@536 186
james@536 187 switch (letter)
james@536 188 {
james@536 189 case 0:
james@536 190 break;
james@536 191 case 'B': /* cause a bug check */
james@536 192 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000001, 0x00000000, 0x00000000, 0x00000000);
james@536 193 break;
james@702 194 case 'A': /* cause an assert */
james@702 195 ASSERT(1 == 0);
james@702 196 break;
james@536 197 default:
james@536 198 KdPrint((" Unhandled sysrq letter %c\n", letter));
james@536 199 break;
james@536 200 }
james@536 201
james@536 202 FUNCTION_EXIT();
james@536 203 }
james@536 204
james@536 205 #if 0
james@536 206 static VOID
james@536 207 XenPci_PrintPendingInterrupts()
james@536 208 {
james@536 209 PULONG bitmap = (PULONG)0xFFFE0200;
james@536 210 int i;
james@536 211 int j;
james@536 212 ULONG value;
james@536 213
james@536 214 for (i = 0; i < 8; i++)
james@536 215 {
james@536 216 value = bitmap[(7 - i) * 4];
james@536 217 if (value)
james@536 218 {
james@536 219 for (j = 0; j < 32; j++)
james@536 220 {
james@536 221 if ((value >> j) & 1)
james@536 222 KdPrint((" Interrupt pending on pin %d\n", ((7 - i) << 5) | j));
james@536 223 }
james@536 224 }
james@536 225 }
james@536 226 }
james@536 227 #endif
james@536 228
james@591 229 static VOID
james@591 230 XenPci_BalloonThreadProc(PVOID StartContext)
james@591 231 {
james@591 232 PXENPCI_DEVICE_DATA xpdd = StartContext;
james@591 233 ULONG new_target = xpdd->current_memory;
james@591 234 LARGE_INTEGER timeout;
james@591 235 PLARGE_INTEGER ptimeout;
james@861 236 PMDL head;
james@794 237 PMDL mdl;
james@794 238 struct xen_memory_reservation reservation;
james@794 239 xen_pfn_t *pfns;
james@794 240 int i;
james@794 241 ULONG ret;
james@794 242 int pfn_count;
james@860 243 int timeout_ms = 1000;
james@867 244 DECLARE_CONST_UNICODE_STRING(low_mem_name, L"\\KernelObjects\\LowMemoryCondition");
james@867 245 //DECLARE_CONST_UNICODE_STRING(high_commit_name, L"\\KernelObjects\\HighCommitCondition");
james@867 246 //DECLARE_CONST_UNICODE_STRING(max_commit_name, L"\\KernelObjects\\MaximumCommitCondition");
james@867 247 PKEVENT low_mem_event;
james@867 248 //PKEVENT high_commit_event;
james@867 249 //PKEVENT max_commit_event;
james@867 250 HANDLE low_mem_handle;
james@867 251 //HANDLE high_commit_handle;
james@867 252 //HANDLE max_commit_handle;
james@794 253
james@591 254 FUNCTION_ENTER();
james@861 255
james@861 256 head = balloon_mdl_head;
james@861 257 balloon_mdl_head = NULL;
james@591 258
james@867 259 low_mem_event = IoCreateNotificationEvent((PUNICODE_STRING)&low_mem_name, &low_mem_handle);
james@867 260 //high_commit_event = IoCreateNotificationEvent((PUNICODE_STRING)&high_commit_name, &high_commit_handle);
james@867 261 //max_commit_event = IoCreateNotificationEvent((PUNICODE_STRING)&max_commit_name, &max_commit_handle);
james@867 262
james@867 263 KdPrint((__DRIVER_NAME " low_mem_event = %p, state = %d\n", low_mem_event, low_mem_event?KeReadStateEvent(low_mem_event):(ULONG)-1));
james@867 264 //KdPrint((__DRIVER_NAME " high_commit_event = %p, state = %d\n", high_commit_event, high_commit_event?KeReadStateEvent(high_commit_event):(ULONG)-1));
james@867 265 //KdPrint((__DRIVER_NAME " max_commit_event = %p, state = %d\n", max_commit_event, max_commit_event?KeReadStateEvent(max_commit_event):(ULONG)-1));
james@867 266
james@591 267 for(;;)
james@591 268 {
james@860 269 /* back off exponentially if we have adjustments to make, or wait for event if we don't */
james@591 270 if (xpdd->current_memory != new_target)
james@591 271 {
james@860 272 timeout.QuadPart = WDF_REL_TIMEOUT_IN_MS(timeout_ms);
james@591 273 ptimeout = &timeout;
james@860 274 timeout_ms <<= 1;
james@860 275 if (timeout_ms > 60000)
james@860 276 timeout_ms = 60000;
james@591 277 }
james@591 278 else
james@591 279 {
james@591 280 ptimeout = NULL;
james@863 281 timeout_ms = 1000;
james@591 282 }
james@591 283 KeWaitForSingleObject(&xpdd->balloon_event, Executive, KernelMode, FALSE, ptimeout);
james@622 284 if (xpdd->balloon_shutdown)
james@622 285 PsTerminateSystemThread(0);
james@591 286 KdPrint((__DRIVER_NAME " Got balloon event, current = %d, target = %d\n", xpdd->current_memory, xpdd->target_memory));
james@591 287 /* not really worried about races here, but cache target so we only read it once */
james@591 288 new_target = xpdd->target_memory;
james@591 289 // perform some sanity checks on target_memory
james@591 290 // make sure target <= initial
james@591 291 // make sure target > some % of initial
james@591 292
james@591 293 if (xpdd->current_memory == new_target)
james@591 294 {
james@591 295 KdPrint((__DRIVER_NAME " No change to memory\n"));
james@591 296 continue;
james@591 297 }
james@591 298 else if (xpdd->current_memory < new_target)
james@591 299 {
james@591 300 KdPrint((__DRIVER_NAME " Trying to take %d MB from Xen\n", new_target - xpdd->current_memory));
james@591 301 while ((mdl = head) != NULL && xpdd->current_memory < new_target)
james@591 302 {
james@794 303 pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
james@794 304 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
james@794 305 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
james@794 306 for (i = 0; i < pfn_count; i++)
james@794 307 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
james@794 308 reservation.address_bits = 0;
james@794 309 reservation.extent_order = 0;
james@794 310 reservation.domid = DOMID_SELF;
james@794 311 reservation.nr_extents = pfn_count;
james@794 312 #pragma warning(disable: 4127) /* conditional expression is constant */
james@794 313 set_xen_guest_handle(reservation.extent_start, pfns);
james@794 314
james@863 315 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_populate_physmap) - pfn_count = %d\n", pfn_count));
james@794 316 ret = HYPERVISOR_memory_op(xpdd, XENMEM_populate_physmap, &reservation);
james@863 317 //KdPrint((__DRIVER_NAME " populated %d pages\n", ret));
james@863 318 if (ret < (ULONG)pfn_count)
james@860 319 {
james@863 320 if (ret > 0)
james@860 321 {
james@860 322 /* We hit the Xen hard limit: reprobe. */
james@860 323 reservation.nr_extents = ret;
james@860 324 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
james@860 325 KdPrint((__DRIVER_NAME " decreased %d pages (xen is out of pages)\n", ret));
james@860 326 }
james@860 327 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
james@860 328 break;
james@860 329 }
james@860 330 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
james@860 331 head = mdl->Next;
james@860 332 mdl->Next = NULL;
james@591 333 MmFreePagesFromMdl(mdl);
james@591 334 ExFreePool(mdl);
james@591 335 xpdd->current_memory++;
james@591 336 }
james@591 337 }
james@591 338 else
james@591 339 {
james@591 340 KdPrint((__DRIVER_NAME " Trying to give %d MB to Xen\n", xpdd->current_memory - new_target));
james@591 341 while (xpdd->current_memory > new_target)
james@591 342 {
james@591 343 PHYSICAL_ADDRESS alloc_low;
james@591 344 PHYSICAL_ADDRESS alloc_high;
james@591 345 PHYSICAL_ADDRESS alloc_skip;
james@591 346 alloc_low.QuadPart = 0;
james@591 347 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
james@591 348 alloc_skip.QuadPart = 0;
james@867 349
james@867 350 if (low_mem_event && KeReadStateEvent(low_mem_event))
james@867 351 {
james@867 352 KdPrint((__DRIVER_NAME " Low memory condition exists. Waiting.\n"));
james@867 353 //KdPrint((__DRIVER_NAME " low_mem_event = %p, state = %d\n", low_mem_event, low_mem_event?KeReadStateEvent(low_mem_event):(ULONG)-1));
james@867 354 //KdPrint((__DRIVER_NAME " high_commit_event = %p, state = %d\n", high_commit_event, high_commit_event?KeReadStateEvent(high_commit_event):(ULONG)-1));
james@867 355 //KdPrint((__DRIVER_NAME " max_commit_event = %p, state = %d\n", max_commit_event, max_commit_event?KeReadStateEvent(max_commit_event):(ULONG)-1));
james@867 356 break;
james@867 357 }
james@867 358
james@795 359 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
james@801 360 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
james@801 361 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS, MmCached, 0);
james@795 362 #else
james@795 363 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS);
james@795 364 #endif
james@591 365 if (!mdl)
james@591 366 {
james@863 367 KdPrint((__DRIVER_NAME " Allocation failed - try again soon\n"));
james@591 368 break;
james@591 369 }
james@591 370 else
james@591 371 {
james@794 372 int i;
james@794 373 ULONG ret;
james@794 374 int pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
james@794 375 if (pfn_count != BALLOON_UNIT_PAGES)
james@794 376 {
james@794 377 /* we could probably do this better but it will only happen in low memory conditions... */
james@794 378 KdPrint((__DRIVER_NAME " wanted %d pages got %d pages\n", BALLOON_UNIT_PAGES, pfn_count));
james@794 379 MmFreePagesFromMdl(mdl);
james@794 380 ExFreePool(mdl);
james@794 381 break;
james@794 382 }
james@794 383 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
james@794 384 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
james@794 385 for (i = 0; i < pfn_count; i++)
james@794 386 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
james@794 387 reservation.address_bits = 0;
james@794 388 reservation.extent_order = 0;
james@794 389 reservation.domid = DOMID_SELF;
james@794 390 reservation.nr_extents = pfn_count;
james@794 391 #pragma warning(disable: 4127) /* conditional expression is constant */
james@794 392 set_xen_guest_handle(reservation.extent_start, pfns);
james@794 393
james@863 394 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_decrease_reservation) - pfn_count = %d\n", pfn_count));
james@794 395 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
james@794 396 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
james@863 397 //KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
james@591 398 if (head)
james@591 399 {
james@591 400 mdl->Next = head;
james@591 401 head = mdl;
james@591 402 }
james@591 403 else
james@591 404 {
james@591 405 head = mdl;
james@591 406 }
james@591 407 xpdd->current_memory--;
james@591 408 }
james@591 409 }
james@591 410 }
james@867 411 KdPrint((__DRIVER_NAME " Memory = %d, Balloon Target = %d\n", xpdd->current_memory, new_target));
james@591 412 }
james@591 413 //FUNCTION_EXIT();
james@591 414 }
james@591 415
james@591 416 static VOID
james@591 417 XenPci_BalloonHandler(char *Path, PVOID Data)
james@591 418 {
james@591 419 WDFDEVICE device = Data;
james@591 420 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@591 421 char *value;
james@591 422 xenbus_transaction_t xbt;
james@591 423 int retry;
james@591 424
james@591 425 UNREFERENCED_PARAMETER(Path);
james@591 426
james@591 427 FUNCTION_ENTER();
james@591 428
james@591 429 XenBus_StartTransaction(xpdd, &xbt);
james@591 430
james@591 431 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
james@591 432
steve@620 433 if (value == NULL)
steve@620 434 {
steve@620 435 KdPrint((__DRIVER_NAME " Failed to read value\n"));
steve@620 436 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
steve@620 437 FUNCTION_EXIT();
steve@620 438 return;
steve@620 439 }
steve@620 440
james@591 441 if (atoi(value) > 0)
james@591 442 xpdd->target_memory = atoi(value) >> 10; /* convert to MB */
james@591 443
james@591 444 KdPrint((__DRIVER_NAME " target memory value = %d (%s)\n", xpdd->target_memory, value));
james@591 445
james@591 446 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
james@591 447
james@591 448 XenPci_FreeMem(value);
james@591 449
james@591 450 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
james@591 451
james@591 452 FUNCTION_EXIT();
james@591 453 }
james@591 454
james@536 455 static VOID
james@536 456 XenPci_Suspend0(PVOID context)
james@536 457 {
james@536 458 PXENPCI_DEVICE_DATA xpdd = context;
james@536 459 ULONG cancelled;
james@835 460 ULONGLONG sysenter_cs, sysenter_esp, sysenter_eip;
james@536 461
james@536 462 FUNCTION_ENTER();
james@536 463
james@536 464 GntTbl_Suspend(xpdd);
james@835 465
james@835 466 sysenter_cs = __readmsr(0x174);
james@835 467 sysenter_esp = __readmsr(0x175);
james@835 468 sysenter_eip = __readmsr(0x176);
james@536 469
james@536 470 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
james@835 471
james@835 472 if (__readmsr(0x174) != sysenter_cs)
james@835 473 {
james@835 474 KdPrint((__DRIVER_NAME " sysenter_cs not restored. Fixing.\n"));
james@835 475 __writemsr(0x174, sysenter_cs);
james@835 476 }
james@835 477 if (__readmsr(0x175) != sysenter_esp)
james@835 478 {
james@835 479 KdPrint((__DRIVER_NAME " sysenter_esp not restored. Fixing.\n"));
james@835 480 __writemsr(0x175, sysenter_esp);
james@835 481 }
james@835 482 if (__readmsr(0x176) != sysenter_eip)
james@835 483 {
james@835 484 KdPrint((__DRIVER_NAME " sysenter_eip not restored. Fixing.\n"));
james@835 485 __writemsr(0x176, sysenter_eip);
james@835 486 }
james@835 487
james@536 488 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
james@536 489
james@747 490 if (qemu_hide_flags_value)
james@536 491 {
james@536 492 XenPci_HideQemuDevices();
james@551 493 }
james@536 494
james@536 495 XenPci_Resume(xpdd);
james@536 496 GntTbl_Resume(xpdd);
james@536 497 EvtChn_Resume(xpdd); /* this enables interrupts again too */
james@536 498
james@536 499 FUNCTION_EXIT();
james@536 500 }
james@536 501
james@536 502 static VOID
james@536 503 XenPci_SuspendN(PVOID context)
james@536 504 {
james@536 505 UNREFERENCED_PARAMETER(context);
james@536 506
james@536 507 FUNCTION_ENTER();
james@536 508 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
james@536 509 FUNCTION_EXIT();
james@536 510 }
james@536 511
james@622 512 static VOID
james@622 513 XenPci_SuspendEvtDpc(PVOID context);
james@622 514 static NTSTATUS
james@622 515 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
james@622 516
james@622 517 /* called at PASSIVE_LEVEL */
james@622 518 static NTSTATUS
james@622 519 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd)
james@622 520 {
james@622 521 CHAR path[128];
james@622 522
james@622 523 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
james@622 524 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
james@622 525 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
james@622 526 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
james@841 527 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device, EVT_ACTION_FLAGS_NO_SUSPEND);
james@622 528
james@622 529 return STATUS_SUCCESS;
james@622 530 }
james@622 531
james@536 532 /* Called at PASSIVE_LEVEL */
james@880 533 static VOID
james@536 534 XenPci_SuspendResume(WDFWORKITEM workitem)
james@536 535 {
james@536 536 NTSTATUS status;
james@536 537 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
james@536 538 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
james@536 539 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@536 540 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
james@536 541 WDF_CHILD_LIST_ITERATOR child_iterator;
james@536 542 WDFDEVICE child_device;
james@536 543
james@536 544 FUNCTION_ENTER();
james@536 545
james@536 546 if (xpdd->suspend_state == SUSPEND_STATE_NONE)
james@536 547 {
james@536 548 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
james@536 549 KeMemoryBarrier();
james@536 550
james@536 551 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
james@536 552 WdfChildListBeginIteration(child_list, &child_iterator);
james@536 553 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
james@536 554 {
james@536 555 KdPrint((__DRIVER_NAME " Suspending child\n"));
james@536 556 XenPci_Pdo_Suspend(child_device);
james@536 557 }
james@536 558 WdfChildListEndIteration(child_list, &child_iterator);
james@536 559
james@536 560 XenBus_Suspend(xpdd);
james@536 561 EvtChn_Suspend(xpdd);
james@536 562 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
james@536 563
james@536 564 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
james@536 565 XenBus_Resume(xpdd);
james@536 566
james@622 567 XenPci_ConnectSuspendEvt(xpdd);
james@622 568
james@536 569 WdfChildListBeginIteration(child_list, &child_iterator);
james@536 570 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
james@536 571 {
james@536 572 KdPrint((__DRIVER_NAME " Resuming child\n"));
james@536 573 XenPci_Pdo_Resume(child_device);
james@536 574 }
james@536 575 WdfChildListEndIteration(child_list, &child_iterator);
james@536 576
james@536 577 xpdd->suspend_state = SUSPEND_STATE_NONE;
james@536 578 }
james@536 579 FUNCTION_EXIT();
james@536 580 }
james@536 581
james@622 582 /* called at DISPATCH_LEVEL */
james@622 583 static VOID
james@622 584 XenPci_SuspendEvtDpc(PVOID context)
james@622 585 {
james@622 586 NTSTATUS status;
james@622 587 WDFDEVICE device = context;
james@622 588 //KIRQL old_irql;
james@622 589 WDF_OBJECT_ATTRIBUTES attributes;
james@622 590 WDF_WORKITEM_CONFIG workitem_config;
james@622 591 WDFWORKITEM workitem;
james@622 592
james@622 593 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
james@622 594 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
james@622 595 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
james@622 596 attributes.ParentObject = device;
james@622 597 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
james@622 598 // TODO: check status here
james@622 599 WdfWorkItemEnqueue(workitem);
james@622 600 }
james@622 601
james@536 602 static void
james@536 603 XenPci_ShutdownHandler(char *path, PVOID context)
james@536 604 {
james@536 605 NTSTATUS status;
james@536 606 WDFDEVICE device = context;
james@536 607 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@536 608 char *res;
james@536 609 char *value;
james@536 610 //KIRQL old_irql;
james@536 611 WDF_OBJECT_ATTRIBUTES attributes;
james@536 612 WDF_WORKITEM_CONFIG workitem_config;
james@536 613 WDFWORKITEM workitem;
james@536 614
james@536 615 UNREFERENCED_PARAMETER(path);
james@536 616
james@536 617 FUNCTION_ENTER();
james@536 618
james@536 619 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
james@536 620 if (res)
james@536 621 {
james@536 622 KdPrint(("Error reading shutdown path - %s\n", res));
james@536 623 XenPci_FreeMem(res);
james@551 624 FUNCTION_EXIT();
james@536 625 return;
james@536 626 }
james@536 627
james@536 628 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
james@536 629
james@536 630 if (strlen(value) && strcmp(value, "suspend") == 0)
james@536 631 {
james@536 632 {
james@536 633 KdPrint((__DRIVER_NAME " Suspend detected\n"));
james@536 634 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
james@536 635 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
james@536 636 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
james@536 637 attributes.ParentObject = device;
james@536 638 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
james@536 639 // TODO: check status here
james@536 640 WdfWorkItemEnqueue(workitem);
james@536 641 }
james@536 642 }
james@536 643
james@536 644 XenPci_FreeMem(value);
james@536 645
james@536 646 FUNCTION_EXIT();
james@536 647 }
james@536 648
james@536 649 static VOID
james@536 650 XenPci_DeviceWatchHandler(char *path, PVOID context)
james@536 651 {
james@536 652 char **bits;
james@536 653 int count;
james@536 654 char *err;
james@536 655 char *value;
james@536 656 PXENPCI_DEVICE_DATA xpdd = context;
james@536 657
james@624 658 FUNCTION_ENTER();
james@536 659
james@536 660 bits = SplitString(path, '/', 4, &count);
james@536 661 if (count == 3)
james@536 662 {
james@536 663 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
james@536 664 if (err)
james@536 665 {
james@536 666 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
james@536 667 XenPci_FreeMem(err);
james@536 668 }
james@536 669 else
james@536 670 {
james@536 671 XenPci_FreeMem(value);
james@536 672 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
james@599 673 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
james@599 674 XenPci_EvtChildListScanForChildren(xpdd->child_list);
james@536 675 }
james@536 676 }
james@536 677 FreeSplitString(bits, count);
james@536 678
james@624 679 FUNCTION_EXIT();
james@536 680 }
james@536 681
james@536 682 NTSTATUS
james@536 683 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
james@536 684 {
james@536 685 NTSTATUS status = STATUS_SUCCESS;
james@536 686 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@536 687 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
james@536 688 ULONG i;
james@536 689
james@536 690 FUNCTION_ENTER();
james@536 691
james@536 692 ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
james@536 693
james@536 694 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
james@536 695 {
james@536 696 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
james@536 697 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
james@536 698 switch (raw_descriptor->Type) {
james@536 699 case CmResourceTypePort:
james@536 700 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
james@536 701 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
james@536 702 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
james@536 703 break;
james@536 704 case CmResourceTypeMemory:
james@536 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));
james@536 706 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
james@536 707 #if 0
james@536 708 mmio_freelist_free = 0;
james@536 709 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
james@536 710 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
james@536 711 #endif
james@536 712 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
james@536 713 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
james@536 714 xpdd->platform_mmio_flags = translated_descriptor->Flags;
james@536 715 break;
james@536 716 case CmResourceTypeInterrupt:
james@536 717 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
james@536 718 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
james@536 719 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
james@536 720 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
james@536 721 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
james@536 722 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
james@536 723 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
james@536 724 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
james@536 725 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
james@536 726 switch(translated_descriptor->ShareDisposition)
james@536 727 {
james@536 728 case CmResourceShareDeviceExclusive:
james@536 729 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
james@536 730 break;
james@536 731 case CmResourceShareDriverExclusive:
james@536 732 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
james@536 733 break;
james@536 734 case CmResourceShareShared:
james@536 735 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
james@536 736 break;
james@536 737 default:
james@536 738 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
james@536 739 break;
james@536 740 }
james@536 741 break;
james@536 742 case CmResourceTypeDevicePrivate:
james@536 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]));
james@536 744 break;
james@536 745 default:
james@536 746 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
james@536 747 break;
james@536 748 }
james@536 749 }
james@536 750
james@536 751 FUNCTION_EXIT();
james@536 752
james@536 753 return status;
james@536 754 }
james@536 755
james@536 756 NTSTATUS
james@536 757 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
james@536 758 {
james@536 759 NTSTATUS status = STATUS_SUCCESS;
james@536 760 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@536 761
james@538 762 FUNCTION_ENTER();
james@536 763
james@538 764 xpdd->hibernated = FALSE;
james@538 765 switch (previous_state)
james@538 766 {
james@538 767 case WdfPowerDeviceD0:
james@538 768 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 769 break;
james@538 770 case WdfPowerDeviceD1:
james@538 771 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 772 break;
james@538 773 case WdfPowerDeviceD2:
james@538 774 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
james@538 775 break;
james@538 776 case WdfPowerDeviceD3:
james@538 777 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
james@538 778 break;
james@538 779 case WdfPowerDeviceD3Final:
james@538 780 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
james@538 781 break;
james@538 782 case WdfPowerDevicePrepareForHibernation:
james@538 783 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
james@538 784 break;
james@538 785 default:
james@538 786 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
james@538 787 break;
james@538 788 }
james@551 789
james@747 790 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value)
james@551 791 {
james@551 792 XenPci_HideQemuDevices();
james@624 793 }
james@536 794
james@624 795 if (previous_state == WdfPowerDeviceD3Final)
james@536 796 {
james@624 797 XenPci_Init(xpdd);
james@624 798 if (tpr_patch_requested && !xpdd->tpr_patched)
james@624 799 {
james@624 800 XenPci_MapHalThenPatchKernel(xpdd);
james@624 801 xpdd->tpr_patched = TRUE;
james@809 802 xpdd->removable = FALSE;
james@624 803 }
james@624 804 GntTbl_Init(xpdd);
james@624 805 EvtChn_Init(xpdd);
james@694 806
james@694 807 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
james@694 808 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
james@551 809 }
james@551 810 else
james@551 811 {
james@624 812 XenPci_Resume(xpdd);
james@624 813 GntTbl_Resume(xpdd);
james@624 814 EvtChn_Resume(xpdd);
james@551 815 }
james@536 816
james@536 817 FUNCTION_EXIT();
james@536 818
james@536 819 return status;
james@536 820 }
james@536 821
james@536 822 NTSTATUS
james@536 823 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
james@536 824 {
james@536 825 NTSTATUS status = STATUS_SUCCESS;
james@536 826 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@536 827 PCHAR response;
james@591 828 char *value;
james@622 829 HANDLE thread_handle;
james@536 830
james@536 831 UNREFERENCED_PARAMETER(previous_state);
james@536 832
james@536 833 FUNCTION_ENTER();
james@536 834
james@624 835 if (previous_state == WdfPowerDeviceD3Final)
james@624 836 {
james@624 837 XenBus_Init(xpdd);
james@536 838
james@624 839 XenPci_ConnectSuspendEvt(xpdd);
james@624 840
james@624 841 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
james@624 842
james@624 843 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
james@536 844
james@624 845 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
james@624 846
james@624 847 if (!xpdd->initial_memory)
james@624 848 {
james@624 849 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
james@624 850 if (atoi(value) > 0)
james@624 851 {
james@624 852 xpdd->initial_memory = atoi(value) >> 10; /* convert to MB */
james@624 853 xpdd->current_memory = xpdd->initial_memory;
james@624 854 xpdd->target_memory = xpdd->initial_memory;
james@624 855 }
james@624 856 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory, value));
james@624 857 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
james@624 858 xpdd->balloon_shutdown = FALSE;
james@624 859 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
james@624 860 if (!NT_SUCCESS(status))
james@624 861 {
james@624 862 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
james@624 863 return status;
james@624 864 }
james@624 865 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
james@624 866 ZwClose(thread_handle);
james@624 867 }
james@624 868 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
james@624 869 }
james@624 870 else
james@536 871 {
james@624 872 XenBus_Resume(xpdd);
james@624 873 XenPci_ConnectSuspendEvt(xpdd);
james@536 874 }
james@536 875 FUNCTION_EXIT();
james@536 876
james@536 877 return status;
james@536 878 }
james@536 879
james@536 880 NTSTATUS
james@536 881 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
james@536 882 {
james@536 883 NTSTATUS status = STATUS_SUCCESS;
james@622 884 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@622 885 LARGE_INTEGER timeout;
james@536 886
james@536 887 FUNCTION_ENTER();
james@538 888
james@538 889 switch (target_state)
james@538 890 {
james@538 891 case WdfPowerDeviceD0:
james@538 892 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 893 break;
james@538 894 case WdfPowerDeviceD1:
james@538 895 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 896 break;
james@538 897 case WdfPowerDeviceD2:
james@538 898 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
james@538 899 break;
james@538 900 case WdfPowerDeviceD3:
james@538 901 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
james@538 902 break;
james@538 903 case WdfPowerDeviceD3Final:
james@538 904 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
james@538 905 break;
james@538 906 case WdfPowerDevicePrepareForHibernation:
james@538 907 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
james@538 908 break;
james@538 909 default:
james@538 910 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
james@538 911 break;
james@538 912 }
james@624 913
james@624 914 if (target_state == WdfPowerDeviceD3Final)
james@624 915 {
james@624 916 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
james@624 917
james@624 918 xpdd->balloon_shutdown = TRUE;
james@624 919 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
james@622 920
james@622 921 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@624 922 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
james@624 923 {
james@624 924 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@624 925 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
james@624 926 }
james@624 927 ObDereferenceObject(xpdd->balloon_thread);
james@624 928
james@624 929 XenBus_Halt(xpdd);
james@622 930 }
james@624 931 else
james@624 932 {
james@624 933 XenBus_Suspend(xpdd);
james@624 934 }
james@622 935
james@536 936 FUNCTION_EXIT();
james@536 937
james@536 938 return status;
james@536 939 }
james@536 940
james@536 941 NTSTATUS
james@536 942 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
james@536 943 {
james@536 944 NTSTATUS status = STATUS_SUCCESS;
james@538 945 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@536 946
james@536 947 FUNCTION_ENTER();
james@538 948
james@538 949 switch (target_state)
james@538 950 {
james@538 951 case WdfPowerDeviceD0:
james@538 952 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 953 break;
james@538 954 case WdfPowerDeviceD1:
james@538 955 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
james@538 956 break;
james@538 957 case WdfPowerDeviceD2:
james@538 958 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
james@538 959 break;
james@538 960 case WdfPowerDeviceD3:
james@538 961 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
james@538 962 break;
james@538 963 case WdfPowerDeviceD3Final:
james@538 964 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
james@538 965 break;
james@538 966 case WdfPowerDevicePrepareForHibernation:
james@538 967 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
james@538 968 xpdd->hibernated = TRUE;
james@538 969 break;
james@538 970 default:
james@538 971 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
james@538 972 break;
james@538 973 }
james@551 974
james@624 975 if (target_state == WdfPowerDeviceD3Final)
james@624 976 {
james@624 977 /* we don't really support exit here */
james@624 978 }
james@624 979 else
james@551 980 {
james@841 981 EvtChn_Suspend(xpdd);
james@551 982 GntTbl_Suspend(xpdd);
james@841 983
james@551 984 }
james@538 985
james@536 986 FUNCTION_EXIT();
james@536 987
james@536 988 return status;
james@536 989 }
james@536 990
james@536 991 NTSTATUS
james@536 992 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
james@536 993 {
james@536 994 NTSTATUS status = STATUS_SUCCESS;
james@536 995
james@536 996 UNREFERENCED_PARAMETER(device);
james@536 997 UNREFERENCED_PARAMETER(resources_translated);
james@536 998
james@536 999 FUNCTION_ENTER();
james@536 1000 FUNCTION_EXIT();
james@536 1001
james@536 1002 return status;
james@536 1003 }
james@536 1004
james@624 1005 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
james@790 1006 /* Can be called concurrently, but KMDF takes care of concurrent calls to WdfChildListXxx */
james@536 1007 VOID
james@536 1008 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
james@536 1009 {
james@536 1010 NTSTATUS status;
james@536 1011 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
james@536 1012 char *msg;
james@536 1013 char **devices;
james@536 1014 char **instances;
james@538 1015 ULONG i, j;
james@536 1016 CHAR path[128];
james@536 1017 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
james@624 1018 PVOID entry;
james@803 1019 WDFDEVICE child_device;
james@803 1020 WDF_CHILD_RETRIEVE_INFO retrieve_info;
james@536 1021
james@536 1022 FUNCTION_ENTER();
james@536 1023
james@536 1024 WdfChildListBeginScan(child_list);
james@536 1025
james@536 1026 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
james@536 1027 if (!msg)
james@536 1028 {
james@536 1029 for (i = 0; devices[i]; i++)
james@536 1030 {
james@628 1031 /* make sure the key is not in the veto list */
james@624 1032 for (entry = xpdd->veto_list.Flink; entry != &xpdd->veto_list; entry = ((PLIST_ENTRY)entry)->Flink)
james@538 1033 {
james@624 1034 if (!strcmp(devices[i], (PCHAR)entry + sizeof(LIST_ENTRY)))
james@538 1035 break;
james@538 1036 }
james@624 1037 if (entry != &xpdd->veto_list)
james@538 1038 {
james@538 1039 XenPci_FreeMem(devices[i]);
james@538 1040 continue;
james@538 1041 }
james@538 1042
james@628 1043 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
james@536 1044 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
james@536 1045 if (!msg)
james@536 1046 {
james@536 1047 for (j = 0; instances[j]; j++)
james@536 1048 {
james@536 1049 /* the device comparison is done as a memory compare so zero-ing the structure is important */
james@536 1050 RtlZeroMemory(&child_description, sizeof(child_description));
james@536 1051 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
james@536 1052 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
james@683 1053 KdPrint((__DRIVER_NAME " Found path = %s\n", path));
james@536 1054 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
james@536 1055 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
james@536 1056 child_description.index = atoi(instances[j]);
james@803 1057 WDF_CHILD_RETRIEVE_INFO_INIT(&retrieve_info, &child_description.header);
james@803 1058 child_device = WdfChildListRetrievePdo(child_list, &retrieve_info);
james@803 1059 if (child_device)
james@803 1060 {
james@803 1061 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(child_device);
james@803 1062 char *err;
james@803 1063 char *value;
james@803 1064 char backend_state_path[128];
james@803 1065
james@803 1066 if (xppdd->do_not_enumerate)
james@803 1067 {
james@803 1068 RtlStringCbPrintfA(backend_state_path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
james@803 1069
james@803 1070 err = XenBus_Read(xpdd, XBT_NIL, backend_state_path, &value);
james@803 1071 if (err)
james@803 1072 {
james@803 1073 XenPci_FreeMem(err);
james@803 1074 xppdd->backend_state = XenbusStateUnknown;
james@803 1075 }
james@803 1076 else
james@803 1077 {
james@803 1078 xppdd->backend_state = atoi(value);
james@803 1079 XenPci_FreeMem(value);
james@803 1080 }
james@803 1081 if (xppdd->backend_state == XenbusStateClosing || xppdd->backend_state == XenbusStateClosed)
james@803 1082 {
james@803 1083 KdPrint((__DRIVER_NAME " Surprise removing %s due to backend initiated remove\n", path));
james@803 1084 XenPci_FreeMem(instances[j]);
james@803 1085 continue;
james@803 1086 }
james@803 1087 else
james@803 1088 {
james@803 1089 /* I guess we are being added again ... */
james@803 1090 xppdd->backend_initiated_remove = FALSE;
james@803 1091 xppdd->do_not_enumerate = FALSE;
james@803 1092 }
james@803 1093 }
james@803 1094 }
james@536 1095 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
james@536 1096 if (!NT_SUCCESS(status))
james@536 1097 {
james@536 1098 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
james@536 1099 }
james@536 1100 XenPci_FreeMem(instances[j]);
james@536 1101 }
james@536 1102 XenPci_FreeMem(instances);
james@536 1103 }
james@536 1104 else
james@536 1105 {
james@536 1106 // wtf do we do here???
james@536 1107 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
james@536 1108 }
james@536 1109 XenPci_FreeMem(devices[i]);
james@536 1110 }
james@536 1111 XenPci_FreeMem(devices);
james@536 1112 }
james@536 1113 else
james@536 1114 {
james@536 1115 // wtf do we do here???
james@536 1116 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
james@536 1117 }
james@536 1118
james@536 1119 WdfChildListEndScan(child_list);
james@624 1120
james@536 1121 FUNCTION_EXIT();
james@536 1122 }