win-pvdrivers

view xenpci/xenpci.c @ 1012:9e076343bb8e

Change GuardedMutex to FastMutex to be compatible with older OS
author James Harper <james.harper@bendigoit.com.au>
date Mon Feb 11 17:28:26 2013 +1100 (2013-02-11)
parents 9fb8690938b3
children cd72cd0e1c19
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 KdPrint((__DRIVER_NAME " notification_type = Paging, flag = %d\n", is_in_notification_path));
68 break;
69 case WdfSpecialFileHibernation:
70 KdPrint((__DRIVER_NAME " notification_type = Hibernation, flag = %d\n", is_in_notification_path));
71 break;
72 case WdfSpecialFileDump:
73 KdPrint((__DRIVER_NAME " notification_type = Dump, flag = %d\n", is_in_notification_path));
74 break;
75 default:
76 KdPrint((__DRIVER_NAME " 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 int i;
108 UNREFERENCED_PARAMETER(driver);
110 FUNCTION_ENTER();
112 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
113 pnp_power_callbacks.EvtDeviceD0Entry = XenPci_EvtDeviceD0Entry;
114 pnp_power_callbacks.EvtDeviceD0EntryPostInterruptsEnabled = XenPci_EvtDeviceD0EntryPostInterruptsEnabled;
115 pnp_power_callbacks.EvtDeviceD0Exit = XenPci_EvtDeviceD0Exit;
116 pnp_power_callbacks.EvtDeviceD0ExitPreInterruptsDisabled = XenPci_EvtDeviceD0ExitPreInterruptsDisabled;
117 pnp_power_callbacks.EvtDevicePrepareHardware = XenPci_EvtDevicePrepareHardware;
118 pnp_power_callbacks.EvtDeviceReleaseHardware = XenPci_EvtDeviceReleaseHardware;
119 pnp_power_callbacks.EvtDeviceQueryRemove = XenPci_EvtDeviceQueryRemove;
120 pnp_power_callbacks.EvtDeviceUsageNotification = XenPci_EvtDeviceUsageNotification;
122 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
124 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_BUS_EXTENDER);
125 WdfDeviceInitSetExclusive(device_init, FALSE);
127 WDF_CHILD_LIST_CONFIG_INIT(&child_list_config, sizeof(XENPCI_PDO_IDENTIFICATION_DESCRIPTION), XenPci_EvtChildListCreateDevice);
128 child_list_config.EvtChildListScanForChildren = XenPci_EvtChildListScanForChildren;
129 WdfFdoInitSetDefaultChildListConfig(device_init, &child_list_config, WDF_NO_OBJECT_ATTRIBUTES);
131 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&file_attributes, XENPCI_DEVICE_INTERFACE_DATA);
132 WDF_FILEOBJECT_CONFIG_INIT(&file_config, XenPci_EvtDeviceFileCreate, XenPci_EvtFileClose, XenPci_EvtFileCleanup);
133 WdfDeviceInitSetFileObjectConfig(device_init, &file_config, &file_attributes);
135 WdfDeviceInitSetIoType(device_init, WdfDeviceIoBuffered);
137 WdfDeviceInitSetPowerNotPageable(device_init);
139 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENPCI_DEVICE_DATA);
140 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
141 if (!NT_SUCCESS(status))
142 {
143 KdPrint(("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 ExInitializeFastMutex(&xpdd->suspend_mutex);
152 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &veto_devices);
153 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &param_key);
154 if (NT_SUCCESS(status))
155 {
156 status = WdfRegistryQueryMultiString(param_key, &veto_devices_name, WDF_NO_OBJECT_ATTRIBUTES, veto_devices);
157 if (!NT_SUCCESS(status))
158 {
159 KdPrint(("Error reading parameters/veto_devices value %08x\n", status));
160 }
161 WdfRegistryClose(param_key);
162 }
163 else
164 {
165 KdPrint(("Error opening parameters key %08x\n", status));
166 }
168 InitializeListHead(&xpdd->veto_list);
169 for (i = 0; i < (int)WdfCollectionGetCount(veto_devices); i++)
170 {
171 WDFOBJECT ws;
172 UNICODE_STRING val;
173 ANSI_STRING s;
174 PVOID entry;
175 ws = WdfCollectionGetItem(veto_devices, i);
176 WdfStringGetUnicodeString(ws, &val);
177 RtlUnicodeStringToAnsiString(&s, &val, TRUE);
178 entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY) + s.Length + 1, XENPCI_POOL_TAG);
179 memcpy((PUCHAR)entry + sizeof(LIST_ENTRY), s.Buffer, s.Length + 1);
180 RtlFreeAnsiString(&s);
181 InsertTailList(&xpdd->veto_list, (PLIST_ENTRY)entry);
182 }
183 WDF_DEVICE_POWER_CAPABILITIES_INIT(&power_capabilities);
184 power_capabilities.DeviceD1 = WdfTrue;
185 power_capabilities.WakeFromD1 = WdfTrue;
186 power_capabilities.DeviceWake = PowerDeviceD1;
187 power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
188 power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
189 power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
190 power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
191 power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
192 power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
193 WdfDeviceSetPowerCapabilities(device, &power_capabilities);
195 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
196 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
197 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
199 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchParallel);
200 queue_config.EvtIoDefault = XenPci_EvtIoDefault;
201 status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->io_queue);
202 if (!NT_SUCCESS(status)) {
203 KdPrint(("Error creating queue 0x%x\n", status));
204 return status;
205 }
207 WDF_INTERRUPT_CONFIG_INIT(&interrupt_config, EvtChn_EvtInterruptIsr, NULL);
208 interrupt_config.EvtInterruptEnable = EvtChn_EvtInterruptEnable;
209 interrupt_config.EvtInterruptDisable = EvtChn_EvtInterruptDisable;
211 status = WdfInterruptCreate(device, &interrupt_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->interrupt);
212 if (!NT_SUCCESS(status))
213 {
214 KdPrint(("Error creating interrupt 0x%x\n", status));
215 return status;
216 }
218 RtlInitUnicodeString(&reference, L"xenbus");
219 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_XENBUS, &reference);
220 if (!NT_SUCCESS(status)) {
221 KdPrint(("Error registering device interface 0x%x\n", status));
222 return status;
223 }
225 RtlInitUnicodeString(&reference, L"evtchn");
226 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_EVTCHN, &reference);
227 if (!NT_SUCCESS(status)) {
228 KdPrint(("Error registering device interface 0x%x\n", status));
229 return status;
230 }
232 RtlInitUnicodeString(&reference, L"gntdev");
233 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_GNTDEV, &reference);
234 if (!NT_SUCCESS(status)) {
235 KdPrint(("Error registering device interface 0x%x\n", status));
236 return status;
237 }
239 pbi.BusTypeGuid = GUID_BUS_TYPE_XEN;
240 pbi.LegacyBusType = PNPBus;
241 pbi.BusNumber = 0;
242 WdfDeviceSetBusInformationForChildren(device, &pbi);
244 xpdd->removable = TRUE;
246 FUNCTION_EXIT();
247 return status;
248 }
250 NTSTATUS
251 XenHide_EvtDevicePrepareHardware(WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
252 {
253 UNREFERENCED_PARAMETER(device);
254 UNREFERENCED_PARAMETER(resources_raw);
255 UNREFERENCED_PARAMETER(resources_translated);
256 FUNCTION_ENTER();
257 FUNCTION_EXIT();
258 return STATUS_UNSUCCESSFUL;
259 }
261 static BOOLEAN
262 XenPci_IdSuffixMatches(PWDFDEVICE_INIT device_init, PWCHAR matching_id)
263 {
264 NTSTATUS status;
265 WDFMEMORY memory;
266 ULONG remaining;
267 size_t string_length;
268 PWCHAR ids;
269 PWCHAR ptr;
270 size_t ids_length;
271 ULONG properties[] = {DevicePropertyCompatibleIDs, DevicePropertyHardwareID};
272 int i;
274 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
275 for (i = 0; i < ARRAY_SIZE(properties); i++)
276 {
278 status = WdfFdoInitAllocAndQueryProperty(device_init, properties[i], NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
279 if (!NT_SUCCESS(status))
280 continue;
281 ids = WdfMemoryGetBuffer(memory, &ids_length);
283 if (!NT_SUCCESS(status))
284 {
285 // KdPrint((__DRIVER_NAME " i = %d, status = %x, ids_length = %d\n", i, status, ids_length));
286 continue;
287 }
289 remaining = (ULONG)ids_length / 2;
290 for (ptr = ids; *ptr != 0; ptr += string_length + 1)
291 {
292 RtlStringCchLengthW(ptr, remaining, &string_length);
293 remaining -= (ULONG)string_length + 1;
294 if (string_length >= wcslen(matching_id))
295 {
296 ptr += string_length - wcslen(matching_id);
297 string_length = wcslen(matching_id);
298 }
299 // KdPrint((__DRIVER_NAME " Comparing '%S' and '%S'\n", ptr, matching_id));
300 if (wcscmp(ptr, matching_id) == 0)
301 {
302 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (Match)\n"));
303 WdfObjectDelete(memory);
304 return TRUE;
305 }
306 }
307 WdfObjectDelete(memory);
308 }
309 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (No match)\n"));
310 return FALSE;
311 }
313 WDFCOLLECTION qemu_hide_devices;
314 USHORT qemu_hide_flags_value;
316 static NTSTATUS
317 XenPci_EvtDeviceAdd_XenHide(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
318 {
319 NTSTATUS status;
320 WDFMEMORY memory;
321 PWCHAR device_description;
322 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
323 WDF_OBJECT_ATTRIBUTES device_attributes;
324 BOOLEAN hide_required = FALSE;
325 WDFDEVICE device;
326 ULONG i;
328 UNREFERENCED_PARAMETER(driver);
330 FUNCTION_ENTER();
332 status = WdfFdoInitAllocAndQueryProperty(device_init, DevicePropertyDeviceDescription, NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
333 if (NT_SUCCESS(status)) {
334 device_description = WdfMemoryGetBuffer(memory, NULL);
335 } else {
336 device_description = L"<unknown device>";
337 }
339 for (i = 0; i < WdfCollectionGetCount(qemu_hide_devices); i++) {
340 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_devices, i);
341 UNICODE_STRING unicode_string;
342 WdfStringGetUnicodeString(wdf_string, &unicode_string);
343 if (XenPci_IdSuffixMatches(device_init, unicode_string.Buffer)) {
344 hide_required = TRUE;
345 break;
346 }
347 }
348 if (!hide_required) {
349 FUNCTION_MSG("(filter not required for %S)\n", device_description);
350 WdfObjectDelete(memory);
351 return STATUS_SUCCESS;
352 }
354 FUNCTION_MSG("Installing Filter for %S\n", device_description);
356 WdfFdoInitSetFilter(device_init);
357 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
358 WdfDeviceInitSetExclusive(device_init, FALSE);
360 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
361 pnp_power_callbacks.EvtDevicePrepareHardware = XenHide_EvtDevicePrepareHardware;
362 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
364 WDF_OBJECT_ATTRIBUTES_INIT(&device_attributes);
365 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
366 if (!NT_SUCCESS(status)) {
367 FUNCTION_MSG("Error creating device %08x\n", status);
368 WdfObjectDelete(memory);
369 FUNCTION_EXIT();
370 return status;
371 }
373 WdfObjectDelete(memory);
374 FUNCTION_EXIT();
376 return status;
377 }
379 static NTSTATUS
380 XenPci_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
381 {
382 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 {
400 #pragma warning(suppress:28138)
401 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, (USHORT)qemu_hide_flags_value); //QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
402 KdPrint((__DRIVER_NAME " Disabled qemu devices %02x\n", qemu_hide_flags_value));
403 }
405 static BOOLEAN
406 XenPci_CheckHideQemuDevices()
407 {
408 #pragma warning(suppress:28138)
409 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2)
410 {
411 #pragma warning(suppress:28138)
412 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
413 KdPrint((__DRIVER_NAME " Version = %d\n", qemu_protocol_version));
414 switch(qemu_protocol_version)
415 {
416 case 1:
417 #pragma warning(suppress:28138)
418 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
419 #pragma warning(suppress:28138)
420 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
421 #pragma warning(suppress:28138)
422 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
423 {
424 KdPrint((__DRIVER_NAME " Blacklisted\n"));
425 break;
426 }
427 /* fall through */
428 case 0:
429 return TRUE;
430 default:
431 KdPrint((__DRIVER_NAME " Unknown qemu version %d\n", qemu_protocol_version));
432 break;
433 }
434 }
435 return FALSE;
436 }
438 /*
439 make sure the load order is System Reserved, Dummy Group, WdfLoadGroup, XenPCI, Boot Bus Extender
440 */
442 static VOID
443 XenPci_FixLoadOrder()
444 {
445 NTSTATUS status;
446 WDFCOLLECTION old_load_order, new_load_order;
447 DECLARE_CONST_UNICODE_STRING(sgo_name, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder");
448 DECLARE_CONST_UNICODE_STRING(list_name, L"List");
449 WDFKEY sgo_key;
450 ULONG i;
451 LONG dummy_group_index = -1;
452 LONG boot_bus_extender_index = -1;
453 LONG xenpci_group_index = -1;
454 LONG wdf_load_group_index = -1;
455 DECLARE_CONST_UNICODE_STRING(dummy_group_name, L"Dummy Group");
456 DECLARE_CONST_UNICODE_STRING(wdf_load_group_name, L"WdfLoadGroup");
457 DECLARE_CONST_UNICODE_STRING(xenpci_group_name, L"XenPCI Group");
458 DECLARE_CONST_UNICODE_STRING(boot_bus_extender_name, L"Boot Bus Extender");
460 FUNCTION_ENTER();
462 status = WdfRegistryOpenKey(NULL, &sgo_name, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &sgo_key);
463 if (!NT_SUCCESS(status))
464 {
465 KdPrint((__DRIVER_NAME " Error opening ServiceGroupOrder key %08x\n", status));
466 return;
467 }
468 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &old_load_order);
469 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &new_load_order);
470 status = WdfRegistryQueryMultiString(sgo_key, &list_name, WDF_NO_OBJECT_ATTRIBUTES, old_load_order);
471 if (!NT_SUCCESS(status))
472 {
473 KdPrint((__DRIVER_NAME " Error reading ServiceGroupOrder\\List value %08x\n", status));
474 WdfObjectDelete(new_load_order);
475 WdfObjectDelete(old_load_order);
476 return;
477 }
478 //KdPrint((__DRIVER_NAME " Current Order:\n"));
479 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
480 {
481 WDFOBJECT ws = WdfCollectionGetItem(old_load_order, i);
482 UNICODE_STRING val;
483 WdfStringGetUnicodeString(ws, &val);
484 if (!RtlCompareUnicodeString(&val, &dummy_group_name, TRUE))
485 dummy_group_index = (ULONG)i;
486 if (!RtlCompareUnicodeString(&val, &wdf_load_group_name, TRUE))
487 wdf_load_group_index = (ULONG)i;
488 if (!RtlCompareUnicodeString(&val, &xenpci_group_name, TRUE))
489 xenpci_group_index = (ULONG)i;
490 if (!RtlCompareUnicodeString(&val, &boot_bus_extender_name, TRUE))
491 boot_bus_extender_index = (ULONG)i;
492 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
493 }
494 KdPrint((__DRIVER_NAME " dummy_group_index = %d\n", dummy_group_index));
495 KdPrint((__DRIVER_NAME " wdf_load_group_index = %d\n", wdf_load_group_index));
496 KdPrint((__DRIVER_NAME " xenpci_group_index = %d\n", xenpci_group_index));
497 KdPrint((__DRIVER_NAME " boot_bus_extender_index = %d\n", boot_bus_extender_index));
498 if (boot_bus_extender_index == -1)
499 {
500 WdfObjectDelete(new_load_order);
501 WdfObjectDelete(old_load_order);
502 WdfRegistryClose(sgo_key);
503 return; /* something is very wrong */
504 }
505 if (dummy_group_index == 1 && wdf_load_group_index != -1 &&
506 (dummy_group_index < wdf_load_group_index
507 && wdf_load_group_index < xenpci_group_index
508 && xenpci_group_index < boot_bus_extender_index))
509 {
510 FUNCTION_EXIT();
511 return; /* our work here is done */
512 }
513 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
514 {
515 WDFOBJECT ws;
516 if (i == 1)
517 {
518 WDFSTRING tmp_wdf_string;
519 WdfStringCreate(&dummy_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
520 WdfCollectionAdd(new_load_order, tmp_wdf_string);
521 WdfObjectDelete(tmp_wdf_string);
522 }
523 if (i == 1)
524 {
525 WDFSTRING tmp_wdf_string;
526 WdfStringCreate(&wdf_load_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
527 WdfCollectionAdd(new_load_order, tmp_wdf_string);
528 WdfObjectDelete(tmp_wdf_string);
529 }
530 if (i == 1)
531 {
532 WDFSTRING tmp_wdf_string;
533 WdfStringCreate(&xenpci_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
534 WdfCollectionAdd(new_load_order, tmp_wdf_string);
535 WdfObjectDelete(tmp_wdf_string);
536 }
537 if (i == (ULONG)dummy_group_index || i == (ULONG)wdf_load_group_index || i == (ULONG)xenpci_group_index)
538 continue;
539 ws = WdfCollectionGetItem(old_load_order, i);
540 WdfCollectionAdd(new_load_order, ws);
541 }
542 WdfRegistryAssignMultiString(sgo_key, &list_name, new_load_order);
543 //KdPrint((__DRIVER_NAME " New Order:\n"));
544 for (i = 0; i < WdfCollectionGetCount(new_load_order); i++)
545 {
546 WDFOBJECT ws = WdfCollectionGetItem(new_load_order, i);
547 UNICODE_STRING val;
548 WdfStringGetUnicodeString(ws, &val);
549 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
550 }
551 WdfObjectDelete(new_load_order);
552 WdfObjectDelete(old_load_order);
553 WdfRegistryClose(sgo_key);
555 FUNCTION_EXIT();
557 return;
558 }
560 VOID
561 XenPci_EvtDriverUnload(WDFDRIVER driver)
562 {
563 UNREFERENCED_PARAMETER(driver);
565 #if DBG
566 XenPci_UnHookDbgPrint();
567 #endif
568 }
570 /* we need to balloon down very early on in the case of PoD, so things get a little messy */
571 static PMDL
572 XenPci_InitialBalloonDown()
573 {
574 PVOID hypercall_stubs;
575 domid_t domid = DOMID_SELF;
576 ULONG maximum_reservation;
577 ULONG current_reservation;
578 ULONG extra_kb;
579 ULONG ret;
580 struct xen_memory_reservation reservation;
581 xen_pfn_t *pfns;
582 PMDL head = NULL;
583 PMDL mdl;
584 int i, j;
585 ULONG curr_pfns_offset;
586 PHYSICAL_ADDRESS alloc_low;
587 PHYSICAL_ADDRESS alloc_high;
588 PHYSICAL_ADDRESS alloc_skip;
590 FUNCTION_ENTER();
592 hypercall_stubs = hvm_get_hypercall_stubs();
593 if (!hypercall_stubs)
594 {
595 KdPrint((__DRIVER_NAME " Failed to copy hypercall stubs. Maybe not running under Xen?\n"));
596 FUNCTION_EXIT();
597 return NULL;
598 }
599 if (xen_version_major < 4)
600 {
601 FUNCTION_MSG("No support for PoD. Cannot do initial balloon down.\n");
602 FUNCTION_MSG("Expect a crash if maxmem is set much larger than memory.\n");
603 FUNCTION_EXIT();
604 return NULL;
605 }
606 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_maximum_reservation, &domid);
607 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
608 maximum_reservation = ret;
609 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_current_reservation, &domid);
610 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
611 current_reservation = ret;
613 extra_kb = (maximum_reservation - current_reservation) << 2;
615 alloc_low.QuadPart = 0;
616 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
617 alloc_skip.QuadPart = PAGE_SIZE;
619 KdPrint((__DRIVER_NAME " Trying to give %d KB (%d MB) to Xen\n", extra_kb, extra_kb >> 10));
621 /* this code is mostly duplicated from the actual balloon thread... too hard to reuse */
622 pfns = ExAllocatePoolWithTag(NonPagedPool, max(BALLOON_UNIT_PAGES, (64 << 8)) * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
623 if (!pfns) {
624 /* If we can't balloon down then we are going to crash in strange ways later. Better to bug check now. */
625 KdPrint((__DRIVER_NAME " Initial Balloon Down failed - no memory for pfn list\n"));
626 #pragma warning(suppress:28159)
627 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000003, 0x00000000, 0x00000000, 0x00000000);
628 }
629 curr_pfns_offset = 0;
630 /* this makes sure we balloon up to the next multiple of BALLOON_UNITS_KB */
631 for (j = 0; j < (int)extra_kb; j += BALLOON_UNITS_KB)
632 {
633 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
634 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
635 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024, MmCached, 0);
636 #else
637 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024);
638 #endif
639 if (!mdl || MmGetMdlByteCount(mdl) != BALLOON_UNITS_KB * 1024)
640 {
641 /* this should actually never happen. If we can't allocate the memory it means windows is using it, and if it was using it we would have crashed already... */
642 KdPrint((__DRIVER_NAME " Initial Balloon Down failed\n"));
643 #pragma warning(suppress:28159)
644 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000002, extra_kb, j, 0x00000000);
645 }
646 else
647 {
648 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
649 for (i = 0; i < BALLOON_UNIT_PAGES; i++)
650 {
651 pfns[curr_pfns_offset] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
652 curr_pfns_offset++;
653 }
654 if (curr_pfns_offset == (ULONG)max(BALLOON_UNIT_PAGES, (64 << 8)) || j + BALLOON_UNITS_KB > (int)extra_kb)
655 {
656 reservation.address_bits = 0;
657 reservation.extent_order = 0;
658 reservation.domid = DOMID_SELF;
659 reservation.nr_extents = curr_pfns_offset;
660 #pragma warning(disable: 4127) /* conditional expression is constant */
661 set_xen_guest_handle(reservation.extent_start, pfns);
662 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_decrease_reservation, &reservation);
663 if (ret != curr_pfns_offset)
664 FUNCTION_MSG("only decreased %d of %d pages\n", ret, curr_pfns_offset);
665 curr_pfns_offset = 0;
666 }
667 if (head)
668 {
669 mdl->Next = head;
670 head = mdl;
671 }
672 else
673 {
674 head = mdl;
675 }
676 }
677 //KdPrint((__DRIVER_NAME " C\n"));
678 }
679 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
680 hvm_free_hypercall_stubs(hypercall_stubs);
682 FUNCTION_EXIT();
684 return head;
685 }
687 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
688 /* this isn't freed on shutdown... perhaps it should be */
689 static PUCHAR dump_header;
690 static ULONG dump_header_size;
691 static ULONG dump_header_refreshed_flag = FALSE;
692 static KBUGCHECK_REASON_CALLBACK_RECORD callback_record;
693 #define DUMP_HEADER_PREFIX_SIZE 8
694 #define DUMP_HEADER_SUFFIX_SIZE 8
696 /* call KeInitializeCrashDumpHeader once on crash */
697 static VOID
698 XenPci_DebugHeaderDumpIoCallback(
699 KBUGCHECK_CALLBACK_REASON reason,
700 PKBUGCHECK_REASON_CALLBACK_RECORD record,
701 PVOID reason_specific_data,
702 ULONG reason_specific_data_length) {
703 UNREFERENCED_PARAMETER(reason);
704 UNREFERENCED_PARAMETER(record);
705 UNREFERENCED_PARAMETER(reason_specific_data);
706 UNREFERENCED_PARAMETER(reason_specific_data_length);
707 if (!dump_header_refreshed_flag) {
708 NTSTATUS status;
709 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
710 /* copy bug check code in? */
711 dump_header_refreshed_flag = TRUE;
712 }
713 }
714 #endif
716 NTSTATUS
717 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
718 {
719 NTSTATUS status = STATUS_SUCCESS;
720 WDF_DRIVER_CONFIG config;
721 WDFDRIVER driver;
722 WDF_OBJECT_ATTRIBUTES parent_attributes;
723 PCONFIGURATION_INFORMATION conf_info;
724 WDFKEY control_key;
725 WDFKEY param_key;
726 ULONG always_patch = 0;
727 ULONG always_hide = 0;
728 DECLARE_CONST_UNICODE_STRING(control_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
729 DECLARE_CONST_UNICODE_STRING(system_start_options_name, L"SystemStartOptions");
730 DECLARE_CONST_UNICODE_STRING(txt_always_hide_name, L"txt_hide_qemu_always");
731 DECLARE_CONST_UNICODE_STRING(hide_devices_name, L"hide_devices");
732 DECLARE_CONST_UNICODE_STRING(txt_always_patch_name, L"txt_patch_tpr_always");
733 WDFSTRING wdf_system_start_options;
734 UNICODE_STRING system_start_options;
735 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
736 PHYSICAL_ADDRESS dump_header_mem_max;
737 #endif
739 UNREFERENCED_PARAMETER(RegistryPath);
741 FUNCTION_ENTER();
743 FUNCTION_MSG(__DRIVER_NAME " " VER_FILEVERSION_STR "\n");
745 #if DBG
746 XenPci_HookDbgPrint();
747 #endif
749 NT_ASSERT(!balloon_mdl_head);
750 balloon_mdl_head = XenPci_InitialBalloonDown();
752 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
753 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, NULL, 0, &dump_header_size);
754 /* try and allocate contiguous memory as low as possible */
755 dump_header = NULL;
756 dump_header_mem_max.QuadPart = 0xFFFFF;
757 while (!dump_header && dump_header_mem_max.QuadPart != 0xFFFFFFFFFFFFFFFF) {
758 dump_header = MmAllocateContiguousMemory(DUMP_HEADER_PREFIX_SIZE + dump_header_size + DUMP_HEADER_SUFFIX_SIZE, dump_header_mem_max);
759 dump_header_mem_max.QuadPart = (dump_header_mem_max.QuadPart << 8) | 0xF;
760 }
761 if (dump_header) {
762 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
763 FUNCTION_MSG("KeInitializeCrashDumpHeader status = %08x, size = %d\n", status, dump_header_size);
764 memcpy(dump_header + 0, "XENXEN", 6); /* magic number */
765 *(PUSHORT)(dump_header + 6) = (USHORT)(INT_PTR)dump_header & (PAGE_SIZE - 1); /* store offset too as additional verification */
766 memcpy(dump_header + DUMP_HEADER_PREFIX_SIZE + dump_header_size, "XENXEN", 6);
767 *(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 */
768 KeInitializeCallbackRecord(&callback_record);
769 KeRegisterBugCheckReasonCallback(&callback_record, XenPci_DebugHeaderDumpIoCallback, KbCallbackDumpIo, (PUCHAR)"XenPci_DebugHeaderDumpIoCallback");
770 } else {
771 FUNCTION_MSG("Failed to allocate memory for crash dump header\n");
772 }
773 #endif
775 /* again after enabling DbgPrint hooking */
776 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
779 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
780 config.EvtDriverUnload = XenPci_EvtDriverUnload;
781 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
782 if (!NT_SUCCESS(status))
783 {
784 KdPrint((__DRIVER_NAME " WdfDriverCreate failed with status 0x%x\n", status));
785 FUNCTION_EXIT();
786 #if DBG
787 XenPci_UnHookDbgPrint();
788 #endif
789 return status;
790 }
791 WDF_OBJECT_ATTRIBUTES_INIT(&parent_attributes);
792 parent_attributes.ParentObject = driver;
794 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, &parent_attributes, &param_key);
795 if (!NT_SUCCESS(status))
796 {
797 KdPrint(("Error opening parameters key %08x\n", status));
798 goto error;
799 }
801 status = AuxKlibInitialize();
802 if(!NT_SUCCESS(status))
803 {
804 KdPrint((__DRIVER_NAME " AuxKlibInitialize failed %08x\n", status));
805 goto error;
806 }
808 XenPci_FixLoadOrder();
810 RtlInitUnicodeString(&system_start_options, L"failed to read");
811 status = WdfRegistryOpenKey(NULL, &control_key_name, GENERIC_READ, &parent_attributes, &control_key);
812 if (NT_SUCCESS(status))
813 {
814 status = WdfStringCreate(NULL, &parent_attributes, &wdf_system_start_options);
815 status = WdfRegistryQueryString(control_key, &system_start_options_name, wdf_system_start_options);
816 if (NT_SUCCESS(status))
817 WdfStringGetUnicodeString(wdf_system_start_options, &system_start_options);
818 }
819 WdfRegistryClose(control_key);
821 KdPrint((__DRIVER_NAME " SystemStartOptions = %wZ\n", &system_start_options));
823 always_patch = 0;
824 WdfRegistryQueryULong(param_key, &txt_always_patch_name, &always_patch);
825 if (always_patch || (system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"PATCHTPR")))
826 {
827 DECLARE_CONST_UNICODE_STRING(verifier_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
828 WDFKEY memory_key;
829 ULONG verifier_value;
831 KdPrint((__DRIVER_NAME " PATCHTPR found\n"));
833 tpr_patch_requested = TRUE;
834 status = WdfRegistryOpenKey(NULL, &verifier_key_name, KEY_READ, &parent_attributes, &memory_key);
835 if (NT_SUCCESS(status))
836 {
837 DECLARE_CONST_UNICODE_STRING(verifier_value_name, L"VerifyDriverLevel");
838 status = WdfRegistryQueryULong(memory_key, &verifier_value_name, &verifier_value);
839 if (NT_SUCCESS(status) && verifier_value != 0)
840 {
841 KdPrint((__DRIVER_NAME " Verifier active - not patching\n"));
842 tpr_patch_requested = FALSE;
843 }
844 WdfRegistryClose(memory_key);
845 }
846 }
848 WdfCollectionCreate(&parent_attributes, &qemu_hide_devices);
849 WdfRegistryQueryULong(param_key, &txt_always_hide_name, &always_hide);
850 conf_info = IoGetConfigurationInformation();
851 if (always_hide || ((conf_info == NULL || conf_info->DiskCount == 0)
852 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOGPLPV"))
853 && !*InitSafeBootMode)) {
854 if (!(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"GPLPVUSEFILTERHIDE")) && XenPci_CheckHideQemuDevices()) {
855 DECLARE_CONST_UNICODE_STRING(qemu_hide_flags_name, L"qemu_hide_flags");
856 DECLARE_CONST_UNICODE_STRING(txt_qemu_hide_flags_name, L"txt_qemu_hide_flags");
857 WDFCOLLECTION qemu_hide_flags;
858 ULONG i;
860 WdfCollectionCreate(&parent_attributes, &qemu_hide_flags);
861 WdfRegistryQueryMultiString(param_key, &qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
862 WdfRegistryQueryMultiString(param_key, &txt_qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
863 for (i = 0; i < WdfCollectionGetCount(qemu_hide_flags); i++) {
864 ULONG value;
865 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_flags, i);
866 UNICODE_STRING unicode_string;
867 WdfStringGetUnicodeString(wdf_string, &unicode_string);
868 status = RtlUnicodeStringToInteger(&unicode_string, 0, &value);
869 qemu_hide_flags_value |= value;
870 }
871 WdfObjectDelete(qemu_hide_flags);
872 XenPci_HideQemuDevices();
873 } else {
874 WdfRegistryQueryMultiString(param_key, &hide_devices_name, &parent_attributes, qemu_hide_devices);
875 }
876 }
877 WdfRegistryClose(param_key);
878 FUNCTION_EXIT();
879 return STATUS_SUCCESS;
881 error:
882 #if DBG
883 XenPci_UnHookDbgPrint();
884 #endif
885 KdPrint(("Failed, returning %08x\n", status));
886 FUNCTION_EXIT();
887 return status;
888 }