win-pvdrivers

view xenpci/xenpci.c @ 1001:c21dd04d3ae6

Less noise for xennet6
author James Harper <james.harper@bendigoit.com.au>
date Fri Dec 14 21:26:22 2012 +1100 (2012-12-14)
parents 58899e6ed48f
children 4f7d5a8636bd
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 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &veto_devices);
152 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &param_key);
153 if (NT_SUCCESS(status))
154 {
155 status = WdfRegistryQueryMultiString(param_key, &veto_devices_name, WDF_NO_OBJECT_ATTRIBUTES, veto_devices);
156 if (!NT_SUCCESS(status))
157 {
158 KdPrint(("Error reading parameters/veto_devices value %08x\n", status));
159 }
160 WdfRegistryClose(param_key);
161 }
162 else
163 {
164 KdPrint(("Error opening parameters key %08x\n", status));
165 }
167 InitializeListHead(&xpdd->veto_list);
168 for (i = 0; i < (int)WdfCollectionGetCount(veto_devices); i++)
169 {
170 WDFOBJECT ws;
171 UNICODE_STRING val;
172 ANSI_STRING s;
173 PVOID entry;
174 ws = WdfCollectionGetItem(veto_devices, i);
175 WdfStringGetUnicodeString(ws, &val);
176 RtlUnicodeStringToAnsiString(&s, &val, TRUE);
177 entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY) + s.Length + 1, XENPCI_POOL_TAG);
178 memcpy((PUCHAR)entry + sizeof(LIST_ENTRY), s.Buffer, s.Length + 1);
179 RtlFreeAnsiString(&s);
180 InsertTailList(&xpdd->veto_list, (PLIST_ENTRY)entry);
181 }
182 WDF_DEVICE_POWER_CAPABILITIES_INIT(&power_capabilities);
183 power_capabilities.DeviceD1 = WdfTrue;
184 power_capabilities.WakeFromD1 = WdfTrue;
185 power_capabilities.DeviceWake = PowerDeviceD1;
186 power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
187 power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
188 power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
189 power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
190 power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
191 power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
192 WdfDeviceSetPowerCapabilities(device, &power_capabilities);
194 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
195 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
196 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
198 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchParallel);
199 queue_config.EvtIoDefault = XenPci_EvtIoDefault;
200 status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->io_queue);
201 if (!NT_SUCCESS(status)) {
202 KdPrint(("Error creating queue 0x%x\n", status));
203 return status;
204 }
206 WDF_INTERRUPT_CONFIG_INIT(&interrupt_config, EvtChn_EvtInterruptIsr, NULL);
207 interrupt_config.EvtInterruptEnable = EvtChn_EvtInterruptEnable;
208 interrupt_config.EvtInterruptDisable = EvtChn_EvtInterruptDisable;
210 status = WdfInterruptCreate(device, &interrupt_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->interrupt);
211 if (!NT_SUCCESS(status))
212 {
213 KdPrint(("Error creating interrupt 0x%x\n", status));
214 return status;
215 }
217 RtlInitUnicodeString(&reference, L"xenbus");
218 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_XENBUS, &reference);
219 if (!NT_SUCCESS(status)) {
220 KdPrint(("Error registering device interface 0x%x\n", status));
221 return status;
222 }
224 RtlInitUnicodeString(&reference, L"evtchn");
225 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_EVTCHN, &reference);
226 if (!NT_SUCCESS(status)) {
227 KdPrint(("Error registering device interface 0x%x\n", status));
228 return status;
229 }
231 RtlInitUnicodeString(&reference, L"gntdev");
232 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_GNTDEV, &reference);
233 if (!NT_SUCCESS(status)) {
234 KdPrint(("Error registering device interface 0x%x\n", status));
235 return status;
236 }
238 pbi.BusTypeGuid = GUID_BUS_TYPE_XEN;
239 pbi.LegacyBusType = PNPBus;
240 pbi.BusNumber = 0;
241 WdfDeviceSetBusInformationForChildren(device, &pbi);
243 xpdd->removable = TRUE;
245 FUNCTION_EXIT();
246 return status;
247 }
249 NTSTATUS
250 XenHide_EvtDevicePrepareHardware(WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
251 {
252 UNREFERENCED_PARAMETER(device);
253 UNREFERENCED_PARAMETER(resources_raw);
254 UNREFERENCED_PARAMETER(resources_translated);
255 FUNCTION_ENTER();
256 FUNCTION_EXIT();
257 return STATUS_UNSUCCESSFUL;
258 }
260 static BOOLEAN
261 XenPci_IdSuffixMatches(PWDFDEVICE_INIT device_init, PWCHAR matching_id)
262 {
263 NTSTATUS status;
264 WDFMEMORY memory;
265 ULONG remaining;
266 size_t string_length;
267 PWCHAR ids;
268 PWCHAR ptr;
269 size_t ids_length;
270 ULONG properties[] = {DevicePropertyCompatibleIDs, DevicePropertyHardwareID};
271 int i;
273 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
274 for (i = 0; i < ARRAY_SIZE(properties); i++)
275 {
277 status = WdfFdoInitAllocAndQueryProperty(device_init, properties[i], NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
278 if (!NT_SUCCESS(status))
279 continue;
280 ids = WdfMemoryGetBuffer(memory, &ids_length);
282 if (!NT_SUCCESS(status))
283 {
284 // KdPrint((__DRIVER_NAME " i = %d, status = %x, ids_length = %d\n", i, status, ids_length));
285 continue;
286 }
288 remaining = (ULONG)ids_length / 2;
289 for (ptr = ids; *ptr != 0; ptr += string_length + 1)
290 {
291 RtlStringCchLengthW(ptr, remaining, &string_length);
292 remaining -= (ULONG)string_length + 1;
293 if (string_length >= wcslen(matching_id))
294 {
295 ptr += string_length - wcslen(matching_id);
296 string_length = wcslen(matching_id);
297 }
298 // KdPrint((__DRIVER_NAME " Comparing '%S' and '%S'\n", ptr, matching_id));
299 if (wcscmp(ptr, matching_id) == 0)
300 {
301 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (Match)\n"));
302 WdfObjectDelete(memory);
303 return TRUE;
304 }
305 }
306 WdfObjectDelete(memory);
307 }
308 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (No match)\n"));
309 return FALSE;
310 }
312 WDFCOLLECTION qemu_hide_devices;
313 USHORT qemu_hide_flags_value;
315 static NTSTATUS
316 XenPci_EvtDeviceAdd_XenHide(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
317 {
318 NTSTATUS status;
319 WDFMEMORY memory;
320 PWCHAR device_description;
321 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
322 WDF_OBJECT_ATTRIBUTES device_attributes;
323 BOOLEAN hide_required = FALSE;
324 WDFDEVICE device;
325 ULONG i;
327 UNREFERENCED_PARAMETER(driver);
329 FUNCTION_ENTER();
331 status = WdfFdoInitAllocAndQueryProperty(device_init, DevicePropertyDeviceDescription, NonPagedPool, WDF_NO_OBJECT_ATTRIBUTES, &memory);
332 if (NT_SUCCESS(status))
333 {
334 device_description = WdfMemoryGetBuffer(memory, NULL);
335 }
336 else
337 {
338 device_description = L"<unknown device>";
339 }
341 for (i = 0; i < WdfCollectionGetCount(qemu_hide_devices); i++)
342 {
343 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_devices, i);
344 UNICODE_STRING unicode_string;
345 WdfStringGetUnicodeString(wdf_string, &unicode_string);
346 if (XenPci_IdSuffixMatches(device_init, unicode_string.Buffer))
347 {
348 hide_required = TRUE;
349 break;
350 }
351 }
352 if (!hide_required)
353 {
354 WdfObjectDelete(memory);
355 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (filter not required for %S)\n", device_description));
356 return STATUS_SUCCESS;
357 }
359 KdPrint((__DRIVER_NAME " Installing Filter for %S\n", device_description));
361 WdfFdoInitSetFilter(device_init);
362 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
363 WdfDeviceInitSetExclusive(device_init, FALSE);
365 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
366 pnp_power_callbacks.EvtDevicePrepareHardware = XenHide_EvtDevicePrepareHardware;
367 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
369 WDF_OBJECT_ATTRIBUTES_INIT(&device_attributes);
370 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
371 if (!NT_SUCCESS(status))
372 {
373 KdPrint(("Error creating device %08x\n", status));
374 WdfObjectDelete(memory);
375 FUNCTION_EXIT();
376 return status;
377 }
379 WdfObjectDelete(memory);
380 FUNCTION_EXIT();
382 return status;
383 }
385 static NTSTATUS
386 XenPci_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
387 {
388 if (XenPci_IdSuffixMatches(device_init, L"VEN_5853&DEV_0001"))
389 {
390 KdPrint((__DRIVER_NAME " Xen PCI device found - must be fdo\n"));
391 return XenPci_EvtDeviceAdd_XenPci(driver, device_init);
392 }
393 else if (WdfCollectionGetCount(qemu_hide_devices) > 0)
394 {
395 KdPrint((__DRIVER_NAME " Xen PCI device not found - must be filter\n"));
396 return XenPci_EvtDeviceAdd_XenHide(driver, device_init);
397 }
398 else
399 return STATUS_SUCCESS;
400 }
402 ULONG qemu_protocol_version;
403 ULONG tpr_patch_requested;
404 extern PULONG InitSafeBootMode;
406 VOID
407 XenPci_HideQemuDevices()
408 {
409 #pragma warning(suppress:28138)
410 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, (USHORT)qemu_hide_flags_value); //QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
411 KdPrint((__DRIVER_NAME " Disabled qemu devices %02x\n", qemu_hide_flags_value));
412 }
414 static BOOLEAN
415 XenPci_CheckHideQemuDevices()
416 {
417 #pragma warning(suppress:28138)
418 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2)
419 {
420 #pragma warning(suppress:28138)
421 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
422 KdPrint((__DRIVER_NAME " Version = %d\n", qemu_protocol_version));
423 switch(qemu_protocol_version)
424 {
425 case 1:
426 #pragma warning(suppress:28138)
427 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
428 #pragma warning(suppress:28138)
429 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
430 #pragma warning(suppress:28138)
431 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
432 {
433 KdPrint((__DRIVER_NAME " Blacklisted\n"));
434 break;
435 }
436 /* fall through */
437 case 0:
438 return TRUE;
439 default:
440 KdPrint((__DRIVER_NAME " Unknown qemu version %d\n", qemu_protocol_version));
441 break;
442 }
443 }
444 return FALSE;
445 }
447 /*
448 make sure the load order is System Reserved, Dummy Group, WdfLoadGroup, XenPCI, Boot Bus Extender
449 */
451 static VOID
452 XenPci_FixLoadOrder()
453 {
454 NTSTATUS status;
455 WDFCOLLECTION old_load_order, new_load_order;
456 DECLARE_CONST_UNICODE_STRING(sgo_name, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder");
457 DECLARE_CONST_UNICODE_STRING(list_name, L"List");
458 WDFKEY sgo_key;
459 ULONG i;
460 LONG dummy_group_index = -1;
461 LONG boot_bus_extender_index = -1;
462 LONG xenpci_group_index = -1;
463 LONG wdf_load_group_index = -1;
464 DECLARE_CONST_UNICODE_STRING(dummy_group_name, L"Dummy Group");
465 DECLARE_CONST_UNICODE_STRING(wdf_load_group_name, L"WdfLoadGroup");
466 DECLARE_CONST_UNICODE_STRING(xenpci_group_name, L"XenPCI Group");
467 DECLARE_CONST_UNICODE_STRING(boot_bus_extender_name, L"Boot Bus Extender");
469 FUNCTION_ENTER();
471 status = WdfRegistryOpenKey(NULL, &sgo_name, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &sgo_key);
472 if (!NT_SUCCESS(status))
473 {
474 KdPrint((__DRIVER_NAME " Error opening ServiceGroupOrder key %08x\n", status));
475 return;
476 }
477 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &old_load_order);
478 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &new_load_order);
479 status = WdfRegistryQueryMultiString(sgo_key, &list_name, WDF_NO_OBJECT_ATTRIBUTES, old_load_order);
480 if (!NT_SUCCESS(status))
481 {
482 KdPrint((__DRIVER_NAME " Error reading ServiceGroupOrder\\List value %08x\n", status));
483 WdfObjectDelete(new_load_order);
484 WdfObjectDelete(old_load_order);
485 return;
486 }
487 //KdPrint((__DRIVER_NAME " Current Order:\n"));
488 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
489 {
490 WDFOBJECT ws = WdfCollectionGetItem(old_load_order, i);
491 UNICODE_STRING val;
492 WdfStringGetUnicodeString(ws, &val);
493 if (!RtlCompareUnicodeString(&val, &dummy_group_name, TRUE))
494 dummy_group_index = (ULONG)i;
495 if (!RtlCompareUnicodeString(&val, &wdf_load_group_name, TRUE))
496 wdf_load_group_index = (ULONG)i;
497 if (!RtlCompareUnicodeString(&val, &xenpci_group_name, TRUE))
498 xenpci_group_index = (ULONG)i;
499 if (!RtlCompareUnicodeString(&val, &boot_bus_extender_name, TRUE))
500 boot_bus_extender_index = (ULONG)i;
501 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
502 }
503 KdPrint((__DRIVER_NAME " dummy_group_index = %d\n", dummy_group_index));
504 KdPrint((__DRIVER_NAME " wdf_load_group_index = %d\n", wdf_load_group_index));
505 KdPrint((__DRIVER_NAME " xenpci_group_index = %d\n", xenpci_group_index));
506 KdPrint((__DRIVER_NAME " boot_bus_extender_index = %d\n", boot_bus_extender_index));
507 if (boot_bus_extender_index == -1)
508 {
509 WdfObjectDelete(new_load_order);
510 WdfObjectDelete(old_load_order);
511 WdfRegistryClose(sgo_key);
512 return; /* something is very wrong */
513 }
514 if (dummy_group_index == 1 && wdf_load_group_index != -1 &&
515 (dummy_group_index < wdf_load_group_index
516 && wdf_load_group_index < xenpci_group_index
517 && xenpci_group_index < boot_bus_extender_index))
518 {
519 FUNCTION_EXIT();
520 return; /* our work here is done */
521 }
522 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
523 {
524 WDFOBJECT ws;
525 if (i == 1)
526 {
527 WDFSTRING tmp_wdf_string;
528 WdfStringCreate(&dummy_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(&wdf_load_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 == 1)
540 {
541 WDFSTRING tmp_wdf_string;
542 WdfStringCreate(&xenpci_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
543 WdfCollectionAdd(new_load_order, tmp_wdf_string);
544 WdfObjectDelete(tmp_wdf_string);
545 }
546 if (i == (ULONG)dummy_group_index || i == (ULONG)wdf_load_group_index || i == (ULONG)xenpci_group_index)
547 continue;
548 ws = WdfCollectionGetItem(old_load_order, i);
549 WdfCollectionAdd(new_load_order, ws);
550 }
551 WdfRegistryAssignMultiString(sgo_key, &list_name, new_load_order);
552 //KdPrint((__DRIVER_NAME " New Order:\n"));
553 for (i = 0; i < WdfCollectionGetCount(new_load_order); i++)
554 {
555 WDFOBJECT ws = WdfCollectionGetItem(new_load_order, i);
556 UNICODE_STRING val;
557 WdfStringGetUnicodeString(ws, &val);
558 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
559 }
560 WdfObjectDelete(new_load_order);
561 WdfObjectDelete(old_load_order);
562 WdfRegistryClose(sgo_key);
564 FUNCTION_EXIT();
566 return;
567 }
569 VOID
570 XenPci_EvtDriverUnload(WDFDRIVER driver)
571 {
572 UNREFERENCED_PARAMETER(driver);
574 #if DBG
575 XenPci_UnHookDbgPrint();
576 #endif
577 }
579 /* we need to balloon down very early on in the case of PoD, so things get a little messy */
580 static PMDL
581 XenPci_InitialBalloonDown()
582 {
583 PVOID hypercall_stubs;
584 domid_t domid = DOMID_SELF;
585 ULONG maximum_reservation;
586 ULONG current_reservation;
587 ULONG extra_kb;
588 ULONG ret;
589 struct xen_memory_reservation reservation;
590 xen_pfn_t *pfns;
591 PMDL head = NULL;
592 PMDL mdl;
593 int i, j;
594 ULONG curr_pfns_offset;
595 PHYSICAL_ADDRESS alloc_low;
596 PHYSICAL_ADDRESS alloc_high;
597 PHYSICAL_ADDRESS alloc_skip;
599 FUNCTION_ENTER();
601 hypercall_stubs = hvm_get_hypercall_stubs();
602 if (!hypercall_stubs)
603 {
604 KdPrint((__DRIVER_NAME " Failed to copy hypercall stubs. Maybe not running under Xen?\n"));
605 FUNCTION_EXIT();
606 return NULL;
607 }
608 if (xen_version_major < 4)
609 {
610 FUNCTION_MSG("No support for PoD. Cannot do initial balloon down.\n");
611 FUNCTION_MSG("Expect a crash if maxmem is set much larger than memory.\n");
612 FUNCTION_EXIT();
613 return NULL;
614 }
615 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_maximum_reservation, &domid);
616 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
617 maximum_reservation = ret;
618 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_current_reservation, &domid);
619 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
620 current_reservation = ret;
622 extra_kb = (maximum_reservation - current_reservation) << 2;
624 alloc_low.QuadPart = 0;
625 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
626 alloc_skip.QuadPart = PAGE_SIZE;
628 KdPrint((__DRIVER_NAME " Trying to give %d KB (%d MB) to Xen\n", extra_kb, extra_kb >> 10));
630 /* this code is mostly duplicated from the actual balloon thread... too hard to reuse */
631 pfns = ExAllocatePoolWithTag(NonPagedPool, max(BALLOON_UNIT_PAGES, (64 << 8)) * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
632 if (!pfns) {
633 /* If we can't balloon down then we are going to crash in strange ways later. Better to bug check now. */
634 KdPrint((__DRIVER_NAME " Initial Balloon Down failed - no memory for pfn list\n"));
635 #pragma warning(suppress:28159)
636 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000003, 0x00000000, 0x00000000, 0x00000000);
637 }
638 curr_pfns_offset = 0;
639 /* this makes sure we balloon up to the next multiple of BALLOON_UNITS_KB */
640 for (j = 0; j < (int)extra_kb; j += BALLOON_UNITS_KB)
641 {
642 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
643 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
644 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024, MmCached, 0);
645 #else
646 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024);
647 #endif
648 if (!mdl || MmGetMdlByteCount(mdl) != BALLOON_UNITS_KB * 1024)
649 {
650 /* 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... */
651 KdPrint((__DRIVER_NAME " Initial Balloon Down failed\n"));
652 #pragma warning(suppress:28159)
653 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000002, extra_kb, j, 0x00000000);
654 }
655 else
656 {
657 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
658 for (i = 0; i < BALLOON_UNIT_PAGES; i++)
659 {
660 pfns[curr_pfns_offset] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
661 curr_pfns_offset++;
662 }
663 if (curr_pfns_offset == (ULONG)max(BALLOON_UNIT_PAGES, (64 << 8)) || j + BALLOON_UNITS_KB > (int)extra_kb)
664 {
665 reservation.address_bits = 0;
666 reservation.extent_order = 0;
667 reservation.domid = DOMID_SELF;
668 reservation.nr_extents = curr_pfns_offset;
669 #pragma warning(disable: 4127) /* conditional expression is constant */
670 set_xen_guest_handle(reservation.extent_start, pfns);
671 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_decrease_reservation, &reservation);
672 if (ret != curr_pfns_offset)
673 FUNCTION_MSG("only decreased %d of %d pages\n", ret, curr_pfns_offset);
674 curr_pfns_offset = 0;
675 }
676 if (head)
677 {
678 mdl->Next = head;
679 head = mdl;
680 }
681 else
682 {
683 head = mdl;
684 }
685 }
686 //KdPrint((__DRIVER_NAME " C\n"));
687 }
688 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
689 hvm_free_hypercall_stubs(hypercall_stubs);
691 FUNCTION_EXIT();
693 return head;
694 }
696 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
697 /* this isn't freed on shutdown... perhaps it should be */
698 static PUCHAR dump_header;
699 static ULONG dump_header_size;
700 static ULONG dump_header_refreshed_flag = FALSE;
701 static KBUGCHECK_REASON_CALLBACK_RECORD callback_record;
702 #define DUMP_HEADER_PREFIX_SIZE 8
703 #define DUMP_HEADER_SUFFIX_SIZE 8
705 /* call KeInitializeCrashDumpHeader once on crash */
706 static VOID
707 XenPci_DebugHeaderDumpIoCallback(
708 KBUGCHECK_CALLBACK_REASON reason,
709 PKBUGCHECK_REASON_CALLBACK_RECORD record,
710 PVOID reason_specific_data,
711 ULONG reason_specific_data_length) {
712 UNREFERENCED_PARAMETER(reason);
713 UNREFERENCED_PARAMETER(record);
714 UNREFERENCED_PARAMETER(reason_specific_data);
715 UNREFERENCED_PARAMETER(reason_specific_data_length);
716 if (!dump_header_refreshed_flag) {
717 NTSTATUS status;
718 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
719 /* copy bug check code in? */
720 dump_header_refreshed_flag = TRUE;
721 }
722 }
723 #endif
725 NTSTATUS
726 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
727 {
728 NTSTATUS status = STATUS_SUCCESS;
729 WDF_DRIVER_CONFIG config;
730 WDFDRIVER driver;
731 WDF_OBJECT_ATTRIBUTES parent_attributes;
732 PCONFIGURATION_INFORMATION conf_info;
733 WDFKEY control_key;
734 WDFKEY param_key;
735 ULONG always_patch = 0;
736 ULONG always_hide = 0;
737 DECLARE_CONST_UNICODE_STRING(control_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
738 DECLARE_CONST_UNICODE_STRING(system_start_options_name, L"SystemStartOptions");
739 DECLARE_CONST_UNICODE_STRING(txt_always_hide_name, L"txt_hide_qemu_always");
740 DECLARE_CONST_UNICODE_STRING(hide_devices_name, L"hide_devices");
741 DECLARE_CONST_UNICODE_STRING(txt_always_patch_name, L"txt_patch_tpr_always");
742 WDFSTRING wdf_system_start_options;
743 UNICODE_STRING system_start_options;
744 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
745 PHYSICAL_ADDRESS dump_header_mem_max;
746 #endif
748 UNREFERENCED_PARAMETER(RegistryPath);
750 FUNCTION_ENTER();
752 FUNCTION_MSG(__DRIVER_NAME " " VER_FILEVERSION_STR "\n");
754 #if DBG
755 XenPci_HookDbgPrint();
756 #endif
758 NT_ASSERT(!balloon_mdl_head);
759 balloon_mdl_head = XenPci_InitialBalloonDown();
761 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
762 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, NULL, 0, &dump_header_size);
763 /* try and allocate contiguous memory as low as possible */
764 dump_header = NULL;
765 dump_header_mem_max.QuadPart = 0xFFFFF;
766 while (!dump_header && dump_header_mem_max.QuadPart != 0xFFFFFFFFFFFFFFFF) {
767 dump_header = MmAllocateContiguousMemory(DUMP_HEADER_PREFIX_SIZE + dump_header_size + DUMP_HEADER_SUFFIX_SIZE, dump_header_mem_max);
768 dump_header_mem_max.QuadPart = (dump_header_mem_max.QuadPart << 8) | 0xF;
769 }
770 if (dump_header) {
771 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_header + DUMP_HEADER_PREFIX_SIZE, dump_header_size, &dump_header_size);
772 FUNCTION_MSG("KeInitializeCrashDumpHeader status = %08x, size = %d\n", status, dump_header_size);
773 memcpy(dump_header + 0, "XENXEN", 6); /* magic number */
774 *(PUSHORT)(dump_header + 6) = (USHORT)(INT_PTR)dump_header & (PAGE_SIZE - 1); /* store offset too as additional verification */
775 memcpy(dump_header + DUMP_HEADER_PREFIX_SIZE + dump_header_size, "XENXEN", 6);
776 *(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 */
777 KeInitializeCallbackRecord(&callback_record);
778 KeRegisterBugCheckReasonCallback(&callback_record, XenPci_DebugHeaderDumpIoCallback, KbCallbackDumpIo, (PUCHAR)"XenPci_DebugHeaderDumpIoCallback");
779 } else {
780 FUNCTION_MSG("Failed to allocate memory for crash dump header\n");
781 }
782 #endif
784 /* again after enabling DbgPrint hooking */
785 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
788 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
789 config.EvtDriverUnload = XenPci_EvtDriverUnload;
790 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
791 if (!NT_SUCCESS(status))
792 {
793 KdPrint((__DRIVER_NAME " WdfDriverCreate failed with status 0x%x\n", status));
794 FUNCTION_EXIT();
795 #if DBG
796 XenPci_UnHookDbgPrint();
797 #endif
798 return status;
799 }
800 WDF_OBJECT_ATTRIBUTES_INIT(&parent_attributes);
801 parent_attributes.ParentObject = driver;
803 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, &parent_attributes, &param_key);
804 if (!NT_SUCCESS(status))
805 {
806 KdPrint(("Error opening parameters key %08x\n", status));
807 goto error;
808 }
810 status = AuxKlibInitialize();
811 if(!NT_SUCCESS(status))
812 {
813 KdPrint((__DRIVER_NAME " AuxKlibInitialize failed %08x\n", status));
814 goto error;
815 }
817 XenPci_FixLoadOrder();
819 RtlInitUnicodeString(&system_start_options, L"failed to read");
820 status = WdfRegistryOpenKey(NULL, &control_key_name, GENERIC_READ, &parent_attributes, &control_key);
821 if (NT_SUCCESS(status))
822 {
823 status = WdfStringCreate(NULL, &parent_attributes, &wdf_system_start_options);
824 status = WdfRegistryQueryString(control_key, &system_start_options_name, wdf_system_start_options);
825 if (NT_SUCCESS(status))
826 WdfStringGetUnicodeString(wdf_system_start_options, &system_start_options);
827 }
828 WdfRegistryClose(control_key);
830 KdPrint((__DRIVER_NAME " SystemStartOptions = %wZ\n", &system_start_options));
832 always_patch = 0;
833 WdfRegistryQueryULong(param_key, &txt_always_patch_name, &always_patch);
834 if (always_patch || (system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"PATCHTPR")))
835 {
836 DECLARE_CONST_UNICODE_STRING(verifier_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
837 WDFKEY memory_key;
838 ULONG verifier_value;
840 KdPrint((__DRIVER_NAME " PATCHTPR found\n"));
842 tpr_patch_requested = TRUE;
843 status = WdfRegistryOpenKey(NULL, &verifier_key_name, KEY_READ, &parent_attributes, &memory_key);
844 if (NT_SUCCESS(status))
845 {
846 DECLARE_CONST_UNICODE_STRING(verifier_value_name, L"VerifyDriverLevel");
847 status = WdfRegistryQueryULong(memory_key, &verifier_value_name, &verifier_value);
848 if (NT_SUCCESS(status) && verifier_value != 0)
849 {
850 KdPrint((__DRIVER_NAME " Verifier active - not patching\n"));
851 tpr_patch_requested = FALSE;
852 }
853 WdfRegistryClose(memory_key);
854 }
855 }
857 WdfCollectionCreate(&parent_attributes, &qemu_hide_devices);
858 WdfRegistryQueryULong(param_key, &txt_always_hide_name, &always_hide);
859 conf_info = IoGetConfigurationInformation();
860 if (always_hide || ((conf_info == NULL || conf_info->DiskCount == 0)
861 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOGPLPV"))
862 && !*InitSafeBootMode))
863 {
864 if (!(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"GPLPVUSEFILTERHIDE")) && XenPci_CheckHideQemuDevices())
865 {
866 DECLARE_CONST_UNICODE_STRING(qemu_hide_flags_name, L"qemu_hide_flags");
867 DECLARE_CONST_UNICODE_STRING(txt_qemu_hide_flags_name, L"txt_qemu_hide_flags");
868 WDFCOLLECTION qemu_hide_flags;
869 ULONG i;
871 WdfCollectionCreate(&parent_attributes, &qemu_hide_flags);
872 WdfRegistryQueryMultiString(param_key, &qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
873 WdfRegistryQueryMultiString(param_key, &txt_qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
874 for (i = 0; i < WdfCollectionGetCount(qemu_hide_flags); i++)
875 {
876 ULONG value;
877 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_flags, i);
878 UNICODE_STRING unicode_string;
879 WdfStringGetUnicodeString(wdf_string, &unicode_string);
880 status = RtlUnicodeStringToInteger(&unicode_string, 0, &value);
881 qemu_hide_flags_value |= value;
882 }
883 WdfObjectDelete(qemu_hide_flags);
884 XenPci_HideQemuDevices();
885 }
886 else
887 {
888 WdfRegistryQueryMultiString(param_key, &hide_devices_name, &parent_attributes, qemu_hide_devices);
889 }
890 }
891 WdfRegistryClose(param_key);
892 FUNCTION_EXIT();
893 return STATUS_SUCCESS;
895 error:
896 #if DBG
897 XenPci_UnHookDbgPrint();
898 #endif
899 KdPrint(("Failed, returning %08x\n", status));
900 FUNCTION_EXIT();
901 return status;
902 }