win-pvdrivers

annotate xenpci/xenpci_fdo.c @ 1093:5be1f70687ad

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