VirtualBox

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

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

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

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