VirtualBox

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

Last change on this file since 41532 was 41292, checked in by vboxsync, 13 years ago

DevVGA_VDMA: don't crash if there is no VGA driver attached

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