win-pvdrivers

view xenpci/xenpci.c @ 547:ac614e49832c

Fixed another typo
author James Harper <james.harper@bendigoit.com.au>
date Sun Mar 08 14:37:45 2009 +1100 (2009-03-08)
parents 0828c553c6c3
children d56ecda9e61f
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 <stdlib.h>
24 #define SYSRQ_PATH "control/sysrq"
25 #define SHUTDOWN_PATH "control/shutdown"
26 #define BALLOON_PATH "memory/target"
28 #pragma warning(disable : 4200) // zero-sized array
30 static VOID
31 XenPci_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
32 {
33 FUNCTION_ENTER();
35 UNREFERENCED_PARAMETER(device);
37 switch (notification_type)
38 {
39 case WdfSpecialFilePaging:
40 KdPrint((__DRIVER_NAME " notification_type = Paging, flag = %d\n", is_in_notification_path));
41 break;
42 case WdfSpecialFileHibernation:
43 KdPrint((__DRIVER_NAME " notification_type = Hibernation, flag = %d\n", is_in_notification_path));
44 break;
45 case WdfSpecialFileDump:
46 KdPrint((__DRIVER_NAME " notification_type = Dump, flag = %d\n", is_in_notification_path));
47 break;
48 default:
49 KdPrint((__DRIVER_NAME " notification_type = %d, flag = %d\n", notification_type, is_in_notification_path));
50 break;
51 }
53 FUNCTION_EXIT();
54 }
56 static NTSTATUS
57 XenPci_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
58 {
59 NTSTATUS status;
60 // PDEVICE_OBJECT fdo = NULL;
61 // PNP_BUS_INFORMATION busInfo;
62 // DECLARE_CONST_UNICODE_STRING(DeviceName, L"\\Device\\XenShutdown");
63 // DECLARE_CONST_UNICODE_STRING(SymbolicName, L"\\DosDevices\\XenShutdown");
64 WDF_CHILD_LIST_CONFIG child_list_config;
65 WDFDEVICE device;
66 PXENPCI_DEVICE_DATA xpdd;
67 UNICODE_STRING reference;
68 WDF_OBJECT_ATTRIBUTES device_attributes;
69 PNP_BUS_INFORMATION pbi;
70 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
71 WDF_INTERRUPT_CONFIG interrupt_config;
72 WDF_OBJECT_ATTRIBUTES file_attributes;
73 WDF_FILEOBJECT_CONFIG file_config;
74 WDF_IO_QUEUE_CONFIG queue_config;
75 WDFKEY param_key;
76 DECLARE_CONST_UNICODE_STRING(veto_devices_name, L"veto_devices");
77 WDF_DEVICE_POWER_CAPABILITIES power_capabilities;
79 UNREFERENCED_PARAMETER(driver);
81 FUNCTION_ENTER();
83 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
84 pnp_power_callbacks.EvtDeviceD0Entry = XenPci_EvtDeviceD0Entry;
85 pnp_power_callbacks.EvtDeviceD0EntryPostInterruptsEnabled = XenPci_EvtDeviceD0EntryPostInterruptsEnabled;
86 pnp_power_callbacks.EvtDeviceD0Exit = XenPci_EvtDeviceD0Exit;
87 pnp_power_callbacks.EvtDeviceD0ExitPreInterruptsDisabled = XenPci_EvtDeviceD0ExitPreInterruptsDisabled;
88 pnp_power_callbacks.EvtDevicePrepareHardware = XenPci_EvtDevicePrepareHardware;
89 pnp_power_callbacks.EvtDeviceReleaseHardware = XenPci_EvtDeviceReleaseHardware;
90 pnp_power_callbacks.EvtDeviceQueryRemove = XenPci_EvtDeviceQueryRemove;
91 pnp_power_callbacks.EvtDeviceUsageNotification = XenPci_EvtDeviceUsageNotification;
93 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
95 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_BUS_EXTENDER);
96 WdfDeviceInitSetExclusive(device_init, FALSE);
98 WDF_CHILD_LIST_CONFIG_INIT(&child_list_config, sizeof(XENPCI_PDO_IDENTIFICATION_DESCRIPTION), XenPci_EvtChildListCreateDevice);
99 child_list_config.EvtChildListScanForChildren = XenPci_EvtChildListScanForChildren;
100 WdfFdoInitSetDefaultChildListConfig(device_init, &child_list_config, WDF_NO_OBJECT_ATTRIBUTES);
102 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&file_attributes, XENPCI_DEVICE_INTERFACE_DATA);
103 WDF_FILEOBJECT_CONFIG_INIT(&file_config, XenPci_EvtDeviceFileCreate, XenPci_EvtFileClose, XenPci_EvtFileCleanup);
104 WdfDeviceInitSetFileObjectConfig(device_init, &file_config, &file_attributes);
106 WdfDeviceInitSetIoType(device_init, WdfDeviceIoBuffered);
108 WdfDeviceInitSetPowerNotPageable(device_init);
110 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENPCI_DEVICE_DATA);
111 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
112 if (!NT_SUCCESS(status))
113 {
114 KdPrint(("Error creating device %08x\n", status));
115 return status;
116 }
118 xpdd = GetXpdd(device);
120 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &xpdd->veto_devices);
121 status = WdfDriverOpenParametersRegistryKey(driver, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &param_key);
122 if (NT_SUCCESS(status))
123 {
124 status = WdfRegistryQueryMultiString(param_key, &veto_devices_name, WDF_NO_OBJECT_ATTRIBUTES, xpdd->veto_devices);
125 if (!NT_SUCCESS(status))
126 {
127 KdPrint(("Error reading parameters/veto_devices value %08x\n", status));
128 }
129 WdfRegistryClose(param_key);
130 }
131 else
132 {
133 KdPrint(("Error opening parameters key %08x\n", status));
134 }
136 WDF_DEVICE_POWER_CAPABILITIES_INIT(&power_capabilities);
137 power_capabilities.DeviceD1 = WdfTrue;
138 power_capabilities.WakeFromD1 = WdfTrue;
139 power_capabilities.DeviceWake = PowerDeviceD1;
140 power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD1;
141 power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
142 power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
143 power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
144 power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
145 power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
146 WdfDeviceSetPowerCapabilities(device, &power_capabilities);
148 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
149 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
150 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
152 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchParallel);
153 queue_config.EvtIoRead = XenPci_EvtIoRead;
154 queue_config.EvtIoWrite = XenPci_EvtIoWrite;
155 status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->io_queue);
156 if (!NT_SUCCESS(status)) {
157 KdPrint(("Error creating queue 0x%x\n", status));
158 return status;
159 }
161 WDF_INTERRUPT_CONFIG_INIT(&interrupt_config, EvtChn_EvtInterruptIsr, NULL);
162 interrupt_config.EvtInterruptEnable = EvtChn_EvtInterruptEnable;
163 interrupt_config.EvtInterruptDisable = EvtChn_EvtInterruptDisable;
165 status = WdfInterruptCreate(device, &interrupt_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdd->interrupt);
166 if (!NT_SUCCESS(status))
167 {
168 KdPrint(("Error creating interrupt 0x%x\n", status));
169 return status;
170 }
172 RtlInitUnicodeString(&reference, L"xenbus");
173 status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_XENBUS, &reference);
174 if (!NT_SUCCESS(status)) {
175 KdPrint(("Error registering device interface 0x%x\n", status));
176 return status;
177 }
179 pbi.BusTypeGuid = GUID_BUS_TYPE_XEN;
180 pbi.LegacyBusType = PNPBus;
181 pbi.BusNumber = 0;
182 WdfDeviceSetBusInformationForChildren(device, &pbi);
184 xpdd->removable = TRUE;
186 FUNCTION_EXIT();
187 return status;
188 }
190 ULONG qemu_filtered;
191 ULONG qemu_filtered_by_qemu;
192 ULONG qemu_protocol_version;
193 ULONG tpr_patch_requested;
194 extern PULONG InitSafeBootMode;
196 VOID
197 XenPci_HideQemuDevices()
198 {
199 qemu_filtered_by_qemu = FALSE;
200 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) == 0x49d2)
201 {
202 qemu_protocol_version = READ_PORT_UCHAR(XEN_IOPORT_VERSION);
203 KdPrint((__DRIVER_NAME " Version = %d\n", qemu_protocol_version));
204 switch(qemu_protocol_version)
205 {
206 case 1:
207 WRITE_PORT_USHORT(XEN_IOPORT_PRODUCT, XEN_PV_PRODUCT_NUMBER);
208 WRITE_PORT_ULONG(XEN_IOPORT_BUILD, XEN_PV_PRODUCT_BUILD);
209 if (READ_PORT_USHORT(XEN_IOPORT_MAGIC) != 0x49d2)
210 {
211 KdPrint((__DRIVER_NAME " Blacklisted\n"));
212 break;
213 }
214 /* fall through */
215 case 0:
216 qemu_filtered = TRUE;
217 qemu_filtered_by_qemu = TRUE;
218 WRITE_PORT_USHORT(XEN_IOPORT_DEVICE_MASK, QEMU_UNPLUG_ALL_IDE_DISKS|QEMU_UNPLUG_ALL_NICS);
219 KdPrint((__DRIVER_NAME " Disabled qemu devices\n"));
220 break;
221 default:
222 KdPrint((__DRIVER_NAME " Unknown qemu version %d\n", qemu_protocol_version));
223 break;
224 }
225 }
226 }
228 /*
229 make sure the load order is System Reserved, Dummy Group, WdfLoadGroup, Boot Bus Extender
230 */
232 static VOID
233 XenPci_FixLoadOrder()
234 {
235 NTSTATUS status;
236 WDFCOLLECTION old_load_order, new_load_order;
237 DECLARE_CONST_UNICODE_STRING(sgo_name, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder");
238 DECLARE_CONST_UNICODE_STRING(list_name, L"List");
239 WDFKEY sgo_key;
240 ULONG i;
241 LONG dummy_group_index = -1;
242 LONG boot_bus_extender_index = -1;
243 LONG wdf_load_group_index = -1;
244 DECLARE_CONST_UNICODE_STRING(dummy_group_name, L"Dummy Group");
245 DECLARE_CONST_UNICODE_STRING(wdf_load_group_name, L"WdfLoadGroup");
246 DECLARE_CONST_UNICODE_STRING(boot_bus_extender_name, L"Boot Bus Extender");
248 FUNCTION_ENTER();
250 status = WdfRegistryOpenKey(NULL, &sgo_name, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &sgo_key);
251 if (!NT_SUCCESS(status))
252 {
253 KdPrint((__DRIVER_NAME " Error opening ServiceGroupOrder key %08x\n", status));
254 return;
255 }
256 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &old_load_order);
257 WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &new_load_order);
258 status = WdfRegistryQueryMultiString(sgo_key, &list_name, WDF_NO_OBJECT_ATTRIBUTES, old_load_order);
259 if (!NT_SUCCESS(status))
260 {
261 KdPrint((__DRIVER_NAME " Error reading ServiceGroupOrder\\List value %08x\n", status));
262 WdfObjectDelete(new_load_order);
263 WdfObjectDelete(old_load_order);
264 return;
265 }
266 KdPrint((__DRIVER_NAME " Current Order:\n"));
267 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
268 {
269 WDFOBJECT ws = WdfCollectionGetItem(old_load_order, i);
270 UNICODE_STRING val;
271 WdfStringGetUnicodeString(ws, &val);
272 if (!RtlCompareUnicodeString(&val, &dummy_group_name, TRUE))
273 dummy_group_index = (ULONG)i;
274 if (!RtlCompareUnicodeString(&val, &wdf_load_group_name, TRUE))
275 wdf_load_group_index = (ULONG)i;
276 if (!RtlCompareUnicodeString(&val, &boot_bus_extender_name, TRUE))
277 boot_bus_extender_index = (ULONG)i;
278 KdPrint((__DRIVER_NAME " %wZ\n", &val));
279 }
280 KdPrint((__DRIVER_NAME " dummy_group_index = %d\n", dummy_group_index));
281 KdPrint((__DRIVER_NAME " wdf_load_group_index = %d\n", wdf_load_group_index));
282 KdPrint((__DRIVER_NAME " boot_bus_extender_index = %d\n", boot_bus_extender_index));
283 if (boot_bus_extender_index == -1)
284 {
285 WdfObjectDelete(new_load_order);
286 WdfObjectDelete(old_load_order);
287 WdfRegistryClose(sgo_key);
288 return; /* something is very wrong */
289 }
290 if (dummy_group_index == 1 && (wdf_load_group_index == -1 || (wdf_load_group_index > dummy_group_index && wdf_load_group_index < boot_bus_extender_index)))
291 {
292 return; /* our work here is done */
293 }
294 for (i = 0; i < WdfCollectionGetCount(old_load_order); i++)
295 {
296 WDFOBJECT ws;
297 if (i == 1)
298 {
299 WDFSTRING tmp_wdf_string;
300 WdfStringCreate(&dummy_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
301 WdfCollectionAdd(new_load_order, tmp_wdf_string);
302 WdfObjectDelete(tmp_wdf_string);
303 }
304 if (i == 1 && wdf_load_group_index != -1)
305 {
306 WDFSTRING tmp_wdf_string;
307 WdfStringCreate(&wdf_load_group_name, WDF_NO_OBJECT_ATTRIBUTES, &tmp_wdf_string);
308 WdfCollectionAdd(new_load_order, tmp_wdf_string);
309 WdfObjectDelete(tmp_wdf_string);
310 }
311 if (i == (ULONG)dummy_group_index || i == (ULONG)wdf_load_group_index)
312 continue;
313 ws = WdfCollectionGetItem(old_load_order, i);
314 WdfCollectionAdd(new_load_order, ws);
315 }
316 WdfRegistryAssignMultiString(sgo_key, &list_name, new_load_order);
317 KdPrint((__DRIVER_NAME " New Order:\n"));
318 for (i = 0; i < WdfCollectionGetCount(new_load_order); i++)
319 {
320 WDFOBJECT ws = WdfCollectionGetItem(new_load_order, i);
321 UNICODE_STRING val;
322 WdfStringGetUnicodeString(ws, &val);
323 KdPrint((__DRIVER_NAME " %wZ\n", &val));
324 }
325 WdfObjectDelete(new_load_order);
326 WdfObjectDelete(old_load_order);
327 WdfRegistryClose(sgo_key);
329 FUNCTION_EXIT();
331 return;
332 }
334 NTSTATUS
335 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
336 {
337 NTSTATUS status = STATUS_SUCCESS;
338 WDF_DRIVER_CONFIG config;
339 WDFDRIVER driver;
340 PCONFIGURATION_INFORMATION conf_info;
341 WCHAR *SystemStartOptions;
342 UNICODE_STRING RegKeyName;
343 UNICODE_STRING RegValueName;
344 HANDLE RegHandle;
345 OBJECT_ATTRIBUTES RegObjectAttributes;
346 char Buf[300];// Sometimes bigger then 200 if system reboot from crash
347 ULONG BufLen = 300;
348 PKEY_VALUE_PARTIAL_INFORMATION KeyPartialValue;
349 #if 0
350 WDF_TIMER_CONFIG timer_config;
351 OBJECT_ATTRIBUTES timer_attributes;
352 #endif
354 UNREFERENCED_PARAMETER(RegistryPath);
356 FUNCTION_ENTER();
358 XenPci_FixLoadOrder();
360 RtlInitUnicodeString(&RegKeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
361 InitializeObjectAttributes(&RegObjectAttributes, &RegKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
362 status = ZwOpenKey(&RegHandle, KEY_READ, &RegObjectAttributes);
363 if(!NT_SUCCESS(status))
364 {
365 KdPrint((__DRIVER_NAME " ZwOpenKey returned %08x\n", status));
366 }
368 RtlInitUnicodeString(&RegValueName, L"SystemStartOptions");
369 status = ZwQueryValueKey(RegHandle, &RegValueName, KeyValuePartialInformation, Buf, BufLen, &BufLen);
370 if(!NT_SUCCESS(status))
371 {
372 KdPrint((__DRIVER_NAME " ZwQueryKeyValue returned %08x\n", status));
373 }
374 else
375 ZwClose(RegHandle);
376 KeyPartialValue = (PKEY_VALUE_PARTIAL_INFORMATION)Buf;
377 SystemStartOptions = (WCHAR *)KeyPartialValue->Data;
379 KdPrint((__DRIVER_NAME " SystemStartOptions = %S\n", SystemStartOptions));
381 if (wcsstr(SystemStartOptions, L"PATCHTPR"))
382 {
383 KdPrint((__DRIVER_NAME " PATCHTPR found\n"));
384 tpr_patch_requested = TRUE;
385 }
387 if (wcsstr(SystemStartOptions, L"NOGPLPV"))
388 KdPrint((__DRIVER_NAME " NOGPLPV found\n"));
389 conf_info = IoGetConfigurationInformation();
390 if ((conf_info == NULL || conf_info->DiskCount == 0)
391 && !wcsstr(SystemStartOptions, L"NOGPLPV")
392 && !*InitSafeBootMode)
393 {
394 /* see if the qemu method of disabling the PCI devices exists */
395 XenPci_HideQemuDevices();
396 /* if not, tell the filter to deny the pci devices their resources */
397 if (!qemu_filtered)
398 {
399 OBJECT_ATTRIBUTES oa;
400 UNICODE_STRING dir_name;
401 NTSTATUS status;
402 HANDLE handle;
404 KdPrint((__DRIVER_NAME " Adding DirectoryObject\n"));
405 RtlInitUnicodeString(&dir_name, L"\\NEED_GPLPV_FILTER");
406 InitializeObjectAttributes(&oa, &dir_name, OBJ_KERNEL_HANDLE, NULL, NULL);
407 status = ZwCreateDirectoryObject(&handle, DIRECTORY_CREATE_OBJECT, &oa);
408 KdPrint((__DRIVER_NAME " ZwCreateDirectoryObject = %08x\n", status));
409 if (!NT_SUCCESS(status))
410 {
411 return status;
412 }
413 qemu_filtered = TRUE;
414 }
415 }
417 if (qemu_filtered)
418 KdPrint((__DRIVER_NAME " PV Devices Active\n"));
419 else
420 KdPrint((__DRIVER_NAME " PV Devices Inactive\n"));
422 WDF_DRIVER_CONFIG_INIT(&config, XenPci_EvtDeviceAdd);
423 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
425 if (!NT_SUCCESS(status)) {
426 KdPrint((__DRIVER_NAME " WdfDriverCreate failed with status 0x%x\n", status));
427 }
429 FUNCTION_EXIT();
431 return status;
432 }