win-pvdrivers

view xenpci/xenpci.c @ 900:938de6b8623d

fix memory leak on suspend/resume
author James Harper <james.harper@bendigoit.com.au>
date Thu Mar 31 20:20:36 2011 +1100 (2011-03-31)
parents ff48ceac3934
children ca56da6bd99a
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 /* this is supposed to be defined in wdm.h, but isn't */
41 NTSTATUS
42 KeInitializeCrashDumpHeader(
43 IN ULONG Type,
44 IN ULONG Flags,
45 OUT PVOID Buffer,
46 IN ULONG BufferSize,
47 OUT PULONG BufferNeeded OPTIONAL
48 );
50 #define DUMP_TYPE_FULL 1
52 static VOID
53 XenPci_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
54 {
55 FUNCTION_ENTER();
57 UNREFERENCED_PARAMETER(device);
58 UNREFERENCED_PARAMETER(is_in_notification_path);
60 switch (notification_type)
61 {
62 case WdfSpecialFilePaging:
63 KdPrint((__DRIVER_NAME " notification_type = Paging, flag = %d\n", is_in_notification_path));
64 break;
65 case WdfSpecialFileHibernation:
66 KdPrint((__DRIVER_NAME " notification_type = Hibernation, flag = %d\n", is_in_notification_path));
67 break;
68 case WdfSpecialFileDump:
69 KdPrint((__DRIVER_NAME " notification_type = Dump, flag = %d\n", is_in_notification_path));
70 break;
71 default:
72 KdPrint((__DRIVER_NAME " notification_type = %d, flag = %d\n", notification_type, is_in_notification_path));
73 break;
74 }
76 FUNCTION_EXIT();
77 }
79 static NTSTATUS
80 XenPci_EvtDeviceAdd_XenPci(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
81 {
82 NTSTATUS status;
83 // PDEVICE_OBJECT fdo = NULL;
84 // PNP_BUS_INFORMATION busInfo;
85 // DECLARE_CONST_UNICODE_STRING(DeviceName, L"\\Device\\XenShutdown");
86 // DECLARE_CONST_UNICODE_STRING(SymbolicName, L"\\DosDevices\\XenShutdown");
87 WDF_CHILD_LIST_CONFIG child_list_config;
88 WDFDEVICE device;
89 PXENPCI_DEVICE_DATA xpdd;
90 UNICODE_STRING reference;
91 WDF_OBJECT_ATTRIBUTES device_attributes;
92 PNP_BUS_INFORMATION pbi;
93 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
94 WDF_INTERRUPT_CONFIG interrupt_config;
95 WDF_OBJECT_ATTRIBUTES file_attributes;
96 WDF_FILEOBJECT_CONFIG file_config;
97 WDF_IO_QUEUE_CONFIG queue_config;
98 WDFCOLLECTION veto_devices;
99 WDFKEY param_key;
100 DECLARE_CONST_UNICODE_STRING(veto_devices_name, L"veto_devices");
101 WDF_DEVICE_POWER_CAPABILITIES power_capabilities;
102 int i;
104 UNREFERENCED_PARAMETER(driver);
106 FUNCTION_ENTER();
108 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
109 pnp_power_callbacks.EvtDeviceD0Entry = XenPci_EvtDeviceD0Entry;
110 pnp_power_callbacks.EvtDeviceD0EntryPostInterruptsEnabled = XenPci_EvtDeviceD0EntryPostInterruptsEnabled;
111 pnp_power_callbacks.EvtDeviceD0Exit = XenPci_EvtDeviceD0Exit;
112 pnp_power_callbacks.EvtDeviceD0ExitPreInterruptsDisabled = XenPci_EvtDeviceD0ExitPreInterruptsDisabled;
113 pnp_power_callbacks.EvtDevicePrepareHardware = XenPci_EvtDevicePrepareHardware;
114 pnp_power_callbacks.EvtDeviceReleaseHardware = XenPci_EvtDeviceReleaseHardware;
115 pnp_power_callbacks.EvtDeviceQueryRemove = XenPci_EvtDeviceQueryRemove;
116 pnp_power_callbacks.EvtDeviceUsageNotification = XenPci_EvtDeviceUsageNotification;
118 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
120 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_BUS_EXTENDER);
121 WdfDeviceInitSetExclusive(device_init, FALSE);
123 WDF_CHILD_LIST_CONFIG_INIT(&child_list_config, sizeof(XENPCI_PDO_IDENTIFICATION_DESCRIPTION), XenPci_EvtChildListCreateDevice);
124 child_list_config.EvtChildListScanForChildren = XenPci_EvtChildListScanForChildren;
125 WdfFdoInitSetDefaultChildListConfig(device_init, &child_list_config, WDF_NO_OBJECT_ATTRIBUTES);
127 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&file_attributes, XENPCI_DEVICE_INTERFACE_DATA);
128 WDF_FILEOBJECT_CONFIG_INIT(&file_config, XenPci_EvtDeviceFileCreate, XenPci_EvtFileClose, XenPci_EvtFileCleanup);
129 WdfDeviceInitSetFileObjectConfig(device_init, &file_config, &file_attributes);
131 WdfDeviceInitSetIoType(device_init, WdfDeviceIoBuffered);
133 WdfDeviceInitSetPowerNotPageable(device_init);
135 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENPCI_DEVICE_DATA);
136 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
137 if (!NT_SUCCESS(status))
138 {
139 KdPrint(("Error creating device %08x\n", status));
140 return status;
141 }
143 xpdd = GetXpdd(device);
144 xpdd->wdf_device = device;
145 xpdd->child_list = WdfFdoGetDefaultChildList(device);
147 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &veto_devices);
148 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &param_key);
149 if (NT_SUCCESS(status))
150 {
151 status = WdfRegistryQueryMultiString(param_key, &veto_devices_name, WDF_NO_OBJECT_ATTRIBUTES, veto_devices);
152 if (!NT_SUCCESS(status))
153 {
154 KdPrint(("Error reading parameters/veto_devices value %08x\n", status));
155 }
156 WdfRegistryClose(param_key);
157 }
158 else
159 {
160 KdPrint(("Error opening parameters key %08x\n", status));
161 }
163 InitializeListHead(&xpdd->veto_list);
164 for (i = 0; i < (int)WdfCollectionGetCount(veto_devices); i++)
165 {
166 WDFOBJECT ws;
167 UNICODE_STRING val;
168 ANSI_STRING s;
169 PVOID entry;
170 ws = WdfCollectionGetItem(veto_devices, i);
171 WdfStringGetUnicodeString(ws, &val);
172 RtlUnicodeStringToAnsiString(&s, &val, TRUE);
173 entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY) + s.Length + 1, XENPCI_POOL_TAG);
174 memcpy((PUCHAR)entry + sizeof(LIST_ENTRY), s.Buffer, s.Length + 1);
175 RtlFreeAnsiString(&s);
176 InsertTailList(&xpdd->veto_list, (PLIST_ENTRY)entry);
177 }
178 WDF_DEVICE_POWER_CAPABILITIES_INIT(&power_capabilities);
179 power_capabilities.DeviceD1 = WdfTrue;
180 power_capabilities.WakeFromD1 = WdfTrue;
181 power_capabilities.DeviceWake = PowerDeviceD1;
182 power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD1;
183 power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
184 power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
185 power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
186 power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
187 power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
188 WdfDeviceSetPowerCapabilities(device, &power_capabilities);
190 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
191 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
192 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
194 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchParallel);
195 queue_config.EvtIoDefault = XenPci_EvtIoDefault;
196 status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->io_queue);
197 if (!NT_SUCCESS(status)) {
198 KdPrint(("Error creating queue 0x%x\n", status));
199 return status;
200 }
202 WDF_INTERRUPT_CONFIG_INIT(&interrupt_config, EvtChn_EvtInterruptIsr, NULL);
203 interrupt_config.EvtInterruptEnable = EvtChn_EvtInterruptEnable;
204 interrupt_config.EvtInterruptDisable = EvtChn_EvtInterruptDisable;
206 status = WdfInterruptCreate(device, &interrupt_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->interrupt);
207 if (!NT_SUCCESS(status))
208 {
209 KdPrint(("Error creating interrupt 0x%x\n", status));
210 return status;
211 }
213 RtlInitUnicodeString(&reference, L"xenbus");
214 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_XENBUS, &reference);
215 if (!NT_SUCCESS(status)) {
216 KdPrint(("Error registering device interface 0x%x\n", status));
217 return status;
218 }
220 RtlInitUnicodeString(&reference, L"evtchn");
221 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_EVTCHN, &reference);
222 if (!NT_SUCCESS(status)) {
223 KdPrint(("Error registering device interface 0x%x\n", status));
224 return status;
225 }
227 RtlInitUnicodeString(&reference, L"gntdev");
228 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_GNTDEV, &reference);
229 if (!NT_SUCCESS(status)) {
230 KdPrint(("Error registering device interface 0x%x\n", status));
231 return status;
232 }
234 pbi.BusTypeGuid = GUID_BUS_TYPE_XEN;
235 pbi.LegacyBusType = PNPBus;
236 pbi.BusNumber = 0;
237 WdfDeviceSetBusInformationForChildren(device, &pbi);
239 xpdd->removable = TRUE;
241 FUNCTION_EXIT();
242 return status;
243 }
245 NTSTATUS
246 XenHide_EvtDevicePrepareHardware(WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
247 {
248 UNREFERENCED_PARAMETER(device);
249 UNREFERENCED_PARAMETER(resources_raw);
250 UNREFERENCED_PARAMETER(resources_translated);
251 FUNCTION_ENTER();
252 FUNCTION_EXIT();
253 return STATUS_UNSUCCESSFUL;
254 }
256 static BOOLEAN
257 XenPci_IdSuffixMatches(PWDFDEVICE_INIT device_init, PWCHAR matching_id)
258 {
259 NTSTATUS status;
260 WDFMEMORY memory;
261 ULONG remaining;
262 size_t string_length;
263 PWCHAR ids;
264 PWCHAR ptr;
265 size_t ids_length;
266 ULONG properties[] = {DevicePropertyCompatibleIDs, DevicePropertyHardwareID};
267 int i;
269 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
270 for (i = 0; i < ARRAY_SIZE(properties); i++)
271 {
273 status = WdfFdoInitAllocAndQueryProperty(device_init, properties[i], NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
274 if (!NT_SUCCESS(status))
275 continue;
276 ids = WdfMemoryGetBuffer(memory, &ids_length);
278 if (!NT_SUCCESS(status))
279 {
280 // KdPrint((__DRIVER_NAME " i = %d, status = %x, ids_length = %d\n", i, status, ids_length));
281 continue;
282 }
284 remaining = (ULONG)ids_length / 2;
285 for (ptr = ids; *ptr != 0; ptr += string_length + 1)
286 {
287 RtlStringCchLengthW(ptr, remaining, &string_length);
288 remaining -= (ULONG)string_length + 1;
289 if (string_length >= wcslen(matching_id))
290 {
291 ptr += string_length - wcslen(matching_id);
292 string_length = wcslen(matching_id);
293 }
294 // KdPrint((__DRIVER_NAME " Comparing '%S' and '%S'\n", ptr, matching_id));
295 if (wcscmp(ptr, matching_id) == 0)
296 {
297 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (Match)\n"));
298 WdfObjectDelete(memory);
299 return TRUE;
300 }
301 }
302 WdfObjectDelete(memory);
303 }
304 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (No match)\n"));
305 return FALSE;
306 }
308 WDFCOLLECTION qemu_hide_devices;
309 USHORT qemu_hide_flags_value;
311 static NTSTATUS
312 XenPci_EvtDeviceAdd_XenHide(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
313 {
314 NTSTATUS status;
315 WDFMEMORY memory;
316 PWCHAR device_description;
317 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
318 WDF_OBJECT_ATTRIBUTES device_attributes;
319 BOOLEAN hide_required = FALSE;
320 WDFDEVICE device;
321 ULONG i;
323 UNREFERENCED_PARAMETER(driver);
325 FUNCTION_ENTER();
327 status = WdfFdoInitAllocAndQueryProperty(device_init, DevicePropertyDeviceDescription, NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
328 if (NT_SUCCESS(status))
329 {
330 device_description = WdfMemoryGetBuffer(memory, NULL);
331 }
332 else
333 {
334 device_description = L"<unknown device>";
335 }
337 for (i = 0; i < WdfCollectionGetCount(qemu_hide_devices); i++)
338 {
339 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_devices, i);
340 UNICODE_STRING unicode_string;
341 WdfStringGetUnicodeString(wdf_string, &unicode_string);
342 if (XenPci_IdSuffixMatches(device_init, unicode_string.Buffer))
343 {
344 hide_required = TRUE;
345 break;
346 }
347 }
348 if (!hide_required)
349 {
350 WdfObjectDelete(memory);
351 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (filter not required for %S)\n", device_description));
352 return STATUS_SUCCESS;
353 }
355 KdPrint((__DRIVER_NAME " Installing Filter for %S\n", device_description));
357 WdfFdoInitSetFilter(device_init);
358 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
359 WdfDeviceInitSetExclusive(device_init, FALSE);
361 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
362 pnp_power_callbacks.EvtDevicePrepareHardware = XenHide_EvtDevicePrepareHardware;
363 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
365 WDF_OBJECT_ATTRIBUTES_INIT(&device_attributes);
366 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
367 if (!NT_SUCCESS(status))
368 {
369 KdPrint(("Error creating device %08x\n", status));
370 WdfObjectDelete(memory);
371 FUNCTION_EXIT();
372 return status;
373 }
375 WdfObjectDelete(memory);
376 FUNCTION_EXIT();
378 return status;
379 }
381 static NTSTATUS
382 XenPci_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
383 {
384 if (XenPci_IdSuffixMatches(device_init, L"VEN_5853&DEV_0001"))
385 {
386 KdPrint((__DRIVER_NAME " Xen PCI device found - must be fdo\n"));
387 return XenPci_EvtDeviceAdd_XenPci(driver, device_init);
388 }
389 else if (WdfCollectionGetCount(qemu_hide_devices) > 0)
390 {
391 KdPrint((__DRIVER_NAME " Xen PCI device not found - must be filter\n"));
392 return XenPci_EvtDeviceAdd_XenHide(driver, device_init);
393 }
394 else
395 return STATUS_SUCCESS;
396 }
398 ULONG qemu_protocol_version;
399 ULONG tpr_patch_requested;
400 extern PULONG InitSafeBootMode;
402 VOID
403 XenPci_HideQemuDevices()
404 {
405 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, (USHORT)qemu_hide_flags_value); //QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
406 KdPrint((__DRIVER_NAME " Disabled qemu devices %02x\n", qemu_hide_flags_value));
407 }
409 static BOOLEAN
410 XenPci_CheckHideQemuDevices()
411 {
412 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2)
413 {
414 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
415 KdPrint((__DRIVER_NAME " Version = %d\n", qemu_protocol_version));
416 switch(qemu_protocol_version)
417 {
418 case 1:
419 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
420 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
421 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
422 {
423 KdPrint((__DRIVER_NAME " Blacklisted\n"));
424 break;
425 }
426 /* fall through */
427 case 0:
428 return TRUE;
429 default:
430 KdPrint((__DRIVER_NAME " Unknown qemu version %d\n", qemu_protocol_version));
431 break;
432 }
433 }
434 return FALSE;
435 }
437 /*
438 make sure the load order is System Reserved, Dummy Group, WdfLoadGroup, XenPCI, Boot Bus Extender
439 */
441 static VOID
442 XenPci_FixLoadOrder()
443 {
444 NTSTATUS status;
445 WDFCOLLECTION old_load_order, new_load_order;
446 DECLARE_CONST_UNICODE_STRING(sgo_name, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder");
447 DECLARE_CONST_UNICODE_STRING(list_name, L"List");
448 WDFKEY sgo_key;
449 ULONG i;
450 LONG dummy_group_index = -1;
451 LONG boot_bus_extender_index = -1;
452 LONG xenpci_group_index = -1;
453 LONG wdf_load_group_index = -1;
454 DECLARE_CONST_UNICODE_STRING(dummy_group_name, L"Dummy Group");
455 DECLARE_CONST_UNICODE_STRING(wdf_load_group_name, L"WdfLoadGroup");
456 DECLARE_CONST_UNICODE_STRING(xenpci_group_name, L"XenPCI Group");
457 DECLARE_CONST_UNICODE_STRING(boot_bus_extender_name, L"Boot Bus Extender");
459 FUNCTION_ENTER();
461 status = WdfRegistryOpenKey(NULL, &sgo_name, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &sgo_key);
462 if (!NT_SUCCESS(status))
463 {
464 KdPrint((__DRIVER_NAME " Error opening ServiceGroupOrder key %08x\n", status));
465 return;
466 }
467 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &old_load_order);
468 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &new_load_order);
469 status = WdfRegistryQueryMultiString(sgo_key, &list_name, WDF_NO_OBJECT_ATTRIBUTES, old_load_order);
470 if (!NT_SUCCESS(status))
471 {
472 KdPrint((__DRIVER_NAME " Error reading ServiceGroupOrder\\List value %08x\n", status));
473 WdfObjectDelete(new_load_order);
474 WdfObjectDelete(old_load_order);
475 return;
476 }
477 //KdPrint((__DRIVER_NAME " Current Order:\n"));
478 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
479 {
480 WDFOBJECT ws = WdfCollectionGetItem(old_load_order, i);
481 UNICODE_STRING val;
482 WdfStringGetUnicodeString(ws, &val);
483 if (!RtlCompareUnicodeString(&val, &dummy_group_name, TRUE))
484 dummy_group_index = (ULONG)i;
485 if (!RtlCompareUnicodeString(&val, &wdf_load_group_name, TRUE))
486 wdf_load_group_index = (ULONG)i;
487 if (!RtlCompareUnicodeString(&val, &xenpci_group_name, TRUE))
488 xenpci_group_index = (ULONG)i;
489 if (!RtlCompareUnicodeString(&val, &boot_bus_extender_name, TRUE))
490 boot_bus_extender_index = (ULONG)i;
491 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
492 }
493 KdPrint((__DRIVER_NAME " dummy_group_index = %d\n", dummy_group_index));
494 KdPrint((__DRIVER_NAME " wdf_load_group_index = %d\n", wdf_load_group_index));
495 KdPrint((__DRIVER_NAME " xenpci_group_index = %d\n", xenpci_group_index));
496 KdPrint((__DRIVER_NAME " boot_bus_extender_index = %d\n", boot_bus_extender_index));
497 if (boot_bus_extender_index == -1)
498 {
499 WdfObjectDelete(new_load_order);
500 WdfObjectDelete(old_load_order);
501 WdfRegistryClose(sgo_key);
502 return; /* something is very wrong */
503 }
504 if (dummy_group_index == 1 && wdf_load_group_index != -1 &&
505 (dummy_group_index < wdf_load_group_index
506 && wdf_load_group_index < xenpci_group_index
507 && xenpci_group_index < boot_bus_extender_index))
508 {
509 FUNCTION_EXIT();
510 return; /* our work here is done */
511 }
512 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
513 {
514 WDFOBJECT ws;
515 if (i == 1)
516 {
517 WDFSTRING tmp_wdf_string;
518 WdfStringCreate(&dummy_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
519 WdfCollectionAdd(new_load_order, tmp_wdf_string);
520 WdfObjectDelete(tmp_wdf_string);
521 }
522 if (i == 1)
523 {
524 WDFSTRING tmp_wdf_string;
525 WdfStringCreate(&wdf_load_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
526 WdfCollectionAdd(new_load_order, tmp_wdf_string);
527 WdfObjectDelete(tmp_wdf_string);
528 }
529 if (i == 1)
530 {
531 WDFSTRING tmp_wdf_string;
532 WdfStringCreate(&xenpci_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
533 WdfCollectionAdd(new_load_order, tmp_wdf_string);
534 WdfObjectDelete(tmp_wdf_string);
535 }
536 if (i == (ULONG)dummy_group_index || i == (ULONG)wdf_load_group_index || i == (ULONG)xenpci_group_index)
537 continue;
538 ws = WdfCollectionGetItem(old_load_order, i);
539 WdfCollectionAdd(new_load_order, ws);
540 }
541 WdfRegistryAssignMultiString(sgo_key, &list_name, new_load_order);
542 //KdPrint((__DRIVER_NAME " New Order:\n"));
543 for (i = 0; i < WdfCollectionGetCount(new_load_order); i++)
544 {
545 WDFOBJECT ws = WdfCollectionGetItem(new_load_order, i);
546 UNICODE_STRING val;
547 WdfStringGetUnicodeString(ws, &val);
548 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
549 }
550 WdfObjectDelete(new_load_order);
551 WdfObjectDelete(old_load_order);
552 WdfRegistryClose(sgo_key);
554 FUNCTION_EXIT();
556 return;
557 }
559 VOID
560 XenPci_EvtDriverUnload(WDFDRIVER driver)
561 {
562 UNREFERENCED_PARAMETER(driver);
564 #if DBG
565 XenPci_UnHookDbgPrint();
566 #endif
567 }
569 /* we need to balloon down very early on in the case of PoD, so things get a little messy */
570 static PMDL
571 XenPci_InitialBalloonDown()
572 {
573 PVOID hypercall_stubs;
574 domid_t domid = DOMID_SELF;
575 ULONG maximum_reservation;
576 ULONG current_reservation;
577 ULONG extra_kb;
578 ULONG extra_mb;
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;
586 FUNCTION_ENTER();
588 hypercall_stubs = hvm_get_hypercall_stubs();
589 if (!hypercall_stubs)
590 {
591 KdPrint((__DRIVER_NAME " Failed to copy hypercall stubs. Maybe not running under Xen?\n"));
592 return NULL;
593 }
594 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_maximum_reservation, &domid);
595 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
596 maximum_reservation = ret;
597 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_current_reservation, &domid);
598 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
599 current_reservation = ret;
601 extra_kb = (maximum_reservation - current_reservation) << 2;
602 extra_mb = ((extra_kb + 1023) >> 10);
604 KdPrint((__DRIVER_NAME " Trying to give %d MB to Xen\n", extra_mb));
606 /* this code is mostly duplicated from the actual balloon thread... too hard to reuse */
607 for (j = 0; j < (int)extra_mb; j++)
608 {
609 PHYSICAL_ADDRESS alloc_low;
610 PHYSICAL_ADDRESS alloc_high;
611 PHYSICAL_ADDRESS alloc_skip;
612 alloc_low.QuadPart = 0;
613 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
614 alloc_skip.QuadPart = 0;
615 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
616 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
617 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS, MmCached, 0);
618 #else
619 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS);
620 #endif
621 if (!mdl)
622 {
623 /* 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... */
624 KdPrint((__DRIVER_NAME " Initial Balloon Down failed\n"));
625 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000002, extra_mb, j, 0x00000000);
626 break;
627 }
628 else
629 {
630 int pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
631 if (pfn_count != BALLOON_UNIT_PAGES)
632 {
633 /* we could probably do this better but it will only happen in low memory conditions... */
634 KdPrint((__DRIVER_NAME " wanted %d pages got %d pages\n", BALLOON_UNIT_PAGES, pfn_count));
635 MmFreePagesFromMdl(mdl);
636 ExFreePool(mdl);
637 break;
638 }
639 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
640 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
641 for (i = 0; i < pfn_count; i++)
642 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
643 reservation.address_bits = 0;
644 reservation.extent_order = 0;
645 reservation.domid = DOMID_SELF;
646 reservation.nr_extents = pfn_count;
647 #pragma warning(disable: 4127) /* conditional expression is constant */
648 set_xen_guest_handle(reservation.extent_start, pfns);
650 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_decrease_reservation) - pfn_count = %d\n", pfn_count));
651 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_decrease_reservation, &reservation);
652 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
653 //KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
654 if (head)
655 {
656 mdl->Next = head;
657 head = mdl;
658 }
659 else
660 {
661 head = mdl;
662 }
663 }
664 }
666 hvm_free_hypercall_stubs(hypercall_stubs);
668 FUNCTION_EXIT();
670 return head;
671 }
673 NTSTATUS
674 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
675 {
676 NTSTATUS status = STATUS_SUCCESS;
677 WDF_DRIVER_CONFIG config;
678 WDFDRIVER driver;
679 WDF_OBJECT_ATTRIBUTES parent_attributes;
680 PCONFIGURATION_INFORMATION conf_info;
681 WDFKEY control_key;
682 WDFKEY param_key;
683 ULONG always_patch = 0;
684 ULONG always_hide = 0;
685 DECLARE_CONST_UNICODE_STRING(control_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
686 DECLARE_CONST_UNICODE_STRING(system_start_options_name, L"SystemStartOptions");
687 DECLARE_CONST_UNICODE_STRING(txt_always_hide_name, L"txt_hide_qemu_always");
688 DECLARE_CONST_UNICODE_STRING(hide_devices_name, L"hide_devices");
689 DECLARE_CONST_UNICODE_STRING(txt_always_patch_name, L"txt_patch_tpr_always");
690 WDFSTRING wdf_system_start_options;
691 UNICODE_STRING system_start_options;
692 PVOID dump_page;
693 ULONG dump_header_size;
695 UNREFERENCED_PARAMETER(RegistryPath);
697 FUNCTION_ENTER();
699 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
701 #if DBG
702 XenPci_HookDbgPrint();
703 #endif
705 ASSERT(!balloon_mdl_head);
706 balloon_mdl_head = XenPci_InitialBalloonDown();
708 dump_page = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENPCI_POOL_TAG);
709 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_page, PAGE_SIZE, &dump_header_size);
710 KdPrint((__DRIVER_NAME " KeInitializeCrashDumpHeader status = %08x, size = %d\n", status, dump_header_size));
712 /* again after enabling DbgPrint hooking */
713 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
716 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
717 config.EvtDriverUnload = XenPci_EvtDriverUnload;
718 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
719 if (!NT_SUCCESS(status))
720 {
721 KdPrint((__DRIVER_NAME " WdfDriverCreate failed with status 0x%x\n", status));
722 FUNCTION_EXIT();
723 #if DBG
724 XenPci_UnHookDbgPrint();
725 #endif
726 return status;
727 }
728 WDF_OBJECT_ATTRIBUTES_INIT(&parent_attributes);
729 parent_attributes.ParentObject = driver;
731 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, &parent_attributes, &param_key);
732 if (!NT_SUCCESS(status))
733 {
734 KdPrint(("Error opening parameters key %08x\n", status));
735 goto error;
736 }
738 status = AuxKlibInitialize();
739 if(!NT_SUCCESS(status))
740 {
741 KdPrint((__DRIVER_NAME " AuxKlibInitialize failed %08x\n", status));
742 goto error;
743 }
745 XenPci_FixLoadOrder();
747 RtlInitUnicodeString(&system_start_options, L"failed to read");
748 status = WdfRegistryOpenKey(NULL, &control_key_name, GENERIC_READ, &parent_attributes, &control_key);
749 if (NT_SUCCESS(status))
750 {
751 status = WdfStringCreate(NULL, &parent_attributes, &wdf_system_start_options);
752 status = WdfRegistryQueryString(control_key, &system_start_options_name, wdf_system_start_options);
753 if (NT_SUCCESS(status))
754 WdfStringGetUnicodeString(wdf_system_start_options, &system_start_options);
755 }
756 WdfRegistryClose(control_key);
758 KdPrint((__DRIVER_NAME " SystemStartOptions = %S\n", system_start_options));
760 always_patch = 0;
761 WdfRegistryQueryULong(param_key, &txt_always_patch_name, &always_patch);
762 if (always_patch || (system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"PATCHTPR")))
763 {
764 DECLARE_CONST_UNICODE_STRING(verifier_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
765 WDFKEY memory_key;
766 ULONG verifier_value;
768 KdPrint((__DRIVER_NAME " PATCHTPR found\n"));
770 tpr_patch_requested = TRUE;
771 status = WdfRegistryOpenKey(NULL, &verifier_key_name, KEY_READ, &parent_attributes, &memory_key);
772 if (NT_SUCCESS(status))
773 {
774 DECLARE_CONST_UNICODE_STRING(verifier_value_name, L"VerifyDriverLevel");
775 status = WdfRegistryQueryULong(memory_key, &verifier_value_name, &verifier_value);
776 if (NT_SUCCESS(status) && verifier_value != 0)
777 {
778 KdPrint((__DRIVER_NAME " Verifier active - not patching\n"));
779 tpr_patch_requested = FALSE;
780 }
781 WdfRegistryClose(memory_key);
782 }
783 }
785 WdfCollectionCreate(&parent_attributes, &qemu_hide_devices);
786 WdfRegistryQueryULong(param_key, &txt_always_hide_name, &always_hide);
787 conf_info = IoGetConfigurationInformation();
788 if (always_hide || ((conf_info == NULL || conf_info->DiskCount == 0)
789 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOGPLPV"))
790 && !*InitSafeBootMode))
791 {
792 if (!(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"GPLPVUSEFILTERHIDE")) && XenPci_CheckHideQemuDevices())
793 {
794 DECLARE_CONST_UNICODE_STRING(qemu_hide_flags_name, L"qemu_hide_flags");
795 DECLARE_CONST_UNICODE_STRING(txt_qemu_hide_flags_name, L"txt_qemu_hide_flags");
796 WDFCOLLECTION qemu_hide_flags;
797 ULONG i;
799 WdfCollectionCreate(&parent_attributes, &qemu_hide_flags);
800 WdfRegistryQueryMultiString(param_key, &qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
801 WdfRegistryQueryMultiString(param_key, &txt_qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
802 for (i = 0; i < WdfCollectionGetCount(qemu_hide_flags); i++)
803 {
804 ULONG value;
805 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_flags, i);
806 UNICODE_STRING unicode_string;
807 WdfStringGetUnicodeString(wdf_string, &unicode_string);
808 status = RtlUnicodeStringToInteger(&unicode_string, 0, &value);
809 qemu_hide_flags_value |= value;
810 }
811 WdfObjectDelete(qemu_hide_flags);
812 XenPci_HideQemuDevices();
813 }
814 else
815 {
816 WdfRegistryQueryMultiString(param_key, &hide_devices_name, &parent_attributes, qemu_hide_devices);
817 }
818 }
819 WdfRegistryClose(param_key);
820 FUNCTION_EXIT();
821 return STATUS_SUCCESS;
823 error:
824 #if DBG
825 XenPci_UnHookDbgPrint();
826 #endif
827 KdPrint(("Failed, returning %08x\n", status));
828 FUNCTION_EXIT();
829 return status;
830 }