win-pvdrivers

view xenpci/xenpci.c @ 1047:0248483f90cc

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