win-pvdrivers

view xenpci/xenpci.c @ 979:8f483a2b2991

Fix up PREfast warnings
author James Harper <james.harper@bendigoit.com.au>
date Sun Apr 15 19:47:10 2012 +1000 (2012-04-15)
parents 63bdd096d8d1
children d4d381253394
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 #pragma warning(suppress:28138)
409 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, (USHORT)qemu_hide_flags_value); //QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
410 KdPrint((__DRIVER_NAME " Disabled qemu devices %02x\n", qemu_hide_flags_value));
411 }
413 static BOOLEAN
414 XenPci_CheckHideQemuDevices()
415 {
416 #pragma warning(suppress:28138)
417 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2)
418 {
419 #pragma warning(suppress:28138)
420 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
421 KdPrint((__DRIVER_NAME " Version = %d\n", qemu_protocol_version));
422 switch(qemu_protocol_version)
423 {
424 case 1:
425 #pragma warning(suppress:28138)
426 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
427 #pragma warning(suppress:28138)
428 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
429 #pragma warning(suppress:28138)
430 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
431 {
432 KdPrint((__DRIVER_NAME " Blacklisted\n"));
433 break;
434 }
435 /* fall through */
436 case 0:
437 return TRUE;
438 default:
439 KdPrint((__DRIVER_NAME " Unknown qemu version %d\n", qemu_protocol_version));
440 break;
441 }
442 }
443 return FALSE;
444 }
446 /*
447 make sure the load order is System Reserved, Dummy Group, WdfLoadGroup, XenPCI, Boot Bus Extender
448 */
450 static VOID
451 XenPci_FixLoadOrder()
452 {
453 NTSTATUS status;
454 WDFCOLLECTION old_load_order, new_load_order;
455 DECLARE_CONST_UNICODE_STRING(sgo_name, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder");
456 DECLARE_CONST_UNICODE_STRING(list_name, L"List");
457 WDFKEY sgo_key;
458 ULONG i;
459 LONG dummy_group_index = -1;
460 LONG boot_bus_extender_index = -1;
461 LONG xenpci_group_index = -1;
462 LONG wdf_load_group_index = -1;
463 DECLARE_CONST_UNICODE_STRING(dummy_group_name, L"Dummy Group");
464 DECLARE_CONST_UNICODE_STRING(wdf_load_group_name, L"WdfLoadGroup");
465 DECLARE_CONST_UNICODE_STRING(xenpci_group_name, L"XenPCI Group");
466 DECLARE_CONST_UNICODE_STRING(boot_bus_extender_name, L"Boot Bus Extender");
468 FUNCTION_ENTER();
470 status = WdfRegistryOpenKey(NULL, &sgo_name, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &sgo_key);
471 if (!NT_SUCCESS(status))
472 {
473 KdPrint((__DRIVER_NAME " Error opening ServiceGroupOrder key %08x\n", status));
474 return;
475 }
476 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &old_load_order);
477 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &new_load_order);
478 status = WdfRegistryQueryMultiString(sgo_key, &list_name, WDF_NO_OBJECT_ATTRIBUTES, old_load_order);
479 if (!NT_SUCCESS(status))
480 {
481 KdPrint((__DRIVER_NAME " Error reading ServiceGroupOrder\\List value %08x\n", status));
482 WdfObjectDelete(new_load_order);
483 WdfObjectDelete(old_load_order);
484 return;
485 }
486 //KdPrint((__DRIVER_NAME " Current Order:\n"));
487 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
488 {
489 WDFOBJECT ws = WdfCollectionGetItem(old_load_order, i);
490 UNICODE_STRING val;
491 WdfStringGetUnicodeString(ws, &val);
492 if (!RtlCompareUnicodeString(&val, &dummy_group_name, TRUE))
493 dummy_group_index = (ULONG)i;
494 if (!RtlCompareUnicodeString(&val, &wdf_load_group_name, TRUE))
495 wdf_load_group_index = (ULONG)i;
496 if (!RtlCompareUnicodeString(&val, &xenpci_group_name, TRUE))
497 xenpci_group_index = (ULONG)i;
498 if (!RtlCompareUnicodeString(&val, &boot_bus_extender_name, TRUE))
499 boot_bus_extender_index = (ULONG)i;
500 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
501 }
502 KdPrint((__DRIVER_NAME " dummy_group_index = %d\n", dummy_group_index));
503 KdPrint((__DRIVER_NAME " wdf_load_group_index = %d\n", wdf_load_group_index));
504 KdPrint((__DRIVER_NAME " xenpci_group_index = %d\n", xenpci_group_index));
505 KdPrint((__DRIVER_NAME " boot_bus_extender_index = %d\n", boot_bus_extender_index));
506 if (boot_bus_extender_index == -1)
507 {
508 WdfObjectDelete(new_load_order);
509 WdfObjectDelete(old_load_order);
510 WdfRegistryClose(sgo_key);
511 return; /* something is very wrong */
512 }
513 if (dummy_group_index == 1 && wdf_load_group_index != -1 &&
514 (dummy_group_index < wdf_load_group_index
515 && wdf_load_group_index < xenpci_group_index
516 && xenpci_group_index < boot_bus_extender_index))
517 {
518 FUNCTION_EXIT();
519 return; /* our work here is done */
520 }
521 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
522 {
523 WDFOBJECT ws;
524 if (i == 1)
525 {
526 WDFSTRING tmp_wdf_string;
527 WdfStringCreate(&dummy_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
528 WdfCollectionAdd(new_load_order, tmp_wdf_string);
529 WdfObjectDelete(tmp_wdf_string);
530 }
531 if (i == 1)
532 {
533 WDFSTRING tmp_wdf_string;
534 WdfStringCreate(&wdf_load_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
535 WdfCollectionAdd(new_load_order, tmp_wdf_string);
536 WdfObjectDelete(tmp_wdf_string);
537 }
538 if (i == 1)
539 {
540 WDFSTRING tmp_wdf_string;
541 WdfStringCreate(&xenpci_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
542 WdfCollectionAdd(new_load_order, tmp_wdf_string);
543 WdfObjectDelete(tmp_wdf_string);
544 }
545 if (i == (ULONG)dummy_group_index || i == (ULONG)wdf_load_group_index || i == (ULONG)xenpci_group_index)
546 continue;
547 ws = WdfCollectionGetItem(old_load_order, i);
548 WdfCollectionAdd(new_load_order, ws);
549 }
550 WdfRegistryAssignMultiString(sgo_key, &list_name, new_load_order);
551 //KdPrint((__DRIVER_NAME " New Order:\n"));
552 for (i = 0; i < WdfCollectionGetCount(new_load_order); i++)
553 {
554 WDFOBJECT ws = WdfCollectionGetItem(new_load_order, i);
555 UNICODE_STRING val;
556 WdfStringGetUnicodeString(ws, &val);
557 //KdPrint((__DRIVER_NAME " %wZ\n", &val));
558 }
559 WdfObjectDelete(new_load_order);
560 WdfObjectDelete(old_load_order);
561 WdfRegistryClose(sgo_key);
563 FUNCTION_EXIT();
565 return;
566 }
568 VOID
569 XenPci_EvtDriverUnload(WDFDRIVER driver)
570 {
571 UNREFERENCED_PARAMETER(driver);
573 #if DBG
574 XenPci_UnHookDbgPrint();
575 #endif
576 }
578 /* we need to balloon down very early on in the case of PoD, so things get a little messy */
579 static PMDL
580 XenPci_InitialBalloonDown()
581 {
582 PVOID hypercall_stubs;
583 domid_t domid = DOMID_SELF;
584 ULONG maximum_reservation;
585 ULONG current_reservation;
586 ULONG extra_kb;
587 ULONG ret;
588 struct xen_memory_reservation reservation;
589 xen_pfn_t *pfns;
590 PMDL head = NULL;
591 PMDL mdl;
592 int i, j;
593 ULONG curr_pfns_offset;
594 PHYSICAL_ADDRESS alloc_low;
595 PHYSICAL_ADDRESS alloc_high;
596 PHYSICAL_ADDRESS alloc_skip;
598 FUNCTION_ENTER();
600 hypercall_stubs = hvm_get_hypercall_stubs();
601 if (!hypercall_stubs)
602 {
603 KdPrint((__DRIVER_NAME " Failed to copy hypercall stubs. Maybe not running under Xen?\n"));
604 FUNCTION_EXIT();
605 return NULL;
606 }
607 if (xen_version_major < 4)
608 {
609 FUNCTION_MSG("No support for PoD. Cannot do initial balloon down.\n");
610 FUNCTION_MSG("Expect a crash if maxmem is set much larger than memory.\n");
611 FUNCTION_EXIT();
612 return NULL;
613 }
614 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_maximum_reservation, &domid);
615 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
616 maximum_reservation = ret;
617 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_current_reservation, &domid);
618 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
619 current_reservation = ret;
621 extra_kb = (maximum_reservation - current_reservation) << 2;
623 alloc_low.QuadPart = 0;
624 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
625 alloc_skip.QuadPart = PAGE_SIZE;
627 KdPrint((__DRIVER_NAME " Trying to give %d KB (%d MB) to Xen\n", extra_kb, extra_kb >> 10));
629 /* this code is mostly duplicated from the actual balloon thread... too hard to reuse */
630 pfns = ExAllocatePoolWithTag(NonPagedPool, max(BALLOON_UNIT_PAGES, (64 << 8)) * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
631 if (!pfns) {
632 /* If we can't balloon down then we are going to crash in strange ways later. Better to bug check now. */
633 KdPrint((__DRIVER_NAME " Initial Balloon Down failed - no memory for pfn list\n"));
634 #pragma warning(suppress:28159)
635 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000003, 0x00000000, 0x00000000, 0x00000000);
636 }
637 curr_pfns_offset = 0;
638 /* this makes sure we balloon up to the next multiple of BALLOON_UNITS_KB */
639 for (j = 0; j < (int)extra_kb; j += BALLOON_UNITS_KB)
640 {
641 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
642 /* our contract says that we must zero pages before returning to xen, so we can't use MM_DONT_ZERO_ALLOCATION */
643 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024, MmCached, 0);
644 #else
645 mdl = MmAllocatePagesForMdl(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS_KB * 1024);
646 #endif
647 if (!mdl || MmGetMdlByteCount(mdl) != BALLOON_UNITS_KB * 1024)
648 {
649 /* 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... */
650 KdPrint((__DRIVER_NAME " Initial Balloon Down failed\n"));
651 #pragma warning(suppress:28159)
652 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000002, extra_kb, j, 0x00000000);
653 }
654 else
655 {
656 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
657 for (i = 0; i < BALLOON_UNIT_PAGES; i++)
658 {
659 pfns[curr_pfns_offset] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
660 curr_pfns_offset++;
661 }
662 if (curr_pfns_offset == (ULONG)max(BALLOON_UNIT_PAGES, (64 << 8)) || j + BALLOON_UNITS_KB > (int)extra_kb)
663 {
664 reservation.address_bits = 0;
665 reservation.extent_order = 0;
666 reservation.domid = DOMID_SELF;
667 reservation.nr_extents = curr_pfns_offset;
668 #pragma warning(disable: 4127) /* conditional expression is constant */
669 set_xen_guest_handle(reservation.extent_start, pfns);
670 ret = _HYPERVISOR_memory_op(hypercall_stubs, XENMEM_decrease_reservation, &reservation);
671 if (ret != curr_pfns_offset)
672 FUNCTION_MSG("only decreased %d of %d pages\n", ret, curr_pfns_offset);
673 curr_pfns_offset = 0;
674 }
675 if (head)
676 {
677 mdl->Next = head;
678 head = mdl;
679 }
680 else
681 {
682 head = mdl;
683 }
684 }
685 //KdPrint((__DRIVER_NAME " C\n"));
686 }
687 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
688 hvm_free_hypercall_stubs(hypercall_stubs);
690 FUNCTION_EXIT();
692 return head;
693 }
695 /* this isn't freed on shutdown... perhaps it should be */
696 PVOID dump_page;
698 NTSTATUS
699 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
700 {
701 NTSTATUS status = STATUS_SUCCESS;
702 WDF_DRIVER_CONFIG config;
703 WDFDRIVER driver;
704 WDF_OBJECT_ATTRIBUTES parent_attributes;
705 PCONFIGURATION_INFORMATION conf_info;
706 WDFKEY control_key;
707 WDFKEY param_key;
708 ULONG always_patch = 0;
709 ULONG always_hide = 0;
710 DECLARE_CONST_UNICODE_STRING(control_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
711 DECLARE_CONST_UNICODE_STRING(system_start_options_name, L"SystemStartOptions");
712 DECLARE_CONST_UNICODE_STRING(txt_always_hide_name, L"txt_hide_qemu_always");
713 DECLARE_CONST_UNICODE_STRING(hide_devices_name, L"hide_devices");
714 DECLARE_CONST_UNICODE_STRING(txt_always_patch_name, L"txt_patch_tpr_always");
715 WDFSTRING wdf_system_start_options;
716 UNICODE_STRING system_start_options;
717 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
718 ULONG dump_header_size;
719 #endif
721 UNREFERENCED_PARAMETER(RegistryPath);
723 FUNCTION_ENTER();
725 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
727 #if DBG
728 XenPci_HookDbgPrint();
729 #endif
731 ASSERT(!balloon_mdl_head);
732 balloon_mdl_head = XenPci_InitialBalloonDown();
734 #if (NTDDI_VERSION >= NTDDI_WS03SP1)
735 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, NULL, 0, &dump_header_size);
736 dump_page = ExAllocatePoolWithTag(NonPagedPool, dump_header_size, XENPCI_POOL_TAG);
737 status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, dump_page, dump_header_size, &dump_header_size);
738 KdPrint((__DRIVER_NAME " KeInitializeCrashDumpHeader status = %08x, size = %d\n", status, dump_header_size));
739 #endif
741 /* again after enabling DbgPrint hooking */
742 KdPrint((__DRIVER_NAME " " VER_FILEVERSION_STR "\n"));
745 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
746 config.EvtDriverUnload = XenPci_EvtDriverUnload;
747 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
748 if (!NT_SUCCESS(status))
749 {
750 KdPrint((__DRIVER_NAME " WdfDriverCreate failed with status 0x%x\n", status));
751 FUNCTION_EXIT();
752 #if DBG
753 XenPci_UnHookDbgPrint();
754 #endif
755 return status;
756 }
757 WDF_OBJECT_ATTRIBUTES_INIT(&parent_attributes);
758 parent_attributes.ParentObject = driver;
760 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, &parent_attributes, &param_key);
761 if (!NT_SUCCESS(status))
762 {
763 KdPrint(("Error opening parameters key %08x\n", status));
764 goto error;
765 }
767 status = AuxKlibInitialize();
768 if(!NT_SUCCESS(status))
769 {
770 KdPrint((__DRIVER_NAME " AuxKlibInitialize failed %08x\n", status));
771 goto error;
772 }
774 XenPci_FixLoadOrder();
776 RtlInitUnicodeString(&system_start_options, L"failed to read");
777 status = WdfRegistryOpenKey(NULL, &control_key_name, GENERIC_READ, &parent_attributes, &control_key);
778 if (NT_SUCCESS(status))
779 {
780 status = WdfStringCreate(NULL, &parent_attributes, &wdf_system_start_options);
781 status = WdfRegistryQueryString(control_key, &system_start_options_name, wdf_system_start_options);
782 if (NT_SUCCESS(status))
783 WdfStringGetUnicodeString(wdf_system_start_options, &system_start_options);
784 }
785 WdfRegistryClose(control_key);
787 KdPrint((__DRIVER_NAME " SystemStartOptions = %wZ\n", &system_start_options));
789 always_patch = 0;
790 WdfRegistryQueryULong(param_key, &txt_always_patch_name, &always_patch);
791 if (always_patch || (system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"PATCHTPR")))
792 {
793 DECLARE_CONST_UNICODE_STRING(verifier_key_name, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
794 WDFKEY memory_key;
795 ULONG verifier_value;
797 KdPrint((__DRIVER_NAME " PATCHTPR found\n"));
799 tpr_patch_requested = TRUE;
800 status = WdfRegistryOpenKey(NULL, &verifier_key_name, KEY_READ, &parent_attributes, &memory_key);
801 if (NT_SUCCESS(status))
802 {
803 DECLARE_CONST_UNICODE_STRING(verifier_value_name, L"VerifyDriverLevel");
804 status = WdfRegistryQueryULong(memory_key, &verifier_value_name, &verifier_value);
805 if (NT_SUCCESS(status) && verifier_value != 0)
806 {
807 KdPrint((__DRIVER_NAME " Verifier active - not patching\n"));
808 tpr_patch_requested = FALSE;
809 }
810 WdfRegistryClose(memory_key);
811 }
812 }
814 WdfCollectionCreate(&parent_attributes, &qemu_hide_devices);
815 WdfRegistryQueryULong(param_key, &txt_always_hide_name, &always_hide);
816 conf_info = IoGetConfigurationInformation();
817 if (always_hide || ((conf_info == NULL || conf_info->DiskCount == 0)
818 && !(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"NOGPLPV"))
819 && !*InitSafeBootMode))
820 {
821 if (!(system_start_options.Buffer && wcsstr(system_start_options.Buffer, L"GPLPVUSEFILTERHIDE")) && XenPci_CheckHideQemuDevices())
822 {
823 DECLARE_CONST_UNICODE_STRING(qemu_hide_flags_name, L"qemu_hide_flags");
824 DECLARE_CONST_UNICODE_STRING(txt_qemu_hide_flags_name, L"txt_qemu_hide_flags");
825 WDFCOLLECTION qemu_hide_flags;
826 ULONG i;
828 WdfCollectionCreate(&parent_attributes, &qemu_hide_flags);
829 WdfRegistryQueryMultiString(param_key, &qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
830 WdfRegistryQueryMultiString(param_key, &txt_qemu_hide_flags_name, &parent_attributes, qemu_hide_flags);
831 for (i = 0; i < WdfCollectionGetCount(qemu_hide_flags); i++)
832 {
833 ULONG value;
834 WDFSTRING wdf_string = WdfCollectionGetItem(qemu_hide_flags, i);
835 UNICODE_STRING unicode_string;
836 WdfStringGetUnicodeString(wdf_string, &unicode_string);
837 status = RtlUnicodeStringToInteger(&unicode_string, 0, &value);
838 qemu_hide_flags_value |= value;
839 }
840 WdfObjectDelete(qemu_hide_flags);
841 XenPci_HideQemuDevices();
842 }
843 else
844 {
845 WdfRegistryQueryMultiString(param_key, &hide_devices_name, &parent_attributes, qemu_hide_devices);
846 }
847 }
848 WdfRegistryClose(param_key);
849 FUNCTION_EXIT();
850 return STATUS_SUCCESS;
852 error:
853 #if DBG
854 XenPci_UnHookDbgPrint();
855 #endif
856 KdPrint(("Failed, returning %08x\n", status));
857 FUNCTION_EXIT();
858 return status;
859 }