VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA_VDMA.cpp@ 33875

Last change on this file since 33875 was 33823, checked in by vboxsync, 14 years ago

wddm/3d: disable debug assertion

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.2 KB
Line 
1/** @file
2 * Video DMA (VDMA) support.
3 */
4
5/*
6 * Copyright (C) 2006-2009 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16//#include <VBox/VMMDev.h>
17#include <VBox/pdmdev.h>
18#include <VBox/VBoxVideo.h>
19#include <iprt/semaphore.h>
20#include <iprt/thread.h>
21#include <iprt/mem.h>
22#include <iprt/asm.h>
23
24#include "DevVGA.h"
25#include "HGSMI/SHGSMIHost.h"
26#include "HGSMI/HGSMIHostHlp.h"
27
28#ifdef VBOX_VDMA_WITH_WORKERTHREAD
29typedef enum
30{
31 VBOXVDMAPIPE_STATE_CLOSED = 0,
32 VBOXVDMAPIPE_STATE_CREATED = 1,
33 VBOXVDMAPIPE_STATE_OPENNED = 2,
34 VBOXVDMAPIPE_STATE_CLOSING = 3
35} VBOXVDMAPIPE_STATE;
36
37typedef struct VBOXVDMAPIPE
38{
39 RTSEMEVENT hEvent;
40 /* critical section for accessing pipe properties */
41 RTCRITSECT hCritSect;
42 VBOXVDMAPIPE_STATE enmState;
43 /* true iff the other end needs Event notification */
44 bool bNeedNotify;
45} VBOXVDMAPIPE, *PVBOXVDMAPIPE;
46
47typedef enum
48{
49 VBOXVDMAPIPE_CMD_TYPE_UNDEFINED = 0,
50 VBOXVDMAPIPE_CMD_TYPE_DMACMD = 1,
51 VBOXVDMAPIPE_CMD_TYPE_DMACTL = 2
52} VBOXVDMAPIPE_CMD_TYPE;
53
54typedef struct VBOXVDMAPIPE_CMD_BODY
55{
56 VBOXVDMAPIPE_CMD_TYPE enmType;
57 union
58 {
59 PVBOXVDMACBUF_DR pDr;
60 PVBOXVDMA_CTL pCtl;
61 void *pvCmd;
62 } u;
63}VBOXVDMAPIPE_CMD_BODY, *PVBOXVDMAPIPE_CMD_BODY;
64
65typedef struct VBOXVDMAPIPE_CMD
66{
67 HGSMILISTENTRY Entry;
68 VBOXVDMAPIPE_CMD_BODY Cmd;
69} VBOXVDMAPIPE_CMD, *PVBOXVDMAPIPE_CMD;
70
71#define VBOXVDMAPIPE_CMD_FROM_ENTRY(_pE) ( (PVBOXVDMAPIPE_CMD)((uint8_t *)(_pE) - RT_OFFSETOF(VBOXVDMAPIPE_CMD, Entry)) )
72
73typedef struct VBOXVDMAPIPE_CMD_POOL
74{
75 HGSMILIST List;
76 uint32_t cCmds;
77 VBOXVDMAPIPE_CMD aCmds[1];
78} VBOXVDMAPIPE_CMD_POOL, *PVBOXVDMAPIPE_CMD_POOL;
79#endif
80
81typedef struct VBOXVDMAHOST
82{
83 PHGSMIINSTANCE pHgsmi;
84 PVGASTATE pVGAState;
85 bool bEnabled;
86#ifdef VBOX_VDMA_WITH_WORKERTHREAD
87 VBOXVDMAPIPE Pipe;
88 HGSMILIST PendingList;
89 RTTHREAD hWorkerThread;
90 VBOXVDMAPIPE_CMD_POOL CmdPool;
91#endif
92} VBOXVDMAHOST, *PVBOXVDMAHOST;
93
94
95#ifdef VBOX_WITH_CRHGSMI
96
97typedef DECLCALLBACK(void) FNVBOXVDMACRCTL_CALLBACK(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext);
98typedef FNVBOXVDMACRCTL_CALLBACK *PFNVBOXVDMACRCTL_CALLBACK;
99
100typedef struct VBOXVDMACMD_CHROMIUM_CTL_PRIVATE
101{
102 uint32_t cRefs;
103 uint32_t rc;
104 PFNVBOXVDMACRCTL_CALLBACK pfnCompletion;
105 void *pvCompletion;
106 VBOXVDMACMD_CHROMIUM_CTL Cmd;
107} VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, *PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE;
108
109#define VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(_p) ((PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, Cmd)))
110
111static PVBOXVDMACMD_CHROMIUM_CTL vboxVDMACrCtlCreate(VBOXVDMACMD_CHROMIUM_CTL_TYPE enmCmd, uint32_t cbCmd)
112{
113 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = (PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE)RTMemAllocZ(cbCmd + RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, Cmd));
114 Assert(pHdr);
115 if (pHdr)
116 {
117 pHdr->cRefs = 1;
118 pHdr->rc = VERR_NOT_IMPLEMENTED;
119 pHdr->Cmd.enmType = enmCmd;
120 pHdr->Cmd.cbCmd = cbCmd;
121 return &pHdr->Cmd;
122 }
123
124 return NULL;
125}
126
127DECLINLINE(void) vboxVDMACrCtlRelease (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
128{
129 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
130 uint32_t cRefs = ASMAtomicDecU32(&pHdr->cRefs);
131 if(!cRefs)
132 {
133 RTMemFree(pHdr);
134 }
135}
136
137DECLINLINE(void) vboxVDMACrCtlRetain (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
138{
139 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
140 ASMAtomicIncU32(&pHdr->cRefs);
141}
142
143DECLINLINE(int) vboxVDMACrCtlGetRc (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
144{
145 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
146 return pHdr->rc;
147}
148
149static DECLCALLBACK(void) vboxVDMACrCtlCbSetEvent(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext)
150{
151 RTSemEventSignal((RTSEMEVENT)pvContext);
152}
153
154static DECLCALLBACK(void) vboxVDMACrCtlCbReleaseCmd(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext)
155{
156 vboxVDMACrCtlRelease(pCmd);
157}
158
159
160static int vboxVDMACrCtlPostAsync (PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, PFNVBOXVDMACRCTL_CALLBACK pfnCompletion, void *pvCompletion)
161{
162 if (pVGAState->pDrv->pfnCrHgsmiControlProcess)
163 {
164 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
165 pHdr->pfnCompletion = pfnCompletion;
166 pHdr->pvCompletion = pvCompletion;
167 pVGAState->pDrv->pfnCrHgsmiControlProcess(pVGAState->pDrv, pCmd);
168 return VINF_SUCCESS;
169 }
170#ifdef DEBUG_misha
171 Assert(0);
172#endif
173 return VERR_NOT_SUPPORTED;
174}
175
176static int vboxVDMACrCtlPost(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd)
177{
178 RTSEMEVENT hComplEvent;
179 int rc = RTSemEventCreate(&hComplEvent);
180 AssertRC(rc);
181 if(RT_SUCCESS(rc))
182 {
183 rc = vboxVDMACrCtlPostAsync (pVGAState, pCmd, vboxVDMACrCtlCbSetEvent, (void*)hComplEvent);
184#ifdef DEBUG_misha
185 AssertRC(rc);
186#endif
187 if (RT_SUCCESS(rc))
188 {
189 rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT);
190 AssertRC(rc);
191 if(RT_SUCCESS(rc))
192 {
193 RTSemEventDestroy(hComplEvent);
194 }
195 }
196 else
197 {
198 /* the command is completed */
199 RTSemEventDestroy(hComplEvent);
200 }
201 }
202 return rc;
203}
204
205static int vboxVDMACrCtlHgsmiSetupAsync(struct VBOXVDMAHOST *pVdma)
206{
207 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pCmd = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)vboxVDMACrCtlCreate(
208 VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP, sizeof (*pCmd));
209 if (pCmd)
210 {
211 PVGASTATE pVGAState = pVdma->pVGAState;
212 pCmd->pvRamBase = pVGAState->vram_ptrR3;
213 int rc = vboxVDMACrCtlPostAsync(pVGAState, &pCmd->Hdr, vboxVDMACrCtlCbReleaseCmd, NULL);
214#ifdef DEBUG_misha
215 AssertRC(rc);
216#endif
217#if 0
218 if (RT_SUCCESS(rc))
219 {
220 rc = vboxVDMACrCtlGetRc(&pCmd->Hdr);
221 }
222 vboxVDMACrCtlRelease(&pCmd->Hdr);
223#endif
224 return rc;
225 }
226 return VERR_NO_MEMORY;
227}
228
229static int vboxVDMACmdExecBpbTransfer(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer, uint32_t cbBuffer);
230
231/* check if this is external cmd to be passed to chromium backend */
232static bool vboxVDMACmdCheckCrCmd(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmd)
233{
234 PVBOXVDMACMD pDmaCmd;
235 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
236 bool bCompleted = false;
237
238 if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
239 pDmaCmd = VBOXVDMACBUF_DR_TAIL(pCmd, VBOXVDMACMD);
240 else
241 pDmaCmd = NULL;
242
243 if (pDmaCmd)
244 {
245 uint32_t cbCmd = pCmd->cbBuf;
246 Assert(cbCmd >= VBOXVDMACMD_HEADER_SIZE());
247
248 if (cbCmd >= VBOXVDMACMD_HEADER_SIZE())
249 {
250 switch (pDmaCmd->enmType)
251 {
252 case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
253 {
254 PVBOXVDMACMD_CHROMIUM_CMD pCrCmd = VBOXVDMACMD_BODY(pDmaCmd, VBOXVDMACMD_CHROMIUM_CMD);
255 PVGASTATE pVGAState = pVdma->pVGAState;
256 bCompleted = true;
257 if (pVGAState->pDrv->pfnCrHgsmiCommandProcess)
258 {
259 VBoxSHGSMICommandMarkAsynchCompletion(pCmd);
260 pVGAState->pDrv->pfnCrHgsmiCommandProcess(pVGAState->pDrv, pCrCmd);
261 break;
262 }
263 else
264 {
265 Assert(0);
266 }
267
268 int tmpRc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmd);
269 AssertRC(tmpRc);
270// uint32_t cBufs = pCrCmd->cBuffers;
271// for (uint32_t i = 0; i < cBufs; ++i)
272// {
273// PVBOXVDMACMD_CHROMIUM_BUFFER pBuf = &pCrCmd->aBuffers[i];
274// void *pvBuffer = pvRam + pBuf->offBuffer;
275// uint32_t cbBuffer = pBuf->cbBuffer;
276// }
277 break;
278 }
279 case VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER:
280 {
281 PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer = VBOXVDMACMD_BODY(pDmaCmd, VBOXVDMACMD_DMA_BPB_TRANSFER);
282 int rc = vboxVDMACmdExecBpbTransfer(pVdma, pTransfer, sizeof (*pTransfer));
283 AssertRC(rc);
284 if (RT_SUCCESS(rc))
285 {
286 pCmd->rc = VINF_SUCCESS;
287 rc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmd);
288 AssertRC(rc);
289 bCompleted = true;
290 }
291 break;
292 }
293 default:
294 break;
295 }
296 }
297 }
298 return bCompleted;
299}
300
301int vboxVDMACrHgsmiCommandCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, int rc)
302{
303 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
304 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
305 VBOXVDMACMD *pDmaHdr = VBOXVDMACMD_FROM_BODY(pCmd);
306 VBOXVDMACBUF_DR *pDr = VBOXVDMACBUF_DR_FROM_TAIL(pDmaHdr);
307 AssertRC(rc);
308 pDr->rc = rc;
309
310 Assert(pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD);
311 rc = VBoxSHGSMICommandComplete(pIns, pDr);
312 AssertRC(rc);
313 return rc;
314}
315
316int vboxVDMACrHgsmiControlCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd, int rc)
317{
318 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
319 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pCmdPrivate = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
320 pCmdPrivate->rc = rc;
321#ifdef DEBUG_misha
322 AssertRC(rc);
323#endif
324 if (pCmdPrivate->pfnCompletion)
325 {
326 pCmdPrivate->pfnCompletion(pVGAState, pCmd, pCmdPrivate->pvCompletion);
327 }
328 return VINF_SUCCESS;
329}
330
331#endif
332
333#ifdef VBOX_VDMA_WITH_WORKERTHREAD
334/* to simplify things and to avoid extra backend if modifications we assume the VBOXVDMA_RECTL is the same as VBVACMDHDR */
335AssertCompile(sizeof(VBOXVDMA_RECTL) == sizeof(VBVACMDHDR));
336AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, left) == RT_SIZEOFMEMB(VBVACMDHDR, x));
337AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, top) == RT_SIZEOFMEMB(VBVACMDHDR, y));
338AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, width) == RT_SIZEOFMEMB(VBVACMDHDR, w));
339AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, height) == RT_SIZEOFMEMB(VBVACMDHDR, h));
340AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, left) == RT_OFFSETOF(VBVACMDHDR, x));
341AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, top) == RT_OFFSETOF(VBVACMDHDR, y));
342AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, width) == RT_OFFSETOF(VBVACMDHDR, w));
343AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, height) == RT_OFFSETOF(VBVACMDHDR, h));
344
345static int vboxVDMANotifyPrimaryUpdate (PVGASTATE pVGAState, unsigned uScreenId, const VBOXVDMA_RECTL * pRectl)
346{
347 pVGAState->pDrv->pfnVBVAUpdateBegin (pVGAState->pDrv, uScreenId);
348
349 /* Updates the rectangle and sends the command to the VRDP server. */
350 pVGAState->pDrv->pfnVBVAUpdateProcess (pVGAState->pDrv, uScreenId,
351 (const PVBVACMDHDR)pRectl /* <- see above AssertCompile's and comments */,
352 sizeof (VBOXVDMA_RECTL));
353
354 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, pRectl->left, pRectl->top,
355 pRectl->width, pRectl->height);
356
357 return VINF_SUCCESS;
358}
359#endif
360
361static int vboxVDMACmdExecBltPerform(PVBOXVDMAHOST pVdma,
362 uint8_t *pvDstSurf, const uint8_t *pvSrcSurf,
363 const PVBOXVDMA_SURF_DESC pDstDesc, const PVBOXVDMA_SURF_DESC pSrcDesc,
364 const VBOXVDMA_RECTL * pDstRectl, const VBOXVDMA_RECTL * pSrcRectl)
365{
366 /* we do not support color conversion */
367 Assert(pDstDesc->format == pSrcDesc->format);
368 /* we do not support stretching */
369 Assert(pDstRectl->height == pSrcRectl->height);
370 Assert(pDstRectl->width == pSrcRectl->width);
371 if (pDstDesc->format != pSrcDesc->format)
372 return VERR_INVALID_FUNCTION;
373 if (pDstDesc->width == pDstRectl->width
374 && pSrcDesc->width == pSrcRectl->width
375 && pSrcDesc->width == pDstDesc->width)
376 {
377 Assert(!pDstRectl->left);
378 Assert(!pSrcRectl->left);
379 uint32_t cbOff = pDstDesc->pitch * pDstRectl->top;
380 uint32_t cbSize = pDstDesc->pitch * pDstRectl->height;
381 memcpy(pvDstSurf + cbOff, pvSrcSurf + cbOff, cbSize);
382 }
383 else
384 {
385 uint32_t offDstLineStart = pDstRectl->left * pDstDesc->bpp >> 3;
386 uint32_t offDstLineEnd = ((pDstRectl->left * pDstDesc->bpp + 7) >> 3) + ((pDstDesc->bpp * pDstRectl->width + 7) >> 3);
387 uint32_t cbDstLine = offDstLineEnd - offDstLineStart;
388 uint32_t offDstStart = pDstDesc->pitch * pDstRectl->top + offDstLineStart;
389 Assert(cbDstLine <= pDstDesc->pitch);
390 uint32_t cbDstSkip = pDstDesc->pitch;
391 uint8_t * pvDstStart = pvDstSurf + offDstStart;
392
393 uint32_t offSrcLineStart = pSrcRectl->left * pSrcDesc->bpp >> 3;
394 uint32_t offSrcLineEnd = ((pSrcRectl->left * pSrcDesc->bpp + 7) >> 3) + ((pSrcDesc->bpp * pSrcRectl->width + 7) >> 3);
395 uint32_t cbSrcLine = offSrcLineEnd - offSrcLineStart;
396 uint32_t offSrcStart = pSrcDesc->pitch * pSrcRectl->top + offSrcLineStart;
397 Assert(cbSrcLine <= pSrcDesc->pitch);
398 uint32_t cbSrcSkip = pSrcDesc->pitch;
399 const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
400
401 Assert(cbDstLine == cbSrcLine);
402
403 for (uint32_t i = 0; ; ++i)
404 {
405 memcpy (pvDstStart, pvSrcStart, cbDstLine);
406 if (i == pDstRectl->height)
407 break;
408 pvDstStart += cbDstSkip;
409 pvSrcStart += cbSrcSkip;
410 }
411 }
412 return VINF_SUCCESS;
413}
414
415static void vboxVDMARectlUnite(VBOXVDMA_RECTL * pRectl1, const VBOXVDMA_RECTL * pRectl2)
416{
417 if (!pRectl1->width)
418 *pRectl1 = *pRectl2;
419 else
420 {
421 int16_t x21 = pRectl1->left + pRectl1->width;
422 int16_t x22 = pRectl2->left + pRectl2->width;
423 if (pRectl1->left > pRectl2->left)
424 {
425 pRectl1->left = pRectl2->left;
426 pRectl1->width = x21 < x22 ? x22 - pRectl1->left : x21 - pRectl1->left;
427 }
428 else if (x21 < x22)
429 pRectl1->width = x22 - pRectl1->left;
430
431 x21 = pRectl1->top + pRectl1->height;
432 x22 = pRectl2->top + pRectl2->height;
433 if (pRectl1->top > pRectl2->top)
434 {
435 pRectl1->top = pRectl2->top;
436 pRectl1->height = x21 < x22 ? x22 - pRectl1->top : x21 - pRectl1->top;
437 }
438 else if (x21 < x22)
439 pRectl1->height = x22 - pRectl1->top;
440 }
441}
442
443/*
444 * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
445 */
446static int vboxVDMACmdExecBlt(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt, uint32_t cbBuffer)
447{
448 const uint32_t cbBlt = VBOXVDMACMD_BODY_FIELD_OFFSET(uint32_t, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[pBlt->cDstSubRects]);
449 Assert(cbBlt <= cbBuffer);
450 if (cbBuffer < cbBlt)
451 return VERR_INVALID_FUNCTION;
452
453 /* we do not support stretching for now */
454 Assert(pBlt->srcRectl.width == pBlt->dstRectl.width);
455 Assert(pBlt->srcRectl.height == pBlt->dstRectl.height);
456 if (pBlt->srcRectl.width != pBlt->dstRectl.width)
457 return VERR_INVALID_FUNCTION;
458 if (pBlt->srcRectl.height != pBlt->dstRectl.height)
459 return VERR_INVALID_FUNCTION;
460 Assert(pBlt->cDstSubRects);
461
462 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
463 VBOXVDMA_RECTL updateRectl = {0};
464
465 if (pBlt->cDstSubRects)
466 {
467 VBOXVDMA_RECTL dstRectl, srcRectl;
468 const VBOXVDMA_RECTL *pDstRectl, *pSrcRectl;
469 for (uint32_t i = 0; i < pBlt->cDstSubRects; ++i)
470 {
471 pDstRectl = &pBlt->aDstSubRects[i];
472 if (pBlt->dstRectl.left || pBlt->dstRectl.top)
473 {
474 dstRectl.left = pDstRectl->left + pBlt->dstRectl.left;
475 dstRectl.top = pDstRectl->top + pBlt->dstRectl.top;
476 dstRectl.width = pDstRectl->width;
477 dstRectl.height = pDstRectl->height;
478 pDstRectl = &dstRectl;
479 }
480
481 pSrcRectl = &pBlt->aDstSubRects[i];
482 if (pBlt->srcRectl.left || pBlt->srcRectl.top)
483 {
484 srcRectl.left = pSrcRectl->left + pBlt->srcRectl.left;
485 srcRectl.top = pSrcRectl->top + pBlt->srcRectl.top;
486 srcRectl.width = pSrcRectl->width;
487 srcRectl.height = pSrcRectl->height;
488 pSrcRectl = &srcRectl;
489 }
490
491 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
492 &pBlt->dstDesc, &pBlt->srcDesc,
493 pDstRectl,
494 pSrcRectl);
495 AssertRC(rc);
496 if (!RT_SUCCESS(rc))
497 return rc;
498
499 vboxVDMARectlUnite(&updateRectl, pDstRectl);
500 }
501 }
502 else
503 {
504 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
505 &pBlt->dstDesc, &pBlt->srcDesc,
506 &pBlt->dstRectl,
507 &pBlt->srcRectl);
508 AssertRC(rc);
509 if (!RT_SUCCESS(rc))
510 return rc;
511
512 vboxVDMARectlUnite(&updateRectl, &pBlt->dstRectl);
513 }
514
515#ifdef VBOX_VDMA_WITH_WORKERTHREAD
516 int iView = 0;
517 /* @todo: fixme: check if update is needed and get iView */
518 vboxVDMANotifyPrimaryUpdate (pVdma->pVGAState, iView, &updateRectl);
519#endif
520
521 return cbBlt;
522}
523
524static int vboxVDMACmdExecBpbTransfer(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer, uint32_t cbBuffer)
525{
526 if (cbBuffer < sizeof (*pTransfer))
527 return VERR_INVALID_PARAMETER;
528
529 PVGASTATE pVGAState = pVdma->pVGAState;
530 uint8_t * pvRam = pVGAState->vram_ptrR3;
531 PGMPAGEMAPLOCK SrcLock;
532 PGMPAGEMAPLOCK DstLock;
533 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
534 const void * pvSrc;
535 void * pvDst;
536 int rc = VINF_SUCCESS;
537 uint32_t cbTransfer = pTransfer->cbTransferSize;
538 uint32_t cbTransfered = 0;
539 bool bSrcLocked = false;
540 bool bDstLocked = false;
541 do
542 {
543 uint32_t cbSubTransfer = cbTransfer;
544 if (pTransfer->fFlags & VBOXVDMACMD_DMA_BPB_TRANSFER_F_SRC_VRAMOFFSET)
545 {
546 pvSrc = pvRam + pTransfer->Src.offVramBuf + cbTransfered;
547 }
548 else
549 {
550 RTGCPHYS phPage = pTransfer->Src.phBuf;
551 phPage += cbTransfered;
552 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvSrc, &SrcLock);
553 AssertRC(rc);
554 if (RT_SUCCESS(rc))
555 {
556 bSrcLocked = true;
557 cbSubTransfer = RT_MIN(cbSubTransfer, 0x1000);
558 }
559 else
560 {
561 break;
562 }
563 }
564
565 if (pTransfer->fFlags & VBOXVDMACMD_DMA_BPB_TRANSFER_F_DST_VRAMOFFSET)
566 {
567 pvDst = pvRam + pTransfer->Dst.offVramBuf + cbTransfered;
568 }
569 else
570 {
571 RTGCPHYS phPage = pTransfer->Dst.phBuf;
572 phPage += cbTransfered;
573 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, phPage, 0, &pvDst, &DstLock);
574 AssertRC(rc);
575 if (RT_SUCCESS(rc))
576 {
577 bDstLocked = true;
578 cbSubTransfer = RT_MIN(cbSubTransfer, 0x1000);
579 }
580 else
581 {
582 break;
583 }
584 }
585
586 if (RT_SUCCESS(rc))
587 {
588 memcpy(pvDst, pvSrc, cbSubTransfer);
589 cbTransfer -= cbSubTransfer;
590 cbTransfered += cbSubTransfer;
591 }
592 else
593 {
594 cbTransfer = 0; /* to break */
595 }
596
597 if (bSrcLocked)
598 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &SrcLock);
599 if (bDstLocked)
600 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &DstLock);
601 } while (cbTransfer);
602
603 if (RT_SUCCESS(rc))
604 return sizeof (*pTransfer);
605 return rc;
606}
607
608static int vboxVDMACmdExec(PVBOXVDMAHOST pVdma, const uint8_t *pvBuffer, uint32_t cbBuffer)
609{
610 do
611 {
612 Assert(pvBuffer);
613 Assert(cbBuffer >= VBOXVDMACMD_HEADER_SIZE());
614
615 if (!pvBuffer)
616 return VERR_INVALID_PARAMETER;
617 if (cbBuffer < VBOXVDMACMD_HEADER_SIZE())
618 return VERR_INVALID_PARAMETER;
619
620 PVBOXVDMACMD pCmd = (PVBOXVDMACMD)pvBuffer;
621 uint32_t cbCmd = 0;
622 switch (pCmd->enmType)
623 {
624 case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
625 {
626#ifdef VBOXWDDM_TEST_UHGSMI
627 static int count = 0;
628 static uint64_t start, end;
629 if (count==0)
630 {
631 start = RTTimeNanoTS();
632 }
633 ++count;
634 if (count==100000)
635 {
636 end = RTTimeNanoTS();
637 float ems = (end-start)/1000000.f;
638 LogRel(("100000 calls took %i ms, %i cps\n", (int)ems, (int)(100000.f*1000.f/ems) ));
639 }
640#endif
641 /* todo: post the buffer to chromium */
642 return VINF_SUCCESS;
643 }
644 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
645 {
646 const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_PRESENT_BLT);
647 int cbBlt = vboxVDMACmdExecBlt(pVdma, pBlt, cbBuffer);
648 Assert(cbBlt >= 0);
649 Assert((uint32_t)cbBlt <= cbBuffer);
650 if (cbBlt >= 0)
651 {
652 if ((uint32_t)cbBlt == cbBuffer)
653 return VINF_SUCCESS;
654 else
655 {
656 cbBuffer -= (uint32_t)cbBlt;
657 pvBuffer -= cbBlt;
658 }
659 }
660 else
661 return cbBlt; /* error */
662 break;
663 }
664 case VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER:
665 {
666 const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_BPB_TRANSFER);
667 int cbTransfer = vboxVDMACmdExecBpbTransfer(pVdma, pTransfer, cbBuffer);
668 Assert(cbTransfer >= 0);
669 Assert((uint32_t)cbTransfer <= cbBuffer);
670 if (cbTransfer >= 0)
671 {
672 if ((uint32_t)cbTransfer == cbBuffer)
673 return VINF_SUCCESS;
674 else
675 {
676 cbBuffer -= (uint32_t)cbTransfer;
677 pvBuffer -= cbTransfer;
678 }
679 }
680 else
681 return cbTransfer; /* error */
682 break;
683 }
684 default:
685 AssertBreakpoint();
686 return VERR_INVALID_FUNCTION;
687 }
688 } while (1);
689
690 /* we should not be here */
691 AssertBreakpoint();
692 return VERR_INVALID_STATE;
693}
694
695#ifdef VBOX_VDMA_WITH_WORKERTHREAD
696
697int vboxVDMAPipeConstruct(PVBOXVDMAPIPE pPipe)
698{
699 int rc = RTSemEventCreate(&pPipe->hEvent);
700 AssertRC(rc);
701 if (RT_SUCCESS(rc))
702 {
703 rc = RTCritSectInit(&pPipe->hCritSect);
704 AssertRC(rc);
705 if (RT_SUCCESS(rc))
706 {
707 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
708 pPipe->bNeedNotify = true;
709 return VINF_SUCCESS;
710// RTCritSectDelete(pPipe->hCritSect);
711 }
712 RTSemEventDestroy(pPipe->hEvent);
713 }
714 return rc;
715}
716
717int vboxVDMAPipeOpenServer(PVBOXVDMAPIPE pPipe)
718{
719 int rc = RTCritSectEnter(&pPipe->hCritSect);
720 AssertRC(rc);
721 if (RT_SUCCESS(rc))
722 {
723 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
724 switch (pPipe->enmState)
725 {
726 case VBOXVDMAPIPE_STATE_CREATED:
727 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
728 pPipe->bNeedNotify = false;
729 rc = VINF_SUCCESS;
730 break;
731 case VBOXVDMAPIPE_STATE_OPENNED:
732 pPipe->bNeedNotify = false;
733 rc = VINF_ALREADY_INITIALIZED;
734 break;
735 default:
736 AssertBreakpoint();
737 rc = VERR_INVALID_STATE;
738 break;
739 }
740
741 RTCritSectLeave(&pPipe->hCritSect);
742 }
743 return rc;
744}
745
746int vboxVDMAPipeCloseServer(PVBOXVDMAPIPE pPipe)
747{
748 int rc = RTCritSectEnter(&pPipe->hCritSect);
749 AssertRC(rc);
750 if (RT_SUCCESS(rc))
751 {
752 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
753 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
754 switch (pPipe->enmState)
755 {
756 case VBOXVDMAPIPE_STATE_CLOSING:
757 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
758 rc = VINF_SUCCESS;
759 break;
760 case VBOXVDMAPIPE_STATE_CLOSED:
761 rc = VINF_ALREADY_INITIALIZED;
762 break;
763 default:
764 AssertBreakpoint();
765 rc = VERR_INVALID_STATE;
766 break;
767 }
768
769 RTCritSectLeave(&pPipe->hCritSect);
770 }
771 return rc;
772}
773
774int vboxVDMAPipeCloseClient(PVBOXVDMAPIPE pPipe)
775{
776 int rc = RTCritSectEnter(&pPipe->hCritSect);
777 AssertRC(rc);
778 if (RT_SUCCESS(rc))
779 {
780 bool bNeedNotify = false;
781 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
782 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
783 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
784 switch (pPipe->enmState)
785 {
786 case VBOXVDMAPIPE_STATE_OPENNED:
787 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
788 bNeedNotify = pPipe->bNeedNotify;
789 pPipe->bNeedNotify = false;
790 break;
791 case VBOXVDMAPIPE_STATE_CREATED:
792 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
793 pPipe->bNeedNotify = false;
794 break;
795 case VBOXVDMAPIPE_STATE_CLOSED:
796 rc = VINF_ALREADY_INITIALIZED;
797 break;
798 default:
799 AssertBreakpoint();
800 rc = VERR_INVALID_STATE;
801 break;
802 }
803
804 RTCritSectLeave(&pPipe->hCritSect);
805
806 if (bNeedNotify)
807 {
808 rc = RTSemEventSignal(pPipe->hEvent);
809 AssertRC(rc);
810 }
811 }
812 return rc;
813}
814
815
816typedef DECLCALLBACK(bool) FNHVBOXVDMARWCB(PVBOXVDMAPIPE pPipe, void *pvCallback);
817typedef FNHVBOXVDMARWCB *PFNHVBOXVDMARWCB;
818
819int vboxVDMAPipeModifyServer(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
820{
821 int rc = RTCritSectEnter(&pPipe->hCritSect);
822 AssertRC(rc);
823 if (RT_SUCCESS(rc))
824 {
825 do
826 {
827 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
828 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
829
830 if (pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED)
831 {
832 bool bProcessing = pfnCallback(pPipe, pvCallback);
833 pPipe->bNeedNotify = !bProcessing;
834 if (bProcessing)
835 {
836 RTCritSectLeave(&pPipe->hCritSect);
837 rc = VINF_SUCCESS;
838 break;
839 }
840 else if (pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING)
841 {
842 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
843 RTCritSectLeave(&pPipe->hCritSect);
844 rc = VINF_EOF;
845 break;
846 }
847 }
848 else
849 {
850 AssertBreakpoint();
851 rc = VERR_INVALID_STATE;
852 RTCritSectLeave(&pPipe->hCritSect);
853 break;
854 }
855
856 RTCritSectLeave(&pPipe->hCritSect);
857
858 rc = RTSemEventWait(pPipe->hEvent, RT_INDEFINITE_WAIT);
859 AssertRC(rc);
860 if (!RT_SUCCESS(rc))
861 break;
862
863 rc = RTCritSectEnter(&pPipe->hCritSect);
864 AssertRC(rc);
865 if (!RT_SUCCESS(rc))
866 break;
867 } while (1);
868 }
869
870 return rc;
871}
872
873int vboxVDMAPipeModifyClient(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
874{
875 int rc = RTCritSectEnter(&pPipe->hCritSect);
876 AssertRC(rc);
877 if (RT_SUCCESS(rc))
878 {
879 bool bNeedNotify = false;
880 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
881 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
882 {
883 bool bModified = pfnCallback(pPipe, pvCallback);
884 if (bModified)
885 {
886 bNeedNotify = pPipe->bNeedNotify;
887 pPipe->bNeedNotify = false;
888 }
889 }
890 else
891 rc = VERR_INVALID_STATE;
892
893 RTCritSectLeave(&pPipe->hCritSect);
894
895 if (bNeedNotify)
896 {
897 rc = RTSemEventSignal(pPipe->hEvent);
898 AssertRC(rc);
899 }
900 }
901 return rc;
902}
903
904int vboxVDMAPipeDestruct(PVBOXVDMAPIPE pPipe)
905{
906 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
907 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
908 /* ensure the pipe is closed */
909 vboxVDMAPipeCloseClient(pPipe);
910
911 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
912
913 if (pPipe->enmState != VBOXVDMAPIPE_STATE_CLOSED)
914 return VERR_INVALID_STATE;
915
916 int rc = RTCritSectDelete(&pPipe->hCritSect);
917 AssertRC(rc);
918
919 rc = RTSemEventDestroy(pPipe->hEvent);
920 AssertRC(rc);
921
922 return VINF_SUCCESS;
923}
924#endif
925
926static void vboxVDMACommandProcess(PVBOXVDMAHOST pVdma, PVBOXVDMACBUF_DR pCmd)
927{
928 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
929 const uint8_t * pvBuf;
930 PGMPAGEMAPLOCK Lock;
931 int rc;
932 bool bReleaseLocked = false;
933
934 do
935 {
936 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
937
938 if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
939 pvBuf = VBOXVDMACBUF_DR_TAIL(pCmd, const uint8_t);
940 else if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET)
941 {
942 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
943 pvBuf = pvRam + pCmd->Location.offVramBuf;
944 }
945 else
946 {
947 RTGCPHYS phPage = pCmd->Location.phBuf & ~0xfffULL;
948 uint32_t offset = pCmd->Location.phBuf & 0xfff;
949 Assert(offset + pCmd->cbBuf <= 0x1000);
950 if (offset + pCmd->cbBuf > 0x1000)
951 {
952 /* @todo: more advanced mechanism of command buffer proc is actually needed */
953 rc = VERR_INVALID_PARAMETER;
954 break;
955 }
956
957 const void * pvPageBuf;
958 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvPageBuf, &Lock);
959 AssertRC(rc);
960 if (!RT_SUCCESS(rc))
961 {
962 /* @todo: if (rc == VERR_PGM_PHYS_PAGE_RESERVED) -> fall back on using PGMPhysRead ?? */
963 break;
964 }
965
966 pvBuf = (const uint8_t *)pvPageBuf;
967 pvBuf += offset;
968
969 bReleaseLocked = true;
970 }
971
972 rc = vboxVDMACmdExec(pVdma, pvBuf, pCmd->cbBuf);
973 AssertRC(rc);
974
975 if (bReleaseLocked)
976 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
977 } while (0);
978
979 pCmd->rc = rc;
980
981 rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
982 AssertRC(rc);
983}
984
985static void vboxVDMAControlProcess(PVBOXVDMAHOST pVdma, PVBOXVDMA_CTL pCmd)
986{
987 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
988 pCmd->i32Result = VINF_SUCCESS;
989 int rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
990 AssertRC(rc);
991}
992
993#ifdef VBOX_VDMA_WITH_WORKERTHREAD
994typedef struct
995{
996 struct VBOXVDMAHOST *pVdma;
997 VBOXVDMAPIPE_CMD_BODY Cmd;
998 bool bHasCmd;
999} VBOXVDMACMD_PROCESS_CONTEXT, *PVBOXVDMACMD_PROCESS_CONTEXT;
1000
1001static DECLCALLBACK(bool) vboxVDMACommandProcessCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
1002{
1003 PVBOXVDMACMD_PROCESS_CONTEXT pContext = (PVBOXVDMACMD_PROCESS_CONTEXT)pvCallback;
1004 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
1005 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->PendingList);
1006 if (pEntry)
1007 {
1008 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
1009 Assert(pPipeCmd);
1010 pContext->Cmd = pPipeCmd->Cmd;
1011 hgsmiListPrepend(&pVdma->CmdPool.List, pEntry);
1012 pContext->bHasCmd = true;
1013 return true;
1014 }
1015
1016 pContext->bHasCmd = false;
1017 return false;
1018}
1019
1020static DECLCALLBACK(int) vboxVDMAWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
1021{
1022 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvUser;
1023 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
1024 VBOXVDMACMD_PROCESS_CONTEXT Context;
1025 Context.pVdma = pVdma;
1026
1027 int rc = vboxVDMAPipeOpenServer(&pVdma->Pipe);
1028 AssertRC(rc);
1029 if (RT_SUCCESS(rc))
1030 {
1031 do
1032 {
1033 rc = vboxVDMAPipeModifyServer(&pVdma->Pipe, vboxVDMACommandProcessCb, &Context);
1034 AssertRC(rc);
1035 if (RT_SUCCESS(rc))
1036 {
1037 switch (Context.Cmd.enmType)
1038 {
1039 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
1040 {
1041 PVBOXVDMACBUF_DR pDr = Context.Cmd.u.pDr;
1042 vboxVDMACommandProcess(pVdma, pDr);
1043 break;
1044 }
1045 case VBOXVDMAPIPE_CMD_TYPE_DMACTL:
1046 {
1047 PVBOXVDMA_CTL pCtl = Context.Cmd.u.pCtl;
1048 vboxVDMAControlProcess(pVdma, pCtl);
1049 break;
1050 }
1051 default:
1052 AssertBreakpoint();
1053 break;
1054 }
1055
1056 if (rc == VINF_EOF)
1057 {
1058 rc = VINF_SUCCESS;
1059 break;
1060 }
1061 }
1062 else
1063 break;
1064 } while (1);
1065 }
1066
1067 /* always try to close the pipe to make sure the client side is notified */
1068 int tmpRc = vboxVDMAPipeCloseServer(&pVdma->Pipe);
1069 AssertRC(tmpRc);
1070 return rc;
1071}
1072#endif
1073
1074int vboxVDMAConstruct(PVGASTATE pVGAState, struct VBOXVDMAHOST **ppVdma, uint32_t cPipeElements)
1075{
1076 int rc;
1077#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1078 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ (RT_OFFSETOF(VBOXVDMAHOST, CmdPool.aCmds[cPipeElements]));
1079#else
1080 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ (sizeof (*pVdma));
1081#endif
1082 Assert(pVdma);
1083 if (pVdma)
1084 {
1085 pVdma->pHgsmi = pVGAState->pHGSMI;
1086 pVdma->pVGAState = pVGAState;
1087#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1088 hgsmiListInit(&pVdma->PendingList);
1089 rc = vboxVDMAPipeConstruct(&pVdma->Pipe);
1090 AssertRC(rc);
1091 if (RT_SUCCESS(rc))
1092 {
1093 rc = RTThreadCreate(&pVdma->hWorkerThread, vboxVDMAWorkerThread, pVdma, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "VDMA");
1094 AssertRC(rc);
1095 if (RT_SUCCESS(rc))
1096 {
1097 hgsmiListInit(&pVdma->CmdPool.List);
1098 pVdma->CmdPool.cCmds = cPipeElements;
1099 for (uint32_t i = 0; i < cPipeElements; ++i)
1100 {
1101 hgsmiListAppend(&pVdma->CmdPool.List, &pVdma->CmdPool.aCmds[i].Entry);
1102 }
1103# if 0 //def VBOX_WITH_CRHGSMI
1104 int tmpRc = vboxVDMACrCtlHgsmiSetup(pVdma);
1105# ifdef DEBUG_misha
1106 AssertRC(tmpRc);
1107# endif
1108# endif
1109#endif
1110 *ppVdma = pVdma;
1111 return VINF_SUCCESS;
1112#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1113 }
1114
1115 int tmpRc = vboxVDMAPipeDestruct(&pVdma->Pipe);
1116 AssertRC(tmpRc);
1117 }
1118
1119 RTMemFree(pVdma);
1120#endif
1121 }
1122 else
1123 rc = VERR_OUT_OF_RESOURCES;
1124
1125 return rc;
1126}
1127
1128int vboxVDMADestruct(struct VBOXVDMAHOST *pVdma)
1129{
1130#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1131 /* @todo: implement*/
1132 AssertBreakpoint();
1133#endif
1134 RTMemFree(pVdma);
1135 return VINF_SUCCESS;
1136}
1137
1138#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1139typedef struct
1140{
1141 struct VBOXVDMAHOST *pVdma;
1142 VBOXVDMAPIPE_CMD_BODY Cmd;
1143 bool bQueued;
1144} VBOXVDMACMD_SUBMIT_CONTEXT, *PVBOXVDMACMD_SUBMIT_CONTEXT;
1145
1146DECLCALLBACK(bool) vboxVDMACommandSubmitCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
1147{
1148 PVBOXVDMACMD_SUBMIT_CONTEXT pContext = (PVBOXVDMACMD_SUBMIT_CONTEXT)pvCallback;
1149 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
1150 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->CmdPool.List);
1151 Assert(pEntry);
1152 if (pEntry)
1153 {
1154 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
1155 pPipeCmd->Cmd = pContext->Cmd;
1156 VBoxSHGSMICommandMarkAsynchCompletion(pContext->Cmd.u.pvCmd);
1157 pContext->bQueued = true;
1158 hgsmiListAppend(&pVdma->PendingList, pEntry);
1159 return true;
1160 }
1161
1162 /* @todo: should we try to flush some commands here? */
1163 pContext->bQueued = false;
1164 return false;
1165}
1166#endif
1167
1168void vboxVDMAControl(struct VBOXVDMAHOST *pVdma, PVBOXVDMA_CTL pCmd)
1169{
1170#if 1
1171 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
1172
1173 switch (pCmd->enmCtl)
1174 {
1175 case VBOXVDMA_CTL_TYPE_ENABLE:
1176 {
1177 pVdma->bEnabled = true;
1178 pCmd->i32Result = VINF_SUCCESS;
1179#ifdef VBOX_WITH_CRHGSMI
1180 /* @todo: use async completion to ensure we notify a status to guest */
1181 int tmpRc = vboxVDMACrCtlHgsmiSetupAsync(pVdma);
1182 AssertRC(tmpRc);
1183#endif
1184 }
1185 break;
1186 case VBOXVDMA_CTL_TYPE_DISABLE:
1187 pVdma->bEnabled = false;
1188 pCmd->i32Result = VINF_SUCCESS;
1189 break;
1190 case VBOXVDMA_CTL_TYPE_FLUSH:
1191 pCmd->i32Result = VINF_SUCCESS;
1192 break;
1193 default:
1194 AssertBreakpoint();
1195 pCmd->i32Result = VERR_NOT_SUPPORTED;
1196 }
1197
1198 int rc = VBoxSHGSMICommandComplete (pIns, pCmd);
1199 AssertRC(rc);
1200#else
1201 /* test asinch completion */
1202 VBOXVDMACMD_SUBMIT_CONTEXT Context;
1203 Context.pVdma = pVdma;
1204 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACTL;
1205 Context.Cmd.u.pCtl = pCmd;
1206
1207 int rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
1208 AssertRC(rc);
1209 if (RT_SUCCESS(rc))
1210 {
1211 Assert(Context.bQueued);
1212 if (Context.bQueued)
1213 {
1214 /* success */
1215 return;
1216 }
1217 rc = VERR_OUT_OF_RESOURCES;
1218 }
1219
1220 /* failure */
1221 Assert(RT_FAILURE(rc));
1222 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
1223 pCmd->i32Result = rc;
1224 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
1225 AssertRC(tmpRc);
1226
1227#endif
1228}
1229
1230void vboxVDMACommand(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmd)
1231{
1232#ifdef VBOX_WITH_CRHGSMI
1233 if (vboxVDMACmdCheckCrCmd(pVdma, pCmd))
1234 return;
1235#endif
1236
1237 int rc = VERR_NOT_IMPLEMENTED;
1238
1239#ifdef VBOX_VDMA_WITH_WORKERTHREAD
1240
1241#ifdef DEBUG_misha
1242 Assert(0);
1243#endif
1244
1245 VBOXVDMACMD_SUBMIT_CONTEXT Context;
1246 Context.pVdma = pVdma;
1247 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACMD;
1248 Context.Cmd.u.pDr = pCmd;
1249
1250 rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
1251 AssertRC(rc);
1252 if (RT_SUCCESS(rc))
1253 {
1254 Assert(Context.bQueued);
1255 if (Context.bQueued)
1256 {
1257 /* success */
1258 return;
1259 }
1260 rc = VERR_OUT_OF_RESOURCES;
1261 }
1262#endif
1263 /* failure */
1264 Assert(RT_FAILURE(rc));
1265 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
1266 pCmd->rc = rc;
1267 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
1268 AssertRC(tmpRc);
1269}
1270
1271bool vboxVDMAIsEnabled(PVBOXVDMAHOST pVdma)
1272{
1273 return pVdma->bEnabled;
1274}
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