win-pvdrivers

view xenpci/xenpci.c @ 1099:27bd2a5a4704

License change from GPL to BSD
author James Harper <james.harper@bendigoit.com.au>
date Thu Mar 13 13:38:31 2014 +1100 (2014-03-13)
parents 470198964cf0
children
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
4 Copyright (c) 2014, James Harper
5 All rights reserved.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of James Harper nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL JAMES HARPER BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
30 #define INITGUID
31 #include "xenpci.h"
32 #include <aux_klib.h>
33 #include <stdlib.h>
35 #pragma warning(disable : 4200) // zero-sized array
37 PMDL balloon_mdl_head = NULL;
39 /* Not really necessary but keeps PREfast happy */
40 DRIVER_INITIALIZE DriverEntry;
41 static EVT_WDF_DRIVER_UNLOAD XenPci_EvtDriverUnload;
42 static EVT_WDF_DRIVER_DEVICE_ADD XenPci_EvtDeviceAdd;
43 static EVT_WDF_DEVICE_USAGE_NOTIFICATION XenPci_EvtDeviceUsageNotification;
44 static EVT_WDF_DEVICE_PREPARE_HARDWARE XenHide_EvtDevicePrepareHardware;
46 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
47 static KBUGCHECK_REASON_CALLBACK_ROUTINE XenPci_DebugHeaderDumpIoCallback;
49 /* this is supposed to be defined in wdm.h, but isn't */
50 NTSTATUS
51 KeInitializeCrashDumpHeader(
52 IN ULONG Type,
53 IN ULONG Flags,
54 OUT PVOID Buffer,
55 IN ULONG BufferSize,
56 OUT PULONG BufferNeeded OPTIONAL
57 );
58 #endif
60 #define DUMP_TYPE_FULL 1
62 static VOID
63 XenPci_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
64 {
65 FUNCTION_ENTER();
67 UNREFERENCED_PARAMETER(device);
68 UNREFERENCED_PARAMETER(is_in_notification_path);
70 switch (notification_type)
71 {
72 case WdfSpecialFilePaging:
73 FUNCTION_MSG("notification_type = Paging, flag = %d\n", is_in_notification_path);
74 break;
75 case WdfSpecialFileHibernation:
76 FUNCTION_MSG("notification_type = Hibernation, flag = %d\n", is_in_notification_path);
77 break;
78 case WdfSpecialFileDump:
79 FUNCTION_MSG("notification_type = Dump, flag = %d\n", is_in_notification_path);
80 break;
81 default:
82 FUNCTION_MSG("notification_type = %d, flag = %d\n", notification_type, is_in_notification_path);
83 break;
84 }
86 FUNCTION_EXIT();
87 }
89 static NTSTATUS
90 XenPci_EvtDeviceAdd_XenPci(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
91 {
92 NTSTATUS status;
93 // PDEVICE_OBJECT fdo = NULL;
94 // PNP_BUS_INFORMATION busInfo;
95 // DECLARE_CONST_UNICODE_STRING(DeviceName, L"\\Device\\XenShutdown");
96 // DECLARE_CONST_UNICODE_STRING(SymbolicName, L"\\DosDevices\\XenShutdown");
97 WDF_CHILD_LIST_CONFIG child_list_config;
98 WDFDEVICE device;
99 PXENPCI_DEVICE_DATA xpdd;
100 UNICODE_STRING reference;
101 WDF_OBJECT_ATTRIBUTES device_attributes;
102 PNP_BUS_INFORMATION pbi;
103 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
104 WDF_INTERRUPT_CONFIG interrupt_config;
105 WDF_OBJECT_ATTRIBUTES file_attributes;
106 WDF_FILEOBJECT_CONFIG file_config;
107 WDF_IO_QUEUE_CONFIG queue_config;
108 WDFCOLLECTION veto_devices;
109 WDFKEY param_key;
110 DECLARE_CONST_UNICODE_STRING(veto_devices_name, L"veto_devices");
111 WDF_DEVICE_POWER_CAPABILITIES power_capabilities;
112 PPHYSICAL_MEMORY_RANGE pmr_head, pmr;
113 int i;
115 UNREFERENCED_PARAMETER(driver);
117 FUNCTION_ENTER();
119 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
120 pnp_power_callbacks.EvtDeviceD0Entry = XenPci_EvtDeviceD0Entry;
121 pnp_power_callbacks.EvtDeviceD0EntryPostInterruptsEnabled = XenPci_EvtDeviceD0EntryPostInterruptsEnabled;
122 pnp_power_callbacks.EvtDeviceD0Exit = XenPci_EvtDeviceD0Exit;
123 pnp_power_callbacks.EvtDeviceD0ExitPreInterruptsDisabled = XenPci_EvtDeviceD0ExitPreInterruptsDisabled;
124 pnp_power_callbacks.EvtDevicePrepareHardware = XenPci_EvtDevicePrepareHardware;
125 pnp_power_callbacks.EvtDeviceReleaseHardware = XenPci_EvtDeviceReleaseHardware;
126 pnp_power_callbacks.EvtDeviceQueryRemove = XenPci_EvtDeviceQueryRemove;
127 pnp_power_callbacks.EvtDeviceUsageNotification = XenPci_EvtDeviceUsageNotification;
129 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
131 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_BUS_EXTENDER);
132 WdfDeviceInitSetExclusive(device_init, FALSE);
134 WDF_CHILD_LIST_CONFIG_INIT(&child_list_config, sizeof(XENPCI_PDO_IDENTIFICATION_DESCRIPTION), XenPci_EvtChildListCreateDevice);
135 child_list_config.EvtChildListScanForChildren = XenPci_EvtChildListScanForChildren;
136 WdfFdoInitSetDefaultChildListConfig(device_init, &child_list_config, WDF_NO_OBJECT_ATTRIBUTES);
138 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&file_attributes, XENPCI_DEVICE_INTERFACE_DATA);
139 WDF_FILEOBJECT_CONFIG_INIT(&file_config, XenPci_EvtDeviceFileCreate, XenPci_EvtFileClose, XenPci_EvtFileCleanup);
140 WdfDeviceInitSetFileObjectConfig(device_init, &file_config, &file_attributes);
142 WdfDeviceInitSetIoType(device_init, WdfDeviceIoBuffered);
144 WdfDeviceInitSetPowerNotPageable(device_init);
146 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENPCI_DEVICE_DATA);
147 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
148 if (!NT_SUCCESS(status)) {
149 FUNCTION_MSG("Error creating device %08x\n", status);
150 return status;
151 }
153 xpdd = GetXpdd(device);
154 xpdd->wdf_device = device;
155 xpdd->child_list = WdfFdoGetDefaultChildList(device);
157 /* this is not a documented function */
158 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
159 pmr_head = MmGetPhysicalMemoryRanges();
160 xpdd->current_memory_kb = 0;
161 for (pmr = pmr_head; !(pmr->BaseAddress.QuadPart == 0 && pmr->NumberOfBytes.QuadPart == 0); pmr++) {
162 xpdd->current_memory_kb += (ULONG)(pmr->NumberOfBytes.QuadPart / 1024);
163 }
164 FUNCTION_MSG("current_memory_kb = %d\n", xpdd->current_memory_kb);
165 /* round to MB increments because that is what balloon deals in */
166 xpdd->current_memory_kb = (xpdd->current_memory_kb + 0x1FF) & 0xFFFFFC00;
167 FUNCTION_MSG("current_memory_kb rounded to %d\n", xpdd->current_memory_kb);
169 ExInitializeFastMutex(&xpdd->suspend_mutex);
170 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &veto_devices);
171 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &param_key);
172 if (NT_SUCCESS(status)) {
173 status = WdfRegistryQueryMultiString(param_key, &veto_devices_name, WDF_NO_OBJECT_ATTRIBUTES, veto_devices);
174 if (!NT_SUCCESS(status)) {
175 FUNCTION_MSG("Error reading parameters/veto_devices value %08x\n", status);
176 }
177 WdfRegistryClose(param_key);
178 } else {
179 FUNCTION_MSG("Error opening parameters key %08x\n", status);
180 }
182 InitializeListHead(&xpdd->veto_list);
183 for (i = 0; i < (int)WdfCollectionGetCount(veto_devices); i++) {
184 WDFOBJECT ws;
185 UNICODE_STRING val;
186 ANSI_STRING s;
187 PVOID entry;
188 ws = WdfCollectionGetItem(veto_devices, i);
189 WdfStringGetUnicodeString(ws, &val);
190 RtlUnicodeStringToAnsiString(&s, &val, TRUE);
191 entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY) + s.Length + 1, XENPCI_POOL_TAG);
192 memcpy((PUCHAR)entry + sizeof(LIST_ENTRY), s.Buffer, s.Length + 1);
193 RtlFreeAnsiString(&s);
194 InsertTailList(&xpdd->veto_list, (PLIST_ENTRY)entry);
195 }
196 WDF_DEVICE_POWER_CAPABILITIES_INIT(&power_capabilities);
197 power_capabilities.DeviceD1 = WdfTrue;
198 power_capabilities.WakeFromD1 = WdfTrue;
199 power_capabilities.DeviceWake = PowerDeviceD1;
200 power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
201 power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
202 power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
203 power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
204 power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
205 power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
206 WdfDeviceSetPowerCapabilities(device, &power_capabilities);
208 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
209 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
210 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
212 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchParallel);
213 queue_config.EvtIoDefault = XenPci_EvtIoDefault;
214 status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->io_queue);
215 if (!NT_SUCCESS(status)) {
216 FUNCTION_MSG("Error creating queue 0x%x\n", status);
217 return status;
218 }
220 WDF_INTERRUPT_CONFIG_INIT(&interrupt_config, EvtChn_EvtInterruptIsr, NULL);
221 interrupt_config.EvtInterruptEnable = EvtChn_EvtInterruptEnable;
222 interrupt_config.EvtInterruptDisable = EvtChn_EvtInterruptDisable;
224 status = WdfInterruptCreate(device, &interrupt_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->interrupt);
225 if (!NT_SUCCESS(status))
226 {
227 FUNCTION_MSG("Error creating interrupt 0x%x\n", status);
228 return status;
229 }
231 RtlInitUnicodeString(&reference, L"xenbus");
232 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_XENBUS, &reference);
233 if (!NT_SUCCESS(status)) {
234 FUNCTION_MSG("Error registering device interface 0x%x\n", status);
235 return status;
236 }
238 RtlInitUnicodeString(&reference, L"evtchn");
239 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_EVTCHN, &reference);
240 if (!NT_SUCCESS(status)) {
241 FUNCTION_MSG("Error registering device interface 0x%x\n", status);
242 return status;
243 }
245 RtlInitUnicodeString(&reference, L"gntdev");
246 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_GNTDEV, &reference);
247 if (!NT_SUCCESS(status)) {
248 FUNCTION_MSG("Error registering device interface 0x%x\n", status);
249 return status;
250 }
252 pbi.BusTypeGuid = GUID_BUS_TYPE_XEN;
253 pbi.LegacyBusType = PNPBus;
254 pbi.BusNumber = 0;
255 WdfDeviceSetBusInformationForChildren(device, &pbi);
257 xpdd->removable = TRUE;
259 FUNCTION_EXIT();
260 return status;
261 }
263 NTSTATUS
264 XenHide_EvtDevicePrepareHardware(WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
265 {
266 UNREFERENCED_PARAMETER(device);
267 UNREFERENCED_PARAMETER(resources_raw);
268 UNREFERENCED_PARAMETER(resources_translated);
269 FUNCTION_ENTER();
270 FUNCTION_EXIT();
271 return STATUS_UNSUCCESSFUL;
272 }
274 static BOOLEAN
275 XenPci_IdSuffixMatches(PWDFDEVICE_INIT device_init, PWCHAR matching_id) {
276 NTSTATUS status;
277 WDFMEMORY memory;
278 ULONG remaining;
279 size_t string_length;
280 PWCHAR ids;
281 PWCHAR ptr;
282 size_t ids_length;
283 ULONG properties[] = {DevicePropertyCompatibleIDs, DevicePropertyHardwareID};
284 int i;
286 // FUNCTION_ENTER();
287 for (i = 0; i < ARRAY_SIZE(properties); i++)
288 {
290 status = WdfFdoInitAllocAndQueryProperty(device_init, properties[i], NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
291 if (!NT_SUCCESS(status))
292 continue;
293 ids = WdfMemoryGetBuffer(memory, &ids_length);
295 if (!NT_SUCCESS(status)) {
296 continue;
297 }
299 remaining = (ULONG)ids_length / 2;
300 for (ptr = ids; *ptr != 0; ptr += string_length + 1) {
301 RtlStringCchLengthW(ptr, remaining, &string_length);
302 remaining -= (ULONG)string_length + 1;
303 if (string_length >= wcslen(matching_id)) {
304 ptr += string_length - wcslen(matching_id);
305 string_length = wcslen(matching_id);
306 }
307 if (wcscmp(ptr, matching_id) == 0) {
308 WdfObjectDelete(memory);
309 return TRUE;
310 }
311 }
312 WdfObjectDelete(memory);
313 }
314 return FALSE;
315 }
317 WDFCOLLECTION qemu_hide_devices;
318 USHORT qemu_hide_flags_value;
320 static NTSTATUS
321 XenPci_EvtDeviceAdd_XenHide(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
322 {
323 NTSTATUS status;
324 WDFMEMORY memory;
325 PWCHAR device_description;
326 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
327 WDF_OBJECT_ATTRIBUTES device_attributes;
328 BOOLEAN hide_required = FALSE;
329 WDFDEVICE device;
330 ULONG i;
332 UNREFERENCED_PARAMETER(driver);
334 FUNCTION_ENTER();
336 status = WdfFdoInitAllocAndQueryProperty(device_init, DevicePropertyDeviceDescription, NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
337 if (NT_SUCCESS(status)) {
338 device_description = WdfMemoryGetBuffer(memory, NULL);
339 } else {
340 device_description = L"<unknown device>";
341 }
343 for (i = 0; i < WdfCollectionGetCount(qemu_hide_devices); i++) {
344 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_devices, i);
345 UNICODE_STRING unicode_string;
346 WdfStringGetUnicodeString(wdf_string, &unicode_string);
347 if (XenPci_IdSuffixMatches(device_init, unicode_string.Buffer)) {
348 hide_required = TRUE;
349 break;
350 }
351 }
352 if (!hide_required) {
353 FUNCTION_MSG("(filter not required for %S)\n", device_description);
354 WdfObjectDelete(memory);
355 return STATUS_SUCCESS;
356 }
358 FUNCTION_MSG("Installing Filter for %S\n", device_description);
360 WdfFdoInitSetFilter(device_init);
361 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
362 WdfDeviceInitSetExclusive(device_init, FALSE);
364 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
365 pnp_power_callbacks.EvtDevicePrepareHardware = XenHide_EvtDevicePrepareHardware;
366 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
368 WDF_OBJECT_ATTRIBUTES_INIT(&device_attributes);
369 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
370 if (!NT_SUCCESS(status)) {
371 FUNCTION_MSG("Error creating device %08x\n", status);
372 WdfObjectDelete(memory);
373 FUNCTION_EXIT();
374 return status;
375 }
377 WdfObjectDelete(memory);
378 FUNCTION_EXIT();
380 return status;
381 }
383 static NTSTATUS
384 XenPci_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
385 {
386 if (!hypercall_stubs) {
387 return STATUS_SUCCESS;
388 } else if (XenPci_IdSuffixMatches(device_init, L"VEN_5853&DEV_0001")) {
389 FUNCTION_MSG("Xen PCI device found - must be fdo\n");
390 return XenPci_EvtDeviceAdd_XenPci(driver, device_init);
391 } else if (WdfCollectionGetCount(qemu_hide_devices) > 0) {
392 FUNCTION_MSG("Xen PCI device not found - must be filter\n");
393 return XenPci_EvtDeviceAdd_XenHide(driver, device_init);
394 } else {
395 return STATUS_SUCCESS;
396 }
397 }
399 ULONG qemu_protocol_version;
400 ULONG tpr_patch_requested;
401 extern PULONG InitSafeBootMode;
403 VOID
404 XenPci_HideQemuDevices() {
405 #pragma warning(suppress:28138)
406 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, (USHORT)qemu_hide_flags_value); //QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
407 XnDebugPrint("disabled qemu devices %02x\n", qemu_hide_flags_value);
408 }
410 static BOOLEAN
411 XenPci_CheckHideQemuDevices() {
412 #pragma warning(suppress:28138)
413 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2) {
414 #pragma warning(suppress:28138)
415 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
416 XnDebugPrint("qemu version = %d\n", qemu_protocol_version);
417 switch(qemu_protocol_version) {
418 case 1:
419 #pragma warning(suppress:28138)
420 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
421 #pragma warning(suppress:28138)
422 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
423 #pragma warning(suppress:28138)
424 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
425 {
426 XnDebugPrint("qemu we are blacklisted\n");
427 break;
428 }
429 /* fall through */
430 case 0:
431 return TRUE;
432 default:
433 XnDebugPrint("unknown qemu version %d\n", qemu_protocol_version);
434 break;
435 }
436 }
437 return FALSE;
438 }
440 /*
441 make sure the load order is System Reserved, Dummy Group, WdfLoadGroup, XenPCI, Boot Bus Extender
442 */
444 static VOID
445 XenPci_FixLoadOrder()
446 {
447 NTSTATUS status;
448 WDFCOLLECTION old_load_order, new_load_order;
449 DECLARE_CONST_UNICODE_STRING(sgo_name, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder");
450 DECLARE_CONST_UNICODE_STRING(list_name, L"List");
451 WDFKEY sgo_key;
452 ULONG i;
453 LONG dummy_group_index = -1;
454 LONG boot_bus_extender_index = -1;
455 LONG xenpci_group_index = -1;
456 LONG wdf_load_group_index = -1;
457 DECLARE_CONST_UNICODE_STRING(dummy_group_name, L"Dummy Group");
458 DECLARE_CONST_UNICODE_STRING(wdf_load_group_name, L"WdfLoadGroup");
459 DECLARE_CONST_UNICODE_STRING(xenpci_group_name, L"XenPCI Group");
460 DECLARE_CONST_UNICODE_STRING(boot_bus_extender_name, L"Boot Bus Extender");
462 FUNCTION_ENTER();
464 status = WdfRegistryOpenKey(NULL, &sgo_name, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &sgo_key);
465 if (!NT_SUCCESS(status))
466 {
467 FUNCTION_MSG("Error opening ServiceGroupOrder key %08x\n", status);
468 return;
469 }
470 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &old_load_order);
471 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &new_load_order);
472 status = WdfRegistryQueryMultiString(sgo_key, &list_name, WDF_NO_OBJECT_ATTRIBUTES, old_load_order);
473 if (!NT_SUCCESS(status))
474 {
475 FUNCTION_MSG("Error reading ServiceGroupOrder\\List value %08x\n", status);
476 WdfObjectDelete(new_load_order);
477 WdfObjectDelete(old_load_order);
478 return;
479 }
480 //FUNCTION_MSG("Current Order:\n");
481 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
482 {
483 WDFOBJECT ws = WdfCollectionGetItem(old_load_order, i);
484 UNICODE_STRING val;
485 WdfStringGetUnicodeString(ws, &val);
486 if (!RtlCompareUnicodeString(&val, &dummy_group_name, TRUE))
487 dummy_group_index = (ULONG)i;
488 if (!RtlCompareUnicodeString(&val, &wdf_load_group_name, TRUE))
489 wdf_load_group_index = (ULONG)i;
490 if (!RtlCompareUnicodeString(&val, &xenpci_group_name, TRUE))
491 xenpci_group_index = (ULONG)i;
492 if (!RtlCompareUnicodeString(&val, &boot_bus_extender_name, TRUE))
493 boot_bus_extender_index = (ULONG)i;
494 //FUNCTION_MSG(" %wZ\n", &val);
495 }
496 FUNCTION_MSG("dummy_group_index = %d\n", dummy_group_index);
497 FUNCTION_MSG("wdf_load_group_index = %d\n", wdf_load_group_index);
498 FUNCTION_MSG("xenpci_group_index = %d\n", xenpci_group_index);
499 FUNCTION_MSG("boot_bus_extender_index = %d\n", boot_bus_extender_index);
500 if (boot_bus_extender_index == -1)
501 {
502 WdfObjectDelete(new_load_order);
503 WdfObjectDelete(old_load_order);
504 WdfRegistryClose(sgo_key);
505 return; /* something is very wrong */
506 }
507 if (dummy_group_index == 1 && wdf_load_group_index != -1 &&
508 (dummy_group_index < wdf_load_group_index
509 && wdf_load_group_index < xenpci_group_index
510 && xenpci_group_index < boot_bus_extender_index))
511 {
512 FUNCTION_EXIT();
513 return; /* our work here is done */
514 }
515 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
516 {
517 WDFOBJECT ws;
518 if (i == 1)
519 {
520 WDFSTRING tmp_wdf_string;
521 WdfStringCreate(&dummy_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
522 WdfCollectionAdd(new_load_order, tmp_wdf_string);
523 WdfObjectDelete(tmp_wdf_string);
524 }
525 if (i == 1)
526 {
527 WDFSTRING tmp_wdf_string;
528 WdfStringCreate(&wdf_load_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
529 WdfCollectionAdd(new_load_order, tmp_wdf_string);
530 WdfObjectDelete(tmp_wdf_string);
531 }
532 if (i == 1)
533 {
534 WDFSTRING tmp_wdf_string;
535 WdfStringCreate(&xenpci_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
536 WdfCollectionAdd(new_load_order, tmp_wdf_string);
537 WdfObjectDelete(tmp_wdf_string);
538 }
539 if (i == (ULONG)dummy_group_index || i == (ULONG)wdf_load_group_index || i == (ULONG)xenpci_group_index)
540 continue;
541 ws = WdfCollectionGetItem(old_load_order, i);
542 WdfCollectionAdd(new_load_order, ws);
543 }
544 WdfRegistryAssignMultiString(sgo_key, &list_name, new_load_order);
545 //FUNCTION_MSG("New Order:\n");
546 for (i = 0; i < WdfCollectionGetCount(new_load_order); i++)
547 {
548 WDFOBJECT ws = WdfCollectionGetItem(new_load_order, i);
549 UNICODE_STRING val;
550 WdfStringGetUnicodeString(ws, &val);
551 //FUNCTION_MSG(" %wZ\n", &val);
552 }
553 WdfObjectDelete(new_load_order);
554 WdfObjectDelete(old_load_order);
555 WdfRegistryClose(sgo_key);
557 FUNCTION_EXIT();
559 return;
560 }
562 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
563 /* this isn't freed on shutdown... perhaps it should be */
564 static PUCHAR dump_header = NULL;
565 static ULONG dump_header_size;
566 static KBUGCHECK_REASON_CALLBACK_RECORD callback_record;
567 static ULONG64 dump_current_offset = 0;
568 #define DUMP_HEADER_PREFIX_SIZE 8
569 #define DUMP_HEADER_SUFFIX_SIZE 8
571 /* call KeInitializeCrashDumpHeader once on crash */
572 static VOID
573 XenPci_DebugHeaderDumpIoCallback(
574 KBUGCHECK_CALLBACK_REASON reason,
575 PKBUGCHECK_REASON_CALLBACK_RECORD record,
576 PVOID reason_specific_data,
577 ULONG reason_specific_data_length) {
578 UNREFERENCED_PARAMETER(record);
579 UNREFERENCED_PARAMETER(reason_specific_data);
580 UNREFERENCED_PARAMETER(reason_specific_data_length);
582 if (dump_header && reason == KbCallbackDumpIo) {
583 PKBUGCHECK_DUMP_IO dump_io = reason_specific_data;
584 if (dump_io->Type == KbDumpIoHeader ) {
585 if (dump_io->Offset != -1) {
586 dump_current_offset = dump_io->Offset;
587 }
588 XN_ASSERT(dump_current_offset + dump_io->BufferLength <= dump_header_size);
589 RtlCopyMemory(dump_header + DUMP_HEADER_PREFIX_SIZE + dump_current_offset, dump_io->Buffer, dump_io->BufferLength);
590 dump_current_offset += dump_io->BufferLength;
591 } else if (dump_io->Type == KbDumpIoComplete) {
592 dump_current_offset = 0;
593 }
594 }
595 }
596 #endif
598 #define XEN_SIGNATURE_LOWER 0x40000000
599 #define XEN_SIGNATURE_UPPER 0x4000FFFF
601 USHORT xen_version_major = (USHORT)-1;
602 USHORT xen_version_minor = (USHORT)-1;
603 PVOID hypercall_stubs = NULL;
605 static VOID
606 XenPCI_GetHypercallStubs() {
607 ULONG base;
608 DWORD32 cpuid_output[4];
609 char xensig[13];
610 ULONG i;
611 ULONG pages;
612 ULONG msr;
614 if (hypercall_stubs) {
615 FUNCTION_MSG("hypercall_stubs already set\n");
616 return;
617 }
619 for (base = XEN_SIGNATURE_LOWER; base < XEN_SIGNATURE_UPPER; base += 0x100) {
620 __cpuid(cpuid_output, base);
621 *(ULONG*)(xensig + 0) = cpuid_output[1];
622 *(ULONG*)(xensig + 4) = cpuid_output[2];
623 *(ULONG*)(xensig + 8) = cpuid_output[3];
624 xensig[12] = '\0';
625 FUNCTION_MSG("base = 0x%08x, Xen Signature = %s, EAX = 0x%08x\n", base, xensig, cpuid_output[0]);
626 if (!strncmp("XenVMMXenVMM", xensig, 12) && ((cpuid_output[0] - base) >= 2))
627 break;
628 }
629 if (base >= XEN_SIGNATURE_UPPER) {
630 FUNCTION_MSG("Cannot find Xen signature\n");
631 return;
632 }
634 __cpuid(cpuid_output, base + 1);
635 xen_version_major = (USHORT)(cpuid_output[0] >> 16);
636 xen_version_minor = (USHORT)(cpuid_output[0] & 0xFFFF);
637 FUNCTION_MSG("Xen Version %d.%d\n", xen_version_major, xen_version_minor);
639 __cpuid(cpuid_output, base + 2);
640 pages = cpuid_output[0];
641 msr = cpuid_output[1];
643 hypercall_stubs = ExAllocatePoolWithTag(NonPagedPool, pages * PAGE_SIZE, XENPCI_POOL_TAG);
644 FUNCTION_MSG("Hypercall area at %p\n", hypercall_stubs);
646 if (!hypercall_stubs)
647 return;
648 for (i = 0; i < pages; i++) {
649 ULONGLONG pfn;
650 pfn = (MmGetPhysicalAddress((PUCHAR)hypercall_stubs + i * PAGE_SIZE).QuadPart >> PAGE_SHIFT);
651 __writemsr(msr, (pfn << PAGE_SHIFT) + i);
652 }
653 }
655 static VOID
656 XenPCI_FreeHypercallStubs() {
657 if (hypercall_stubs) {
658 ExFreePoolWithTag(hypercall_stubs, XENPCI_POOL_TAG);
659 }
660 hypercall_stubs = NULL;
661 }
663 VOID
664 XenPci_EvtDriverUnload(WDFDRIVER driver) {
665 UNREFERENCED_PARAMETER(driver);
667 FUNCTION_ENTER();
669 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
670 KeDeregisterBugCheckReasonCallback(&callback_record);
671 if (dump_header) {
672 MmFreeContiguousMemory(dump_header);
673 }
674 #endif
675 FUNCTION_EXIT();
676 }
679 NTSTATUS
680 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
681 {
682 NTSTATUS status = STATUS_SUCCESS;
683 WDF_DRIVER_CONFIG config;
684 WDFDRIVER driver;
685 WDF_OBJECT_ATTRIBUTES parent_attributes;
686 PCONFIGURATION_INFORMATION conf_info;
687 WDFKEY control_key;
688 WDFKEY param_key;
689 ULONG always_patch = 0;
690 ULONG always_hide = 0;
691 DECLARE_CONST_UNICODE_STRING(control_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
692 DECLARE_CONST_UNICODE_STRING(system_start_options_name, L"SystemStartOptions");
693 DECLARE_CONST_UNICODE_STRING(txt_always_hide_name, L"txt_hide_qemu_always");
694 DECLARE_CONST_UNICODE_STRING(hide_devices_name, L"hide_devices");
695 DECLARE_CONST_UNICODE_STRING(txt_always_patch_name, L"txt_patch_tpr_always");
696 WDFSTRING wdf_system_start_options;
697 UNICODE_STRING system_start_options;
698 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
699 PHYSICAL_ADDRESS dump_header_mem_max;
700 #endif
702 UNREFERENCED_PARAMETER(RegistryPath);
704 FUNCTION_ENTER();
706 FUNCTION_MSG(__DRIVER_NAME " " VER_FILEVERSION_STR "\n");
708 XenPCI_GetHypercallStubs();
710 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
711 if (hypercall_stubs) {
712 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, NULL, 0, &dump_header_size);
713 /* try and allocate contiguous memory as low as possible */
714 dump_header_mem_max.QuadPart = 0xFFFFF;
715 while (!dump_header && dump_header_mem_max.QuadPart != 0xFFFFFFFFFFFFFFFF) {
716 dump_header = MmAllocateContiguousMemory(DUMP_HEADER_PREFIX_SIZE + dump_header_size + DUMP_HEADER_SUFFIX_SIZE, dump_header_mem_max);
717 if (dump_header) {
718 FUNCTION_MSG("Allocated crash dump header < 0x%016I64x\n", dump_header_mem_max.QuadPart);
719 break;
720 }
721 dump_header_mem_max.QuadPart = (dump_header_mem_max.QuadPart << 4) | 0xF;
722 }
723 if (dump_header) {
724 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
725 FUNCTION_MSG("KeInitializeCrashDumpHeader status = %08x, size = %d\n", status, dump_header_size);
726 memcpy(dump_header + 0, "XENXEN", 6); /* magic number */
727 *(PUSHORT)(dump_header + 6) = (USHORT)(INT_PTR)dump_header & (PAGE_SIZE - 1); /* store offset too as additional verification */
728 memcpy(dump_header + DUMP_HEADER_PREFIX_SIZE + dump_header_size, "XENXEN", 6);
729 *(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 */
730 KeInitializeCallbackRecord(&callback_record);
731 KeRegisterBugCheckReasonCallback(&callback_record, XenPci_DebugHeaderDumpIoCallback, KbCallbackDumpIo, (PUCHAR)"XenPci_DebugHeaderDumpIoCallback");
732 } else {
733 FUNCTION_MSG("Failed to allocate memory for crash dump header\n");
734 }
735 }
736 #endif
737 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
738 config.EvtDriverUnload = XenPci_EvtDriverUnload;
739 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
740 if (!NT_SUCCESS(status)) {
741 FUNCTION_MSG("WdfDriverCreate failed with status 0x%x\n", status);
742 FUNCTION_EXIT();
743 return status;
744 }
745 if (hypercall_stubs) {
746 WDF_OBJECT_ATTRIBUTES_INIT(&parent_attributes);
747 parent_attributes.ParentObject = driver;
749 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, &parent_attributes, &param_key);
750 if (!NT_SUCCESS(status)) {
751 FUNCTION_MSG("Error opening parameters key %08x\n", status);
752 goto error;
753 }
755 status = AuxKlibInitialize();
756 if(!NT_SUCCESS(status)) {
757 FUNCTION_MSG("AuxKlibInitialize failed %08x\n", status);
758 goto error;
759 }
761 XenPci_FixLoadOrder();
763 RtlInitUnicodeString(&system_start_options, L"failed to read");
764 status = WdfRegistryOpenKey(NULL, &control_key_name, GENERIC_READ, &parent_attributes, &control_key);
765 if (NT_SUCCESS(status)) {
766 status = WdfStringCreate(NULL, &parent_attributes, &wdf_system_start_options);
767 status = WdfRegistryQueryString(control_key, &system_start_options_name, wdf_system_start_options);
768 if (NT_SUCCESS(status))
769 WdfStringGetUnicodeString(wdf_system_start_options, &system_start_options);
770 }
771 WdfRegistryClose(control_key);
773 FUNCTION_MSG("SystemStartOptions = %wZ\n", &system_start_options);
775 always_patch = 0;
776 WdfRegistryQueryULong(param_key, &txt_always_patch_name, &always_patch);
777 if (always_patch || (system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"PATCHTPR"))) {
778 DECLARE_CONST_UNICODE_STRING(verifier_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
779 WDFKEY memory_key;
780 ULONG verifier_value;
782 FUNCTION_MSG("PATCHTPR found\n");
784 tpr_patch_requested = TRUE;
785 status = WdfRegistryOpenKey(NULL, &verifier_key_name, KEY_READ, &parent_attributes, &memory_key);
786 if (NT_SUCCESS(status))
787 {
788 DECLARE_CONST_UNICODE_STRING(verifier_value_name, L"VerifyDriverLevel");
789 status = WdfRegistryQueryULong(memory_key, &verifier_value_name, &verifier_value);
790 if (NT_SUCCESS(status) && verifier_value != 0)
791 {
792 FUNCTION_MSG("Verifier active - not patching\n");
793 tpr_patch_requested = FALSE;
794 }
795 WdfRegistryClose(memory_key);
796 }
797 }
799 WdfCollectionCreate(&parent_attributes, &qemu_hide_devices);
800 WdfRegistryQueryULong(param_key, &txt_always_hide_name, &always_hide);
801 conf_info = IoGetConfigurationInformation();
802 if (always_hide || ((conf_info == NULL || conf_info->DiskCount == 0)
803 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOGPLPV"))
804 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOEJBPV"))
805 && !*InitSafeBootMode)) {
806 if (!(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"EJBPVUSEFILTERHIDE")) && XenPci_CheckHideQemuDevices()) {
807 DECLARE_CONST_UNICODE_STRING(qemu_hide_flags_name, L"qemu_hide_flags");
808 DECLARE_CONST_UNICODE_STRING(txt_qemu_hide_flags_name, L"txt_qemu_hide_flags");
809 WDFCOLLECTION qemu_hide_flags;
810 ULONG i;
812 WdfCollectionCreate(&parent_attributes, &qemu_hide_flags);
813 WdfRegistryQueryMultiString(param_key, &qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
814 WdfRegistryQueryMultiString(param_key, &txt_qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
815 for (i = 0; i < WdfCollectionGetCount(qemu_hide_flags); i++) {
816 ULONG value;
817 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_flags, i);
818 UNICODE_STRING unicode_string;
819 WdfStringGetUnicodeString(wdf_string, &unicode_string);
820 status = RtlUnicodeStringToInteger(&unicode_string, 0, &value);
821 qemu_hide_flags_value |= value;
822 }
823 WdfObjectDelete(qemu_hide_flags);
824 XenPci_HideQemuDevices();
825 } else {
826 WdfRegistryQueryMultiString(param_key, &hide_devices_name, &parent_attributes, qemu_hide_devices);
827 }
828 }
829 WdfRegistryClose(param_key);
830 }
831 FUNCTION_EXIT();
832 return STATUS_SUCCESS;
834 error:
835 FUNCTION_MSG("Failed, returning %08x\n", status);
836 FUNCTION_EXIT();
837 return status;
838 }