win-pvdrivers

annotate xenpci/xenpci_fdo.c @ 1054:471c94d04d8a

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