VirtualBox

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

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

wddm: graphics dev partial screen update fix

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