VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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