win-pvdrivers

annotate xenpci/xenpci_fdo.c @ 794:aee3767c191d

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