win-pvdrivers

annotate xenpci/xenpci_fdo.c @ 1030:37c0c84a42e8

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