win-pvdrivers

view xenpci/xenpci.c @ 1093:5be1f70687ad

Refactor xenpci init to fix a bug when drivers are installed on a non-xen machine
author James Harper <james.harper@bendigoit.com.au>
date Mon Jan 13 20:24:56 2014 +1100 (2014-01-13)
parents 0248483f90cc
children 470198964cf0
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 (!hypercall_stubs) {
381 return STATUS_SUCCESS;
382 } else if (XenPci_IdSuffixMatches(device_init, L"VEN_5853&DEV_0001")) {
383 FUNCTION_MSG("Xen PCI device found - must be fdo\n");
384 return XenPci_EvtDeviceAdd_XenPci(driver, device_init);
385 } else if (WdfCollectionGetCount(qemu_hide_devices) > 0) {
386 FUNCTION_MSG("Xen PCI device not found - must be filter\n");
387 return XenPci_EvtDeviceAdd_XenHide(driver, device_init);
388 } else {
389 return STATUS_SUCCESS;
390 }
391 }
393 ULONG qemu_protocol_version;
394 ULONG tpr_patch_requested;
395 extern PULONG InitSafeBootMode;
397 VOID
398 XenPci_HideQemuDevices() {
399 #pragma warning(suppress:28138)
400 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, (USHORT)qemu_hide_flags_value); //QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
401 XnDebugPrint("disabled qemu devices %02x\n", qemu_hide_flags_value);
402 }
404 static BOOLEAN
405 XenPci_CheckHideQemuDevices() {
406 #pragma warning(suppress:28138)
407 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2) {
408 #pragma warning(suppress:28138)
409 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
410 XnDebugPrint("qemu version = %d\n", qemu_protocol_version);
411 switch(qemu_protocol_version) {
412 case 1:
413 #pragma warning(suppress:28138)
414 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
415 #pragma warning(suppress:28138)
416 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
417 #pragma warning(suppress:28138)
418 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
419 {
420 XnDebugPrint("qemu we are blacklisted\n");
421 break;
422 }
423 /* fall through */
424 case 0:
425 return TRUE;
426 default:
427 XnDebugPrint("unknown qemu version %d\n", qemu_protocol_version);
428 break;
429 }
430 }
431 return FALSE;
432 }
434 /*
435 make sure the load order is System Reserved, Dummy Group, WdfLoadGroup, XenPCI, Boot Bus Extender
436 */
438 static VOID
439 XenPci_FixLoadOrder()
440 {
441 NTSTATUS status;
442 WDFCOLLECTION old_load_order, new_load_order;
443 DECLARE_CONST_UNICODE_STRING(sgo_name, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder");
444 DECLARE_CONST_UNICODE_STRING(list_name, L"List");
445 WDFKEY sgo_key;
446 ULONG i;
447 LONG dummy_group_index = -1;
448 LONG boot_bus_extender_index = -1;
449 LONG xenpci_group_index = -1;
450 LONG wdf_load_group_index = -1;
451 DECLARE_CONST_UNICODE_STRING(dummy_group_name, L"Dummy Group");
452 DECLARE_CONST_UNICODE_STRING(wdf_load_group_name, L"WdfLoadGroup");
453 DECLARE_CONST_UNICODE_STRING(xenpci_group_name, L"XenPCI Group");
454 DECLARE_CONST_UNICODE_STRING(boot_bus_extender_name, L"Boot Bus Extender");
456 FUNCTION_ENTER();
458 status = WdfRegistryOpenKey(NULL, &sgo_name, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &sgo_key);
459 if (!NT_SUCCESS(status))
460 {
461 FUNCTION_MSG("Error opening ServiceGroupOrder key %08x\n", status);
462 return;
463 }
464 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &old_load_order);
465 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &new_load_order);
466 status = WdfRegistryQueryMultiString(sgo_key, &list_name, WDF_NO_OBJECT_ATTRIBUTES, old_load_order);
467 if (!NT_SUCCESS(status))
468 {
469 FUNCTION_MSG("Error reading ServiceGroupOrder\\List value %08x\n", status);
470 WdfObjectDelete(new_load_order);
471 WdfObjectDelete(old_load_order);
472 return;
473 }
474 //FUNCTION_MSG("Current Order:\n");
475 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
476 {
477 WDFOBJECT ws = WdfCollectionGetItem(old_load_order, i);
478 UNICODE_STRING val;
479 WdfStringGetUnicodeString(ws, &val);
480 if (!RtlCompareUnicodeString(&val, &dummy_group_name, TRUE))
481 dummy_group_index = (ULONG)i;
482 if (!RtlCompareUnicodeString(&val, &wdf_load_group_name, TRUE))
483 wdf_load_group_index = (ULONG)i;
484 if (!RtlCompareUnicodeString(&val, &xenpci_group_name, TRUE))
485 xenpci_group_index = (ULONG)i;
486 if (!RtlCompareUnicodeString(&val, &boot_bus_extender_name, TRUE))
487 boot_bus_extender_index = (ULONG)i;
488 //FUNCTION_MSG(" %wZ\n", &val);
489 }
490 FUNCTION_MSG("dummy_group_index = %d\n", dummy_group_index);
491 FUNCTION_MSG("wdf_load_group_index = %d\n", wdf_load_group_index);
492 FUNCTION_MSG("xenpci_group_index = %d\n", xenpci_group_index);
493 FUNCTION_MSG("boot_bus_extender_index = %d\n", boot_bus_extender_index);
494 if (boot_bus_extender_index == -1)
495 {
496 WdfObjectDelete(new_load_order);
497 WdfObjectDelete(old_load_order);
498 WdfRegistryClose(sgo_key);
499 return; /* something is very wrong */
500 }
501 if (dummy_group_index == 1 && wdf_load_group_index != -1 &&
502 (dummy_group_index < wdf_load_group_index
503 && wdf_load_group_index < xenpci_group_index
504 && xenpci_group_index < boot_bus_extender_index))
505 {
506 FUNCTION_EXIT();
507 return; /* our work here is done */
508 }
509 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
510 {
511 WDFOBJECT ws;
512 if (i == 1)
513 {
514 WDFSTRING tmp_wdf_string;
515 WdfStringCreate(&dummy_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
516 WdfCollectionAdd(new_load_order, tmp_wdf_string);
517 WdfObjectDelete(tmp_wdf_string);
518 }
519 if (i == 1)
520 {
521 WDFSTRING tmp_wdf_string;
522 WdfStringCreate(&wdf_load_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
523 WdfCollectionAdd(new_load_order, tmp_wdf_string);
524 WdfObjectDelete(tmp_wdf_string);
525 }
526 if (i == 1)
527 {
528 WDFSTRING tmp_wdf_string;
529 WdfStringCreate(&xenpci_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
530 WdfCollectionAdd(new_load_order, tmp_wdf_string);
531 WdfObjectDelete(tmp_wdf_string);
532 }
533 if (i == (ULONG)dummy_group_index || i == (ULONG)wdf_load_group_index || i == (ULONG)xenpci_group_index)
534 continue;
535 ws = WdfCollectionGetItem(old_load_order, i);
536 WdfCollectionAdd(new_load_order, ws);
537 }
538 WdfRegistryAssignMultiString(sgo_key, &list_name, new_load_order);
539 //FUNCTION_MSG("New Order:\n");
540 for (i = 0; i < WdfCollectionGetCount(new_load_order); i++)
541 {
542 WDFOBJECT ws = WdfCollectionGetItem(new_load_order, i);
543 UNICODE_STRING val;
544 WdfStringGetUnicodeString(ws, &val);
545 //FUNCTION_MSG(" %wZ\n", &val);
546 }
547 WdfObjectDelete(new_load_order);
548 WdfObjectDelete(old_load_order);
549 WdfRegistryClose(sgo_key);
551 FUNCTION_EXIT();
553 return;
554 }
556 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
557 /* this isn't freed on shutdown... perhaps it should be */
558 static PUCHAR dump_header = NULL;
559 static ULONG dump_header_size;
560 static ULONG dump_header_refreshed_flag = FALSE;
561 static KBUGCHECK_REASON_CALLBACK_RECORD callback_record;
562 #define DUMP_HEADER_PREFIX_SIZE 8
563 #define DUMP_HEADER_SUFFIX_SIZE 8
565 /* call KeInitializeCrashDumpHeader once on crash */
566 static VOID
567 XenPci_DebugHeaderDumpIoCallback(
568 KBUGCHECK_CALLBACK_REASON reason,
569 PKBUGCHECK_REASON_CALLBACK_RECORD record,
570 PVOID reason_specific_data,
571 ULONG reason_specific_data_length) {
572 UNREFERENCED_PARAMETER(reason);
573 UNREFERENCED_PARAMETER(record);
574 UNREFERENCED_PARAMETER(reason_specific_data);
575 UNREFERENCED_PARAMETER(reason_specific_data_length);
576 if (!dump_header_refreshed_flag) {
577 NTSTATUS status;
578 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
579 /* copy bug check code in? */
580 dump_header_refreshed_flag = TRUE;
581 }
582 }
583 #endif
585 #define XEN_SIGNATURE_LOWER 0x40000000
586 #define XEN_SIGNATURE_UPPER 0x4000FFFF
588 USHORT xen_version_major = (USHORT)-1;
589 USHORT xen_version_minor = (USHORT)-1;
590 PVOID hypercall_stubs = NULL;
592 static VOID
593 XenPCI_GetHypercallStubs() {
594 ULONG base;
595 DWORD32 cpuid_output[4];
596 char xensig[13];
597 ULONG i;
598 ULONG pages;
599 ULONG msr;
601 if (hypercall_stubs) {
602 FUNCTION_MSG("hypercall_stubs already set\n");
603 return;
604 }
606 for (base = XEN_SIGNATURE_LOWER; base < XEN_SIGNATURE_UPPER; base += 0x100) {
607 __cpuid(cpuid_output, base);
608 *(ULONG*)(xensig + 0) = cpuid_output[1];
609 *(ULONG*)(xensig + 4) = cpuid_output[2];
610 *(ULONG*)(xensig + 8) = cpuid_output[3];
611 xensig[12] = '\0';
612 FUNCTION_MSG("base = 0x%08x, Xen Signature = %s, EAX = 0x%08x\n", base, xensig, cpuid_output[0]);
613 if (!strncmp("XenVMMXenVMM", xensig, 12) && ((cpuid_output[0] - base) >= 2))
614 break;
615 }
616 if (base >= XEN_SIGNATURE_UPPER) {
617 FUNCTION_MSG("Cannot find Xen signature\n");
618 return;
619 }
621 __cpuid(cpuid_output, base + 1);
622 xen_version_major = (USHORT)(cpuid_output[0] >> 16);
623 xen_version_minor = (USHORT)(cpuid_output[0] & 0xFFFF);
624 FUNCTION_MSG("Xen Version %d.%d\n", xen_version_major, xen_version_minor);
626 __cpuid(cpuid_output, base + 2);
627 pages = cpuid_output[0];
628 msr = cpuid_output[1];
630 hypercall_stubs = ExAllocatePoolWithTag(NonPagedPool, pages * PAGE_SIZE, XENPCI_POOL_TAG);
631 FUNCTION_MSG("Hypercall area at %p\n", hypercall_stubs);
633 if (!hypercall_stubs)
634 return;
635 for (i = 0; i < pages; i++) {
636 ULONGLONG pfn;
637 pfn = (MmGetPhysicalAddress((PUCHAR)hypercall_stubs + i * PAGE_SIZE).QuadPart >> PAGE_SHIFT);
638 __writemsr(msr, (pfn << PAGE_SHIFT) + i);
639 }
640 }
642 static VOID
643 XenPCI_FreeHypercallStubs() {
644 if (hypercall_stubs) {
645 ExFreePoolWithTag(hypercall_stubs, XENPCI_POOL_TAG);
646 }
647 hypercall_stubs = NULL;
648 }
650 VOID
651 XenPci_EvtDriverUnload(WDFDRIVER driver) {
652 UNREFERENCED_PARAMETER(driver);
654 FUNCTION_ENTER();
656 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
657 KeDeregisterBugCheckReasonCallback(&callback_record);
658 if (dump_header) {
659 MmFreeContiguousMemory(dump_header);
660 }
661 #endif
662 FUNCTION_EXIT();
663 }
666 NTSTATUS
667 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
668 {
669 NTSTATUS status = STATUS_SUCCESS;
670 WDF_DRIVER_CONFIG config;
671 WDFDRIVER driver;
672 WDF_OBJECT_ATTRIBUTES parent_attributes;
673 PCONFIGURATION_INFORMATION conf_info;
674 WDFKEY control_key;
675 WDFKEY param_key;
676 ULONG always_patch = 0;
677 ULONG always_hide = 0;
678 DECLARE_CONST_UNICODE_STRING(control_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
679 DECLARE_CONST_UNICODE_STRING(system_start_options_name, L"SystemStartOptions");
680 DECLARE_CONST_UNICODE_STRING(txt_always_hide_name, L"txt_hide_qemu_always");
681 DECLARE_CONST_UNICODE_STRING(hide_devices_name, L"hide_devices");
682 DECLARE_CONST_UNICODE_STRING(txt_always_patch_name, L"txt_patch_tpr_always");
683 WDFSTRING wdf_system_start_options;
684 UNICODE_STRING system_start_options;
685 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
686 PHYSICAL_ADDRESS dump_header_mem_max;
687 #endif
689 UNREFERENCED_PARAMETER(RegistryPath);
691 FUNCTION_ENTER();
693 FUNCTION_MSG(__DRIVER_NAME " " VER_FILEVERSION_STR "\n");
695 XenPCI_GetHypercallStubs();
697 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
698 if (hypercall_stubs) {
699 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, NULL, 0, &dump_header_size);
700 /* try and allocate contiguous memory as low as possible */
701 dump_header_mem_max.QuadPart = 0xFFFFF;
702 while (!dump_header && dump_header_mem_max.QuadPart != 0xFFFFFFFFFFFFFFFF) {
703 dump_header = MmAllocateContiguousMemory(DUMP_HEADER_PREFIX_SIZE + dump_header_size + DUMP_HEADER_SUFFIX_SIZE, dump_header_mem_max);
704 if (dump_header) {
705 FUNCTION_MSG("Allocated crash dump header < 0x%016I64x\n", dump_header_mem_max.QuadPart);
706 break;
707 }
708 dump_header_mem_max.QuadPart = (dump_header_mem_max.QuadPart << 4) | 0xF;
709 }
710 if (dump_header) {
711 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
712 FUNCTION_MSG("KeInitializeCrashDumpHeader status = %08x, size = %d\n", status, dump_header_size);
713 memcpy(dump_header + 0, "XENXEN", 6); /* magic number */
714 *(PUSHORT)(dump_header + 6) = (USHORT)(INT_PTR)dump_header & (PAGE_SIZE - 1); /* store offset too as additional verification */
715 memcpy(dump_header + DUMP_HEADER_PREFIX_SIZE + dump_header_size, "XENXEN", 6);
716 *(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 */
717 KeInitializeCallbackRecord(&callback_record);
718 KeRegisterBugCheckReasonCallback(&callback_record, XenPci_DebugHeaderDumpIoCallback, KbCallbackDumpIo, (PUCHAR)"XenPci_DebugHeaderDumpIoCallback");
719 } else {
720 FUNCTION_MSG("Failed to allocate memory for crash dump header\n");
721 }
722 }
723 #endif
724 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
725 config.EvtDriverUnload = XenPci_EvtDriverUnload;
726 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
727 if (!NT_SUCCESS(status)) {
728 FUNCTION_MSG("WdfDriverCreate failed with status 0x%x\n", status);
729 FUNCTION_EXIT();
730 return status;
731 }
732 if (hypercall_stubs) {
733 WDF_OBJECT_ATTRIBUTES_INIT(&parent_attributes);
734 parent_attributes.ParentObject = driver;
736 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, &parent_attributes, &param_key);
737 if (!NT_SUCCESS(status)) {
738 FUNCTION_MSG("Error opening parameters key %08x\n", status);
739 goto error;
740 }
742 status = AuxKlibInitialize();
743 if(!NT_SUCCESS(status)) {
744 FUNCTION_MSG("AuxKlibInitialize failed %08x\n", status);
745 goto error;
746 }
748 XenPci_FixLoadOrder();
750 RtlInitUnicodeString(&system_start_options, L"failed to read");
751 status = WdfRegistryOpenKey(NULL, &control_key_name, GENERIC_READ, &parent_attributes, &control_key);
752 if (NT_SUCCESS(status)) {
753 status = WdfStringCreate(NULL, &parent_attributes, &wdf_system_start_options);
754 status = WdfRegistryQueryString(control_key, &system_start_options_name, wdf_system_start_options);
755 if (NT_SUCCESS(status))
756 WdfStringGetUnicodeString(wdf_system_start_options, &system_start_options);
757 }
758 WdfRegistryClose(control_key);
760 FUNCTION_MSG("SystemStartOptions = %wZ\n", &system_start_options);
762 always_patch = 0;
763 WdfRegistryQueryULong(param_key, &txt_always_patch_name, &always_patch);
764 if (always_patch || (system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"PATCHTPR"))) {
765 DECLARE_CONST_UNICODE_STRING(verifier_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
766 WDFKEY memory_key;
767 ULONG verifier_value;
769 FUNCTION_MSG("PATCHTPR found\n");
771 tpr_patch_requested = TRUE;
772 status = WdfRegistryOpenKey(NULL, &verifier_key_name, KEY_READ, &parent_attributes, &memory_key);
773 if (NT_SUCCESS(status))
774 {
775 DECLARE_CONST_UNICODE_STRING(verifier_value_name, L"VerifyDriverLevel");
776 status = WdfRegistryQueryULong(memory_key, &verifier_value_name, &verifier_value);
777 if (NT_SUCCESS(status) && verifier_value != 0)
778 {
779 FUNCTION_MSG("Verifier active - not patching\n");
780 tpr_patch_requested = FALSE;
781 }
782 WdfRegistryClose(memory_key);
783 }
784 }
786 WdfCollectionCreate(&parent_attributes, &qemu_hide_devices);
787 WdfRegistryQueryULong(param_key, &txt_always_hide_name, &always_hide);
788 conf_info = IoGetConfigurationInformation();
789 if (always_hide || ((conf_info == NULL || conf_info->DiskCount == 0)
790 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOGPLPV"))
791 && !*InitSafeBootMode)) {
792 if (!(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"GPLPVUSEFILTERHIDE")) && XenPci_CheckHideQemuDevices()) {
793 DECLARE_CONST_UNICODE_STRING(qemu_hide_flags_name, L"qemu_hide_flags");
794 DECLARE_CONST_UNICODE_STRING(txt_qemu_hide_flags_name, L"txt_qemu_hide_flags");
795 WDFCOLLECTION qemu_hide_flags;
796 ULONG i;
798 WdfCollectionCreate(&parent_attributes, &qemu_hide_flags);
799 WdfRegistryQueryMultiString(param_key, &qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
800 WdfRegistryQueryMultiString(param_key, &txt_qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
801 for (i = 0; i < WdfCollectionGetCount(qemu_hide_flags); i++) {
802 ULONG value;
803 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_flags, i);
804 UNICODE_STRING unicode_string;
805 WdfStringGetUnicodeString(wdf_string, &unicode_string);
806 status = RtlUnicodeStringToInteger(&unicode_string, 0, &value);
807 qemu_hide_flags_value |= value;
808 }
809 WdfObjectDelete(qemu_hide_flags);
810 XenPci_HideQemuDevices();
811 } else {
812 WdfRegistryQueryMultiString(param_key, &hide_devices_name, &parent_attributes, qemu_hide_devices);
813 }
814 }
815 WdfRegistryClose(param_key);
816 }
817 FUNCTION_EXIT();
818 return STATUS_SUCCESS;
820 error:
821 FUNCTION_MSG("Failed, returning %08x\n", status);
822 FUNCTION_EXIT();
823 return status;
824 }