VirtualBox

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

Last change on this file since 49493 was 49474, checked in by vboxsync, 11 years ago

crOpenGL: some host bits for buffer-based command submission

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette