win-pvdrivers

view xenpci/xenpci.c @ 1005:4f7d5a8636bd

xenvbd rewrite. combined scsiport and storport code where possible.
author James Harper <james.harper@bendigoit.com.au>
date Sat Feb 02 18:51:07 2013 +1100 (2013-02-02)
parents 58899e6ed48f
children 9fb8690938b3
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 KeInitializeGuardedMutex(&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 {
335 device_description = WdfMemoryGetBuffer(memory, NULL);
336 }
337 else
338 {
339 device_description = L"<unknown device>";
340 }
342 for (i = 0; i < WdfCollectionGetCount(qemu_hide_devices); i++)
343 {
344 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_devices, i);
345 UNICODE_STRING unicode_string;
346 WdfStringGetUnicodeString(wdf_string, &unicode_string);
347 if (XenPci_IdSuffixMatches(device_init, unicode_string.Buffer))
348 {
349 hide_required = TRUE;
350 break;
351 }
352 }
353 if (!hide_required)
354 {
355 WdfObjectDelete(memory);
356 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (filter not required for %S)\n", device_description));
357 return STATUS_SUCCESS;
358 }
360 KdPrint((__DRIVER_NAME " Installing Filter for %S\n", device_description));
362 WdfFdoInitSetFilter(device_init);
363 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
364 WdfDeviceInitSetExclusive(device_init, FALSE);
366 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
367 pnp_power_callbacks.EvtDevicePrepareHardware = XenHide_EvtDevicePrepareHardware;
368 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
370 WDF_OBJECT_ATTRIBUTES_INIT(&device_attributes);
371 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
372 if (!NT_SUCCESS(status))
373 {
374 KdPrint(("Error creating device %08x\n", status));
375 WdfObjectDelete(memory);
376 FUNCTION_EXIT();
377 return status;
378 }
380 WdfObjectDelete(memory);
381 FUNCTION_EXIT();
383 return status;
384 }
386 static NTSTATUS
387 XenPci_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
388 {
389 if (XenPci_IdSuffixMatches(device_init, L"VEN_5853&DEV_0001"))
390 {
391 KdPrint((__DRIVER_NAME " Xen PCI device found - must be fdo\n"));
392 return XenPci_EvtDeviceAdd_XenPci(driver, device_init);
393 }
394 else if (WdfCollectionGetCount(qemu_hide_devices) > 0)
395 {
396 KdPrint((__DRIVER_NAME " Xen PCI device not found - must be filter\n"));
397 return XenPci_EvtDeviceAdd_XenHide(driver, device_init);
398 }
399 else
400 return STATUS_SUCCESS;
401 }
403 ULONG qemu_protocol_version;
404 ULONG tpr_patch_requested;
405 extern PULONG InitSafeBootMode;
407 VOID
408 XenPci_HideQemuDevices()
409 {
410 #pragma warning(suppress:28138)
411 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, (USHORT)qemu_hide_flags_value); //QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
412 KdPrint((__DRIVER_NAME " Disabled qemu devices %02x\n", qemu_hide_flags_value));
413 }
415 static BOOLEAN
416 XenPci_CheckHideQemuDevices()
417 {
418 #pragma warning(suppress:28138)
419 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2)
420 {
421 #pragma warning(suppress:28138)
422 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
423 KdPrint((__DRIVER_NAME " Version = %d\n", qemu_protocol_version));
424 switch(qemu_protocol_version)
425 {
426 case 1:
427 #pragma warning(suppress:28138)
428 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
429 #pragma warning(suppress:28138)
430 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
431 #pragma warning(suppress:28138)
432 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
433 {
434 KdPrint((__DRIVER_NAME " Blacklisted\n"));
435 break;
436 }
437 /* fall through */
438 case 0:
439 return TRUE;
440 default:
441 KdPrint((__DRIVER_NAME " Unknown qemu version %d\n", qemu_protocol_version));
442 break;
443 }
444 }
445 return FALSE;
446 }
448 /*
449 make sure the load order is System Reserved, Dummy Group, WdfLoadGroup, XenPCI, Boot Bus Extender
450 */
452 static VOID
453 XenPci_FixLoadOrder()
454 {
455 NTSTATUS status;
456 WDFCOLLECTION old_load_order, new_load_order;
457 DECLARE_CONST_UNICODE_STRING(sgo_name, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder");
458 DECLARE_CONST_UNICODE_STRING(list_name, L"List");
459 WDFKEY sgo_key;
460 ULONG i;
461 LONG dummy_group_index = -1;
462 LONG boot_bus_extender_index = -1;
463 LONG xenpci_group_index = -1;
464 LONG wdf_load_group_index = -1;
465 DECLARE_CONST_UNICODE_STRING(dummy_group_name, L"Dummy Group");
466 DECLARE_CONST_UNICODE_STRING(wdf_load_group_name, L"WdfLoadGroup");
467 DECLARE_CONST_UNICODE_STRING(xenpci_group_name, L"XenPCI Group");
468 DECLARE_CONST_UNICODE_STRING(boot_bus_extender_name, L"Boot Bus Extender");
470 FUNCTION_ENTER();
472 status = WdfRegistryOpenKey(NULL, &sgo_name, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &sgo_key);
473 if (!NT_SUCCESS(status))
474 {
475 KdPrint((__DRIVER_NAME " Error opening ServiceGroupOrder key %08x\n", status));
476 return;
477 }
478 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &old_load_order);
479 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &new_load_order);
480 status = WdfRegistryQueryMultiString(sgo_key, &list_name, WDF_NO_OBJECT_ATTRIBUTES, old_load_order);
481 if (!NT_SUCCESS(status))
482 {
483 KdPrint((__DRIVER_NAME " Error reading ServiceGroupOrder\\List value %08x\n", status));
484 WdfObjectDelete(new_load_order);
485 WdfObjectDelete(old_load_order);
486 return;
487 }
488 //KdPrint((__DRIVER_NAME " Current Order:\n"));
489 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
490 {
491 WDFOBJECT ws = WdfCollectionGetItem(old_load_order, i);
492 UNICODE_STRING val;
493 WdfStringGetUnicodeString(ws, &val);
494 if (!RtlCompareUnicodeString(&val, &dummy_group_name, TRUE))
495 dummy_group_index = (ULONG)i;
496 if (!RtlCompareUnicodeString(&val, &wdf_load_group_name, TRUE))
497 wdf_load_group_index = (ULONG)i;
498 if (!RtlCompareUnicodeString(&val, &xenpci_group_name, TRUE))
499 xenpci_group_index = (ULONG)i;
500 if (!RtlCompareUnicodeString(&val, &boot_bus_extender_name, TRUE))
501 boot_bus_extender_index = (ULONG)i;
502 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
503 }
504 KdPrint((__DRIVER_NAME " dummy_group_index = %d\n", dummy_group_index));
505 KdPrint((__DRIVER_NAME " wdf_load_group_index = %d\n", wdf_load_group_index));
506 KdPrint((__DRIVER_NAME " xenpci_group_index = %d\n", xenpci_group_index));
507 KdPrint((__DRIVER_NAME " boot_bus_extender_index = %d\n", boot_bus_extender_index));
508 if (boot_bus_extender_index == -1)
509 {
510 WdfObjectDelete(new_load_order);
511 WdfObjectDelete(old_load_order);
512 WdfRegistryClose(sgo_key);
513 return; /* something is very wrong */
514 }
515 if (dummy_group_index == 1 && wdf_load_group_index != -1 &&
516 (dummy_group_index < wdf_load_group_index
517 && wdf_load_group_index < xenpci_group_index
518 && xenpci_group_index < boot_bus_extender_index))
519 {
520 FUNCTION_EXIT();
521 return; /* our work here is done */
522 }
523 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
524 {
525 WDFOBJECT ws;
526 if (i == 1)
527 {
528 WDFSTRING tmp_wdf_string;
529 WdfStringCreate(&dummy_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
530 WdfCollectionAdd(new_load_order, tmp_wdf_string);
531 WdfObjectDelete(tmp_wdf_string);
532 }
533 if (i == 1)
534 {
535 WDFSTRING tmp_wdf_string;
536 WdfStringCreate(&wdf_load_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
537 WdfCollectionAdd(new_load_order, tmp_wdf_string);
538 WdfObjectDelete(tmp_wdf_string);
539 }
540 if (i == 1)
541 {
542 WDFSTRING tmp_wdf_string;
543 WdfStringCreate(&xenpci_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
544 WdfCollectionAdd(new_load_order, tmp_wdf_string);
545 WdfObjectDelete(tmp_wdf_string);
546 }
547 if (i == (ULONG)dummy_group_index || i == (ULONG)wdf_load_group_index || i == (ULONG)xenpci_group_index)
548 continue;
549 ws = WdfCollectionGetItem(old_load_order, i);
550 WdfCollectionAdd(new_load_order, ws);
551 }
552 WdfRegistryAssignMultiString(sgo_key, &list_name, new_load_order);
553 //KdPrint((__DRIVER_NAME " New Order:\n"));
554 for (i = 0; i < WdfCollectionGetCount(new_load_order); i++)
555 {
556 WDFOBJECT ws = WdfCollectionGetItem(new_load_order, i);
557 UNICODE_STRING val;
558 WdfStringGetUnicodeString(ws, &val);
559 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
560 }
561 WdfObjectDelete(new_load_order);
562 WdfObjectDelete(old_load_order);
563 WdfRegistryClose(sgo_key);
565 FUNCTION_EXIT();
567 return;
568 }
570 VOID
571 XenPci_EvtDriverUnload(WDFDRIVER driver)
572 {
573 UNREFERENCED_PARAMETER(driver);
575 #if DBG
576 XenPci_UnHookDbgPrint();
577 #endif
578 }
580 /* we need to balloon down very early on in the case of PoD, so things get a little messy */
581 static PMDL
582 XenPci_InitialBalloonDown()
583 {
584 PVOID hypercall_stubs;
585 domid_t domid = DOMID_SELF;
586 ULONG maximum_reservation;
587 ULONG current_reservation;
588 ULONG extra_kb;
589 ULONG ret;
590 struct xen_memory_reservation reservation;
591 xen_pfn_t *pfns;
592 PMDL head = NULL;
593 PMDL mdl;
594 int i, j;
595 ULONG curr_pfns_offset;
596 PHYSICAL_ADDRESS alloc_low;
597 PHYSICAL_ADDRESS alloc_high;
598 PHYSICAL_ADDRESS alloc_skip;
600 FUNCTION_ENTER();
602 hypercall_stubs = hvm_get_hypercall_stubs();
603 if (!hypercall_stubs)
604 {
605 KdPrint((__DRIVER_NAME " Failed to copy hypercall stubs. Maybe not running under Xen?\n"));
606 FUNCTION_EXIT();
607 return NULL;
608 }
609 if (xen_version_major < 4)
610 {
611 FUNCTION_MSG("No support for PoD. Cannot do initial balloon down.\n");
612 FUNCTION_MSG("Expect a crash if maxmem is set much larger than memory.\n");
613 FUNCTION_EXIT();
614 return NULL;
615 }
616 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_maximum_reservation, &domid);
617 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
618 maximum_reservation = ret;
619 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_current_reservation, &domid);
620 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
621 current_reservation = ret;
623 extra_kb = (maximum_reservation - current_reservation) << 2;
625 alloc_low.QuadPart = 0;
626 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
627 alloc_skip.QuadPart = PAGE_SIZE;
629 KdPrint((__DRIVER_NAME " Trying to give %d KB (%d MB) to Xen\n", extra_kb, extra_kb >> 10));
631 /* this code is mostly duplicated from the actual balloon thread... too hard to reuse */
632 pfns = ExAllocatePoolWithTag(NonPagedPool, max(BALLOON_UNIT_PAGES, (64 << 8)) * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
633 if (!pfns) {
634 /* If we can't balloon down then we are going to crash in strange ways later. Better to bug check now. */
635 KdPrint((__DRIVER_NAME " Initial Balloon Down failed - no memory for pfn list\n"));
636 #pragma warning(suppress:28159)
637 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000003, 0x00000000, 0x00000000, 0x00000000);
638 }
639 curr_pfns_offset = 0;
640 /* this makes sure we balloon up to the next multiple of BALLOON_UNITS_KB */
641 for (j = 0; j < (int)extra_kb; j += BALLOON_UNITS_KB)
642 {
643 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
644 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
645 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024, MmCached, 0);
646 #else
647 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024);
648 #endif
649 if (!mdl || MmGetMdlByteCount(mdl) != BALLOON_UNITS_KB * 1024)
650 {
651 /* 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... */
652 KdPrint((__DRIVER_NAME " Initial Balloon Down failed\n"));
653 #pragma warning(suppress:28159)
654 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000002, extra_kb, j, 0x00000000);
655 }
656 else
657 {
658 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
659 for (i = 0; i < BALLOON_UNIT_PAGES; i++)
660 {
661 pfns[curr_pfns_offset] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
662 curr_pfns_offset++;
663 }
664 if (curr_pfns_offset == (ULONG)max(BALLOON_UNIT_PAGES, (64 << 8)) || j + BALLOON_UNITS_KB > (int)extra_kb)
665 {
666 reservation.address_bits = 0;
667 reservation.extent_order = 0;
668 reservation.domid = DOMID_SELF;
669 reservation.nr_extents = curr_pfns_offset;
670 #pragma warning(disable: 4127) /* conditional expression is constant */
671 set_xen_guest_handle(reservation.extent_start, pfns);
672 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_decrease_reservation, &reservation);
673 if (ret != curr_pfns_offset)
674 FUNCTION_MSG("only decreased %d of %d pages\n", ret, curr_pfns_offset);
675 curr_pfns_offset = 0;
676 }
677 if (head)
678 {
679 mdl->Next = head;
680 head = mdl;
681 }
682 else
683 {
684 head = mdl;
685 }
686 }
687 //KdPrint((__DRIVER_NAME " C\n"));
688 }
689 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
690 hvm_free_hypercall_stubs(hypercall_stubs);
692 FUNCTION_EXIT();
694 return head;
695 }
697 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
698 /* this isn't freed on shutdown... perhaps it should be */
699 static PUCHAR dump_header;
700 static ULONG dump_header_size;
701 static ULONG dump_header_refreshed_flag = FALSE;
702 static KBUGCHECK_REASON_CALLBACK_RECORD callback_record;
703 #define DUMP_HEADER_PREFIX_SIZE 8
704 #define DUMP_HEADER_SUFFIX_SIZE 8
706 /* call KeInitializeCrashDumpHeader once on crash */
707 static VOID
708 XenPci_DebugHeaderDumpIoCallback(
709 KBUGCHECK_CALLBACK_REASON reason,
710 PKBUGCHECK_REASON_CALLBACK_RECORD record,
711 PVOID reason_specific_data,
712 ULONG reason_specific_data_length) {
713 UNREFERENCED_PARAMETER(reason);
714 UNREFERENCED_PARAMETER(record);
715 UNREFERENCED_PARAMETER(reason_specific_data);
716 UNREFERENCED_PARAMETER(reason_specific_data_length);
717 if (!dump_header_refreshed_flag) {
718 NTSTATUS status;
719 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
720 /* copy bug check code in? */
721 dump_header_refreshed_flag = TRUE;
722 }
723 }
724 #endif
726 NTSTATUS
727 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
728 {
729 NTSTATUS status = STATUS_SUCCESS;
730 WDF_DRIVER_CONFIG config;
731 WDFDRIVER driver;
732 WDF_OBJECT_ATTRIBUTES parent_attributes;
733 PCONFIGURATION_INFORMATION conf_info;
734 WDFKEY control_key;
735 WDFKEY param_key;
736 ULONG always_patch = 0;
737 ULONG always_hide = 0;
738 DECLARE_CONST_UNICODE_STRING(control_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
739 DECLARE_CONST_UNICODE_STRING(system_start_options_name, L"SystemStartOptions");
740 DECLARE_CONST_UNICODE_STRING(txt_always_hide_name, L"txt_hide_qemu_always");
741 DECLARE_CONST_UNICODE_STRING(hide_devices_name, L"hide_devices");
742 DECLARE_CONST_UNICODE_STRING(txt_always_patch_name, L"txt_patch_tpr_always");
743 WDFSTRING wdf_system_start_options;
744 UNICODE_STRING system_start_options;
745 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
746 PHYSICAL_ADDRESS dump_header_mem_max;
747 #endif
749 UNREFERENCED_PARAMETER(RegistryPath);
751 FUNCTION_ENTER();
753 FUNCTION_MSG(__DRIVER_NAME " " VER_FILEVERSION_STR "\n");
755 #if DBG
756 XenPci_HookDbgPrint();
757 #endif
759 NT_ASSERT(!balloon_mdl_head);
760 balloon_mdl_head = XenPci_InitialBalloonDown();
762 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
763 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, NULL, 0, &dump_header_size);
764 /* try and allocate contiguous memory as low as possible */
765 dump_header = NULL;
766 dump_header_mem_max.QuadPart = 0xFFFFF;
767 while (!dump_header && dump_header_mem_max.QuadPart != 0xFFFFFFFFFFFFFFFF) {
768 dump_header = MmAllocateContiguousMemory(DUMP_HEADER_PREFIX_SIZE + dump_header_size + DUMP_HEADER_SUFFIX_SIZE, dump_header_mem_max);
769 dump_header_mem_max.QuadPart = (dump_header_mem_max.QuadPart << 8) | 0xF;
770 }
771 if (dump_header) {
772 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
773 FUNCTION_MSG("KeInitializeCrashDumpHeader status = %08x, size = %d\n", status, dump_header_size);
774 memcpy(dump_header + 0, "XENXEN", 6); /* magic number */
775 *(PUSHORT)(dump_header + 6) = (USHORT)(INT_PTR)dump_header & (PAGE_SIZE - 1); /* store offset too as additional verification */
776 memcpy(dump_header + DUMP_HEADER_PREFIX_SIZE + dump_header_size, "XENXEN", 6);
777 *(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 */
778 KeInitializeCallbackRecord(&callback_record);
779 KeRegisterBugCheckReasonCallback(&callback_record, XenPci_DebugHeaderDumpIoCallback, KbCallbackDumpIo, (PUCHAR)"XenPci_DebugHeaderDumpIoCallback");
780 } else {
781 FUNCTION_MSG("Failed to allocate memory for crash dump header\n");
782 }
783 #endif
785 /* again after enabling DbgPrint hooking */
786 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
789 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
790 config.EvtDriverUnload = XenPci_EvtDriverUnload;
791 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
792 if (!NT_SUCCESS(status))
793 {
794 KdPrint((__DRIVER_NAME " WdfDriverCreate failed with status 0x%x\n", status));
795 FUNCTION_EXIT();
796 #if DBG
797 XenPci_UnHookDbgPrint();
798 #endif
799 return status;
800 }
801 WDF_OBJECT_ATTRIBUTES_INIT(&parent_attributes);
802 parent_attributes.ParentObject = driver;
804 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, &parent_attributes, &param_key);
805 if (!NT_SUCCESS(status))
806 {
807 KdPrint(("Error opening parameters key %08x\n", status));
808 goto error;
809 }
811 status = AuxKlibInitialize();
812 if(!NT_SUCCESS(status))
813 {
814 KdPrint((__DRIVER_NAME " AuxKlibInitialize failed %08x\n", status));
815 goto error;
816 }
818 XenPci_FixLoadOrder();
820 RtlInitUnicodeString(&system_start_options, L"failed to read");
821 status = WdfRegistryOpenKey(NULL, &control_key_name, GENERIC_READ, &parent_attributes, &control_key);
822 if (NT_SUCCESS(status))
823 {
824 status = WdfStringCreate(NULL, &parent_attributes, &wdf_system_start_options);
825 status = WdfRegistryQueryString(control_key, &system_start_options_name, wdf_system_start_options);
826 if (NT_SUCCESS(status))
827 WdfStringGetUnicodeString(wdf_system_start_options, &system_start_options);
828 }
829 WdfRegistryClose(control_key);
831 KdPrint((__DRIVER_NAME " SystemStartOptions = %wZ\n", &system_start_options));
833 always_patch = 0;
834 WdfRegistryQueryULong(param_key, &txt_always_patch_name, &always_patch);
835 if (always_patch || (system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"PATCHTPR")))
836 {
837 DECLARE_CONST_UNICODE_STRING(verifier_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
838 WDFKEY memory_key;
839 ULONG verifier_value;
841 KdPrint((__DRIVER_NAME " PATCHTPR found\n"));
843 tpr_patch_requested = TRUE;
844 status = WdfRegistryOpenKey(NULL, &verifier_key_name, KEY_READ, &parent_attributes, &memory_key);
845 if (NT_SUCCESS(status))
846 {
847 DECLARE_CONST_UNICODE_STRING(verifier_value_name, L"VerifyDriverLevel");
848 status = WdfRegistryQueryULong(memory_key, &verifier_value_name, &verifier_value);
849 if (NT_SUCCESS(status) && verifier_value != 0)
850 {
851 KdPrint((__DRIVER_NAME " Verifier active - not patching\n"));
852 tpr_patch_requested = FALSE;
853 }
854 WdfRegistryClose(memory_key);
855 }
856 }
858 WdfCollectionCreate(&parent_attributes, &qemu_hide_devices);
859 WdfRegistryQueryULong(param_key, &txt_always_hide_name, &always_hide);
860 conf_info = IoGetConfigurationInformation();
861 if (always_hide || ((conf_info == NULL || conf_info->DiskCount == 0)
862 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOGPLPV"))
863 && !*InitSafeBootMode))
864 {
865 if (!(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"GPLPVUSEFILTERHIDE")) && XenPci_CheckHideQemuDevices())
866 {
867 DECLARE_CONST_UNICODE_STRING(qemu_hide_flags_name, L"qemu_hide_flags");
868 DECLARE_CONST_UNICODE_STRING(txt_qemu_hide_flags_name, L"txt_qemu_hide_flags");
869 WDFCOLLECTION qemu_hide_flags;
870 ULONG i;
872 WdfCollectionCreate(&parent_attributes, &qemu_hide_flags);
873 WdfRegistryQueryMultiString(param_key, &qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
874 WdfRegistryQueryMultiString(param_key, &txt_qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
875 for (i = 0; i < WdfCollectionGetCount(qemu_hide_flags); i++)
876 {
877 ULONG value;
878 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_flags, i);
879 UNICODE_STRING unicode_string;
880 WdfStringGetUnicodeString(wdf_string, &unicode_string);
881 status = RtlUnicodeStringToInteger(&unicode_string, 0, &value);
882 qemu_hide_flags_value |= value;
883 }
884 WdfObjectDelete(qemu_hide_flags);
885 XenPci_HideQemuDevices();
886 }
887 else
888 {
889 WdfRegistryQueryMultiString(param_key, &hide_devices_name, &parent_attributes, qemu_hide_devices);
890 }
891 }
892 WdfRegistryClose(param_key);
893 FUNCTION_EXIT();
894 return STATUS_SUCCESS;
896 error:
897 #if DBG
898 XenPci_UnHookDbgPrint();
899 #endif
900 KdPrint(("Failed, returning %08x\n", status));
901 FUNCTION_EXIT();
902 return status;
903 }