VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.cpp@ 89361

Last change on this file since 89361 was 85121, checked in by vboxsync, 5 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.7 KB
Line 
1/* $Id: VBoxMPCm.cpp 85121 2020-07-08 19:33:26Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver
4 */
5
6/*
7 * Copyright (C) 2011-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "VBoxMPWddm.h"
19
20typedef struct VBOXVIDEOCM_CMD_DR
21{
22 LIST_ENTRY QueueList;
23 PVBOXVIDEOCM_CTX pContext;
24 uint32_t cbMaxCmdSize;
25 volatile uint32_t cRefs;
26
27 VBOXVIDEOCM_CMD_HDR CmdHdr;
28} VBOXVIDEOCM_CMD_DR, *PVBOXVIDEOCM_CMD_DR;
29
30typedef enum
31{
32 VBOXVIDEOCM_CMD_CTL_KM_TYPE_POST_INVOKE = 1,
33 VBOXVIDEOCM_CMD_CTL_KM_TYPE_PRE_INVOKE,
34 VBOXVIDEOCM_CMD_CTL_KM_TYPE_DUMMY_32BIT = 0x7fffffff
35} VBOXVIDEOCM_CMD_CTL_KM_TYPE;
36
37typedef DECLCALLBACKTYPE(VOID, FNVBOXVIDEOCM_CMD_CB,(PVBOXVIDEOCM_CTX pContext, struct VBOXVIDEOCM_CMD_CTL_KM *pCmd,
38 PVOID pvContext));
39typedef FNVBOXVIDEOCM_CMD_CB *PFNVBOXVIDEOCM_CMD_CB;
40
41typedef struct VBOXVIDEOCM_CMD_CTL_KM
42{
43 VBOXVIDEOCM_CMD_CTL_KM_TYPE enmType;
44 uint32_t u32Reserved;
45 PFNVBOXVIDEOCM_CMD_CB pfnCb;
46 PVOID pvCb;
47} VBOXVIDEOCM_CMD_CTL_KM, *PVBOXVIDEOCM_CMD_CTL_KM;
48
49AssertCompile(VBOXWDDM_ROUNDBOUND(RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, CmdHdr), 8) == RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, CmdHdr));
50
51#define VBOXVIDEOCM_HEADER_SIZE() (VBOXWDDM_ROUNDBOUND(sizeof (VBOXVIDEOCM_CMD_DR), 8))
52#define VBOXVIDEOCM_SIZE_FROMBODYSIZE(_s) (VBOXVIDEOCM_HEADER_SIZE() + (_s))
53//#define VBOXVIDEOCM_SIZE(_t) (VBOXVIDEOCM_SIZE_FROMBODYSIZE(sizeof (_t)))
54#define VBOXVIDEOCM_BODY(_pCmd, _t) ( (_t*)(((uint8_t*)(_pCmd)) + VBOXVIDEOCM_HEADER_SIZE()) )
55#define VBOXVIDEOCM_HEAD(_pCmd) ( (PVBOXVIDEOCM_CMD_DR)(((uint8_t*)(_pCmd)) - VBOXVIDEOCM_HEADER_SIZE()) )
56
57#define VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(_s) ( VBOXVIDEOCM_SIZE_FROMBODYSIZE(_s) - RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, CmdHdr))
58
59//#define VBOXVIDEOCM_BODY_FIELD_OFFSET(_ot, _t, _f) ( (_ot)( VBOXVIDEOCM_BODY(0, uint8_t) + RT_OFFSETOF(_t, _f) ) )
60
61typedef struct VBOXVIDEOCM_SESSION
62{
63 /* contexts in this session */
64 LIST_ENTRY QueueEntry;
65 /* contexts in this session */
66 LIST_ENTRY ContextList;
67 /* commands list */
68 LIST_ENTRY CommandsList;
69 /* post process commands list */
70 LIST_ENTRY PpCommandsList;
71 /* event used to notify UMD about pending commands */
72 PKEVENT pUmEvent;
73 /* sync lock */
74 KSPIN_LOCK SynchLock;
75 /* indicates whether event signaling is needed on cmd add */
76 bool bEventNeeded;
77} VBOXVIDEOCM_SESSION, *PVBOXVIDEOCM_SESSION;
78
79#define VBOXCMENTRY_2_CMD(_pE) ((PVBOXVIDEOCM_CMD_DR)((uint8_t*)(_pE) - RT_UOFFSETOF(VBOXVIDEOCM_CMD_DR, QueueList)))
80
81void* vboxVideoCmCmdReinitForContext(void *pvCmd, PVBOXVIDEOCM_CTX pContext)
82{
83 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
84 pHdr->pContext = pContext;
85 pHdr->CmdHdr.u64UmData = pContext->u64UmData;
86 return pvCmd;
87}
88
89void* vboxVideoCmCmdCreate(PVBOXVIDEOCM_CTX pContext, uint32_t cbSize)
90{
91 Assert(cbSize);
92 if (!cbSize)
93 return NULL;
94
95 Assert(VBOXWDDM_ROUNDBOUND(cbSize, 8) == cbSize);
96 cbSize = VBOXWDDM_ROUNDBOUND(cbSize, 8);
97
98 Assert(pContext->pSession);
99 if (!pContext->pSession)
100 return NULL;
101
102 uint32_t cbCmd = VBOXVIDEOCM_SIZE_FROMBODYSIZE(cbSize);
103 PVBOXVIDEOCM_CMD_DR pCmd = (PVBOXVIDEOCM_CMD_DR)vboxWddmMemAllocZero(cbCmd);
104 Assert(pCmd);
105 if (pCmd)
106 {
107 InitializeListHead(&pCmd->QueueList);
108 pCmd->pContext = pContext;
109 pCmd->cbMaxCmdSize = VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(cbSize);
110 pCmd->cRefs = 1;
111 pCmd->CmdHdr.u64UmData = pContext->u64UmData;
112 pCmd->CmdHdr.cbCmd = pCmd->cbMaxCmdSize;
113 }
114 return VBOXVIDEOCM_BODY(pCmd, void);
115}
116
117static PVBOXVIDEOCM_CMD_CTL_KM vboxVideoCmCmdCreateKm(PVBOXVIDEOCM_CTX pContext, VBOXVIDEOCM_CMD_CTL_KM_TYPE enmType,
118 PFNVBOXVIDEOCM_CMD_CB pfnCb, PVOID pvCb,
119 uint32_t cbSize)
120{
121 PVBOXVIDEOCM_CMD_CTL_KM pCmd = (PVBOXVIDEOCM_CMD_CTL_KM)vboxVideoCmCmdCreate(pContext, cbSize + sizeof (*pCmd));
122 pCmd->enmType = enmType;
123 pCmd->pfnCb = pfnCb;
124 pCmd->pvCb = pvCb;
125 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pCmd);
126 pHdr->CmdHdr.enmType = VBOXVIDEOCM_CMD_TYPE_CTL_KM;
127 return pCmd;
128}
129
130static DECLCALLBACK(VOID) vboxVideoCmCmdCbSetEventAndDereference(PVBOXVIDEOCM_CTX pContext, PVBOXVIDEOCM_CMD_CTL_KM pCmd,
131 PVOID pvContext)
132{
133 RT_NOREF(pContext);
134 PKEVENT pEvent = (PKEVENT)pvContext;
135 KeSetEvent(pEvent, 0, FALSE);
136 ObDereferenceObject(pEvent);
137 vboxVideoCmCmdRelease(pCmd);
138}
139
140NTSTATUS vboxVideoCmCmdSubmitCompleteEvent(PVBOXVIDEOCM_CTX pContext, PKEVENT pEvent)
141{
142 Assert(pEvent);
143 PVBOXVIDEOCM_CMD_CTL_KM pCmd = vboxVideoCmCmdCreateKm(pContext, VBOXVIDEOCM_CMD_CTL_KM_TYPE_POST_INVOKE,
144 vboxVideoCmCmdCbSetEventAndDereference, pEvent, 0);
145 if (!pCmd)
146 {
147 WARN(("vboxVideoCmCmdCreateKm failed"));
148 return STATUS_NO_MEMORY;
149 }
150
151 vboxVideoCmCmdSubmit(pCmd, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
152
153 return STATUS_SUCCESS;
154}
155
156DECLINLINE(void) vboxVideoCmCmdRetainByHdr(PVBOXVIDEOCM_CMD_DR pHdr)
157{
158 ASMAtomicIncU32(&pHdr->cRefs);
159}
160
161DECLINLINE(void) vboxVideoCmCmdReleaseByHdr(PVBOXVIDEOCM_CMD_DR pHdr)
162{
163 uint32_t cRefs = ASMAtomicDecU32(&pHdr->cRefs);
164 Assert(cRefs < UINT32_MAX/2);
165 if (!cRefs)
166 vboxWddmMemFree(pHdr);
167}
168
169static void vboxVideoCmCmdCancel(PVBOXVIDEOCM_CMD_DR pHdr)
170{
171 InitializeListHead(&pHdr->QueueList);
172 vboxVideoCmCmdReleaseByHdr(pHdr);
173}
174
175static void vboxVideoCmCmdPostByHdr(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CMD_DR pHdr, uint32_t cbSize)
176{
177 bool bSignalEvent = false;
178 if (cbSize != VBOXVIDEOCM_SUBMITSIZE_DEFAULT)
179 {
180 cbSize = VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(cbSize);
181 Assert(cbSize <= pHdr->cbMaxCmdSize);
182 pHdr->CmdHdr.cbCmd = cbSize;
183 }
184
185 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
186
187 KIRQL OldIrql;
188 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
189
190 InsertHeadList(&pSession->CommandsList, &pHdr->QueueList);
191 if (pSession->bEventNeeded)
192 {
193 pSession->bEventNeeded = false;
194 bSignalEvent = true;
195 }
196
197 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
198
199 if (bSignalEvent)
200 KeSetEvent(pSession->pUmEvent, 0, FALSE);
201}
202
203void vboxVideoCmCmdRetain(void *pvCmd)
204{
205 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
206 vboxVideoCmCmdRetainByHdr(pHdr);
207}
208
209void vboxVideoCmCmdRelease(void *pvCmd)
210{
211 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
212 vboxVideoCmCmdReleaseByHdr(pHdr);
213}
214
215/**
216 * @param pvCmd memory buffer returned by vboxVideoCmCmdCreate
217 * @param cbSize should be <= cbSize posted to vboxVideoCmCmdCreate on command creation
218 */
219void vboxVideoCmCmdSubmit(void *pvCmd, uint32_t cbSize)
220{
221 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
222 vboxVideoCmCmdPostByHdr(pHdr->pContext->pSession, pHdr, cbSize);
223}
224
225NTSTATUS vboxVideoCmCmdVisit(PVBOXVIDEOCM_CTX pContext, BOOLEAN bEntireSession, PFNVBOXVIDEOCMCMDVISITOR pfnVisitor,
226 PVOID pvVisitor)
227{
228 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
229 PLIST_ENTRY pCurEntry = NULL;
230 PVBOXVIDEOCM_CMD_DR pHdr;
231
232 KIRQL OldIrql;
233 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
234
235 pCurEntry = pSession->CommandsList.Blink;
236 do
237 {
238 if (pCurEntry != &pSession->CommandsList)
239 {
240 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
241 pCurEntry = pHdr->QueueList.Blink;
242 if (bEntireSession || pHdr->pContext == pContext)
243 {
244 if (pHdr->CmdHdr.enmType == VBOXVIDEOCM_CMD_TYPE_UM)
245 {
246 void * pvBody = VBOXVIDEOCM_BODY(pHdr, void);
247 UINT fRet = pfnVisitor(pHdr->pContext, pvBody, pHdr->CmdHdr.cbCmd, pvVisitor);
248 if (fRet & VBOXVIDEOCMCMDVISITOR_RETURN_RMCMD)
249 {
250 RemoveEntryList(&pHdr->QueueList);
251 }
252 if ((fRet & VBOXVIDEOCMCMDVISITOR_RETURN_BREAK))
253 break;
254 }
255 else
256 {
257 WARN(("non-um cmd on visit, skipping"));
258 }
259 }
260 }
261 else
262 {
263 break;
264 }
265 } while (1);
266
267
268 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
269
270 return STATUS_SUCCESS;
271}
272
273void vboxVideoCmCtxInitEmpty(PVBOXVIDEOCM_CTX pContext)
274{
275 InitializeListHead(&pContext->SessionEntry);
276 pContext->pSession = NULL;
277 pContext->u64UmData = 0ULL;
278}
279
280static void vboxVideoCmSessionCtxAddLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
281{
282 InsertHeadList(&pSession->ContextList, &pContext->SessionEntry);
283 pContext->pSession = pSession;
284}
285
286void vboxVideoCmSessionCtxAdd(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
287{
288 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
289 KIRQL OldIrql;
290 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
291
292 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
293
294 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
295}
296
297void vboxVideoCmSessionSignalEvent(PVBOXVIDEOCM_SESSION pSession)
298{
299 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
300 if (pSession->pUmEvent)
301 KeSetEvent(pSession->pUmEvent, 0, FALSE);
302}
303
304static void vboxVideoCmSessionDestroyLocked(PVBOXVIDEOCM_SESSION pSession)
305{
306 /* signal event so that user-space client can figure out the context is destroyed
307 * in case the context destroyal is caused by Graphics device reset or miniport driver update */
308 KeSetEvent(pSession->pUmEvent, 0, FALSE);
309 ObDereferenceObject(pSession->pUmEvent);
310 Assert(IsListEmpty(&pSession->ContextList));
311 Assert(IsListEmpty(&pSession->CommandsList));
312 Assert(IsListEmpty(&pSession->PpCommandsList));
313 RemoveEntryList(&pSession->QueueEntry);
314 vboxWddmMemFree(pSession);
315}
316
317static void vboxVideoCmSessionCtxPpList(PVBOXVIDEOCM_CTX pContext, PLIST_ENTRY pHead)
318{
319 LIST_ENTRY *pCur;
320 for (pCur = pHead->Flink; pCur != pHead; pCur = pHead->Flink)
321 {
322 RemoveEntryList(pCur);
323 PVBOXVIDEOCM_CMD_DR pHdr = VBOXCMENTRY_2_CMD(pCur);
324 PVBOXVIDEOCM_CMD_CTL_KM pCmd = VBOXVIDEOCM_BODY(pHdr, VBOXVIDEOCM_CMD_CTL_KM);
325 pCmd->pfnCb(pContext, pCmd, pCmd->pvCb);
326 }
327}
328
329static void vboxVideoCmSessionCtxDetachCmdsLocked(PLIST_ENTRY pEntriesHead, PVBOXVIDEOCM_CTX pContext, PLIST_ENTRY pDstHead)
330{
331 LIST_ENTRY *pCur;
332 LIST_ENTRY *pPrev;
333 pCur = pEntriesHead->Flink;
334 pPrev = pEntriesHead;
335 while (pCur != pEntriesHead)
336 {
337 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
338 if (pCmd->pContext == pContext)
339 {
340 RemoveEntryList(pCur);
341 InsertTailList(pDstHead, pCur);
342 pCur = pPrev;
343 /* pPrev - remains unchanged */
344 }
345 else
346 {
347 pPrev = pCur;
348 }
349 pCur = pCur->Flink;
350 }
351}
352/**
353 * @return true iff the given session is destroyed
354 */
355bool vboxVideoCmSessionCtxRemoveLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
356{
357 bool bDestroy;
358 LIST_ENTRY RemainedList;
359 LIST_ENTRY RemainedPpList;
360 LIST_ENTRY *pCur;
361 InitializeListHead(&RemainedList);
362 InitializeListHead(&RemainedPpList);
363 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
364 KIRQL OldIrql;
365 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
366
367 pContext->pSession = NULL;
368 RemoveEntryList(&pContext->SessionEntry);
369 bDestroy = !!(IsListEmpty(&pSession->ContextList));
370 /* ensure there are no commands left for the given context */
371 if (bDestroy)
372 {
373 vboxVideoLeDetach(&pSession->CommandsList, &RemainedList);
374 vboxVideoLeDetach(&pSession->PpCommandsList, &RemainedPpList);
375 }
376 else
377 {
378 vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->CommandsList, pContext, &RemainedList);
379 vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->PpCommandsList, pContext, &RemainedPpList);
380 }
381
382 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
383
384 for (pCur = RemainedList.Flink; pCur != &RemainedList; pCur = RemainedList.Flink)
385 {
386 RemoveEntryList(pCur);
387 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
388 vboxVideoCmCmdCancel(pCmd);
389 }
390
391 vboxVideoCmSessionCtxPpList(pContext, &RemainedPpList);
392
393 if (bDestroy)
394 {
395 vboxVideoCmSessionDestroyLocked(pSession);
396 }
397
398 return bDestroy;
399}
400
401/* the session gets destroyed once the last context is removed from it */
402NTSTATUS vboxVideoCmSessionCreateLocked(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_SESSION *ppSession, PKEVENT pUmEvent,
403 PVBOXVIDEOCM_CTX pContext)
404{
405 NTSTATUS Status = STATUS_UNSUCCESSFUL;
406 PVBOXVIDEOCM_SESSION pSession = (PVBOXVIDEOCM_SESSION)vboxWddmMemAllocZero(sizeof (VBOXVIDEOCM_SESSION));
407 Assert(pSession);
408 if (pSession)
409 {
410 InitializeListHead(&pSession->ContextList);
411 InitializeListHead(&pSession->CommandsList);
412 InitializeListHead(&pSession->PpCommandsList);
413 pSession->pUmEvent = pUmEvent;
414 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
415 KeInitializeSpinLock(&pSession->SynchLock);
416 pSession->bEventNeeded = true;
417 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
418 InsertHeadList(&pMgr->SessionList, &pSession->QueueEntry);
419 *ppSession = pSession;
420 return STATUS_SUCCESS;
421// vboxWddmMemFree(pSession);
422 }
423 else
424 {
425 Status = STATUS_NO_MEMORY;
426 }
427 return Status;
428}
429
430#define VBOXCMENTRY_2_SESSION(_pE) ((PVBOXVIDEOCM_SESSION)((uint8_t*)(_pE) - RT_UOFFSETOF(VBOXVIDEOCM_SESSION, QueueEntry)))
431
432NTSTATUS vboxVideoCmCtxAdd(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext, HANDLE hUmEvent, uint64_t u64UmData)
433{
434 PKEVENT pUmEvent = NULL;
435 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
436 NTSTATUS Status = ObReferenceObjectByHandle(hUmEvent, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
437 (PVOID*)&pUmEvent,
438 NULL);
439 AssertNtStatusSuccess(Status);
440 if (Status == STATUS_SUCCESS)
441 {
442 KIRQL OldIrql;
443 KeAcquireSpinLock(&pMgr->SynchLock, &OldIrql);
444
445 bool bFound = false;
446 PVBOXVIDEOCM_SESSION pSession = NULL;
447 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
448 {
449 pSession = VBOXCMENTRY_2_SESSION(pEntry);
450 if (pSession->pUmEvent == pUmEvent)
451 {
452 bFound = true;
453 break;
454 }
455 }
456
457 pContext->u64UmData = u64UmData;
458
459 if (!bFound)
460 {
461 Status = vboxVideoCmSessionCreateLocked(pMgr, &pSession, pUmEvent, pContext);
462 AssertNtStatusSuccess(Status);
463 }
464 else
465 {
466 /* Status = */vboxVideoCmSessionCtxAdd(pSession, pContext);
467 /*AssertNtStatusSuccess(Status);*/
468 }
469
470 KeReleaseSpinLock(&pMgr->SynchLock, OldIrql);
471
472 if (Status == STATUS_SUCCESS)
473 {
474 return STATUS_SUCCESS;
475 }
476
477 ObDereferenceObject(pUmEvent);
478 }
479 return Status;
480}
481
482NTSTATUS vboxVideoCmCtxRemove(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext)
483{
484 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
485 if (!pSession)
486 return STATUS_SUCCESS;
487
488 KIRQL OldIrql;
489 KeAcquireSpinLock(&pMgr->SynchLock, &OldIrql);
490
491 vboxVideoCmSessionCtxRemoveLocked(pSession, pContext);
492
493 KeReleaseSpinLock(&pMgr->SynchLock, OldIrql);
494
495 return STATUS_SUCCESS;
496}
497
498NTSTATUS vboxVideoCmInit(PVBOXVIDEOCM_MGR pMgr)
499{
500 KeInitializeSpinLock(&pMgr->SynchLock);
501 InitializeListHead(&pMgr->SessionList);
502 return STATUS_SUCCESS;
503}
504
505NTSTATUS vboxVideoCmTerm(PVBOXVIDEOCM_MGR pMgr)
506{
507 RT_NOREF(pMgr);
508 Assert(IsListEmpty(&pMgr->SessionList));
509 return STATUS_SUCCESS;
510}
511
512NTSTATUS vboxVideoCmSignalEvents(PVBOXVIDEOCM_MGR pMgr)
513{
514 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
515 PVBOXVIDEOCM_SESSION pSession = NULL;
516
517 KIRQL OldIrql;
518 KeAcquireSpinLock(&pMgr->SynchLock, &OldIrql);
519
520 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
521 {
522 pSession = VBOXCMENTRY_2_SESSION(pEntry);
523 vboxVideoCmSessionSignalEvent(pSession);
524 }
525
526 KeReleaseSpinLock(&pMgr->SynchLock, OldIrql);
527
528 return STATUS_SUCCESS;
529}
530
531VOID vboxVideoCmProcessKm(PVBOXVIDEOCM_CTX pContext, PVBOXVIDEOCM_CMD_CTL_KM pCmd)
532{
533 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
534
535 switch (pCmd->enmType)
536 {
537 case VBOXVIDEOCM_CMD_CTL_KM_TYPE_PRE_INVOKE:
538 {
539 pCmd->pfnCb(pContext, pCmd, pCmd->pvCb);
540 break;
541 }
542
543 case VBOXVIDEOCM_CMD_CTL_KM_TYPE_POST_INVOKE:
544 {
545 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pCmd);
546 KIRQL OldIrql;
547 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
548 InsertTailList(&pSession->PpCommandsList, &pHdr->QueueList);
549 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
550 break;
551 }
552
553 default:
554 {
555 WARN(("unsupported cmd type %d", pCmd->enmType));
556 break;
557 }
558 }
559}
560
561NTSTATUS vboxVideoCmEscape(PVBOXVIDEOCM_CTX pContext, PVBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD pCmd, uint32_t cbCmd)
562{
563 Assert(cbCmd >= sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD));
564 if (cbCmd < sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD))
565 return STATUS_BUFFER_TOO_SMALL;
566
567 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
568 PVBOXVIDEOCM_CMD_DR pHdr;
569 LIST_ENTRY DetachedList;
570 LIST_ENTRY DetachedPpList;
571 PLIST_ENTRY pCurEntry = NULL;
572 uint32_t cbRemainingCmds = 0;
573 uint32_t cbRemainingFirstCmd = 0;
574 uint32_t cbData = cbCmd - sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
575 uint8_t * pvData = ((uint8_t *)pCmd) + sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
576 bool bDetachMode = true;
577 InitializeListHead(&DetachedList);
578 InitializeListHead(&DetachedPpList);
579// PVBOXWDDM_GETVBOXVIDEOCMCMD_HDR *pvCmd
580
581 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
582 KIRQL OldIrql;
583 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
584
585 vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->PpCommandsList, pContext, &DetachedPpList);
586
587 do
588 {
589 if (bDetachMode)
590 {
591 if (!IsListEmpty(&pSession->CommandsList))
592 {
593 Assert(!pCurEntry);
594 pHdr = VBOXCMENTRY_2_CMD(pSession->CommandsList.Blink);
595 Assert(pHdr->CmdHdr.cbCmd);
596 uint32_t cbUserCmd = pHdr->CmdHdr.enmType == VBOXVIDEOCM_CMD_TYPE_UM ? pHdr->CmdHdr.cbCmd : 0;
597 if (cbData >= cbUserCmd)
598 {
599 RemoveEntryList(&pHdr->QueueList);
600 InsertHeadList(&DetachedList, &pHdr->QueueList);
601 cbData -= cbUserCmd;
602 }
603 else
604 {
605 Assert(cbUserCmd);
606 cbRemainingFirstCmd = cbUserCmd;
607 cbRemainingCmds = cbUserCmd;
608 pCurEntry = pHdr->QueueList.Blink;
609 bDetachMode = false;
610 }
611 }
612 else
613 {
614 pSession->bEventNeeded = true;
615 break;
616 }
617 }
618 else
619 {
620 Assert(pCurEntry);
621 if (pCurEntry != &pSession->CommandsList)
622 {
623 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
624 uint32_t cbUserCmd = pHdr->CmdHdr.enmType == VBOXVIDEOCM_CMD_TYPE_UM ? pHdr->CmdHdr.cbCmd : 0;
625 Assert(cbRemainingFirstCmd);
626 cbRemainingCmds += cbUserCmd;
627 pCurEntry = pHdr->QueueList.Blink;
628 }
629 else
630 {
631 Assert(cbRemainingFirstCmd);
632 Assert(cbRemainingCmds);
633 break;
634 }
635 }
636 } while (1);
637
638 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
639
640 vboxVideoCmSessionCtxPpList(pContext, &DetachedPpList);
641
642 pCmd->Hdr.cbCmdsReturned = 0;
643 for (pCurEntry = DetachedList.Blink; pCurEntry != &DetachedList; pCurEntry = DetachedList.Blink)
644 {
645 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
646 RemoveEntryList(pCurEntry);
647 switch (pHdr->CmdHdr.enmType)
648 {
649 case VBOXVIDEOCM_CMD_TYPE_UM:
650 {
651 memcpy(pvData, &pHdr->CmdHdr, pHdr->CmdHdr.cbCmd);
652 pvData += pHdr->CmdHdr.cbCmd;
653 pCmd->Hdr.cbCmdsReturned += pHdr->CmdHdr.cbCmd;
654 vboxVideoCmCmdReleaseByHdr(pHdr);
655 break;
656 }
657
658 case VBOXVIDEOCM_CMD_TYPE_CTL_KM:
659 {
660 vboxVideoCmProcessKm(pContext, VBOXVIDEOCM_BODY(pHdr, VBOXVIDEOCM_CMD_CTL_KM));
661 break;
662 }
663
664 default:
665 {
666 WARN(("unsupported cmd type %d", pHdr->CmdHdr.enmType));
667 break;
668 }
669 }
670 }
671
672 pCmd->Hdr.cbRemainingCmds = cbRemainingCmds;
673 pCmd->Hdr.cbRemainingFirstCmd = cbRemainingFirstCmd;
674 pCmd->Hdr.u32Reserved = 0;
675
676 return STATUS_SUCCESS;
677}
678
679static BOOLEAN vboxVideoCmHasUncompletedCmdsLocked(PVBOXVIDEOCM_MGR pMgr)
680{
681 PVBOXVIDEOCM_SESSION pSession = NULL;
682 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
683 {
684 pSession = VBOXCMENTRY_2_SESSION(pEntry);
685 KIRQL OldIrql;
686 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
687
688 if (pSession->bEventNeeded)
689 {
690 /* commands still being processed */
691 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
692 return TRUE;
693 }
694 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
695 }
696 return FALSE;
697}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette