VirtualBox

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

Last change on this file since 28587 was 28379, checked in by vboxsync, 15 years ago

dev/VGA: avoid extra resizes when HGSMI & VBVA is used (for now enabled only when Wddm driver is isnatalled in the guest)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.4 KB
Line 
1/** @file
2 * Video DMA (VDMA) support.
3 */
4
5/*
6 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
17 * Clara, CA 95054 USA or visit http://www.sun.com if you need
18 * additional information or have any questions.
19 */
20//#include <VBox/VMMDev.h>
21#include <VBox/pdmdev.h>
22#include <VBox/VBoxVideo.h>
23#include <iprt/semaphore.h>
24#include <iprt/thread.h>
25#include <iprt/mem.h>
26
27#include "DevVGA.h"
28#include "HGSMI/SHGSMIHost.h"
29#include "HGSMI/HGSMIHostHlp.h"
30
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
82typedef struct VBOXVDMAHOST
83{
84 VBOXVDMAPIPE Pipe;
85 HGSMILIST PendingList;
86 RTTHREAD hWorkerThread;
87 PHGSMIINSTANCE pHgsmi;
88 PVGASTATE pVGAState;
89 bool bEnabled;
90 VBOXVDMAPIPE_CMD_POOL CmdPool;
91} VBOXVDMAHOST, *PVBOXVDMAHOST;
92
93/* to simplify things and to avoid extra backend if modifications we assume the VBOXVDMA_RECTL is the same as VBVACMDHDR */
94AssertCompile(sizeof(VBOXVDMA_RECTL) == sizeof(VBVACMDHDR));
95AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, left) == RT_SIZEOFMEMB(VBVACMDHDR, x));
96AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, top) == RT_SIZEOFMEMB(VBVACMDHDR, y));
97AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, width) == RT_SIZEOFMEMB(VBVACMDHDR, w));
98AssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, height) == RT_SIZEOFMEMB(VBVACMDHDR, h));
99AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, left) == RT_OFFSETOF(VBVACMDHDR, x));
100AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, top) == RT_OFFSETOF(VBVACMDHDR, y));
101AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, width) == RT_OFFSETOF(VBVACMDHDR, w));
102AssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, height) == RT_OFFSETOF(VBVACMDHDR, h));
103
104static int vboxVDMANotifyPrimaryUpdate (PVGASTATE pVGAState, unsigned uScreenId, const VBOXVDMA_RECTL * pRectl)
105{
106 pVGAState->pDrv->pfnVBVAUpdateBegin (pVGAState->pDrv, uScreenId);
107
108 /* Updates the rectangle and sends the command to the VRDP server. */
109 pVGAState->pDrv->pfnVBVAUpdateProcess (pVGAState->pDrv, uScreenId,
110 (const PVBVACMDHDR)pRectl /* <- see above AssertCompile's and comments */,
111 sizeof (VBOXVDMA_RECTL));
112
113 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, pRectl->left, pRectl->top,
114 pRectl->width, pRectl->height);
115
116 return VINF_SUCCESS;
117}
118
119static int vboxVDMACmdExecBltPerform(PVBOXVDMAHOST pVdma,
120 uint8_t *pvDstSurf, const uint8_t *pvSrcSurf,
121 const PVBOXVDMA_SURF_DESC pDstDesc, const PVBOXVDMA_SURF_DESC pSrcDesc,
122 const VBOXVDMA_RECTL * pDstRectl, const VBOXVDMA_RECTL * pSrcRectl)
123{
124 /* we do not support color conversion */
125 Assert(pDstDesc->format == pSrcDesc->format);
126 /* we do not support stretching */
127 Assert(pDstRectl->height == pSrcRectl->height);
128 Assert(pDstRectl->width == pSrcRectl->width);
129 if (pDstDesc->format != pSrcDesc->format)
130 return VERR_INVALID_FUNCTION;
131 if (pDstDesc->width == pDstRectl->width
132 && pSrcDesc->width == pSrcRectl->width
133 && pSrcDesc->width == pDstDesc->width)
134 {
135 Assert(!pDstRectl->left);
136 Assert(!pSrcRectl->left);
137 uint32_t cbOff = pDstDesc->pitch * pDstRectl->top;
138 uint32_t cbSize = pDstDesc->pitch * pDstRectl->height;
139 memcpy(pvDstSurf + cbOff, pvSrcSurf + cbOff, cbSize);
140 }
141 else
142 {
143 uint32_t offDstLineStart = pDstRectl->left * pDstDesc->bpp >> 3;
144 uint32_t offDstLineEnd = ((pDstRectl->left * pDstDesc->bpp + 7) >> 3) + ((pDstDesc->bpp * pDstRectl->width + 7) >> 3);
145 uint32_t cbDstLine = offDstLineEnd - offDstLineStart;
146 uint32_t offDstStart = pDstDesc->pitch * pDstRectl->top + offDstLineStart;
147 Assert(cbDstLine <= pDstDesc->pitch);
148 uint32_t cbDstSkip = pDstDesc->pitch;
149 uint8_t * pvDstStart = pvDstSurf + offDstStart;
150
151 uint32_t offSrcLineStart = pSrcRectl->left * pSrcDesc->bpp >> 3;
152 uint32_t offSrcLineEnd = ((pSrcRectl->left * pSrcDesc->bpp + 7) >> 3) + ((pSrcDesc->bpp * pSrcRectl->width + 7) >> 3);
153 uint32_t cbSrcLine = offSrcLineEnd - offSrcLineStart;
154 uint32_t offSrcStart = pSrcDesc->pitch * pSrcRectl->top + offSrcLineStart;
155 Assert(cbSrcLine <= pSrcDesc->pitch);
156 uint32_t cbSrcSkip = pSrcDesc->pitch;
157 const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
158
159 Assert(cbDstLine == cbSrcLine);
160
161 for (uint32_t i = 0; ; ++i)
162 {
163 memcpy (pvDstStart, pvSrcStart, cbDstLine);
164 if (i == pDstRectl->height)
165 break;
166 pvDstStart += cbDstSkip;
167 pvSrcStart += cbSrcSkip;
168 }
169 }
170 return VINF_SUCCESS;
171}
172
173static void vboxVDMARectlUnite(VBOXVDMA_RECTL * pRectl1, const VBOXVDMA_RECTL * pRectl2)
174{
175 if (!pRectl1->width)
176 *pRectl1 = *pRectl2;
177 else
178 {
179 int16_t x21 = pRectl1->left + pRectl1->width;
180 int16_t x22 = pRectl2->left + pRectl2->width;
181 if (pRectl1->left > pRectl2->left)
182 {
183 pRectl1->left = pRectl2->left;
184 pRectl1->width = x21 < x22 ? x22 - pRectl1->left : x21 - pRectl1->left;
185 }
186 else if (x21 < x22)
187 pRectl1->width = x22 - pRectl1->left;
188
189 x21 = pRectl1->top + pRectl1->height;
190 x22 = pRectl2->top + pRectl2->height;
191 if (pRectl1->top > pRectl2->top)
192 {
193 pRectl1->top = pRectl2->top;
194 pRectl1->height = x21 < x22 ? x22 - pRectl1->top : x21 - pRectl1->top;
195 }
196 else if (x21 < x22)
197 pRectl1->height = x22 - pRectl1->top;
198 }
199}
200
201/*
202 * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
203 */
204static int vboxVDMACmdExecBlt(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt, uint32_t cbBuffer)
205{
206 const uint32_t cbBlt = VBOXVDMACMD_BODY_FIELD_OFFSET(uint32_t, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[pBlt->cDstSubRects]);
207 Assert(cbBlt <= cbBuffer);
208 if (cbBuffer < cbBlt)
209 return VERR_INVALID_FUNCTION;
210
211 /* we do not support stretching for now */
212 Assert(pBlt->srcRectl.width == pBlt->dstRectl.width);
213 Assert(pBlt->srcRectl.height == pBlt->dstRectl.height);
214 if (pBlt->srcRectl.width != pBlt->dstRectl.width)
215 return VERR_INVALID_FUNCTION;
216 if (pBlt->srcRectl.height != pBlt->dstRectl.height)
217 return VERR_INVALID_FUNCTION;
218 Assert(pBlt->cDstSubRects);
219
220 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
221 VBOXVDMA_RECTL updateRectl = {0};
222
223 if (pBlt->cDstSubRects)
224 {
225 VBOXVDMA_RECTL dstRectl, srcRectl;
226 const VBOXVDMA_RECTL *pDstRectl, *pSrcRectl;
227 for (uint32_t i = 0; i < pBlt->cDstSubRects; ++i)
228 {
229 pDstRectl = &pBlt->aDstSubRects[i];
230 if (pBlt->dstRectl.left || pBlt->dstRectl.top)
231 {
232 dstRectl.left = pDstRectl->left + pBlt->dstRectl.left;
233 dstRectl.top = pDstRectl->top + pBlt->dstRectl.top;
234 dstRectl.width = pDstRectl->width;
235 dstRectl.height = pDstRectl->height;
236 pDstRectl = &dstRectl;
237 }
238
239 pSrcRectl = &pBlt->aDstSubRects[i];
240 if (pBlt->srcRectl.left || pBlt->srcRectl.top)
241 {
242 srcRectl.left = pSrcRectl->left + pBlt->srcRectl.left;
243 srcRectl.top = pSrcRectl->top + pBlt->srcRectl.top;
244 srcRectl.width = pSrcRectl->width;
245 srcRectl.height = pSrcRectl->height;
246 pSrcRectl = &srcRectl;
247 }
248
249 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
250 &pBlt->dstDesc, &pBlt->srcDesc,
251 pDstRectl,
252 pSrcRectl);
253 AssertRC(rc);
254 if (!RT_SUCCESS(rc))
255 return rc;
256
257 vboxVDMARectlUnite(&updateRectl, pDstRectl);
258 }
259 }
260 else
261 {
262 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
263 &pBlt->dstDesc, &pBlt->srcDesc,
264 &pBlt->dstRectl,
265 &pBlt->srcRectl);
266 AssertRC(rc);
267 if (!RT_SUCCESS(rc))
268 return rc;
269
270 vboxVDMARectlUnite(&updateRectl, &pBlt->dstRectl);
271 }
272
273 int iView = 0;
274 /* @todo: fixme: check if update is needed and get iView */
275 vboxVDMANotifyPrimaryUpdate (pVdma->pVGAState, iView, &updateRectl);
276
277 return cbBlt;
278}
279
280static int vboxVDMACmdExec(PVBOXVDMAHOST pVdma, const uint8_t *pvBuffer, uint32_t cbBuffer)
281{
282 do
283 {
284 Assert(pvBuffer);
285 Assert(cbBuffer >= VBOXVDMACMD_HEADER_SIZE());
286
287 if (!pvBuffer)
288 return VERR_INVALID_PARAMETER;
289 if (cbBuffer < VBOXVDMACMD_HEADER_SIZE())
290 return VERR_INVALID_PARAMETER;
291
292 PVBOXVDMACMD pCmd = (PVBOXVDMACMD)pvBuffer;
293 uint32_t cbCmd = 0;
294 switch (pCmd->enmType)
295 {
296 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
297 {
298 const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_PRESENT_BLT);
299 int cbBlt = vboxVDMACmdExecBlt(pVdma, pBlt, cbBuffer);
300 Assert(cbBlt >= 0);
301 Assert((uint32_t)cbBlt <= cbBuffer);
302 if (cbBlt >= 0)
303 {
304 if (cbBlt == cbBuffer)
305 return VINF_SUCCESS;
306 else
307 {
308 cbBuffer -= (uint32_t)cbBlt;
309 pvBuffer -= cbBlt;
310 }
311 }
312 else
313 return cbBlt; /* error */
314 break;
315 }
316 default:
317 AssertBreakpoint();
318 return VERR_INVALID_FUNCTION;
319 }
320 } while (1);
321
322 /* we should not be here */
323 AssertBreakpoint();
324 return VERR_INVALID_STATE;
325}
326
327int vboxVDMAPipeConstruct(PVBOXVDMAPIPE pPipe)
328{
329 int rc = RTSemEventCreate(&pPipe->hEvent);
330 AssertRC(rc);
331 if (RT_SUCCESS(rc))
332 {
333 rc = RTCritSectInit(&pPipe->hCritSect);
334 AssertRC(rc);
335 if (RT_SUCCESS(rc))
336 {
337 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
338 pPipe->bNeedNotify = true;
339 return VINF_SUCCESS;
340// RTCritSectDelete(pPipe->hCritSect);
341 }
342 RTSemEventDestroy(pPipe->hEvent);
343 }
344 return rc;
345}
346
347int vboxVDMAPipeOpenServer(PVBOXVDMAPIPE pPipe)
348{
349 int rc = RTCritSectEnter(&pPipe->hCritSect);
350 AssertRC(rc);
351 if (RT_SUCCESS(rc))
352 {
353 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
354 switch (pPipe->enmState)
355 {
356 case VBOXVDMAPIPE_STATE_CREATED:
357 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
358 pPipe->bNeedNotify = false;
359 rc = VINF_SUCCESS;
360 break;
361 case VBOXVDMAPIPE_STATE_OPENNED:
362 pPipe->bNeedNotify = false;
363 rc = VINF_ALREADY_INITIALIZED;
364 break;
365 default:
366 AssertBreakpoint();
367 rc = VERR_INVALID_STATE;
368 break;
369 }
370
371 RTCritSectLeave(&pPipe->hCritSect);
372 }
373 return rc;
374}
375
376int vboxVDMAPipeCloseServer(PVBOXVDMAPIPE pPipe)
377{
378 int rc = RTCritSectEnter(&pPipe->hCritSect);
379 AssertRC(rc);
380 if (RT_SUCCESS(rc))
381 {
382 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
383 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
384 switch (pPipe->enmState)
385 {
386 case VBOXVDMAPIPE_STATE_CLOSING:
387 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
388 rc = VINF_SUCCESS;
389 break;
390 case VBOXVDMAPIPE_STATE_CLOSED:
391 rc = VINF_ALREADY_INITIALIZED;
392 break;
393 default:
394 AssertBreakpoint();
395 rc = VERR_INVALID_STATE;
396 break;
397 }
398
399 RTCritSectLeave(&pPipe->hCritSect);
400 }
401 return rc;
402}
403
404int vboxVDMAPipeCloseClient(PVBOXVDMAPIPE pPipe)
405{
406 int rc = RTCritSectEnter(&pPipe->hCritSect);
407 AssertRC(rc);
408 if (RT_SUCCESS(rc))
409 {
410 bool bNeedNotify = false;
411 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
412 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
413 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
414 switch (pPipe->enmState)
415 {
416 case VBOXVDMAPIPE_STATE_OPENNED:
417 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
418 bNeedNotify = pPipe->bNeedNotify;
419 pPipe->bNeedNotify = false;
420 break;
421 case VBOXVDMAPIPE_STATE_CREATED:
422 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
423 pPipe->bNeedNotify = false;
424 break;
425 case VBOXVDMAPIPE_STATE_CLOSED:
426 rc = VINF_ALREADY_INITIALIZED;
427 break;
428 default:
429 AssertBreakpoint();
430 rc = VERR_INVALID_STATE;
431 break;
432 }
433
434 RTCritSectLeave(&pPipe->hCritSect);
435
436 if (bNeedNotify)
437 {
438 rc = RTSemEventSignal(pPipe->hEvent);
439 AssertRC(rc);
440 }
441 }
442 return rc;
443}
444
445
446typedef DECLCALLBACK(bool) FNHVBOXVDMARWCB(PVBOXVDMAPIPE pPipe, void *pvCallback);
447typedef FNHVBOXVDMARWCB *PFNHVBOXVDMARWCB;
448
449int vboxVDMAPipeModifyServer(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
450{
451 int rc = RTCritSectEnter(&pPipe->hCritSect);
452 AssertRC(rc);
453 if (RT_SUCCESS(rc))
454 {
455 do
456 {
457 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
458 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
459
460 if (pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED)
461 {
462 bool bProcessing = pfnCallback(pPipe, pvCallback);
463 pPipe->bNeedNotify = !bProcessing;
464 if (bProcessing)
465 {
466 RTCritSectLeave(&pPipe->hCritSect);
467 rc = VINF_SUCCESS;
468 break;
469 }
470 else if (pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING)
471 {
472 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
473 RTCritSectLeave(&pPipe->hCritSect);
474 rc = VINF_EOF;
475 break;
476 }
477 }
478 else
479 {
480 AssertBreakpoint();
481 rc = VERR_INVALID_STATE;
482 RTCritSectLeave(&pPipe->hCritSect);
483 break;
484 }
485
486 RTCritSectLeave(&pPipe->hCritSect);
487
488 rc = RTSemEventWait(pPipe->hEvent, RT_INDEFINITE_WAIT);
489 AssertRC(rc);
490 if (!RT_SUCCESS(rc))
491 break;
492
493 rc = RTCritSectEnter(&pPipe->hCritSect);
494 AssertRC(rc);
495 if (!RT_SUCCESS(rc))
496 break;
497 } while (1);
498 }
499
500 return rc;
501}
502
503int vboxVDMAPipeModifyClient(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
504{
505 int rc = RTCritSectEnter(&pPipe->hCritSect);
506 AssertRC(rc);
507 if (RT_SUCCESS(rc))
508 {
509 bool bNeedNotify = false;
510 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
511 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
512 {
513 bool bModified = pfnCallback(pPipe, pvCallback);
514 if (bModified)
515 {
516 bNeedNotify = pPipe->bNeedNotify;
517 pPipe->bNeedNotify = false;
518 }
519 }
520 else
521 rc = VERR_INVALID_STATE;
522
523 RTCritSectLeave(&pPipe->hCritSect);
524
525 if (bNeedNotify)
526 {
527 rc = RTSemEventSignal(pPipe->hEvent);
528 AssertRC(rc);
529 }
530 }
531 return rc;
532}
533
534int vboxVDMAPipeDestruct(PVBOXVDMAPIPE pPipe)
535{
536 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
537 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
538 /* ensure the pipe is closed */
539 vboxVDMAPipeCloseClient(pPipe);
540
541 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
542
543 if (pPipe->enmState != VBOXVDMAPIPE_STATE_CLOSED)
544 return VERR_INVALID_STATE;
545
546 int rc = RTCritSectDelete(&pPipe->hCritSect);
547 AssertRC(rc);
548
549 rc = RTSemEventDestroy(pPipe->hEvent);
550 AssertRC(rc);
551
552 return VINF_SUCCESS;
553}
554
555static void vboxVDMACommandProcess(PVBOXVDMAHOST pVdma, PVBOXVDMACBUF_DR pCmd)
556{
557 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
558 const uint8_t * pvBuf;
559 PGMPAGEMAPLOCK Lock;
560 int rc;
561 bool bReleaseLocked = false;
562
563 do
564 {
565 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
566
567 if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
568 pvBuf = VBOXVDMACBUF_DR_TAIL(pCmd, const uint8_t);
569 else if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET)
570 {
571 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
572 pvBuf = pvRam + pCmd->Location.offVramBuf;
573 }
574 else
575 {
576 RTGCPHYS phPage = pCmd->Location.phBuf & ~0xfffULL;
577 uint32_t offset = pCmd->Location.phBuf & 0xfff;
578 Assert(offset + pCmd->cbBuf <= 0x1000);
579 if (offset + pCmd->cbBuf > 0x1000)
580 {
581 /* @todo: more advanced mechanism of command buffer proc is actually needed */
582 rc = VERR_INVALID_PARAMETER;
583 break;
584 }
585
586 const void * pvPageBuf;
587 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvPageBuf, &Lock);
588 AssertRC(rc);
589 if (!RT_SUCCESS(rc))
590 {
591 /* @todo: if (rc == VERR_PGM_PHYS_PAGE_RESERVED) -> fall back on using PGMPhysRead ?? */
592 break;
593 }
594
595 pvBuf = (const uint8_t *)pvPageBuf;
596 pvBuf += offset;
597
598 bReleaseLocked = true;
599 }
600
601 rc = vboxVDMACmdExec(pVdma, pvBuf, pCmd->cbBuf);
602 AssertRC(rc);
603
604 if (bReleaseLocked)
605 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
606 } while (0);
607
608 pCmd->rc = rc;
609
610 rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
611 AssertRC(rc);
612}
613
614static void vboxVDMAControlProcess(PVBOXVDMAHOST pVdma, PVBOXVDMA_CTL pCmd)
615{
616 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
617 pCmd->i32Result = VINF_SUCCESS;
618 int rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
619 AssertRC(rc);
620}
621
622typedef struct
623{
624 struct VBOXVDMAHOST *pVdma;
625 VBOXVDMAPIPE_CMD_BODY Cmd;
626 bool bHasCmd;
627} VBOXVDMACMD_PROCESS_CONTEXT, *PVBOXVDMACMD_PROCESS_CONTEXT;
628
629static DECLCALLBACK(bool) vboxVDMACommandProcessCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
630{
631 PVBOXVDMACMD_PROCESS_CONTEXT pContext = (PVBOXVDMACMD_PROCESS_CONTEXT)pvCallback;
632 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
633 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->PendingList);
634 if (pEntry)
635 {
636 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
637 Assert(pPipeCmd);
638 pContext->Cmd = pPipeCmd->Cmd;
639 hgsmiListPrepend(&pVdma->CmdPool.List, pEntry);
640 pContext->bHasCmd = true;
641 return true;
642 }
643
644 pContext->bHasCmd = false;
645 return false;
646}
647
648static DECLCALLBACK(int) vboxVDMAWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
649{
650 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvUser;
651 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
652 VBOXVDMACMD_PROCESS_CONTEXT Context;
653 Context.pVdma = pVdma;
654
655 int rc = vboxVDMAPipeOpenServer(&pVdma->Pipe);
656 AssertRC(rc);
657 if (RT_SUCCESS(rc))
658 {
659 do
660 {
661 rc = vboxVDMAPipeModifyServer(&pVdma->Pipe, vboxVDMACommandProcessCb, &Context);
662 AssertRC(rc);
663 if (RT_SUCCESS(rc))
664 {
665 switch (Context.Cmd.enmType)
666 {
667 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
668 {
669 PVBOXVDMACBUF_DR pDr = Context.Cmd.u.pDr;
670 vboxVDMACommandProcess(pVdma, pDr);
671 break;
672 }
673 case VBOXVDMAPIPE_CMD_TYPE_DMACTL:
674 {
675 PVBOXVDMA_CTL pCtl = Context.Cmd.u.pCtl;
676 vboxVDMAControlProcess(pVdma, pCtl);
677 break;
678 }
679 default:
680 AssertBreakpoint();
681 break;
682 }
683
684 if (rc == VINF_EOF)
685 {
686 rc = VINF_SUCCESS;
687 break;
688 }
689 }
690 else
691 break;
692 } while (1);
693 }
694
695 /* always try to close the pipe to make sure the client side is notified */
696 int tmpRc = vboxVDMAPipeCloseServer(&pVdma->Pipe);
697 AssertRC(tmpRc);
698 return rc;
699}
700
701int vboxVDMAConstruct(PVGASTATE pVGAState, struct VBOXVDMAHOST **ppVdma, uint32_t cPipeElements)
702{
703 int rc;
704 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ (RT_OFFSETOF(VBOXVDMAHOST, CmdPool.aCmds[cPipeElements]));
705 Assert(pVdma);
706 if (pVdma)
707 {
708 hgsmiListInit(&pVdma->PendingList);
709 pVdma->pHgsmi = pVGAState->pHGSMI;
710 pVdma->pVGAState = pVGAState;
711 rc = vboxVDMAPipeConstruct(&pVdma->Pipe);
712 AssertRC(rc);
713 if (RT_SUCCESS(rc))
714 {
715 rc = RTThreadCreate(&pVdma->hWorkerThread, vboxVDMAWorkerThread, pVdma, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "VDMA");
716 AssertRC(rc);
717 if (RT_SUCCESS(rc))
718 {
719 hgsmiListInit(&pVdma->CmdPool.List);
720 pVdma->CmdPool.cCmds = cPipeElements;
721 for (uint32_t i = 0; i < cPipeElements; ++i)
722 {
723 hgsmiListAppend(&pVdma->CmdPool.List, &pVdma->CmdPool.aCmds[i].Entry);
724 }
725 *ppVdma = pVdma;
726 return VINF_SUCCESS;
727 }
728
729 int tmpRc = vboxVDMAPipeDestruct(&pVdma->Pipe);
730 AssertRC(tmpRc);
731 }
732
733 RTMemFree(pVdma);
734 }
735 else
736 rc = VERR_OUT_OF_RESOURCES;
737
738 return rc;
739}
740
741int vboxVDMADestruct(struct VBOXVDMAHOST **pVdma)
742{
743 AssertBreakpoint();
744 return VINF_SUCCESS;
745}
746
747typedef struct
748{
749 struct VBOXVDMAHOST *pVdma;
750 VBOXVDMAPIPE_CMD_BODY Cmd;
751 bool bQueued;
752} VBOXVDMACMD_SUBMIT_CONTEXT, *PVBOXVDMACMD_SUBMIT_CONTEXT;
753
754DECLCALLBACK(bool) vboxVDMACommandSubmitCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
755{
756 PVBOXVDMACMD_SUBMIT_CONTEXT pContext = (PVBOXVDMACMD_SUBMIT_CONTEXT)pvCallback;
757 struct VBOXVDMAHOST *pVdma = pContext->pVdma;
758 HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->CmdPool.List);
759 Assert(pEntry);
760 if (pEntry)
761 {
762 PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
763 pPipeCmd->Cmd = pContext->Cmd;
764 VBoxSHGSMICommandMarkAsynchCompletion(pContext->Cmd.u.pvCmd);
765 pContext->bQueued = true;
766 hgsmiListAppend(&pVdma->PendingList, pEntry);
767 return true;
768 }
769
770 /* @todo: should we try to flush some commands here? */
771 pContext->bQueued = false;
772 return false;
773}
774
775void vboxVDMAControl(struct VBOXVDMAHOST *pVdma, PVBOXVDMA_CTL pCmd)
776{
777#if 1
778 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
779
780 switch (pCmd->enmCtl)
781 {
782 case VBOXVDMA_CTL_TYPE_ENABLE:
783 pVdma->bEnabled = true;
784 pCmd->i32Result = VINF_SUCCESS;
785 break;
786 case VBOXVDMA_CTL_TYPE_DISABLE:
787 pVdma->bEnabled = false;
788 pCmd->i32Result = VINF_SUCCESS;
789 break;
790 case VBOXVDMA_CTL_TYPE_FLUSH:
791 pCmd->i32Result = VINF_SUCCESS;
792 break;
793 default:
794 AssertBreakpoint();
795 pCmd->i32Result = VERR_NOT_SUPPORTED;
796 }
797
798 int rc = VBoxSHGSMICommandComplete (pIns, pCmd);
799 AssertRC(rc);
800#else
801 /* test asinch completion */
802 VBOXVDMACMD_SUBMIT_CONTEXT Context;
803 Context.pVdma = pVdma;
804 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACTL;
805 Context.Cmd.u.pCtl = pCmd;
806
807 int rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
808 AssertRC(rc);
809 if (RT_SUCCESS(rc))
810 {
811 Assert(Context.bQueued);
812 if (Context.bQueued)
813 {
814 /* success */
815 return;
816 }
817 rc = VERR_OUT_OF_RESOURCES;
818 }
819
820 /* failure */
821 Assert(RT_FAILURE(rc));
822 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
823 pCmd->i32Result = rc;
824 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
825 AssertRC(tmpRc);
826
827#endif
828}
829
830void vboxVDMACommand(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmd)
831{
832 VBOXVDMACMD_SUBMIT_CONTEXT Context;
833 Context.pVdma = pVdma;
834 Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACMD;
835 Context.Cmd.u.pDr = pCmd;
836
837 int rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
838 AssertRC(rc);
839 if (RT_SUCCESS(rc))
840 {
841 Assert(Context.bQueued);
842 if (Context.bQueued)
843 {
844 /* success */
845 return;
846 }
847 rc = VERR_OUT_OF_RESOURCES;
848 }
849
850 /* failure */
851 Assert(RT_FAILURE(rc));
852 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
853 pCmd->rc = rc;
854 int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
855 AssertRC(tmpRc);
856}
857
858bool vboxVDMAIsEnabled(PVBOXVDMAHOST pVdma)
859{
860 return pVdma->bEnabled;
861}
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