VirtualBox

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

Last change on this file since 47469 was 44528, checked in by vboxsync, 11 years ago

header (C) fixes

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

© 2023 Oracle
ContactPrivacy policyTerms of Use