kvm-guest-drivers-windows
1188 строк · 33.6 Кб
1/*
2* Placeholder for the device related functions
3*
4* Copyright (c) 2019 Virtuozzo International GmbH
5*
6* Redistribution and use in source and binary forms, with or without
7* modification, are permitted provided that the following conditions
8* are met :
9* 1. Redistributions of source code must retain the above copyright
10* notice, this list of conditions and the following disclaimer.
11* 2. Redistributions in binary form must reproduce the above copyright
12* notice, this list of conditions and the following disclaimer in the
13* documentation and / or other materials provided with the distribution.
14* 3. Neither the names of the copyright holders nor the names of their contributors
15* may be used to endorse or promote products derived from this software
16* without specific prior written permission.
17* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
18* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20* ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
21* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27* SUCH DAMAGE.
28*/
29
30#include "precomp.h"
31#include "viosock.h"
32
33#if defined(EVENT_TRACING)
34#include "Device.tmh"
35#endif
36
37EVT_WDF_DEVICE_PREPARE_HARDWARE VIOSockEvtDevicePrepareHardware;
38EVT_WDF_DEVICE_RELEASE_HARDWARE VIOSockEvtDeviceReleaseHardware;
39EVT_WDF_DEVICE_D0_ENTRY VIOSockEvtDeviceD0Entry;
40EVT_WDF_DEVICE_D0_EXIT VIOSockEvtDeviceD0Exit;
41EVT_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED VIOSockEvtDeviceD0EntryPostInterruptsEnabled;
42EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND VIOSockEvtDeviceSelfManagedIoSuspend;
43EVT_WDF_DEVICE_SELF_MANAGED_IO_RESTART VIOSockEvtDeviceSelfManagedIoRestart;
44
45EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL VIOSockEvtIoDeviceControl;
46EVT_WDF_REQUEST_CANCEL VIOSockSelectCancel;
47EVT_WDF_WORKITEM VIOSockSelectWorkitem;
48EVT_WDF_TIMER VIOSockSelectTimerFunc;
49
50VOID
51VIOSockQueuesCleanup(
52IN WDFDEVICE hDevice
53);
54
55NTSTATUS
56VIOSockQueuesInit(
57IN WDFDEVICE hDevice
58);
59
60NTSTATUS
61VIOSockDeviceGetConfig(
62IN WDFREQUEST Request,
63OUT size_t *pLength
64);
65
66NTSTATUS
67VIOSockDeviceGetAf(
68IN WDFREQUEST Request,
69OUT size_t *pLength
70);
71
72typedef struct _VIOSOCK_SELECT_HANDLE
73{
74ULONGLONG hSocket;
75WDFFILEOBJECT Socket;
76}VIOSOCK_SELECT_HANDLE, *PVIOSOCK_SELECT_HANDLE;
77
78typedef struct _VIOSOCK_SELECT_PKT
79{
80LIST_ENTRY ListEntry;
81LONGLONG Timeout;
82PVIRTIO_VSOCK_SELECT pSelect;
83ULONG FdCount[FDSET_MAX];
84NTSTATUS Status;
85VIOSOCK_SELECT_HANDLE Fds[FD_SETSIZE];
86}VIOSOCK_SELECT_PKT, *PVIOSOCK_SELECT_PKT;
87
88WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(VIOSOCK_SELECT_PKT, GetSelectContext);
89
90NTSTATUS
91VIOSockSelectInit(
92IN PDEVICE_CONTEXT pContext
93);
94
95VOID
96VIOSockSelectCleanupFds(
97IN PVIOSOCK_SELECT_PKT pPkt,
98IN VIRTIO_VSOCK_FDSET_TYPE iFdSet,
99IN ULONG uStartIndex
100);
101
102BOOLEAN
103VIOSockSelectCheckPkt(
104IN PVIOSOCK_SELECT_PKT pPkt
105);
106
107BOOLEAN
108VIOSockSelectCopyFds(
109IN PDEVICE_CONTEXT pContext,
110IN BOOLEAN bIs32BitProcess,
111IN PVIRTIO_VSOCK_SELECT pSelect,
112IN PVIOSOCK_SELECT_PKT pPkt,
113IN VIRTIO_VSOCK_FDSET_TYPE iFdSet,
114IN ULONG uStartIndex
115);
116
117NTSTATUS
118VIOSockSelect(
119IN WDFREQUEST Request,
120IN OUT size_t *pLength
121);
122
123#ifdef ALLOC_PRAGMA
124#pragma alloc_text (PAGE, VIOSockEvtDeviceAdd)
125#pragma alloc_text (PAGE, VIOSockQueuesCleanup)
126
127#pragma alloc_text (PAGE, VIOSockEvtDevicePrepareHardware)
128#pragma alloc_text (PAGE, VIOSockEvtDeviceReleaseHardware)
129#pragma alloc_text (PAGE, VIOSockEvtDeviceD0Exit)
130#pragma alloc_text (PAGE, VIOSockEvtDeviceSelfManagedIoSuspend)
131
132#pragma alloc_text (PAGE, VIOSockDeviceGetConfig)
133#pragma alloc_text (PAGE, VIOSockDeviceGetAf)
134#pragma alloc_text (PAGE, VIOSockEvtIoDeviceControl)
135#pragma alloc_text (PAGE, VIOSockSelectInit)
136#pragma alloc_text (PAGE, VIOSockSelectCleanupFds)
137#pragma alloc_text (PAGE, VIOSockSelectCheckPkt)
138#pragma alloc_text (PAGE, VIOSockSelectWorkitem)
139#pragma alloc_text (PAGE, VIOSockSelectCopyFds)
140#pragma alloc_text (PAGE, VIOSockSelect)
141#endif
142
143static
144VOID
145VIOSockQueuesCleanup(
146IN WDFDEVICE hDevice
147)
148{
149PDEVICE_CONTEXT pContext = GetDeviceContext(hDevice);
150NTSTATUS status = STATUS_SUCCESS;
151
152ULONG uBufferSize;
153
154PAGED_CODE();
155
156TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
157
158if (pContext->RxVq)
159VIOSockRxVqCleanup(pContext);
160
161if (pContext->TxVq)
162VIOSockTxVqCleanup(pContext);
163
164if (pContext->EvtVq)
165VIOSockEvtVqCleanup(pContext);
166
167VirtIOWdfDestroyQueues(&pContext->VDevice);
168}
169
170static
171NTSTATUS
172VIOSockQueuesInit(
173IN WDFDEVICE hDevice
174)
175{
176PDEVICE_CONTEXT pContext = GetDeviceContext(hDevice);
177NTSTATUS status = STATUS_SUCCESS;
178VIRTIO_WDF_QUEUE_PARAM params[VIOSOCK_VQ_MAX];
179PVIOSOCK_VQ vqs[VIOSOCK_VQ_MAX];
180
181ULONG uBufferSize;
182
183TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
184
185// rx
186params[VIOSOCK_VQ_RX].Interrupt = pContext->WdfInterrupt;
187// tx
188params[VIOSOCK_VQ_TX].Interrupt = pContext->WdfInterrupt;
189// event
190params[VIOSOCK_VQ_EVT].Interrupt = pContext->WdfInterrupt;
191
192status = VirtIOWdfInitQueues(&pContext->VDevice, VIOSOCK_VQ_MAX, vqs, params);
193if (!NT_SUCCESS(status))
194{
195TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "VirtIOWdfInitQueues failed: 0x%x\n", status);
196return status;
197}
198
199pContext->RxVq = vqs[VIOSOCK_VQ_RX];
200status = VIOSockRxVqInit(pContext);
201if (NT_SUCCESS(status))
202{
203pContext->TxVq = vqs[VIOSOCK_VQ_TX];
204status = VIOSockTxVqInit(pContext);
205if (NT_SUCCESS(status))
206{
207pContext->EvtVq = vqs[VIOSOCK_VQ_EVT];
208status = VIOSockEvtVqInit(pContext);
209if (!NT_SUCCESS(status))
210pContext->EvtVq = NULL;
211}
212else
213pContext->TxVq = NULL;
214}
215else
216pContext->RxVq = NULL;
217
218if (!NT_SUCCESS(status))
219VIOSockQueuesCleanup(hDevice);
220
221TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
222
223return status;
224}
225
226//////////////////////////////////////////////////////////////////////////
227NTSTATUS
228VIOSockEvtDeviceAdd(
229IN WDFDRIVER Driver,
230IN PWDFDEVICE_INIT DeviceInit
231)
232{
233NTSTATUS status = STATUS_SUCCESS;
234WDF_OBJECT_ATTRIBUTES Attributes;
235WDFDEVICE hDevice;
236WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks;
237PDEVICE_CONTEXT pContext = NULL;
238WDF_FILEOBJECT_CONFIG fileConfig;
239WDF_IO_QUEUE_CONFIG queueConfig;
240WDF_WORKITEM_CONFIG wrkConfig;
241
242DECLARE_CONST_UNICODE_STRING(usDeviceName, VIOSOCK_DEVICE_NAME);
243DECLARE_CONST_UNICODE_STRING(usDosDeviceName, VIOSOCK_SYMLINK_NAME);
244
245UNREFERENCED_PARAMETER(Driver);
246
247PAGED_CODE();
248
249TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);
250
251// Configure Pnp/power callbacks
252WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks);
253PnpPowerCallbacks.EvtDevicePrepareHardware = VIOSockEvtDevicePrepareHardware;
254PnpPowerCallbacks.EvtDeviceReleaseHardware = VIOSockEvtDeviceReleaseHardware;
255PnpPowerCallbacks.EvtDeviceD0Entry = VIOSockEvtDeviceD0Entry;
256PnpPowerCallbacks.EvtDeviceD0Exit = VIOSockEvtDeviceD0Exit;
257PnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = VIOSockEvtDeviceD0EntryPostInterruptsEnabled;
258PnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = VIOSockEvtDeviceSelfManagedIoSuspend;
259PnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = VIOSockEvtDeviceSelfManagedIoRestart;
260WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpPowerCallbacks);
261
262// Set DirectIO mode
263WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
264
265// Set device name (for kernel mode clients)
266status = WdfDeviceInitAssignName(DeviceInit, &usDeviceName);
267if (!NT_SUCCESS(status))
268{
269TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceInitAssignName failed - 0x%x\n", status);
270return status;
271}
272
273// Set device access (for user mode clients)
274status = WdfDeviceInitAssignSDDLString(DeviceInit, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);
275if (!NT_SUCCESS(status))
276{
277TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceInitAssignSDDLString failed - 0x%x\n", status);
278return status;
279}
280
281// Configure file object callbacks
282WDF_FILEOBJECT_CONFIG_INIT(
283&fileConfig,
284VIOSockCreateStub,
285WDF_NO_EVENT_CALLBACK, // Close
286VIOSockCleanup
287);
288fileConfig.FileObjectClass = WdfFileObjectWdfCanUseFsContext;
289
290WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, SOCKET_CONTEXT);
291
292WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig, &Attributes);
293
294// Create device
295WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, DEVICE_CONTEXT);
296
297status = WdfDeviceCreate(&DeviceInit, &Attributes, &hDevice);
298if (!NT_SUCCESS(status))
299{
300TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreate failed - 0x%x\n", status);
301return status;
302}
303
304status = WdfDeviceCreateDeviceInterface(
305hDevice,
306&GUID_DEVINTERFACE_VIOSOCK,
307NULL
308);
309if (!NT_SUCCESS(status))
310{
311TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreateDeviceInterface failed - 0x%x\n", status);
312return status;
313}
314
315status = WdfDeviceCreateSymbolicLink(
316hDevice,
317&usDosDeviceName
318);
319
320if (!NT_SUCCESS(status))
321{
322TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreateSymbolicLink failed - 0x%x\n", status);
323return status;
324}
325
326status = VIOSockBoundListInit(hDevice);
327if (!NT_SUCCESS(status))
328{
329TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "VIOSockBoundListInit failed - 0x%x\n", status);
330return status;
331}
332
333status = VIOSockConnectedListInit(hDevice);
334if (!NT_SUCCESS(status))
335{
336TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "VIOSockConnectedListInit failed - 0x%x\n", status);
337return status;
338}
339
340pContext = GetDeviceContext(hDevice);
341
342pContext->ThisDevice = hDevice;
343
344WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
345Attributes.ParentObject = hDevice;
346
347status = WdfLookasideListCreate(&Attributes,
348sizeof(VIOSOCK_ACCEPT_ENTRY), NonPagedPoolNx,
349&Attributes, VIOSOCK_DRIVER_MEMORY_TAG,
350&pContext->AcceptMemoryList);
351
352if (!NT_SUCCESS(status))
353{
354TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
355"WdfLookasideListCreate failed: 0x%x\n", status);
356return status;
357}
358
359// Create sequential queue for IoCtl requests
360WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,
361WdfIoQueueDispatchParallel
362);
363queueConfig.EvtIoDeviceControl = VIOSockEvtIoDeviceControl;
364queueConfig.AllowZeroLengthRequests = WdfFalse;
365
366status = WdfIoQueueCreate(hDevice,
367&queueConfig,
368WDF_NO_OBJECT_ATTRIBUTES,
369&pContext->IoCtlQueue
370);
371
372if (!NT_SUCCESS(status))
373{
374TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
375"WdfIoQueueCreate failed (IoCtrl Queue): 0x%x\n", status);
376return status;
377}
378
379status = WdfDeviceConfigureRequestDispatching(hDevice,
380pContext->IoCtlQueue,
381WdfRequestTypeDeviceControl);
382
383if (!NT_SUCCESS(status))
384{
385TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
386"WdfDeviceConfigureRequestDispatching failed (IoCtrl Queue): 0x%x\n", status);
387return status;
388}
389
390// Create parallel queue for Write requests
391status = VIOSockWriteQueueInit(hDevice);
392if (!NT_SUCCESS(status))
393{
394TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
395"VIOSockWriteQueueInit failed (Write Queue): 0x%x\n", status);
396return status;
397}
398
399// Create parallel queue for Read requests
400status = VIOSockReadQueueInit(hDevice);
401if (!NT_SUCCESS(status))
402{
403TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
404"VIOSockReadQueueInit failed (Read Queue): 0x%x\n", status);
405return status;
406}
407
408status = VIOSockSelectInit(pContext);
409if (!NT_SUCCESS(status))
410{
411TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
412"VIOSockSelectInit failed: 0x%x\n", status);
413return status;
414}
415
416status = VIOSockInterruptInit(hDevice);
417if(!NT_SUCCESS(status))
418{
419TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "VIOSockInterruptInit failed - 0x%x\n", status);
420}
421
422TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__);
423return status;
424}
425
426static
427NTSTATUS
428VIOSockEvtDevicePrepareHardware(
429IN WDFDEVICE Device,
430IN WDFCMRESLIST ResourcesRaw,
431IN WDFCMRESLIST ResourcesTranslated)
432{
433PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
434NTSTATUS status = STATUS_SUCCESS;
435UINT nr_ports;
436u64 u64HostFeatures;
437u64 u64GuestFeatures = 0;
438
439UNREFERENCED_PARAMETER(ResourcesRaw);
440PAGED_CODE();
441
442TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
443
444status = VirtIOWdfInitialize(
445&pContext->VDevice,
446Device,
447ResourcesTranslated,
448NULL,
449VIOSOCK_DRIVER_MEMORY_TAG);
450if (!NT_SUCCESS(status))
451{
452TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "VirtIOWdfInitialize failed with 0x%x\n", status);
453return status;
454}
455
456u64HostFeatures = VirtIOWdfGetDeviceFeatures(&pContext->VDevice);
457
458if (virtio_is_feature_enabled(u64HostFeatures, VIRTIO_RING_F_INDIRECT_DESC))
459{
460TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "Enable indirect feature.\n");
461
462virtio_feature_enable(u64GuestFeatures, VIRTIO_RING_F_INDIRECT_DESC);
463}
464
465status = VirtIOWdfSetDriverFeatures(&pContext->VDevice, u64GuestFeatures, 0);
466if (!NT_SUCCESS(status))
467{
468TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "VirtIOWdfSetDriverFeatures failed: 0x%x\n", status);
469VirtIOWdfSetDriverFailed(&pContext->VDevice);
470}
471
472TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
473return status;
474}
475
476static
477NTSTATUS
478VIOSockEvtDeviceReleaseHardware(
479IN WDFDEVICE Device,
480IN WDFCMRESLIST ResourcesTranslated)
481{
482PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
483
484UNREFERENCED_PARAMETER(ResourcesTranslated);
485PAGED_CODE();
486
487TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
488
489VirtIOWdfShutdown(&pContext->VDevice);
490
491return STATUS_SUCCESS;
492}
493
494static
495NTSTATUS
496VIOSockEvtDeviceD0Entry(
497IN WDFDEVICE Device,
498IN WDF_POWER_DEVICE_STATE PreviousState
499)
500{
501NTSTATUS status = STATUS_SUCCESS;
502PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
503
504UNREFERENCED_PARAMETER(PreviousState);
505
506TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> %s\n", __FUNCTION__);
507
508status = VIOSockQueuesInit(Device);
509if (!NT_SUCCESS(status))
510{
511TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIOSockQueuesInit failed: 0x%x\n", status);
512return status;
513}
514
515VirtIOWdfDeviceGet(&pContext->VDevice,
5160,
517&pContext->Config,
518sizeof(pContext->Config));
519
520TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
521"guest_cid %lld\n", pContext->Config.guest_cid);
522
523return status;
524}
525
526static
527NTSTATUS
528VIOSockEvtDeviceD0Exit(
529IN WDFDEVICE Device,
530IN WDF_POWER_DEVICE_STATE TargetState
531)
532{
533PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
534
535PAGED_CODE();
536
537TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> %s TargetState: %d\n",
538__FUNCTION__, TargetState);
539
540VIOSockQueuesCleanup(Device);
541
542return STATUS_SUCCESS;
543}
544
545static
546NTSTATUS
547VIOSockEvtDeviceD0EntryPostInterruptsEnabled(
548IN WDFDEVICE WdfDevice,
549IN WDF_POWER_DEVICE_STATE PreviousState
550)
551{
552PDEVICE_CONTEXT pContext = GetDeviceContext(WdfDevice);
553UNREFERENCED_PARAMETER(PreviousState);
554
555TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
556
557TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "Setting VIRTIO_CONFIG_S_DRIVER_OK flag\n");
558VirtIOWdfSetDriverOK(&pContext->VDevice);
559
560ASSERT(pContext->RxVq && pContext->EvtVq);
561
562return STATUS_SUCCESS;
563}
564
565
566NTSTATUS
567VIOSockEvtDeviceSelfManagedIoSuspend(
568IN WDFDEVICE Device
569)
570{
571PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
572
573PAGED_CODE();
574
575VIOSockWriteIoSuspend(pContext);
576
577return STATUS_SUCCESS;
578}
579
580NTSTATUS
581VIOSockEvtDeviceSelfManagedIoRestart(
582IN WDFDEVICE Device
583)
584{
585
586PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
587
588VIOSockWriteIoRestart(pContext);
589
590return STATUS_SUCCESS;
591}
592
593static
594NTSTATUS
595VIOSockDeviceGetConfig(
596IN WDFREQUEST Request,
597OUT size_t *pLength
598)
599{
600PVIRTIO_VSOCK_CONFIG pConfig = NULL;
601NTSTATUS status;
602
603PAGED_CODE();
604
605TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> %s\n", __FUNCTION__);
606
607status = WdfRequestRetrieveOutputBuffer(Request, sizeof(VIRTIO_VSOCK_CONFIG), (PVOID*)&pConfig, pLength);
608if (!NT_SUCCESS(status))
609{
610TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
611"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
612return status;
613}
614
615// minimum length guaranteed by WdfRequestRetrieveOutputBuffer above
616_Analysis_assume_(*pLength >= sizeof(VIRTIO_VSOCK_CONFIG));
617
618*pConfig = GetDeviceContextFromRequest(Request)->Config;
619*pLength = sizeof(*pConfig);
620
621return STATUS_SUCCESS;
622}
623
624static
625NTSTATUS
626VIOSockDeviceGetAf(
627IN WDFREQUEST Request,
628OUT size_t *pLength
629)
630{
631PULONG pulAF = NULL;
632NTSTATUS status;
633
634PAGED_CODE();
635
636TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> %s\n", __FUNCTION__);
637
638status = WdfRequestRetrieveOutputBuffer(Request, sizeof(*pulAF), (PVOID*)&pulAF, pLength);
639if (!NT_SUCCESS(status))
640{
641TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
642"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
643return status;
644}
645
646// minimum length guaranteed by WdfRequestRetrieveOutputBuffer above
647_Analysis_assume_(*pLength >= sizeof(*pulAF));
648
649*pulAF = AF_VSOCK;
650*pLength = sizeof(*pulAF);
651
652TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- %s, AF: %d\n", __FUNCTION__, *pulAF);
653
654return STATUS_SUCCESS;
655}
656
657static
658VOID
659VIOSockEvtIoDeviceControl(
660IN WDFQUEUE Queue,
661IN WDFREQUEST Request,
662IN size_t OutputBufferLength,
663IN size_t InputBufferLength,
664IN ULONG IoControlCode
665)
666{
667size_t Length = 0;
668NTSTATUS status = STATUS_SUCCESS;
669
670PAGED_CODE();
671
672TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> %s\n", __FUNCTION__);
673
674switch (IoControlCode)
675{
676case IOCTL_GET_CONFIG:
677status = VIOSockDeviceGetConfig(Request, &Length);
678break;
679
680case IOCTL_SELECT:
681status = VIOSockSelect(Request, &Length);
682break;
683
684case IOCTL_GET_AF:
685status = VIOSockDeviceGetAf(Request, &Length);
686break;
687
688default:
689if (IsControlRequest(Request))
690{
691TraceEvents(TRACE_LEVEL_WARNING, DBG_IOCTLS, "Invalid socket type\n");
692status = STATUS_NOT_SOCKET;
693}
694else
695{
696status = VIOSockDeviceControl(
697Request,
698IoControlCode,
699&Length);
700}
701}
702
703if (status != STATUS_PENDING)
704WdfRequestCompleteWithInformation(Request, status, Length);
705
706TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- %s, status: 0x%08x\n", __FUNCTION__, status);
707}
708
709//////////////////////////////////////////////////////////////////////////
710static
711NTSTATUS
712VIOSockSelectInit(
713IN PDEVICE_CONTEXT pContext
714)
715{
716NTSTATUS status;
717WDF_OBJECT_ATTRIBUTES Attributes;
718WDF_WORKITEM_CONFIG wrkConfig;
719
720PAGED_CODE();
721
722TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
723
724InitializeListHead(&pContext->SelectList);
725pContext->SelectInProgress = 0;
726
727WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
728Attributes.ParentObject = pContext->ThisDevice;
729
730status = WdfWaitLockCreate(&Attributes, &pContext->SelectLock);
731if (!NT_SUCCESS(status))
732{
733TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT,
734"WdfWaitLockCreate failed (Select): 0x%x\n", status);
735return status;
736}
737
738WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
739Attributes.ParentObject = pContext->ThisDevice;
740
741WDF_WORKITEM_CONFIG_INIT(&wrkConfig, VIOSockSelectWorkitem);
742status = WdfWorkItemCreate(&wrkConfig, &Attributes, &pContext->SelectWorkitem);
743if (!NT_SUCCESS(status))
744{
745TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT,
746"WdfWorkItemCreate failed (Select): 0x%x\n", status);
747return status;
748}
749
750VIOSockTimerCreate(&pContext->SelectTimer, pContext->ThisDevice, VIOSockSelectTimerFunc);
751if (!NT_SUCCESS(status))
752{
753TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT,
754"VIOSockTimerCreate failed (Select): 0x%x\n", status);
755}
756
757TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "<-- %s\n", __FUNCTION__);
758
759return status;
760}
761
762static
763VOID
764VIOSockSelectCleanupFds(
765IN PVIOSOCK_SELECT_PKT pPkt,
766IN VIRTIO_VSOCK_FDSET_TYPE iFdSet,
767IN ULONG uStartIndex
768
769)
770{
771ULONG i;
772PVIOSOCK_SELECT_HANDLE pHandleSet = &pPkt->Fds[uStartIndex];
773
774PAGED_CODE();
775
776for (i = 0; i < pPkt->FdCount[iFdSet]; ++i)
777{
778ASSERT(pHandleSet[i].Socket);
779
780InterlockedDecrement(&GetSocketContext(pHandleSet[i].Socket)->SelectRefs[iFdSet]); //dereference socket
781VioSockDereference(pHandleSet[i].Socket);
782}
783
784pPkt->FdCount[iFdSet] = 0;
785}
786
787__inline
788VOID
789VIOSockSelectCleanupPkt(
790IN PVIOSOCK_SELECT_PKT pPkt
791)
792{
793TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s, status: 0x%08x\n", __FUNCTION__, pPkt->Status);
794
795VIOSockSelectCleanupFds(pPkt, FDSET_READ, 0);
796VIOSockSelectCleanupFds(pPkt, FDSET_WRITE, pPkt->FdCount[FDSET_READ]);
797VIOSockSelectCleanupFds(pPkt, FDSET_EXCPT, pPkt->FdCount[FDSET_READ] + pPkt->FdCount[FDSET_WRITE]);
798}
799
800static
801VOID
802VIOSockSelectTimerFunc(
803IN WDFTIMER Timer
804)
805{
806PDEVICE_CONTEXT pContext = GetDeviceContext(WdfTimerGetParentObject(Timer));
807
808TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
809
810if (InterlockedIncrement(&pContext->SelectInProgress) == 1)
811{
812WdfWorkItemEnqueue(pContext->SelectWorkitem);
813}
814}
815
816static
817BOOLEAN
818VIOSockSelectCheckPkt(
819IN PVIOSOCK_SELECT_PKT pPkt
820)
821{
822ULONG i;
823PVIOSOCK_SELECT_HANDLE pHandleSet;
824PVIRTIO_VSOCK_FD_SET pFds;
825
826PAGED_CODE();
827
828TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
829
830pFds = &pPkt->pSelect->Fdss[FDSET_READ];
831pHandleSet = pPkt->Fds;
832
833pFds->fd_count = 0;
834for (i = 0; i < pPkt->FdCount[FDSET_READ]; ++i)
835{
836PSOCKET_CONTEXT pSocket = GetSocketContext(pHandleSet[i].Socket);
837if (pSocket->Events & (FD_ACCEPT | FD_READ | FD_CLOSE))
838{
839pFds->fd_array[pFds->fd_count++] = pHandleSet[i].hSocket;
840}
841}
842
843pFds = &pPkt->pSelect->Fdss[FDSET_WRITE];
844pHandleSet = &pPkt->Fds[pPkt->FdCount[FDSET_READ]];
845
846pFds->fd_count = 0;
847for (i = 0; i < pPkt->FdCount[FDSET_WRITE]; ++i)
848{
849PSOCKET_CONTEXT pSocket = GetSocketContext(pHandleSet[i].Socket);
850if (pSocket->Events & FD_WRITE ||
851(pSocket->Events & FD_CONNECT) && NT_SUCCESS(pSocket->EventsStatus[FD_CONNECT_BIT]))
852{
853pFds->fd_array[pFds->fd_count++] = pHandleSet[i].hSocket;
854}
855}
856
857pFds = &pPkt->pSelect->Fdss[FDSET_EXCPT];
858pHandleSet = &pPkt->Fds[pPkt->FdCount[FDSET_READ] + pPkt->FdCount[FDSET_WRITE]];
859
860pFds->fd_count = 0;
861for (i = 0; i < pPkt->FdCount[FDSET_EXCPT]; ++i)
862{
863PSOCKET_CONTEXT pSocket = GetSocketContext(pHandleSet[i].Socket);
864if ((pSocket->Events & FD_CONNECT) &&
865!NT_SUCCESS(pSocket->EventsStatus[FD_CONNECT_BIT]))
866{
867pFds->fd_array[pFds->fd_count++] = pHandleSet[i].hSocket;
868}
869}
870
871return pPkt->pSelect->Fdss[FDSET_READ].fd_count ||
872pPkt->pSelect->Fdss[FDSET_WRITE].fd_count ||
873pPkt->pSelect->Fdss[FDSET_EXCPT].fd_count;
874}
875
876static
877VOID
878VIOSockSelectCancel(
879IN WDFREQUEST Request
880)
881{
882PDEVICE_CONTEXT pContext = GetDeviceContextFromRequest(Request);
883
884TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
885
886if (InterlockedIncrement(&pContext->SelectInProgress) == 1)
887{
888WdfWorkItemEnqueue(pContext->SelectWorkitem);
889}
890}
891
892static
893VOID
894VIOSockSelectWorkitem(
895IN WDFWORKITEM Workitem
896)
897{
898PDEVICE_CONTEXT pContext = GetDeviceContext(WdfWorkItemGetParentObject(Workitem));
899
900PAGED_CODE();
901
902TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
903
904do
905{
906LIST_ENTRY CompletionList;
907WDFREQUEST Request;
908LONGLONG TimePassed, Timeout = LONGLONG_MAX;
909PLIST_ENTRY CurrentItem;
910BOOLEAN bRemove;
911
912InterlockedExchange(&pContext->SelectInProgress, 1);
913
914InitializeListHead(&CompletionList);
915
916WdfWaitLockAcquire(pContext->SelectLock, NULL);
917
918TimePassed = VIOSockTimerPassed(&pContext->SelectTimer);
919
920for (CurrentItem = pContext->SelectList.Flink;
921CurrentItem != &pContext->SelectList;
922CurrentItem = CurrentItem->Flink)
923{
924PVIOSOCK_SELECT_PKT pPkt = CONTAINING_RECORD(CurrentItem, VIOSOCK_SELECT_PKT, ListEntry);
925WDFREQUEST Request = WdfObjectContextGetObject(pPkt);
926NTSTATUS status = WdfRequestUnmarkCancelable(Request);
927
928ASSERT(NT_SUCCESS(status) || status == STATUS_CANCELLED);
929
930bRemove = FALSE;
931
932if (status == STATUS_CANCELLED)
933{
934bRemove = TRUE;
935pPkt->Status = STATUS_CANCELLED;
936}
937else if (VIOSockSelectCheckPkt(pPkt))
938{
939bRemove = TRUE;
940pPkt->Status = STATUS_SUCCESS;
941}
942else if (pPkt->Timeout)
943{
944if (pPkt->Timeout <= TimePassed + VIOSOCK_TIMER_TOLERANCE)
945{
946bRemove = TRUE;
947pPkt->Status = STATUS_IO_TIMEOUT;
948}
949else
950{
951pPkt->Timeout -= TimePassed;
952
953if (pPkt->Timeout < Timeout)
954Timeout = pPkt->Timeout;
955}
956}
957
958if (!bRemove)
959{
960status = WdfRequestMarkCancelableEx(Request, VIOSockSelectCancel);
961
962ASSERT(NT_SUCCESS(status) || status == STATUS_CANCELLED);
963
964if (status == STATUS_CANCELLED)
965{
966bRemove = TRUE;
967pPkt->Status = STATUS_CANCELLED;
968}
969}
970
971if (bRemove)
972{
973CurrentItem = pPkt->ListEntry.Blink;
974RemoveEntryList(&pPkt->ListEntry);
975InsertTailList(&CompletionList, &pPkt->ListEntry);
976if (pPkt->Timeout)
977VIOSockTimerDeref(&pContext->SelectTimer, TRUE);
978}
979}
980
981if(Timeout!=LONGLONG_MAX)
982VIOSockTimerSet(&pContext->SelectTimer, Timeout);
983
984WdfWaitLockRelease(pContext->SelectLock);
985
986while (!IsListEmpty(&CompletionList))
987{
988PVIOSOCK_SELECT_PKT pPkt = CONTAINING_RECORD(RemoveHeadList(&CompletionList), VIOSOCK_SELECT_PKT, ListEntry);
989
990VIOSockSelectCleanupPkt(pPkt);
991WdfRequestCompleteWithInformation(WdfObjectContextGetObject(pPkt), pPkt->Status, pPkt->Status == STATUS_SUCCESS ? sizeof(VIRTIO_VSOCK_SELECT) : 0);
992}
993
994} while (InterlockedCompareExchange(&pContext->SelectInProgress, 0, 1) != 1);
995
996TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "<-- %s\n", __FUNCTION__);
997}
998
999_IRQL_requires_max_(DISPATCH_LEVEL)
1000VOID
1001VIOSockSelectRun(
1002IN PSOCKET_CONTEXT pSocket
1003)
1004{
1005BOOLEAN bRun = FALSE;
1006PDEVICE_CONTEXT pContext = GetDeviceContextFromSocket(pSocket);
1007
1008TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
1009
1010if (pSocket->SelectRefs[FDSET_READ])
1011{
1012bRun |= pSocket->Events & (FD_ACCEPT | FD_READ | FD_CLOSE);
1013}
1014
1015if (pSocket->SelectRefs[FDSET_WRITE])
1016{
1017bRun |= pSocket->Events & FD_WRITE ||
1018(pSocket->Events & FD_CONNECT) && NT_SUCCESS(pSocket->EventsStatus[FD_CONNECT_BIT]);
1019}
1020
1021if (pSocket->SelectRefs[FDSET_EXCPT])
1022{
1023bRun |= (pSocket->Events & FD_CONNECT) &&
1024!NT_SUCCESS(pSocket->EventsStatus[FD_CONNECT_BIT]);
1025}
1026
1027if (bRun && InterlockedIncrement(&pContext->SelectInProgress) == 1)
1028{
1029TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "Enqueue workitem\n");
1030WdfWorkItemEnqueue(pContext->SelectWorkitem);
1031}
1032
1033}
1034
1035static
1036BOOLEAN
1037VIOSockSelectCopyFds(
1038IN PDEVICE_CONTEXT pContext,
1039IN BOOLEAN bIs32BitProcess,
1040IN PVIRTIO_VSOCK_SELECT pSelect,
1041IN PVIOSOCK_SELECT_PKT pPkt,
1042IN VIRTIO_VSOCK_FDSET_TYPE iFdSet,
1043IN ULONG uStartIndex
1044)
1045{
1046ULONG i;
1047PVIOSOCK_SELECT_HANDLE pHandleSet = &pPkt->Fds[uStartIndex];
1048
1049PAGED_CODE();
1050
1051pPkt->FdCount[iFdSet] = 0;
1052for (i = 0; i < pSelect->Fdss[iFdSet].fd_count; ++i)
1053{
1054ULONGLONG hSocket = pSelect->Fdss[iFdSet].fd_array[i];
1055if (hSocket)
1056{
1057WDFFILEOBJECT Socket = VIOSockGetSocketFromHandle(pContext, hSocket, bIs32BitProcess);
1058if (Socket != WDF_NO_HANDLE)
1059{
1060PSOCKET_CONTEXT pSocket = GetSocketContext(Socket);
1061
1062pHandleSet[i].hSocket = hSocket;
1063pHandleSet[i].Socket = Socket;
1064InterlockedIncrement(&pSocket->SelectRefs[iFdSet]); //reference socket
1065}
1066else
1067break;
1068}
1069else
1070break;
1071}
1072
1073pPkt->FdCount[iFdSet] = i;
1074
1075return i == pSelect->Fdss[iFdSet].fd_count;
1076}
1077
1078static
1079NTSTATUS
1080VIOSockSelect(
1081IN WDFREQUEST Request,
1082IN OUT size_t *pLength
1083)
1084{
1085PDEVICE_CONTEXT pContext = GetDeviceContextFromRequest(Request);
1086PVIRTIO_VSOCK_SELECT pSelect;
1087SIZE_T stSelectLen;
1088NTSTATUS status;
1089BOOLEAN bIs32BitProcess = FALSE;
1090WDF_OBJECT_ATTRIBUTES Attributes;
1091PVIOSOCK_SELECT_PKT pPkt = NULL;
1092
1093PAGED_CODE();
1094
1095TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
1096
1097*pLength = 0;
1098
1099status = WdfRequestRetrieveInputBuffer(Request, sizeof(*pSelect), &pSelect, &stSelectLen);
1100if (!NT_SUCCESS(status))
1101{
1102TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT, "WdfRequestRetrieveInputBuffer failed: 0x%x\n", status);
1103return status;
1104}
1105
1106// minimum length guaranteed by WdfRequestRetrieveInputBuffer above
1107_Analysis_assume_(stSelectLen >= sizeof(*pSelect));
1108
1109status = WdfRequestRetrieveOutputBuffer(Request, sizeof(*pSelect), &pSelect, &stSelectLen);
1110if (!NT_SUCCESS(status))
1111{
1112TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT, "WdfRequestRetrieveOutputBuffer failed: 0x%x\n", status);
1113return status;
1114}
1115
1116// minimum length guaranteed by WdfRequestRetrieveInputBuffer above
1117_Analysis_assume_(stSelectLen >= sizeof(*pSelect));
1118
1119if (FD_SETSIZE < pSelect->Fdss[FDSET_READ].fd_count +
1120pSelect->Fdss[FDSET_WRITE].fd_count +
1121pSelect->Fdss[FDSET_EXCPT].fd_count)
1122{
1123return STATUS_INVALID_PARAMETER;
1124}
1125
1126#ifdef _WIN64
1127bIs32BitProcess = WdfRequestIsFrom32BitProcess(Request);
1128#endif //_WIN64
1129
1130WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
1131&Attributes,
1132VIOSOCK_SELECT_PKT
1133);
1134
1135status = WdfObjectAllocateContext(Request, &Attributes, &pPkt);
1136if (!NT_SUCCESS(status))
1137{
1138TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT, "WdfObjectAllocateContext failed: 0x%x\n", status);
1139return status;
1140}
1141
1142pPkt->pSelect = pSelect;
1143
1144if (!VIOSockSelectCopyFds(pContext, bIs32BitProcess, pSelect, pPkt, FDSET_READ, 0) ||
1145!VIOSockSelectCopyFds(pContext, bIs32BitProcess, pSelect, pPkt, FDSET_WRITE, pPkt->FdCount[FDSET_READ]) ||
1146!VIOSockSelectCopyFds(pContext, bIs32BitProcess, pSelect, pPkt, FDSET_EXCPT,
1147pPkt->FdCount[FDSET_READ] + pPkt->FdCount[FDSET_WRITE]))
1148{
1149TraceEvents(TRACE_LEVEL_WARNING, DBG_SELECT, "VIOSockSelectCopyFds failed\n");
1150status = STATUS_INVALID_HANDLE;
1151}
1152
1153if (NT_SUCCESS(status))
1154{
1155WdfWaitLockAcquire(pContext->SelectLock, NULL);
1156
1157pPkt->Status = status = VIOSockSelectCheckPkt(pPkt) ? STATUS_SUCCESS : STATUS_PENDING;
1158
1159if (status == STATUS_PENDING)
1160{
1161status = WdfRequestMarkCancelableEx(Request, VIOSockSelectCancel);
1162
1163ASSERT(NT_SUCCESS(status) || status == STATUS_CANCELLED);
1164
1165if (NT_SUCCESS(status))
1166{
1167status = STATUS_PENDING;
1168
1169InsertTailList(&pContext->SelectList, &pPkt->ListEntry);
1170pPkt->Timeout = pSelect->Timeout;
1171
1172if (pPkt->Timeout)
1173VIOSockTimerStart(&pContext->SelectTimer, pPkt->Timeout);
1174}
1175}
1176else
1177*pLength = sizeof(*pSelect);
1178
1179WdfWaitLockRelease(pContext->SelectLock);
1180}
1181
1182if (status != STATUS_PENDING)
1183VIOSockSelectCleanupPkt(pPkt);
1184
1185TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "<-- %s\n", __FUNCTION__);
1186
1187return status;
1188}
1189