VirtualBox

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

Last change on this file since 40754 was 39603, checked in by vboxsync, 12 years ago

crHgsmi: cleanup

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

© 2023 Oracle
ContactPrivacy policyTerms of Use