win-pvdrivers

view xenpci/xenpci.c @ 965:63bdd096d8d1

Fix KeInitializeCrashDumpHeader - buffer was too small under newer systems
author James Harper <james.harper@bendigoit.com.au>
date Tue Jan 10 12:11:30 2012 +1100 (2012-01-10)
parents da0e40d12a9c
children 8f483a2b2991
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)
42 /* this is supposed to be defined in wdm.h, but isn't */
43 NTSTATUS
44 KeInitializeCrashDumpHeader(
45 IN ULONG Type,
46 IN ULONG Flags,
47 OUT PVOID Buffer,
48 IN ULONG BufferSize,
49 OUT PULONG BufferNeeded OPTIONAL
50 );
51 #endif
53 #define DUMP_TYPE_FULL 1
55 static VOID
56 XenPci_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
57 {
58 FUNCTION_ENTER();
60 UNREFERENCED_PARAMETER(device);
61 UNREFERENCED_PARAMETER(is_in_notification_path);
63 switch (notification_type)
64 {
65 case WdfSpecialFilePaging:
66 KdPrint((__DRIVER_NAME " notification_type = Paging, flag = %d\n", is_in_notification_path));
67 break;
68 case WdfSpecialFileHibernation:
69 KdPrint((__DRIVER_NAME " notification_type = Hibernation, flag = %d\n", is_in_notification_path));
70 break;
71 case WdfSpecialFileDump:
72 KdPrint((__DRIVER_NAME " notification_type = Dump, flag = %d\n", is_in_notification_path));
73 break;
74 default:
75 KdPrint((__DRIVER_NAME " notification_type = %d, flag = %d\n", notification_type, is_in_notification_path));
76 break;
77 }
79 FUNCTION_EXIT();
80 }
82 static NTSTATUS
83 XenPci_EvtDeviceAdd_XenPci(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
84 {
85 NTSTATUS status;
86 // PDEVICE_OBJECT fdo = NULL;
87 // PNP_BUS_INFORMATION busInfo;
88 // DECLARE_CONST_UNICODE_STRING(DeviceName, L"\\Device\\XenShutdown");
89 // DECLARE_CONST_UNICODE_STRING(SymbolicName, L"\\DosDevices\\XenShutdown");
90 WDF_CHILD_LIST_CONFIG child_list_config;
91 WDFDEVICE device;
92 PXENPCI_DEVICE_DATA xpdd;
93 UNICODE_STRING reference;
94 WDF_OBJECT_ATTRIBUTES device_attributes;
95 PNP_BUS_INFORMATION pbi;
96 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
97 WDF_INTERRUPT_CONFIG interrupt_config;
98 WDF_OBJECT_ATTRIBUTES file_attributes;
99 WDF_FILEOBJECT_CONFIG file_config;
100 WDF_IO_QUEUE_CONFIG queue_config;
101 WDFCOLLECTION veto_devices;
102 WDFKEY param_key;
103 DECLARE_CONST_UNICODE_STRING(veto_devices_name, L"veto_devices");
104 WDF_DEVICE_POWER_CAPABILITIES power_capabilities;
105 int i;
107 UNREFERENCED_PARAMETER(driver);
109 FUNCTION_ENTER();
111 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
112 pnp_power_callbacks.EvtDeviceD0Entry = XenPci_EvtDeviceD0Entry;
113 pnp_power_callbacks.EvtDeviceD0EntryPostInterruptsEnabled = XenPci_EvtDeviceD0EntryPostInterruptsEnabled;
114 pnp_power_callbacks.EvtDeviceD0Exit = XenPci_EvtDeviceD0Exit;
115 pnp_power_callbacks.EvtDeviceD0ExitPreInterruptsDisabled = XenPci_EvtDeviceD0ExitPreInterruptsDisabled;
116 pnp_power_callbacks.EvtDevicePrepareHardware = XenPci_EvtDevicePrepareHardware;
117 pnp_power_callbacks.EvtDeviceReleaseHardware = XenPci_EvtDeviceReleaseHardware;
118 pnp_power_callbacks.EvtDeviceQueryRemove = XenPci_EvtDeviceQueryRemove;
119 pnp_power_callbacks.EvtDeviceUsageNotification = XenPci_EvtDeviceUsageNotification;
121 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
123 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_BUS_EXTENDER);
124 WdfDeviceInitSetExclusive(device_init, FALSE);
126 WDF_CHILD_LIST_CONFIG_INIT(&child_list_config, sizeof(XENPCI_PDO_IDENTIFICATION_DESCRIPTION), XenPci_EvtChildListCreateDevice);
127 child_list_config.EvtChildListScanForChildren = XenPci_EvtChildListScanForChildren;
128 WdfFdoInitSetDefaultChildListConfig(device_init, &child_list_config, WDF_NO_OBJECT_ATTRIBUTES);
130 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&file_attributes, XENPCI_DEVICE_INTERFACE_DATA);
131 WDF_FILEOBJECT_CONFIG_INIT(&file_config, XenPci_EvtDeviceFileCreate, XenPci_EvtFileClose, XenPci_EvtFileCleanup);
132 WdfDeviceInitSetFileObjectConfig(device_init, &file_config, &file_attributes);
134 WdfDeviceInitSetIoType(device_init, WdfDeviceIoBuffered);
136 WdfDeviceInitSetPowerNotPageable(device_init);
138 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENPCI_DEVICE_DATA);
139 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
140 if (!NT_SUCCESS(status))
141 {
142 KdPrint(("Error creating device %08x\n", status));
143 return status;
144 }
146 xpdd = GetXpdd(device);
147 xpdd->wdf_device = device;
148 xpdd->child_list = WdfFdoGetDefaultChildList(device);
150 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &veto_devices);
151 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &param_key);
152 if (NT_SUCCESS(status))
153 {
154 status = WdfRegistryQueryMultiString(param_key, &veto_devices_name, WDF_NO_OBJECT_ATTRIBUTES, veto_devices);
155 if (!NT_SUCCESS(status))
156 {
157 KdPrint(("Error reading parameters/veto_devices value %08x\n", status));
158 }
159 WdfRegistryClose(param_key);
160 }
161 else
162 {
163 KdPrint(("Error opening parameters key %08x\n", status));
164 }
166 InitializeListHead(&xpdd->veto_list);
167 for (i = 0; i < (int)WdfCollectionGetCount(veto_devices); i++)
168 {
169 WDFOBJECT ws;
170 UNICODE_STRING val;
171 ANSI_STRING s;
172 PVOID entry;
173 ws = WdfCollectionGetItem(veto_devices, i);
174 WdfStringGetUnicodeString(ws, &val);
175 RtlUnicodeStringToAnsiString(&s, &val, TRUE);
176 entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY) + s.Length + 1, XENPCI_POOL_TAG);
177 memcpy((PUCHAR)entry + sizeof(LIST_ENTRY), s.Buffer, s.Length + 1);
178 RtlFreeAnsiString(&s);
179 InsertTailList(&xpdd->veto_list, (PLIST_ENTRY)entry);
180 }
181 WDF_DEVICE_POWER_CAPABILITIES_INIT(&power_capabilities);
182 power_capabilities.DeviceD1 = WdfTrue;
183 power_capabilities.WakeFromD1 = WdfTrue;
184 power_capabilities.DeviceWake = PowerDeviceD1;
185 power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
186 power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
187 power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
188 power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
189 power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
190 power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
191 WdfDeviceSetPowerCapabilities(device, &power_capabilities);
193 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
194 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
195 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
197 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchParallel);
198 queue_config.EvtIoDefault = XenPci_EvtIoDefault;
199 status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->io_queue);
200 if (!NT_SUCCESS(status)) {
201 KdPrint(("Error creating queue 0x%x\n", status));
202 return status;
203 }
205 WDF_INTERRUPT_CONFIG_INIT(&interrupt_config, EvtChn_EvtInterruptIsr, NULL);
206 interrupt_config.EvtInterruptEnable = EvtChn_EvtInterruptEnable;
207 interrupt_config.EvtInterruptDisable = EvtChn_EvtInterruptDisable;
209 status = WdfInterruptCreate(device, &interrupt_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->interrupt);
210 if (!NT_SUCCESS(status))
211 {
212 KdPrint(("Error creating interrupt 0x%x\n", status));
213 return status;
214 }
216 RtlInitUnicodeString(&reference, L"xenbus");
217 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_XENBUS, &reference);
218 if (!NT_SUCCESS(status)) {
219 KdPrint(("Error registering device interface 0x%x\n", status));
220 return status;
221 }
223 RtlInitUnicodeString(&reference, L"evtchn");
224 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_EVTCHN, &reference);
225 if (!NT_SUCCESS(status)) {
226 KdPrint(("Error registering device interface 0x%x\n", status));
227 return status;
228 }
230 RtlInitUnicodeString(&reference, L"gntdev");
231 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_GNTDEV, &reference);
232 if (!NT_SUCCESS(status)) {
233 KdPrint(("Error registering device interface 0x%x\n", status));
234 return status;
235 }
237 pbi.BusTypeGuid = GUID_BUS_TYPE_XEN;
238 pbi.LegacyBusType = PNPBus;
239 pbi.BusNumber = 0;
240 WdfDeviceSetBusInformationForChildren(device, &pbi);
242 xpdd->removable = TRUE;
244 FUNCTION_EXIT();
245 return status;
246 }
248 NTSTATUS
249 XenHide_EvtDevicePrepareHardware(WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
250 {
251 UNREFERENCED_PARAMETER(device);
252 UNREFERENCED_PARAMETER(resources_raw);
253 UNREFERENCED_PARAMETER(resources_translated);
254 FUNCTION_ENTER();
255 FUNCTION_EXIT();
256 return STATUS_UNSUCCESSFUL;
257 }
259 static BOOLEAN
260 XenPci_IdSuffixMatches(PWDFDEVICE_INIT device_init, PWCHAR matching_id)
261 {
262 NTSTATUS status;
263 WDFMEMORY memory;
264 ULONG remaining;
265 size_t string_length;
266 PWCHAR ids;
267 PWCHAR ptr;
268 size_t ids_length;
269 ULONG properties[] = {DevicePropertyCompatibleIDs, DevicePropertyHardwareID};
270 int i;
272 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
273 for (i = 0; i < ARRAY_SIZE(properties); i++)
274 {
276 status = WdfFdoInitAllocAndQueryProperty(device_init, properties[i], NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
277 if (!NT_SUCCESS(status))
278 continue;
279 ids = WdfMemoryGetBuffer(memory, &ids_length);
281 if (!NT_SUCCESS(status))
282 {
283 // KdPrint((__DRIVER_NAME " i = %d, status = %x, ids_length = %d\n", i, status, ids_length));
284 continue;
285 }
287 remaining = (ULONG)ids_length / 2;
288 for (ptr = ids; *ptr != 0; ptr += string_length + 1)
289 {
290 RtlStringCchLengthW(ptr, remaining, &string_length);
291 remaining -= (ULONG)string_length + 1;
292 if (string_length >= wcslen(matching_id))
293 {
294 ptr += string_length - wcslen(matching_id);
295 string_length = wcslen(matching_id);
296 }
297 // KdPrint((__DRIVER_NAME " Comparing '%S' and '%S'\n", ptr, matching_id));
298 if (wcscmp(ptr, matching_id) == 0)
299 {
300 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (Match)\n"));
301 WdfObjectDelete(memory);
302 return TRUE;
303 }
304 }
305 WdfObjectDelete(memory);
306 }
307 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (No match)\n"));
308 return FALSE;
309 }
311 WDFCOLLECTION qemu_hide_devices;
312 USHORT qemu_hide_flags_value;
314 static NTSTATUS
315 XenPci_EvtDeviceAdd_XenHide(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
316 {
317 NTSTATUS status;
318 WDFMEMORY memory;
319 PWCHAR device_description;
320 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
321 WDF_OBJECT_ATTRIBUTES device_attributes;
322 BOOLEAN hide_required = FALSE;
323 WDFDEVICE device;
324 ULONG i;
326 UNREFERENCED_PARAMETER(driver);
328 FUNCTION_ENTER();
330 status = WdfFdoInitAllocAndQueryProperty(device_init, DevicePropertyDeviceDescription, NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
331 if (NT_SUCCESS(status))
332 {
333 device_description = WdfMemoryGetBuffer(memory, NULL);
334 }
335 else
336 {
337 device_description = L"<unknown device>";
338 }
340 for (i = 0; i < WdfCollectionGetCount(qemu_hide_devices); i++)
341 {
342 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_devices, i);
343 UNICODE_STRING unicode_string;
344 WdfStringGetUnicodeString(wdf_string, &unicode_string);
345 if (XenPci_IdSuffixMatches(device_init, unicode_string.Buffer))
346 {
347 hide_required = TRUE;
348 break;
349 }
350 }
351 if (!hide_required)
352 {
353 WdfObjectDelete(memory);
354 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (filter not required for %S)\n", device_description));
355 return STATUS_SUCCESS;
356 }
358 KdPrint((__DRIVER_NAME " 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 {
372 KdPrint(("Error creating device %08x\n", status));
373 WdfObjectDelete(memory);
374 FUNCTION_EXIT();
375 return status;
376 }
378 WdfObjectDelete(memory);
379 FUNCTION_EXIT();
381 return status;
382 }
384 static NTSTATUS
385 XenPci_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
386 {
387 if (XenPci_IdSuffixMatches(device_init, L"VEN_5853&DEV_0001"))
388 {
389 KdPrint((__DRIVER_NAME " Xen PCI device found - must be fdo\n"));
390 return XenPci_EvtDeviceAdd_XenPci(driver, device_init);
391 }
392 else if (WdfCollectionGetCount(qemu_hide_devices) > 0)
393 {
394 KdPrint((__DRIVER_NAME " Xen PCI device not found - must be filter\n"));
395 return XenPci_EvtDeviceAdd_XenHide(driver, device_init);
396 }
397 else
398 return STATUS_SUCCESS;
399 }
401 ULONG qemu_protocol_version;
402 ULONG tpr_patch_requested;
403 extern PULONG InitSafeBootMode;
405 VOID
406 XenPci_HideQemuDevices()
407 {
408 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, (USHORT)qemu_hide_flags_value); //QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
409 KdPrint((__DRIVER_NAME " Disabled qemu devices %02x\n", qemu_hide_flags_value));
410 }
412 static BOOLEAN
413 XenPci_CheckHideQemuDevices()
414 {
415 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2)
416 {
417 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
418 KdPrint((__DRIVER_NAME " Version = %d\n", qemu_protocol_version));
419 switch(qemu_protocol_version)
420 {
421 case 1:
422 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
423 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
424 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
425 {
426 KdPrint((__DRIVER_NAME " Blacklisted\n"));
427 break;
428 }
429 /* fall through */
430 case 0:
431 return TRUE;
432 default:
433 KdPrint((__DRIVER_NAME " 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 KdPrint((__DRIVER_NAME " 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 KdPrint((__DRIVER_NAME " Error reading ServiceGroupOrder\\List value %08x\n", status));
476 WdfObjectDelete(new_load_order);
477 WdfObjectDelete(old_load_order);
478 return;
479 }
480 //KdPrint((__DRIVER_NAME " 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 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
495 }
496 KdPrint((__DRIVER_NAME " dummy_group_index = %d\n", dummy_group_index));
497 KdPrint((__DRIVER_NAME " wdf_load_group_index = %d\n", wdf_load_group_index));
498 KdPrint((__DRIVER_NAME " xenpci_group_index = %d\n", xenpci_group_index));
499 KdPrint((__DRIVER_NAME " 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 //KdPrint((__DRIVER_NAME " 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 //KdPrint((__DRIVER_NAME " %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 VOID
563 XenPci_EvtDriverUnload(WDFDRIVER driver)
564 {
565 UNREFERENCED_PARAMETER(driver);
567 #if DBG
568 XenPci_UnHookDbgPrint();
569 #endif
570 }
572 /* we need to balloon down very early on in the case of PoD, so things get a little messy */
573 static PMDL
574 XenPci_InitialBalloonDown()
575 {
576 PVOID hypercall_stubs;
577 domid_t domid = DOMID_SELF;
578 ULONG maximum_reservation;
579 ULONG current_reservation;
580 ULONG extra_kb;
581 ULONG ret;
582 struct xen_memory_reservation reservation;
583 xen_pfn_t *pfns;
584 PMDL head = NULL;
585 PMDL mdl;
586 int i, j;
587 ULONG curr_pfns_offset;
588 PHYSICAL_ADDRESS alloc_low;
589 PHYSICAL_ADDRESS alloc_high;
590 PHYSICAL_ADDRESS alloc_skip;
592 FUNCTION_ENTER();
594 hypercall_stubs = hvm_get_hypercall_stubs();
595 if (!hypercall_stubs)
596 {
597 KdPrint((__DRIVER_NAME " Failed to copy hypercall stubs. Maybe not running under Xen?\n"));
598 FUNCTION_EXIT();
599 return NULL;
600 }
601 if (xen_version_major < 4)
602 {
603 FUNCTION_MSG("No support for PoD. Cannot do initial balloon down.\n");
604 FUNCTION_MSG("Expect a crash if maxmem is set much larger than memory.\n");
605 FUNCTION_EXIT();
606 return NULL;
607 }
608 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_maximum_reservation, &domid);
609 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
610 maximum_reservation = ret;
611 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_current_reservation, &domid);
612 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
613 current_reservation = ret;
615 extra_kb = (maximum_reservation - current_reservation) << 2;
617 alloc_low.QuadPart = 0;
618 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
619 alloc_skip.QuadPart = PAGE_SIZE;
621 KdPrint((__DRIVER_NAME " Trying to give %d KB (%d MB) to Xen\n", extra_kb, extra_kb >> 10));
623 /* this code is mostly duplicated from the actual balloon thread... too hard to reuse */
624 pfns = ExAllocatePoolWithTag(NonPagedPool, max(BALLOON_UNIT_PAGES, (64 << 8)) * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
625 curr_pfns_offset = 0;
626 /* this makes sure we balloon up to the next multiple of BALLOON_UNITS_KB */
627 for (j = 0; j < (int)extra_kb; j += BALLOON_UNITS_KB)
628 {
629 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
630 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
631 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024, MmCached, 0);
632 #else
633 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024);
634 #endif
635 if (!mdl || MmGetMdlByteCount(mdl) != BALLOON_UNITS_KB * 1024)
636 {
637 /* 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... */
638 KdPrint((__DRIVER_NAME " Initial Balloon Down failed\n"));
639 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000002, extra_kb, j, 0x00000000);
640 break;
641 }
642 else
643 {
644 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
645 for (i = 0; i < BALLOON_UNIT_PAGES; i++)
646 {
647 pfns[curr_pfns_offset] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
648 curr_pfns_offset++;
649 }
650 if (curr_pfns_offset == (ULONG)max(BALLOON_UNIT_PAGES, (64 << 8)) || j + BALLOON_UNITS_KB > (int)extra_kb)
651 {
652 reservation.address_bits = 0;
653 reservation.extent_order = 0;
654 reservation.domid = DOMID_SELF;
655 reservation.nr_extents = curr_pfns_offset;
656 #pragma warning(disable: 4127) /* conditional expression is constant */
657 set_xen_guest_handle(reservation.extent_start, pfns);
658 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_decrease_reservation, &reservation);
659 if (ret != curr_pfns_offset)
660 FUNCTION_MSG("only decreased %d of %d pages\n", ret, curr_pfns_offset);
661 curr_pfns_offset = 0;
662 }
663 if (head)
664 {
665 mdl->Next = head;
666 head = mdl;
667 }
668 else
669 {
670 head = mdl;
671 }
672 }
673 //KdPrint((__DRIVER_NAME " C\n"));
674 }
675 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
676 hvm_free_hypercall_stubs(hypercall_stubs);
678 FUNCTION_EXIT();
680 return head;
681 }
683 NTSTATUS
684 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
685 {
686 NTSTATUS status = STATUS_SUCCESS;
687 WDF_DRIVER_CONFIG config;
688 WDFDRIVER driver;
689 WDF_OBJECT_ATTRIBUTES parent_attributes;
690 PCONFIGURATION_INFORMATION conf_info;
691 WDFKEY control_key;
692 WDFKEY param_key;
693 ULONG always_patch = 0;
694 ULONG always_hide = 0;
695 DECLARE_CONST_UNICODE_STRING(control_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
696 DECLARE_CONST_UNICODE_STRING(system_start_options_name, L"SystemStartOptions");
697 DECLARE_CONST_UNICODE_STRING(txt_always_hide_name, L"txt_hide_qemu_always");
698 DECLARE_CONST_UNICODE_STRING(hide_devices_name, L"hide_devices");
699 DECLARE_CONST_UNICODE_STRING(txt_always_patch_name, L"txt_patch_tpr_always");
700 WDFSTRING wdf_system_start_options;
701 UNICODE_STRING system_start_options;
702 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
703 PVOID dump_page;
704 ULONG dump_header_size;
705 #endif
707 UNREFERENCED_PARAMETER(RegistryPath);
709 FUNCTION_ENTER();
711 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
713 #if DBG
714 XenPci_HookDbgPrint();
715 #endif
717 ASSERT(!balloon_mdl_head);
718 balloon_mdl_head = XenPci_InitialBalloonDown();
720 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
721 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, NULL, 0, &dump_header_size);
722 dump_page = ExAllocatePoolWithTag(NonPagedPool, dump_header_size, XENPCI_POOL_TAG);
723 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_page, dump_header_size, &dump_header_size);
724 KdPrint((__DRIVER_NAME " KeInitializeCrashDumpHeader status = %08x, size = %d\n", status, dump_header_size));
725 #endif
727 /* again after enabling DbgPrint hooking */
728 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
731 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
732 config.EvtDriverUnload = XenPci_EvtDriverUnload;
733 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
734 if (!NT_SUCCESS(status))
735 {
736 KdPrint((__DRIVER_NAME " WdfDriverCreate failed with status 0x%x\n", status));
737 FUNCTION_EXIT();
738 #if DBG
739 XenPci_UnHookDbgPrint();
740 #endif
741 return status;
742 }
743 WDF_OBJECT_ATTRIBUTES_INIT(&parent_attributes);
744 parent_attributes.ParentObject = driver;
746 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, &parent_attributes, &param_key);
747 if (!NT_SUCCESS(status))
748 {
749 KdPrint(("Error opening parameters key %08x\n", status));
750 goto error;
751 }
753 status = AuxKlibInitialize();
754 if(!NT_SUCCESS(status))
755 {
756 KdPrint((__DRIVER_NAME " AuxKlibInitialize failed %08x\n", status));
757 goto error;
758 }
760 XenPci_FixLoadOrder();
762 RtlInitUnicodeString(&system_start_options, L"failed to read");
763 status = WdfRegistryOpenKey(NULL, &control_key_name, GENERIC_READ, &parent_attributes, &control_key);
764 if (NT_SUCCESS(status))
765 {
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 KdPrint((__DRIVER_NAME " 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 {
779 DECLARE_CONST_UNICODE_STRING(verifier_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
780 WDFKEY memory_key;
781 ULONG verifier_value;
783 KdPrint((__DRIVER_NAME " PATCHTPR found\n"));
785 tpr_patch_requested = TRUE;
786 status = WdfRegistryOpenKey(NULL, &verifier_key_name, KEY_READ, &parent_attributes, &memory_key);
787 if (NT_SUCCESS(status))
788 {
789 DECLARE_CONST_UNICODE_STRING(verifier_value_name, L"VerifyDriverLevel");
790 status = WdfRegistryQueryULong(memory_key, &verifier_value_name, &verifier_value);
791 if (NT_SUCCESS(status) && verifier_value != 0)
792 {
793 KdPrint((__DRIVER_NAME " Verifier active - not patching\n"));
794 tpr_patch_requested = FALSE;
795 }
796 WdfRegistryClose(memory_key);
797 }
798 }
800 WdfCollectionCreate(&parent_attributes, &qemu_hide_devices);
801 WdfRegistryQueryULong(param_key, &txt_always_hide_name, &always_hide);
802 conf_info = IoGetConfigurationInformation();
803 if (always_hide || ((conf_info == NULL || conf_info->DiskCount == 0)
804 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOGPLPV"))
805 && !*InitSafeBootMode))
806 {
807 if (!(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"GPLPVUSEFILTERHIDE")) && XenPci_CheckHideQemuDevices())
808 {
809 DECLARE_CONST_UNICODE_STRING(qemu_hide_flags_name, L"qemu_hide_flags");
810 DECLARE_CONST_UNICODE_STRING(txt_qemu_hide_flags_name, L"txt_qemu_hide_flags");
811 WDFCOLLECTION qemu_hide_flags;
812 ULONG i;
814 WdfCollectionCreate(&parent_attributes, &qemu_hide_flags);
815 WdfRegistryQueryMultiString(param_key, &qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
816 WdfRegistryQueryMultiString(param_key, &txt_qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
817 for (i = 0; i < WdfCollectionGetCount(qemu_hide_flags); i++)
818 {
819 ULONG value;
820 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_flags, i);
821 UNICODE_STRING unicode_string;
822 WdfStringGetUnicodeString(wdf_string, &unicode_string);
823 status = RtlUnicodeStringToInteger(&unicode_string, 0, &value);
824 qemu_hide_flags_value |= value;
825 }
826 WdfObjectDelete(qemu_hide_flags);
827 XenPci_HideQemuDevices();
828 }
829 else
830 {
831 WdfRegistryQueryMultiString(param_key, &hide_devices_name, &parent_attributes, qemu_hide_devices);
832 }
833 }
834 WdfRegistryClose(param_key);
835 FUNCTION_EXIT();
836 return STATUS_SUCCESS;
838 error:
839 #if DBG
840 XenPci_UnHookDbgPrint();
841 #endif
842 KdPrint(("Failed, returning %08x\n", status));
843 FUNCTION_EXIT();
844 return status;
845 }