VirtualBox

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

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

wddm/3d: scrolling with aero 8x speedup, bugfixing + profiling

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