win-pvdrivers

annotate xenpci/xenpci.c @ 1022:cd72cd0e1c19

hooking debug doesn't survive hibernate under win8. Remove it.
Remove initial balloon down - doesn't work under xen 4.2 without xenbus being loaded
author James Harper <james.harper@bendigoit.com.au>
date Tue Feb 19 15:11:49 2013 +1100 (2013-02-19)
parents 9e076343bb8e
children 37c0c84a42e8
rev   line source
james@0 1 /*
james@0 2 PV Drivers for Windows Xen HVM Domains
james@0 3 Copyright (C) 2007 James Harper
james@0 4
james@0 5 This program is free software; you can redistribute it and/or
james@0 6 modify it under the terms of the GNU General Public License
james@0 7 as published by the Free Software Foundation; either version 2
james@0 8 of the License, or (at your option) any later version.
james@0 9
james@0 10 This program is distributed in the hope that it will be useful,
james@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@0 13 GNU General Public License for more details.
james@0 14
james@0 15 You should have received a copy of the GNU General Public License
james@0 16 along with this program; if not, write to the Free Software
james@0 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@0 18 */
james@0 19
andy@346 20 #define INITGUID
james@0 21 #include "xenpci.h"
james@638 22 #include <aux_klib.h>
james@0 23 #include <stdlib.h>
james@0 24
james@116 25 #define SYSRQ_PATH "control/sysrq"
james@0 26 #define SHUTDOWN_PATH "control/shutdown"
james@4 27 #define BALLOON_PATH "memory/target"
james@0 28
andy@88 29 #pragma warning(disable : 4200) // zero-sized array
andy@88 30
james@861 31 PMDL balloon_mdl_head = NULL;
james@861 32
james@716 33 /* Not really necessary but keeps PREfast happy */
james@716 34 DRIVER_INITIALIZE DriverEntry;
james@818 35 static EVT_WDF_DRIVER_UNLOAD XenPci_EvtDriverUnload;
james@716 36 static EVT_WDF_DRIVER_DEVICE_ADD XenPci_EvtDeviceAdd;
james@716 37 static EVT_WDF_DEVICE_USAGE_NOTIFICATION XenPci_EvtDeviceUsageNotification;
james@716 38 static EVT_WDF_DEVICE_PREPARE_HARDWARE XenHide_EvtDevicePrepareHardware;
james@716 39
james@907 40 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
james@987 41 static KBUGCHECK_REASON_CALLBACK_ROUTINE XenPci_DebugHeaderDumpIoCallback;
james@907 42
james@860 43 /* this is supposed to be defined in wdm.h, but isn't */
james@860 44 NTSTATUS
james@860 45 KeInitializeCrashDumpHeader(
james@860 46 IN ULONG Type,
james@860 47 IN ULONG Flags,
james@860 48 OUT PVOID Buffer,
james@860 49 IN ULONG BufferSize,
james@860 50 OUT PULONG BufferNeeded OPTIONAL
james@860 51 );
james@907 52 #endif
james@860 53
james@860 54 #define DUMP_TYPE_FULL 1
james@860 55
james@538 56 static VOID
james@538 57 XenPci_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
james@538 58 {
james@538 59 FUNCTION_ENTER();
james@538 60
james@538 61 UNREFERENCED_PARAMETER(device);
james@700 62 UNREFERENCED_PARAMETER(is_in_notification_path);
james@538 63
james@538 64 switch (notification_type)
james@538 65 {
james@538 66 case WdfSpecialFilePaging:
james@538 67 KdPrint((__DRIVER_NAME " notification_type = Paging, flag = %d\n", is_in_notification_path));
james@538 68 break;
james@538 69 case WdfSpecialFileHibernation:
james@538 70 KdPrint((__DRIVER_NAME " notification_type = Hibernation, flag = %d\n", is_in_notification_path));
james@538 71 break;
james@538 72 case WdfSpecialFileDump:
james@538 73 KdPrint((__DRIVER_NAME " notification_type = Dump, flag = %d\n", is_in_notification_path));
james@538 74 break;
james@538 75 default:
james@538 76 KdPrint((__DRIVER_NAME " notification_type = %d, flag = %d\n", notification_type, is_in_notification_path));
james@538 77 break;
james@538 78 }
james@538 79
james@538 80 FUNCTION_EXIT();
james@538 81 }
james@538 82
james@536 83 static NTSTATUS
james@561 84 XenPci_EvtDeviceAdd_XenPci(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
james@0 85 {
james@258 86 NTSTATUS status;
james@536 87 // PDEVICE_OBJECT fdo = NULL;
james@258 88 // PNP_BUS_INFORMATION busInfo;
james@258 89 // DECLARE_CONST_UNICODE_STRING(DeviceName, L"\\Device\\XenShutdown");
james@258 90 // DECLARE_CONST_UNICODE_STRING(SymbolicName, L"\\DosDevices\\XenShutdown");
james@536 91 WDF_CHILD_LIST_CONFIG child_list_config;
james@536 92 WDFDEVICE device;
andy@16 93 PXENPCI_DEVICE_DATA xpdd;
james@504 94 UNICODE_STRING reference;
james@536 95 WDF_OBJECT_ATTRIBUTES device_attributes;
james@536 96 PNP_BUS_INFORMATION pbi;
james@536 97 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
james@536 98 WDF_INTERRUPT_CONFIG interrupt_config;
james@536 99 WDF_OBJECT_ATTRIBUTES file_attributes;
james@536 100 WDF_FILEOBJECT_CONFIG file_config;
james@536 101 WDF_IO_QUEUE_CONFIG queue_config;
james@624 102 WDFCOLLECTION veto_devices;
james@538 103 WDFKEY param_key;
james@538 104 DECLARE_CONST_UNICODE_STRING(veto_devices_name, L"veto_devices");
james@538 105 WDF_DEVICE_POWER_CAPABILITIES power_capabilities;
james@1022 106 PPHYSICAL_MEMORY_RANGE pmr_head, pmr;
james@624 107 int i;
james@536 108
james@536 109 UNREFERENCED_PARAMETER(driver);
james@0 110
andy@398 111 FUNCTION_ENTER();
james@561 112
james@536 113 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
james@536 114 pnp_power_callbacks.EvtDeviceD0Entry = XenPci_EvtDeviceD0Entry;
james@536 115 pnp_power_callbacks.EvtDeviceD0EntryPostInterruptsEnabled = XenPci_EvtDeviceD0EntryPostInterruptsEnabled;
james@536 116 pnp_power_callbacks.EvtDeviceD0Exit = XenPci_EvtDeviceD0Exit;
james@536 117 pnp_power_callbacks.EvtDeviceD0ExitPreInterruptsDisabled = XenPci_EvtDeviceD0ExitPreInterruptsDisabled;
james@536 118 pnp_power_callbacks.EvtDevicePrepareHardware = XenPci_EvtDevicePrepareHardware;
james@536 119 pnp_power_callbacks.EvtDeviceReleaseHardware = XenPci_EvtDeviceReleaseHardware;
james@537 120 pnp_power_callbacks.EvtDeviceQueryRemove = XenPci_EvtDeviceQueryRemove;
james@538 121 pnp_power_callbacks.EvtDeviceUsageNotification = XenPci_EvtDeviceUsageNotification;
james@538 122
james@536 123 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
james@536 124
james@536 125 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_BUS_EXTENDER);
james@536 126 WdfDeviceInitSetExclusive(device_init, FALSE);
james@536 127
james@536 128 WDF_CHILD_LIST_CONFIG_INIT(&child_list_config, sizeof(XENPCI_PDO_IDENTIFICATION_DESCRIPTION), XenPci_EvtChildListCreateDevice);
james@536 129 child_list_config.EvtChildListScanForChildren = XenPci_EvtChildListScanForChildren;
james@536 130 WdfFdoInitSetDefaultChildListConfig(device_init, &child_list_config, WDF_NO_OBJECT_ATTRIBUTES);
james@536 131
james@536 132 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&file_attributes, XENPCI_DEVICE_INTERFACE_DATA);
james@536 133 WDF_FILEOBJECT_CONFIG_INIT(&file_config, XenPci_EvtDeviceFileCreate, XenPci_EvtFileClose, XenPci_EvtFileCleanup);
james@536 134 WdfDeviceInitSetFileObjectConfig(device_init, &file_config, &file_attributes);
james@536 135
james@536 136 WdfDeviceInitSetIoType(device_init, WdfDeviceIoBuffered);
james@538 137
james@538 138 WdfDeviceInitSetPowerNotPageable(device_init);
james@536 139
james@536 140 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENPCI_DEVICE_DATA);
james@536 141 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
james@1022 142 if (!NT_SUCCESS(status)) {
james@538 143 KdPrint(("Error creating device %08x\n", status));
james@538 144 return status;
james@536 145 }
james@536 146
james@536 147 xpdd = GetXpdd(device);
james@622 148 xpdd->wdf_device = device;
james@599 149 xpdd->child_list = WdfFdoGetDefaultChildList(device);
james@536 150
james@1022 151 /* this is not a documented function */
james@1022 152 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
james@1022 153 pmr_head = MmGetPhysicalMemoryRanges();
james@1022 154 xpdd->current_memory_kb = 0;
james@1022 155 for (pmr = pmr_head; !(pmr->BaseAddress.QuadPart == 0 && pmr->NumberOfBytes.QuadPart == 0); pmr++) {
james@1022 156 xpdd->current_memory_kb += (ULONG)(pmr->NumberOfBytes.QuadPart / 1024);
james@1022 157 }
james@1022 158 FUNCTION_MSG("current_memory_kb = %d\n", xpdd->current_memory_kb);
james@1022 159 /* round to MB increments because that is what balloon deals in */
james@1022 160 xpdd->current_memory_kb = (xpdd->current_memory_kb + 0x1FF) & 0xFFFFFC00;
james@1022 161 FUNCTION_MSG("current_memory_kb rounded to %d\n", xpdd->current_memory_kb);
james@1022 162
james@1012 163 ExInitializeFastMutex(&xpdd->suspend_mutex);
james@624 164 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &veto_devices);
james@538 165 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &param_key);
james@1022 166 if (NT_SUCCESS(status)) {
james@624 167 status = WdfRegistryQueryMultiString(param_key, &veto_devices_name, WDF_NO_OBJECT_ATTRIBUTES, veto_devices);
james@1022 168 if (!NT_SUCCESS(status)) {
james@538 169 KdPrint(("Error reading parameters/veto_devices value %08x\n", status));
james@538 170 }
james@538 171 WdfRegistryClose(param_key);
james@1022 172 } else {
james@538 173 KdPrint(("Error opening parameters key %08x\n", status));
james@538 174 }
james@624 175
james@624 176 InitializeListHead(&xpdd->veto_list);
james@1022 177 for (i = 0; i < (int)WdfCollectionGetCount(veto_devices); i++) {
james@624 178 WDFOBJECT ws;
james@624 179 UNICODE_STRING val;
james@624 180 ANSI_STRING s;
james@624 181 PVOID entry;
james@624 182 ws = WdfCollectionGetItem(veto_devices, i);
james@624 183 WdfStringGetUnicodeString(ws, &val);
james@624 184 RtlUnicodeStringToAnsiString(&s, &val, TRUE);
james@624 185 entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY) + s.Length + 1, XENPCI_POOL_TAG);
james@624 186 memcpy((PUCHAR)entry + sizeof(LIST_ENTRY), s.Buffer, s.Length + 1);
james@624 187 RtlFreeAnsiString(&s);
james@624 188 InsertTailList(&xpdd->veto_list, (PLIST_ENTRY)entry);
james@624 189 }
james@538 190 WDF_DEVICE_POWER_CAPABILITIES_INIT(&power_capabilities);
james@538 191 power_capabilities.DeviceD1 = WdfTrue;
james@538 192 power_capabilities.WakeFromD1 = WdfTrue;
james@538 193 power_capabilities.DeviceWake = PowerDeviceD1;
james@912 194 power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
james@538 195 power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
james@538 196 power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
james@538 197 power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
james@538 198 power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
james@538 199 power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
james@538 200 WdfDeviceSetPowerCapabilities(device, &power_capabilities);
james@538 201
james@536 202 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
james@536 203 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
james@536 204 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
james@536 205
james@536 206 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchParallel);
james@671 207 queue_config.EvtIoDefault = XenPci_EvtIoDefault;
james@536 208 status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->io_queue);
james@536 209 if (!NT_SUCCESS(status)) {
james@536 210 KdPrint(("Error creating queue 0x%x\n", status));
james@536 211 return status;
james@536 212 }
james@536 213
james@536 214 WDF_INTERRUPT_CONFIG_INIT(&interrupt_config, EvtChn_EvtInterruptIsr, NULL);
james@536 215 interrupt_config.EvtInterruptEnable = EvtChn_EvtInterruptEnable;
james@536 216 interrupt_config.EvtInterruptDisable = EvtChn_EvtInterruptDisable;
james@536 217
james@536 218 status = WdfInterruptCreate(device, &interrupt_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->interrupt);
james@536 219 if (!NT_SUCCESS(status))
james@536 220 {
james@536 221 KdPrint(("Error creating interrupt 0x%x\n", status));
james@536 222 return status;
james@536 223 }
james@536 224
james@536 225 RtlInitUnicodeString(&reference, L"xenbus");
james@536 226 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_XENBUS, &reference);
james@536 227 if (!NT_SUCCESS(status)) {
james@536 228 KdPrint(("Error registering device interface 0x%x\n", status));
james@536 229 return status;
james@536 230 }
james@536 231
james@671 232 RtlInitUnicodeString(&reference, L"evtchn");
james@671 233 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_EVTCHN, &reference);
james@671 234 if (!NT_SUCCESS(status)) {
james@671 235 KdPrint(("Error registering device interface 0x%x\n", status));
james@671 236 return status;
james@671 237 }
james@671 238
james@671 239 RtlInitUnicodeString(&reference, L"gntdev");
james@671 240 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_GNTDEV, &reference);
james@671 241 if (!NT_SUCCESS(status)) {
james@671 242 KdPrint(("Error registering device interface 0x%x\n", status));
james@671 243 return status;
james@671 244 }
james@671 245
james@536 246 pbi.BusTypeGuid = GUID_BUS_TYPE_XEN;
james@536 247 pbi.LegacyBusType = PNPBus;
james@536 248 pbi.BusNumber = 0;
james@536 249 WdfDeviceSetBusInformationForChildren(device, &pbi);
james@536 250
james@537 251 xpdd->removable = TRUE;
james@536 252
james@536 253 FUNCTION_EXIT();
james@536 254 return status;
james@0 255 }
james@0 256
james@561 257 NTSTATUS
james@747 258 XenHide_EvtDevicePrepareHardware(WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
james@561 259 {
james@561 260 UNREFERENCED_PARAMETER(device);
james@561 261 UNREFERENCED_PARAMETER(resources_raw);
james@561 262 UNREFERENCED_PARAMETER(resources_translated);
james@561 263 FUNCTION_ENTER();
james@561 264 FUNCTION_EXIT();
james@561 265 return STATUS_UNSUCCESSFUL;
james@561 266 }
james@561 267
james@561 268 static BOOLEAN
james@1022 269 XenPci_IdSuffixMatches(PWDFDEVICE_INIT device_init, PWCHAR matching_id) {
james@561 270 NTSTATUS status;
james@561 271 WDFMEMORY memory;
james@561 272 ULONG remaining;
james@561 273 size_t string_length;
james@561 274 PWCHAR ids;
james@561 275 PWCHAR ptr;
james@561 276 size_t ids_length;
james@561 277 ULONG properties[] = {DevicePropertyCompatibleIDs, DevicePropertyHardwareID};
james@561 278 int i;
james@561 279
james@561 280 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@561 281 for (i = 0; i < ARRAY_SIZE(properties); i++)
james@561 282 {
james@561 283
james@561 284 status = WdfFdoInitAllocAndQueryProperty(device_init, properties[i], NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
james@561 285 if (!NT_SUCCESS(status))
james@561 286 continue;
james@561 287 ids = WdfMemoryGetBuffer(memory, &ids_length);
james@561 288
james@1022 289 if (!NT_SUCCESS(status)) {
james@561 290 continue;
james@561 291 }
james@561 292
james@561 293 remaining = (ULONG)ids_length / 2;
james@1022 294 for (ptr = ids; *ptr != 0; ptr += string_length + 1) {
james@561 295 RtlStringCchLengthW(ptr, remaining, &string_length);
james@561 296 remaining -= (ULONG)string_length + 1;
james@1022 297 if (string_length >= wcslen(matching_id)) {
james@561 298 ptr += string_length - wcslen(matching_id);
james@561 299 string_length = wcslen(matching_id);
james@561 300 }
james@1022 301 if (wcscmp(ptr, matching_id) == 0) {
james@561 302 WdfObjectDelete(memory);
james@561 303 return TRUE;
james@561 304 }
james@561 305 }
james@561 306 WdfObjectDelete(memory);
james@561 307 }
james@561 308 return FALSE;
james@561 309 }
james@561 310
james@747 311 WDFCOLLECTION qemu_hide_devices;
james@747 312 USHORT qemu_hide_flags_value;
james@561 313
james@561 314 static NTSTATUS
james@561 315 XenPci_EvtDeviceAdd_XenHide(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
james@561 316 {
james@561 317 NTSTATUS status;
james@561 318 WDFMEMORY memory;
james@561 319 PWCHAR device_description;
james@561 320 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
james@561 321 WDF_OBJECT_ATTRIBUTES device_attributes;
james@561 322 BOOLEAN hide_required = FALSE;
james@561 323 WDFDEVICE device;
james@561 324 ULONG i;
james@747 325
james@561 326 UNREFERENCED_PARAMETER(driver);
james@561 327
james@561 328 FUNCTION_ENTER();
james@561 329
james@561 330 status = WdfFdoInitAllocAndQueryProperty(device_init, DevicePropertyDeviceDescription, NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
james@1006 331 if (NT_SUCCESS(status)) {
james@561 332 device_description = WdfMemoryGetBuffer(memory, NULL);
james@1006 333 } else {
james@561 334 device_description = L"<unknown device>";
james@561 335 }
james@1006 336
james@1006 337 for (i = 0; i < WdfCollectionGetCount(qemu_hide_devices); i++) {
james@747 338 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_devices, i);
james@561 339 UNICODE_STRING unicode_string;
james@561 340 WdfStringGetUnicodeString(wdf_string, &unicode_string);
james@1006 341 if (XenPci_IdSuffixMatches(device_init, unicode_string.Buffer)) {
james@561 342 hide_required = TRUE;
james@561 343 break;
james@561 344 }
james@561 345 }
james@1006 346 if (!hide_required) {
james@1006 347 FUNCTION_MSG("(filter not required for %S)\n", device_description);
james@561 348 WdfObjectDelete(memory);
james@561 349 return STATUS_SUCCESS;
james@561 350 }
james@561 351
james@1006 352 FUNCTION_MSG("Installing Filter for %S\n", device_description);
james@1006 353
james@561 354 WdfFdoInitSetFilter(device_init);
james@561 355 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
james@561 356 WdfDeviceInitSetExclusive(device_init, FALSE);
james@561 357
james@561 358 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
james@561 359 pnp_power_callbacks.EvtDevicePrepareHardware = XenHide_EvtDevicePrepareHardware;
james@561 360 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
james@561 361
james@561 362 WDF_OBJECT_ATTRIBUTES_INIT(&device_attributes);
james@561 363 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
james@1006 364 if (!NT_SUCCESS(status)) {
james@1006 365 FUNCTION_MSG("Error creating device %08x\n", status);
james@561 366 WdfObjectDelete(memory);
james@561 367 FUNCTION_EXIT();
james@561 368 return status;
james@561 369 }
james@561 370
james@561 371 WdfObjectDelete(memory);
james@561 372 FUNCTION_EXIT();
james@561 373
james@561 374 return status;
james@561 375 }
james@561 376
james@561 377 static NTSTATUS
james@561 378 XenPci_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
james@561 379 {
james@1006 380 if (XenPci_IdSuffixMatches(device_init, L"VEN_5853&DEV_0001")) {
james@1006 381 FUNCTION_MSG("Xen PCI device found - must be fdo\n");
james@561 382 return XenPci_EvtDeviceAdd_XenPci(driver, device_init);
james@1006 383 } else if (WdfCollectionGetCount(qemu_hide_devices) > 0) {
james@1006 384 FUNCTION_MSG("Xen PCI device not found - must be filter\n");
james@1006 385 return XenPci_EvtDeviceAdd_XenHide(driver, device_init);
james@1006 386 } else {
james@1006 387 return STATUS_SUCCESS;
james@561 388 }
james@561 389 }
james@561 390
james@497 391 ULONG qemu_protocol_version;
james@529 392 ULONG tpr_patch_requested;
james@495 393 extern PULONG InitSafeBootMode;
james@486 394
james@536 395 VOID
james@1022 396 XenPci_HideQemuDevices() {
james@979 397 #pragma warning(suppress:28138)
james@747 398 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, (USHORT)qemu_hide_flags_value); //QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
james@800 399 KdPrint((__DRIVER_NAME " Disabled qemu devices %02x\n", qemu_hide_flags_value));
james@747 400 }
james@747 401
james@747 402 static BOOLEAN
james@747 403 XenPci_CheckHideQemuDevices()
james@747 404 {
james@979 405 #pragma warning(suppress:28138)
james@1022 406 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2) {
james@979 407 #pragma warning(suppress:28138)
james@536 408 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
james@536 409 KdPrint((__DRIVER_NAME " Version = %d\n", qemu_protocol_version));
james@1022 410 switch(qemu_protocol_version) {
james@536 411 case 1:
james@979 412 #pragma warning(suppress:28138)
james@536 413 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
james@979 414 #pragma warning(suppress:28138)
james@536 415 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
james@979 416 #pragma warning(suppress:28138)
james@536 417 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
james@536 418 {
james@536 419 KdPrint((__DRIVER_NAME " Blacklisted\n"));
james@536 420 break;
james@536 421 }
james@536 422 /* fall through */
james@536 423 case 0:
james@747 424 return TRUE;
james@536 425 default:
james@536 426 KdPrint((__DRIVER_NAME " Unknown qemu version %d\n", qemu_protocol_version));
james@536 427 break;
james@533 428 }
james@533 429 }
james@747 430 return FALSE;
james@533 431 }
james@533 432
james@539 433 /*
james@561 434 make sure the load order is System Reserved, Dummy Group, WdfLoadGroup, XenPCI, Boot Bus Extender
james@539 435 */
james@539 436
james@539 437 static VOID
james@539 438 XenPci_FixLoadOrder()
james@539 439 {
james@539 440 NTSTATUS status;
james@539 441 WDFCOLLECTION old_load_order, new_load_order;
james@539 442 DECLARE_CONST_UNICODE_STRING(sgo_name, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder");
james@539 443 DECLARE_CONST_UNICODE_STRING(list_name, L"List");
james@539 444 WDFKEY sgo_key;
james@539 445 ULONG i;
james@539 446 LONG dummy_group_index = -1;
james@539 447 LONG boot_bus_extender_index = -1;
james@561 448 LONG xenpci_group_index = -1;
james@539 449 LONG wdf_load_group_index = -1;
james@539 450 DECLARE_CONST_UNICODE_STRING(dummy_group_name, L"Dummy Group");
james@539 451 DECLARE_CONST_UNICODE_STRING(wdf_load_group_name, L"WdfLoadGroup");
james@561 452 DECLARE_CONST_UNICODE_STRING(xenpci_group_name, L"XenPCI Group");
james@539 453 DECLARE_CONST_UNICODE_STRING(boot_bus_extender_name, L"Boot Bus Extender");
james@539 454
james@539 455 FUNCTION_ENTER();
james@539 456
james@539 457 status = WdfRegistryOpenKey(NULL, &sgo_name, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &sgo_key);
james@539 458 if (!NT_SUCCESS(status))
james@539 459 {
james@539 460 KdPrint((__DRIVER_NAME " Error opening ServiceGroupOrder key %08x\n", status));
james@539 461 return;
james@539 462 }
james@539 463 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &old_load_order);
james@539 464 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &new_load_order);
james@539 465 status = WdfRegistryQueryMultiString(sgo_key, &list_name, WDF_NO_OBJECT_ATTRIBUTES, old_load_order);
james@539 466 if (!NT_SUCCESS(status))
james@539 467 {
james@539 468 KdPrint((__DRIVER_NAME " Error reading ServiceGroupOrder\\List value %08x\n", status));
james@539 469 WdfObjectDelete(new_load_order);
james@539 470 WdfObjectDelete(old_load_order);
james@539 471 return;
james@539 472 }
james@789 473 //KdPrint((__DRIVER_NAME " Current Order:\n"));
james@539 474 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
james@539 475 {
james@539 476 WDFOBJECT ws = WdfCollectionGetItem(old_load_order, i);
james@539 477 UNICODE_STRING val;
james@539 478 WdfStringGetUnicodeString(ws, &val);
james@539 479 if (!RtlCompareUnicodeString(&val, &dummy_group_name, TRUE))
james@539 480 dummy_group_index = (ULONG)i;
james@539 481 if (!RtlCompareUnicodeString(&val, &wdf_load_group_name, TRUE))
james@539 482 wdf_load_group_index = (ULONG)i;
james@561 483 if (!RtlCompareUnicodeString(&val, &xenpci_group_name, TRUE))
james@561 484 xenpci_group_index = (ULONG)i;
james@539 485 if (!RtlCompareUnicodeString(&val, &boot_bus_extender_name, TRUE))
james@539 486 boot_bus_extender_index = (ULONG)i;
james@789 487 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
james@539 488 }
james@539 489 KdPrint((__DRIVER_NAME " dummy_group_index = %d\n", dummy_group_index));
james@539 490 KdPrint((__DRIVER_NAME " wdf_load_group_index = %d\n", wdf_load_group_index));
james@561 491 KdPrint((__DRIVER_NAME " xenpci_group_index = %d\n", xenpci_group_index));
james@539 492 KdPrint((__DRIVER_NAME " boot_bus_extender_index = %d\n", boot_bus_extender_index));
james@539 493 if (boot_bus_extender_index == -1)
james@539 494 {
james@539 495 WdfObjectDelete(new_load_order);
james@539 496 WdfObjectDelete(old_load_order);
james@539 497 WdfRegistryClose(sgo_key);
james@539 498 return; /* something is very wrong */
james@539 499 }
james@827 500 if (dummy_group_index == 1 && wdf_load_group_index != -1 &&
james@561 501 (dummy_group_index < wdf_load_group_index
james@561 502 && wdf_load_group_index < xenpci_group_index
james@827 503 && xenpci_group_index < boot_bus_extender_index))
james@539 504 {
james@809 505 FUNCTION_EXIT();
james@539 506 return; /* our work here is done */
james@539 507 }
james@539 508 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
james@539 509 {
james@539 510 WDFOBJECT ws;
james@539 511 if (i == 1)
james@539 512 {
james@539 513 WDFSTRING tmp_wdf_string;
james@539 514 WdfStringCreate(&dummy_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
james@539 515 WdfCollectionAdd(new_load_order, tmp_wdf_string);
james@539 516 WdfObjectDelete(tmp_wdf_string);
james@539 517 }
james@827 518 if (i == 1)
james@539 519 {
james@539 520 WDFSTRING tmp_wdf_string;
james@539 521 WdfStringCreate(&wdf_load_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
james@539 522 WdfCollectionAdd(new_load_order, tmp_wdf_string);
james@539 523 WdfObjectDelete(tmp_wdf_string);
james@539 524 }
james@561 525 if (i == 1)
james@561 526 {
james@561 527 WDFSTRING tmp_wdf_string;
james@561 528 WdfStringCreate(&xenpci_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
james@561 529 WdfCollectionAdd(new_load_order, tmp_wdf_string);
james@561 530 WdfObjectDelete(tmp_wdf_string);
james@561 531 }
james@561 532 if (i == (ULONG)dummy_group_index || i == (ULONG)wdf_load_group_index || i == (ULONG)xenpci_group_index)
james@539 533 continue;
james@539 534 ws = WdfCollectionGetItem(old_load_order, i);
james@539 535 WdfCollectionAdd(new_load_order, ws);
james@539 536 }
james@539 537 WdfRegistryAssignMultiString(sgo_key, &list_name, new_load_order);
james@789 538 //KdPrint((__DRIVER_NAME " New Order:\n"));
james@539 539 for (i = 0; i < WdfCollectionGetCount(new_load_order); i++)
james@539 540 {
james@539 541 WDFOBJECT ws = WdfCollectionGetItem(new_load_order, i);
james@539 542 UNICODE_STRING val;
james@539 543 WdfStringGetUnicodeString(ws, &val);
james@789 544 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
james@539 545 }
james@539 546 WdfObjectDelete(new_load_order);
james@539 547 WdfObjectDelete(old_load_order);
james@539 548 WdfRegistryClose(sgo_key);
james@539 549
james@539 550 FUNCTION_EXIT();
james@539 551
james@539 552 return;
james@539 553 }
james@539 554
james@800 555 VOID
james@800 556 XenPci_EvtDriverUnload(WDFDRIVER driver)
james@800 557 {
james@800 558 UNREFERENCED_PARAMETER(driver);
james@800 559
james@1022 560 // #if DBG
james@1022 561 // XenPci_UnHookDbgPrint();
james@1022 562 // #endif
james@860 563 }
james@860 564
james@987 565 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
james@979 566 /* this isn't freed on shutdown... perhaps it should be */
james@987 567 static PUCHAR dump_header;
james@987 568 static ULONG dump_header_size;
james@987 569 static ULONG dump_header_refreshed_flag = FALSE;
james@987 570 static KBUGCHECK_REASON_CALLBACK_RECORD callback_record;
james@987 571 #define DUMP_HEADER_PREFIX_SIZE 8
james@987 572 #define DUMP_HEADER_SUFFIX_SIZE 8
james@979 573
james@987 574 /* call KeInitializeCrashDumpHeader once on crash */
james@987 575 static VOID
james@987 576 XenPci_DebugHeaderDumpIoCallback(
james@987 577 KBUGCHECK_CALLBACK_REASON reason,
james@987 578 PKBUGCHECK_REASON_CALLBACK_RECORD record,
james@987 579 PVOID reason_specific_data,
james@987 580 ULONG reason_specific_data_length) {
james@987 581 UNREFERENCED_PARAMETER(reason);
james@987 582 UNREFERENCED_PARAMETER(record);
james@987 583 UNREFERENCED_PARAMETER(reason_specific_data);
james@987 584 UNREFERENCED_PARAMETER(reason_specific_data_length);
james@987 585 if (!dump_header_refreshed_flag) {
james@987 586 NTSTATUS status;
james@987 587 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
james@987 588 /* copy bug check code in? */
james@987 589 dump_header_refreshed_flag = TRUE;
james@987 590 }
james@987 591 }
james@987 592 #endif
james@987 593
james@536 594 NTSTATUS
james@259 595 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
james@258 596 {
james@258 597 NTSTATUS status = STATUS_SUCCESS;
james@536 598 WDF_DRIVER_CONFIG config;
james@536 599 WDFDRIVER driver;
james@809 600 WDF_OBJECT_ATTRIBUTES parent_attributes;
james@495 601 PCONFIGURATION_INFORMATION conf_info;
james@809 602 WDFKEY control_key;
james@793 603 WDFKEY param_key;
james@809 604 ULONG always_patch = 0;
james@809 605 ULONG always_hide = 0;
james@809 606 DECLARE_CONST_UNICODE_STRING(control_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
james@809 607 DECLARE_CONST_UNICODE_STRING(system_start_options_name, L"SystemStartOptions");
james@809 608 DECLARE_CONST_UNICODE_STRING(txt_always_hide_name, L"txt_hide_qemu_always");
james@809 609 DECLARE_CONST_UNICODE_STRING(hide_devices_name, L"hide_devices");
james@809 610 DECLARE_CONST_UNICODE_STRING(txt_always_patch_name, L"txt_patch_tpr_always");
james@809 611 WDFSTRING wdf_system_start_options;
james@809 612 UNICODE_STRING system_start_options;
james@988 613 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
james@987 614 PHYSICAL_ADDRESS dump_header_mem_max;
james@988 615 #endif
james@638 616
james@259 617 UNREFERENCED_PARAMETER(RegistryPath);
andy@90 618
james@809 619 FUNCTION_ENTER();
james@809 620
james@987 621 FUNCTION_MSG(__DRIVER_NAME " " VER_FILEVERSION_STR "\n");
james@666 622
james@927 623 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
james@965 624 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, NULL, 0, &dump_header_size);
james@987 625 /* try and allocate contiguous memory as low as possible */
james@987 626 dump_header = NULL;
james@987 627 dump_header_mem_max.QuadPart = 0xFFFFF;
james@987 628 while (!dump_header && dump_header_mem_max.QuadPart != 0xFFFFFFFFFFFFFFFF) {
james@987 629 dump_header = MmAllocateContiguousMemory(DUMP_HEADER_PREFIX_SIZE + dump_header_size + DUMP_HEADER_SUFFIX_SIZE, dump_header_mem_max);
james@1022 630 if (dump_header) {
james@1022 631 FUNCTION_MSG("Allocated crash dump header < 0x%016I64x\n", dump_header_mem_max.QuadPart);
james@1022 632 break;
james@1022 633 }
james@1022 634 dump_header_mem_max.QuadPart = (dump_header_mem_max.QuadPart << 4) | 0xF;
james@987 635 }
james@987 636 if (dump_header) {
james@987 637 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
james@987 638 FUNCTION_MSG("KeInitializeCrashDumpHeader status = %08x, size = %d\n", status, dump_header_size);
james@987 639 memcpy(dump_header + 0, "XENXEN", 6); /* magic number */
james@987 640 *(PUSHORT)(dump_header + 6) = (USHORT)(INT_PTR)dump_header & (PAGE_SIZE - 1); /* store offset too as additional verification */
james@987 641 memcpy(dump_header + DUMP_HEADER_PREFIX_SIZE + dump_header_size, "XENXEN", 6);
james@987 642 *(PUSHORT)(dump_header + DUMP_HEADER_PREFIX_SIZE + dump_header_size + 6) = (USHORT)(INT_PTR)dump_header & (PAGE_SIZE - 1); /* store offset too as additional verification */
james@987 643 KeInitializeCallbackRecord(&callback_record);
james@987 644 KeRegisterBugCheckReasonCallback(&callback_record, XenPci_DebugHeaderDumpIoCallback, KbCallbackDumpIo, (PUCHAR)"XenPci_DebugHeaderDumpIoCallback");
james@987 645 } else {
james@987 646 FUNCTION_MSG("Failed to allocate memory for crash dump header\n");
james@987 647 }
james@907 648 #endif
james@860 649
james@809 650 /* again after enabling DbgPrint hooking */
james@809 651 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
james@809 652
james@860 653
james@809 654 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
james@809 655 config.EvtDriverUnload = XenPci_EvtDriverUnload;
james@809 656 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
james@1022 657 if (!NT_SUCCESS(status)) {
james@809 658 KdPrint((__DRIVER_NAME " WdfDriverCreate failed with status 0x%x\n", status));
james@809 659 FUNCTION_EXIT();
james@1022 660 //#if DBG
james@1022 661 //XenPci_UnHookDbgPrint();
james@1022 662 //#endif
james@809 663 return status;
james@809 664 }
james@809 665 WDF_OBJECT_ATTRIBUTES_INIT(&parent_attributes);
james@809 666 parent_attributes.ParentObject = driver;
james@809 667
james@809 668 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, &parent_attributes, &param_key);
james@1022 669 if (!NT_SUCCESS(status)) {
james@809 670 KdPrint(("Error opening parameters key %08x\n", status));
james@809 671 goto error;
james@809 672 }
james@638 673
james@638 674 status = AuxKlibInitialize();
james@1022 675 if(!NT_SUCCESS(status)) {
james@809 676 KdPrint((__DRIVER_NAME " AuxKlibInitialize failed %08x\n", status));
james@809 677 goto error;
james@638 678 }
james@716 679
james@539 680 XenPci_FixLoadOrder();
james@533 681
james@809 682 RtlInitUnicodeString(&system_start_options, L"failed to read");
james@809 683 status = WdfRegistryOpenKey(NULL, &control_key_name, GENERIC_READ, &parent_attributes, &control_key);
james@1022 684 if (NT_SUCCESS(status)) {
james@809 685 status = WdfStringCreate(NULL, &parent_attributes, &wdf_system_start_options);
james@809 686 status = WdfRegistryQueryString(control_key, &system_start_options_name, wdf_system_start_options);
james@809 687 if (NT_SUCCESS(status))
james@809 688 WdfStringGetUnicodeString(wdf_system_start_options, &system_start_options);
james@495 689 }
james@809 690 WdfRegistryClose(control_key);
james@495 691
james@908 692 KdPrint((__DRIVER_NAME " SystemStartOptions = %wZ\n", &system_start_options));
james@529 693
james@809 694 always_patch = 0;
james@809 695 WdfRegistryQueryULong(param_key, &txt_always_patch_name, &always_patch);
james@1022 696 if (always_patch || (system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"PATCHTPR"))) {
james@809 697 DECLARE_CONST_UNICODE_STRING(verifier_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
james@638 698 WDFKEY memory_key;
james@638 699 ULONG verifier_value;
james@638 700
james@529 701 KdPrint((__DRIVER_NAME " PATCHTPR found\n"));
james@638 702
james@809 703 tpr_patch_requested = TRUE;
james@809 704 status = WdfRegistryOpenKey(NULL, &verifier_key_name, KEY_READ, &parent_attributes, &memory_key);
james@809 705 if (NT_SUCCESS(status))
james@638 706 {
james@809 707 DECLARE_CONST_UNICODE_STRING(verifier_value_name, L"VerifyDriverLevel");
james@638 708 status = WdfRegistryQueryULong(memory_key, &verifier_value_name, &verifier_value);
james@638 709 if (NT_SUCCESS(status) && verifier_value != 0)
james@638 710 {
james@638 711 KdPrint((__DRIVER_NAME " Verifier active - not patching\n"));
james@809 712 tpr_patch_requested = FALSE;
james@638 713 }
james@638 714 WdfRegistryClose(memory_key);
james@638 715 }
james@529 716 }
james@747 717
james@809 718 WdfCollectionCreate(&parent_attributes, &qemu_hide_devices);
james@809 719 WdfRegistryQueryULong(param_key, &txt_always_hide_name, &always_hide);
james@809 720 conf_info = IoGetConfigurationInformation();
james@809 721 if (always_hide || ((conf_info == NULL || conf_info->DiskCount == 0)
james@809 722 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOGPLPV"))
james@1006 723 && !*InitSafeBootMode)) {
james@1006 724 if (!(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"GPLPVUSEFILTERHIDE")) && XenPci_CheckHideQemuDevices()) {
james@809 725 DECLARE_CONST_UNICODE_STRING(qemu_hide_flags_name, L"qemu_hide_flags");
james@809 726 DECLARE_CONST_UNICODE_STRING(txt_qemu_hide_flags_name, L"txt_qemu_hide_flags");
james@809 727 WDFCOLLECTION qemu_hide_flags;
james@809 728 ULONG i;
james@809 729
james@809 730 WdfCollectionCreate(&parent_attributes, &qemu_hide_flags);
james@809 731 WdfRegistryQueryMultiString(param_key, &qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
james@809 732 WdfRegistryQueryMultiString(param_key, &txt_qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
james@1006 733 for (i = 0; i < WdfCollectionGetCount(qemu_hide_flags); i++) {
james@809 734 ULONG value;
james@809 735 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_flags, i);
james@809 736 UNICODE_STRING unicode_string;
james@809 737 WdfStringGetUnicodeString(wdf_string, &unicode_string);
james@809 738 status = RtlUnicodeStringToInteger(&unicode_string, 0, &value);
james@809 739 qemu_hide_flags_value |= value;
james@747 740 }
james@809 741 WdfObjectDelete(qemu_hide_flags);
james@809 742 XenPci_HideQemuDevices();
james@1006 743 } else {
james@809 744 WdfRegistryQueryMultiString(param_key, &hide_devices_name, &parent_attributes, qemu_hide_devices);
james@809 745 }
james@793 746 }
james@809 747 WdfRegistryClose(param_key);
james@809 748 FUNCTION_EXIT();
james@809 749 return STATUS_SUCCESS;
james@536 750
james@809 751 error:
james@809 752 KdPrint(("Failed, returning %08x\n", status));
andy@398 753 FUNCTION_EXIT();
james@809 754 return status;
andy@324 755 }