/xenvbd_filter/xenvbd_filter.c

https://github.com/kielfriedt/win-pvdrivers-mirror · C · 507 lines · 386 code · 75 blank · 46 comment · 38 complexity · 33ee4dfaeaab3ab3484d3130b1eefff8 MD5 · raw file

  1. /*
  2. PV Drivers for Windows Xen HVM Domains
  3. Copyright (c) 2014, James Harper
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in the
  11. documentation and/or other materials provided with the distribution.
  12. * Neither the name of James Harper nor the
  13. names of its contributors may be used to endorse or promote products
  14. derived from this software without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  16. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. DISCLAIMED. IN NO EVENT SHALL JAMES HARPER BE LIABLE FOR ANY
  19. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "xenvbd_filter.h"
  27. #include "ntddscsi.h"
  28. #include "srb.h"
  29. DRIVER_INITIALIZE DriverEntry;
  30. static EVT_WDF_DRIVER_UNLOAD XenVbd_EvtDriverUnload;
  31. static EVT_WDF_DRIVER_DEVICE_ADD XenVbd_EvtDeviceAdd;
  32. static EVT_WDF_REQUEST_COMPLETION_ROUTINE XenVbd_SendEventComplete;
  33. static EVT_WDF_DEVICE_D0_ENTRY XenVbd_EvtDeviceD0Entry;
  34. static EVT_WDF_DEVICE_D0_EXIT XenVbd_EvtDeviceD0Exit;
  35. static EVT_WDFDEVICE_WDM_IRP_PREPROCESS XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE;
  36. static EVT_WDFDEVICE_WDM_IRP_PREPROCESS XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER;
  37. static EVT_WDF_DPC XenVbd_EvtDpcEvent;
  38. static IO_COMPLETION_ROUTINE XenVbd_IoCompletion_START_DEVICE;
  39. static VOID XenVbd_DeviceCallback(PVOID context, ULONG callback_type, PVOID value);
  40. static VOID XenVbd_HandleEventDIRQL(PVOID context);
  41. static VOID XenVbd_StopRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend);
  42. static VOID XenVbd_StartRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend);
  43. #include "../xenvbd_common/common_xen.h"
  44. static VOID XenVbd_SendEvent(WDFDEVICE device);
  45. static VOID
  46. XenVbd_StopRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) {
  47. PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
  48. NTSTATUS status;
  49. WDFREQUEST request;
  50. WDF_REQUEST_SEND_OPTIONS send_options;
  51. IO_STACK_LOCATION stack;
  52. SCSI_REQUEST_BLOCK srb;
  53. SRB_IO_CONTROL sic;
  54. FUNCTION_ENTER();
  55. /* send a 'stop' down if we are suspending */
  56. if (suspend) {
  57. status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
  58. FUNCTION_MSG("WdfRequestCreate = %08x\n", status);
  59. RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
  60. stack.MajorFunction = IRP_MJ_SCSI;
  61. stack.MinorFunction = IRP_MN_SCSI_CLASS;
  62. stack.Parameters.Scsi.Srb = &srb;
  63. RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
  64. srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
  65. srb.Length = SCSI_REQUEST_BLOCK_SIZE;
  66. srb.PathId = 0;
  67. srb.TargetId = 0;
  68. srb.Lun = 0;
  69. srb.OriginalRequest = WdfRequestWdmGetIrp(request);
  70. srb.Function = SRB_FUNCTION_IO_CONTROL;
  71. srb.DataBuffer = &sic;
  72. RtlZeroMemory(&sic, sizeof(SRB_IO_CONTROL));
  73. sic.HeaderLength = sizeof(SRB_IO_CONTROL);
  74. memcpy(sic.Signature, XENVBD_CONTROL_SIG, 8);
  75. sic.Timeout = 60;
  76. sic.ControlCode = XENVBD_CONTROL_STOP;
  77. WdfRequestWdmFormatUsingStackLocation(request, &stack);
  78. WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
  79. if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
  80. FUNCTION_MSG("Request was _NOT_ sent\n");
  81. }
  82. #if DBG
  83. status = WdfRequestGetStatus(request);
  84. FUNCTION_MSG("Request Status = %08x\n", status);
  85. FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus);
  86. #endif
  87. WdfObjectDelete(request);
  88. }
  89. status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "state", XenbusStateClosing);
  90. FUNCTION_EXIT();
  91. }
  92. static VOID
  93. XenVbd_StartRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) {
  94. PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
  95. NTSTATUS status;
  96. WDFREQUEST request;
  97. WDF_REQUEST_SEND_OPTIONS send_options;
  98. IO_STACK_LOCATION stack;
  99. SCSI_REQUEST_BLOCK srb;
  100. SRB_IO_CONTROL sic;
  101. FUNCTION_ENTER();
  102. /* send a 'start' down if we are resuming from a suspend */
  103. if (suspend) {
  104. status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
  105. FUNCTION_MSG("WdfRequestCreate = %08x\n", status);
  106. RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
  107. stack.MajorFunction = IRP_MJ_SCSI;
  108. stack.Parameters.Scsi.Srb = &srb;
  109. RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
  110. srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
  111. srb.Length = SCSI_REQUEST_BLOCK_SIZE;
  112. srb.PathId = 0;
  113. srb.TargetId = 0;
  114. srb.Lun = 0;
  115. srb.OriginalRequest = WdfRequestWdmGetIrp(request);
  116. srb.Function = SRB_FUNCTION_IO_CONTROL;
  117. srb.DataBuffer = &sic;
  118. RtlZeroMemory(&sic, sizeof(SRB_IO_CONTROL));
  119. sic.HeaderLength = sizeof(SRB_IO_CONTROL);
  120. memcpy(sic.Signature, XENVBD_CONTROL_SIG, 8);
  121. sic.Timeout = 60;
  122. sic.ControlCode = XENVBD_CONTROL_START;
  123. WdfRequestWdmFormatUsingStackLocation(request, &stack);
  124. WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
  125. if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
  126. FUNCTION_MSG("Request was _NOT_ sent\n");
  127. }
  128. #if DBG
  129. status = WdfRequestGetStatus(request);
  130. FUNCTION_MSG("Request Status = %08x\n", status);
  131. FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus);
  132. #endif
  133. WdfObjectDelete(request);
  134. }
  135. FUNCTION_EXIT();
  136. }
  137. static VOID
  138. XenVbd_SendEventComplete(WDFREQUEST request, WDFIOTARGET target, PWDF_REQUEST_COMPLETION_PARAMS params, WDFCONTEXT context) {
  139. WDFDEVICE device = WdfIoTargetGetDevice(target);
  140. PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
  141. NTSTATUS status;
  142. PSCSI_REQUEST_BLOCK srb = context;
  143. LARGE_INTEGER systemtime;
  144. ULONGLONG elapsed;
  145. UNREFERENCED_PARAMETER(params);
  146. UNREFERENCED_PARAMETER(context);
  147. status = WdfRequestGetStatus(request);
  148. if (status != 0 || srb->SrbStatus != SRB_STATUS_SUCCESS) {
  149. FUNCTION_MSG("Request Status = %08x, SRB Status = %08x\n", status, srb->SrbStatus);
  150. }
  151. KeQuerySystemTime(&systemtime);
  152. elapsed = systemtime.QuadPart - ((PLARGE_INTEGER)((PUCHAR)context + sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL)))->QuadPart;
  153. elapsed = elapsed / 10000; // now in ms
  154. if (elapsed > 1000) {
  155. FUNCTION_MSG("Event took %d ms\n", (ULONG)elapsed);
  156. }
  157. ExFreePoolWithTag(context, XENVBD_POOL_TAG);
  158. WdfObjectDelete(request);
  159. for (;;) {
  160. if (InterlockedCompareExchange(&xvfd->event_state, 0, 1) == 1) {
  161. /* no pending event, and we cleared outstanding flag */
  162. break;
  163. }
  164. if (InterlockedCompareExchange(&xvfd->event_state, 1, 2) == 2) {
  165. /* there was a pending event, and we set the flag back to outstanding */
  166. //FUNCTION_MSG("sending pended event\n");
  167. XenVbd_SendEvent(device);
  168. break;
  169. }
  170. /* event_state changed while we were looking at it, go round again */
  171. }
  172. }
  173. static VOID
  174. XenVbd_SendEvent(WDFDEVICE device) {
  175. PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
  176. NTSTATUS status;
  177. WDFREQUEST request;
  178. WDF_REQUEST_SEND_OPTIONS send_options;
  179. IO_STACK_LOCATION stack;
  180. PUCHAR buf;
  181. PSCSI_REQUEST_BLOCK srb;
  182. PSRB_IO_CONTROL sic;
  183. status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
  184. if (status != STATUS_SUCCESS) {
  185. FUNCTION_MSG("WdfRequestCreate failed %08x\n", status);
  186. /* this is bad - event will be dropped */
  187. return;
  188. }
  189. buf = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL) + sizeof(LARGE_INTEGER), XENVBD_POOL_TAG);
  190. RtlZeroMemory(buf, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL));
  191. srb = (PSCSI_REQUEST_BLOCK)(buf);
  192. sic = (PSRB_IO_CONTROL)(buf + sizeof(SCSI_REQUEST_BLOCK));
  193. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  194. srb->SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
  195. srb->PathId = 0;
  196. srb->TargetId = 0;
  197. srb->Lun = 0;
  198. srb->OriginalRequest = WdfRequestWdmGetIrp(request);
  199. srb->Function = SRB_FUNCTION_IO_CONTROL;
  200. srb->DataBuffer = sic;
  201. srb->DataTransferLength = sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL);
  202. srb->TimeOutValue = (ULONG)-1;
  203. sic->HeaderLength = sizeof(SRB_IO_CONTROL);
  204. memcpy(sic->Signature, XENVBD_CONTROL_SIG, 8);
  205. sic->Timeout = (ULONG)-1;
  206. sic->ControlCode = XENVBD_CONTROL_EVENT;
  207. KeQuerySystemTime((PLARGE_INTEGER)((PUCHAR)buf + sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL)));
  208. RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
  209. stack.MajorFunction = IRP_MJ_SCSI;
  210. stack.MinorFunction = IRP_MN_SCSI_CLASS;
  211. stack.Parameters.Scsi.Srb = srb;
  212. WdfRequestWdmFormatUsingStackLocation(request, &stack);
  213. WdfRequestSetCompletionRoutine(request, XenVbd_SendEventComplete, buf);
  214. WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, 0); //WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE);
  215. if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
  216. FUNCTION_MSG("Error sending request\n");
  217. }
  218. }
  219. static VOID
  220. XenVbd_EvtDpcEvent(WDFDPC dpc) {
  221. WDFDEVICE device = WdfDpcGetParentObject(dpc);
  222. PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
  223. for (;;) {
  224. if (InterlockedCompareExchange(&xvfd->event_state, 1, 0) == 0) {
  225. /* was no event outstanding, now there is */
  226. XenVbd_SendEvent(device);
  227. break;
  228. }
  229. if (InterlockedCompareExchange(&xvfd->event_state, 2, 1) != 0) {
  230. //FUNCTION_MSG("event already in progress\n");
  231. /* event was outstanding. either we set the need new event flag or it was already set */
  232. break;
  233. }
  234. /* event_state changed while we were looking at it, go around again */
  235. }
  236. }
  237. static VOID
  238. XenVbd_HandleEventDIRQL(PVOID context) {
  239. PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)context;
  240. PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
  241. WdfDpcEnqueue(xvfd->dpc);
  242. }
  243. static NTSTATUS
  244. XenVbd_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state) {
  245. PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
  246. NTSTATUS status;
  247. UNREFERENCED_PARAMETER(previous_state);
  248. // if waking from hibernate then same as suspend... maybe?
  249. FUNCTION_ENTER();
  250. status = XenVbd_Connect(&xvfd->xvdd, FALSE);
  251. FUNCTION_EXIT();
  252. return status;
  253. }
  254. static NTSTATUS
  255. XenVbd_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state) {
  256. PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
  257. NTSTATUS status = STATUS_SUCCESS;
  258. FUNCTION_ENTER();
  259. switch (target_state) {
  260. case WdfPowerDeviceD0:
  261. FUNCTION_MSG("WdfPowerDeviceD1\n");
  262. break;
  263. case WdfPowerDeviceD1:
  264. FUNCTION_MSG("WdfPowerDeviceD1\n");
  265. break;
  266. case WdfPowerDeviceD2:
  267. FUNCTION_MSG("WdfPowerDeviceD2\n");
  268. break;
  269. case WdfPowerDeviceD3:
  270. FUNCTION_MSG("WdfPowerDeviceD3\n");
  271. if (xvfd->hibernate_flag) {
  272. FUNCTION_MSG("(but really WdfPowerDevicePrepareForHibernation)\n");
  273. target_state = WdfPowerDevicePrepareForHibernation;
  274. }
  275. break;
  276. case WdfPowerDeviceD3Final:
  277. FUNCTION_MSG("WdfPowerDeviceD3Final\n");
  278. break;
  279. case WdfPowerDevicePrepareForHibernation:
  280. FUNCTION_MSG("WdfPowerDevicePrepareForHibernation\n");
  281. break;
  282. default:
  283. FUNCTION_MSG("Unknown WdfPowerDevice state %d\n", target_state);
  284. break;
  285. }
  286. if (target_state != WdfPowerDevicePrepareForHibernation) {
  287. status = XenVbd_Disconnect(&xvfd->xvdd, FALSE);
  288. }
  289. FUNCTION_EXIT();
  290. return status;
  291. }
  292. static NTSTATUS
  293. XenVbd_IoCompletion_START_DEVICE(PDEVICE_OBJECT device, PIRP irp, PVOID context) {
  294. UNREFERENCED_PARAMETER(device);
  295. UNREFERENCED_PARAMETER(irp);
  296. FUNCTION_ENTER();
  297. ExFreePoolWithTag(context, XENVBD_POOL_TAG);
  298. FUNCTION_EXIT();
  299. return STATUS_SUCCESS;
  300. }
  301. static NTSTATUS
  302. XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE(WDFDEVICE device, PIRP irp) {
  303. PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
  304. PIO_STACK_LOCATION stack;
  305. PCM_RESOURCE_LIST crl;
  306. PCM_FULL_RESOURCE_DESCRIPTOR cfrd;
  307. PCM_PARTIAL_RESOURCE_LIST cprl;
  308. PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
  309. FUNCTION_ENTER();
  310. /*
  311. Pass down the xvdd area as a memory resource. This gives xenvbd the data in a known place
  312. and also satisifies the scsiport requirement for a memory resource
  313. */
  314. IoCopyCurrentIrpStackLocationToNext(irp);
  315. stack = IoGetNextIrpStackLocation(irp);
  316. crl = ExAllocatePoolWithTag(NonPagedPool,
  317. FIELD_OFFSET(CM_RESOURCE_LIST, List) +
  318. FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
  319. FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
  320. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 1, XENVBD_POOL_TAG);
  321. if (!crl) {
  322. // TODO: Fail this correctly
  323. }
  324. crl->Count = 1;
  325. cfrd = &crl->List[0];
  326. cfrd->InterfaceType = PNPBus;
  327. cfrd->BusNumber = 0;
  328. cprl = &cfrd->PartialResourceList;
  329. cprl->Version = 1;
  330. cprl->Revision = 1;
  331. cprl->Count = 1;
  332. prd = &cprl->PartialDescriptors[0];
  333. prd->Type = CmResourceTypeMemory;
  334. prd->ShareDisposition = CmResourceShareShared;
  335. prd->Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
  336. prd->u.Memory.Start.QuadPart = (ULONG_PTR)&xvfd->xvdd;
  337. prd->u.Memory.Length = sizeof(XENVBD_DEVICE_DATA);
  338. stack->Parameters.StartDevice.AllocatedResources = crl;
  339. stack->Parameters.StartDevice.AllocatedResourcesTranslated = crl;
  340. IoSetCompletionRoutine(irp, XenVbd_IoCompletion_START_DEVICE, crl, TRUE, TRUE, TRUE);
  341. FUNCTION_EXIT();
  342. return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
  343. }
  344. /* scsiport doesn't process SET_POWER correctly so we have to fudge detection of hibernate */
  345. static NTSTATUS
  346. XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER(WDFDEVICE device, PIRP irp) {
  347. PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
  348. PIO_STACK_LOCATION stack;
  349. FUNCTION_ENTER();
  350. stack = IoGetCurrentIrpStackLocation(irp);
  351. if (stack->Parameters.Power.Type == DevicePowerState && stack->Parameters.Power.State.DeviceState == PowerDeviceD3 && stack->Parameters.Power.ShutdownType == PowerActionHibernate) {
  352. FUNCTION_MSG("Going to hibernate\n");
  353. xvfd->hibernate_flag = TRUE;
  354. } else {
  355. xvfd->hibernate_flag = FALSE;
  356. }
  357. IoSkipCurrentIrpStackLocation(irp);
  358. FUNCTION_EXIT();
  359. return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
  360. }
  361. static NTSTATUS
  362. XenVbd_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init) {
  363. PXENVBD_FILTER_DATA xvfd;
  364. NTSTATUS status;
  365. WDFDEVICE device;
  366. WDF_OBJECT_ATTRIBUTES device_attributes;
  367. WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
  368. WDF_DPC_CONFIG dpc_config;
  369. WDF_OBJECT_ATTRIBUTES oa;
  370. UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
  371. UCHAR power_minor_functions[] = { IRP_MN_SET_POWER };
  372. UNREFERENCED_PARAMETER(driver);
  373. FUNCTION_ENTER();
  374. WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
  375. WdfFdoInitSetFilter(device_init);
  376. WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
  377. pnp_power_callbacks.EvtDeviceD0Entry = XenVbd_EvtDeviceD0Entry;
  378. pnp_power_callbacks.EvtDeviceD0Exit = XenVbd_EvtDeviceD0Exit;
  379. WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
  380. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE,
  381. IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
  382. if (!NT_SUCCESS(status)) {
  383. return status;
  384. }
  385. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER,
  386. IRP_MJ_POWER, power_minor_functions, ARRAY_SIZE(power_minor_functions));
  387. if (!NT_SUCCESS(status)) {
  388. return status;
  389. }
  390. WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENVBD_FILTER_DATA);
  391. status = WdfDeviceCreate(&device_init, &device_attributes, &device);
  392. if (!NT_SUCCESS(status)) {
  393. FUNCTION_MSG("Error creating device 0x%x\n", status);
  394. return status;
  395. }
  396. xvfd = GetXvfd(device);
  397. xvfd->wdf_device = device;
  398. xvfd->wdf_target = WdfDeviceGetIoTarget(device);
  399. xvfd->xvdd.xvfd = xvfd;
  400. xvfd->xvdd.pdo = WdfDeviceWdmGetPhysicalDevice(device);
  401. xvfd->xvdd.grant_tag = XENVBD_POOL_TAG;
  402. KeInitializeEvent(&xvfd->xvdd.backend_event, SynchronizationEvent, FALSE);
  403. WDF_DPC_CONFIG_INIT(&dpc_config, XenVbd_EvtDpcEvent);
  404. WDF_OBJECT_ATTRIBUTES_INIT(&oa);
  405. oa.ParentObject = device;
  406. status = WdfDpcCreate(&dpc_config, &oa, &xvfd->dpc);
  407. WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
  408. WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
  409. WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
  410. FUNCTION_EXIT();
  411. return status;
  412. }
  413. NTSTATUS
  414. DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
  415. NTSTATUS status;
  416. WDF_DRIVER_CONFIG config;
  417. WDFDRIVER driver;
  418. UNREFERENCED_PARAMETER(RegistryPath);
  419. FUNCTION_ENTER();
  420. WDF_DRIVER_CONFIG_INIT(&config, XenVbd_EvtDeviceAdd);
  421. status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
  422. if (!NT_SUCCESS(status)) {
  423. FUNCTION_MSG("WdfDriverCreate failed with status 0x%x\n", status);
  424. FUNCTION_EXIT();
  425. return status;
  426. }
  427. FUNCTION_EXIT();
  428. return status;
  429. }