VirtualBox

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

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

wddm: graphics dev update only necessary portion of framebuffer

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