VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp@ 51324

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

DevVGA: fix IRQ handling racing

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.7 KB
Line 
1/* $Id: DevVGA_VBVA.cpp 51324 2014-05-21 13:29:34Z vboxsync $ */
2/** @file
3 * VirtualBox Video Acceleration (VBVA).
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DEV_VGA
22#include <VBox/vmm/pdmifs.h>
23#include <VBox/vmm/pdmdev.h>
24#include <VBox/vmm/pgm.h>
25#include <VBox/vmm/ssm.h>
26#include <VBox/VMMDev.h>
27#include <VBox/VBoxVideo.h>
28#include <iprt/alloc.h>
29#include <iprt/assert.h>
30#include <iprt/asm.h>
31#include <iprt/string.h>
32#include <iprt/param.h>
33#ifdef VBOX_WITH_VIDEOHWACCEL
34#include <iprt/semaphore.h>
35#endif
36
37#include "DevVGA.h"
38
39/* A very detailed logging. */
40#if 0 // def DEBUG_sunlover
41#define LOGVBVABUFFER(a) LogFlow(a)
42#else
43#define LOGVBVABUFFER(a) do {} while (0)
44#endif
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49typedef struct VBVAPARTIALRECORD
50{
51 uint8_t *pu8;
52 uint32_t cb;
53} VBVAPARTIALRECORD;
54
55typedef struct VBVAVIEW
56{
57 VBVAINFOVIEW view;
58 VBVAINFOSCREEN screen;
59 VBVABUFFER *pVBVA;
60 uint32_t u32VBVAOffset;
61 VBVAPARTIALRECORD partialRecord;
62} VBVAVIEW;
63
64typedef struct VBVAMOUSESHAPEINFO
65{
66 bool fSet;
67 bool fVisible;
68 bool fAlpha;
69 uint32_t u32HotX;
70 uint32_t u32HotY;
71 uint32_t u32Width;
72 uint32_t u32Height;
73 uint32_t cbShape;
74 uint32_t cbAllocated;
75 uint8_t *pu8Shape;
76} VBVAMOUSESHAPEINFO;
77
78/** @todo saved state: save and restore VBVACONTEXT */
79typedef struct VBVACONTEXT
80{
81 uint32_t cViews;
82 VBVAVIEW aViews[64 /* @todo SchemaDefs::MaxGuestMonitors*/];
83 VBVAMOUSESHAPEINFO mouseShapeInfo;
84 bool fPaused;
85} VBVACONTEXT;
86
87
88
89/** Copies @a cb bytes from the VBVA ring buffer to the @a pu8Dst.
90 * Used for partial records or for records which cross the ring boundary.
91 */
92static void vbvaFetchBytes (VBVABUFFER *pVBVA, uint8_t *pu8Dst, uint32_t cb)
93{
94 /** @todo replace the 'if' with an assert. The caller must ensure this condition. */
95 if (cb >= pVBVA->cbData)
96 {
97 AssertMsgFailed (("cb = 0x%08X, ring buffer size 0x%08X", cb, pVBVA->cbData));
98 return;
99 }
100
101 const uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
102 const uint8_t *src = &pVBVA->au8Data[pVBVA->off32Data];
103 const int32_t i32Diff = cb - u32BytesTillBoundary;
104
105 if (i32Diff <= 0)
106 {
107 /* Chunk will not cross buffer boundary. */
108 memcpy (pu8Dst, src, cb);
109 }
110 else
111 {
112 /* Chunk crosses buffer boundary. */
113 memcpy (pu8Dst, src, u32BytesTillBoundary);
114 memcpy (pu8Dst + u32BytesTillBoundary, &pVBVA->au8Data[0], i32Diff);
115 }
116
117 /* Advance data offset. */
118 pVBVA->off32Data = (pVBVA->off32Data + cb) % pVBVA->cbData;
119
120 return;
121}
122
123
124static bool vbvaPartialRead (VBVAPARTIALRECORD *pPartialRecord, uint32_t cbRecord, VBVABUFFER *pVBVA)
125{
126 uint8_t *pu8New;
127
128 LOGVBVABUFFER(("vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
129 pPartialRecord->pu8, pPartialRecord->cb, cbRecord));
130
131 if (pPartialRecord->pu8)
132 {
133 Assert (pPartialRecord->cb);
134 pu8New = (uint8_t *)RTMemRealloc (pPartialRecord->pu8, cbRecord);
135 }
136 else
137 {
138 Assert (!pPartialRecord->cb);
139 pu8New = (uint8_t *)RTMemAlloc (cbRecord);
140 }
141
142 if (!pu8New)
143 {
144 /* Memory allocation failed, fail the function. */
145 Log(("vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
146 cbRecord));
147
148 if (pPartialRecord->pu8)
149 {
150 RTMemFree (pPartialRecord->pu8);
151 }
152
153 pPartialRecord->pu8 = NULL;
154 pPartialRecord->cb = 0;
155
156 return false;
157 }
158
159 /* Fetch data from the ring buffer. */
160 vbvaFetchBytes (pVBVA, pu8New + pPartialRecord->cb, cbRecord - pPartialRecord->cb);
161
162 pPartialRecord->pu8 = pu8New;
163 pPartialRecord->cb = cbRecord;
164
165 return true;
166}
167
168/* For contiguous chunks just return the address in the buffer.
169 * For crossing boundary - allocate a buffer from heap.
170 */
171static bool vbvaFetchCmd (VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA, VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
172{
173 uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
174 uint32_t indexRecordFree = pVBVA->indexRecordFree;
175
176 LOGVBVABUFFER(("first = %d, free = %d\n",
177 indexRecordFirst, indexRecordFree));
178
179 if (indexRecordFirst == indexRecordFree)
180 {
181 /* No records to process. Return without assigning output variables. */
182 return true;
183 }
184
185 uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVBVA->aRecords[indexRecordFirst].cbRecord);
186
187 LOGVBVABUFFER(("cbRecord = 0x%08X, pPartialRecord->cb = 0x%08X\n", cbRecordCurrent, pPartialRecord->cb));
188
189 uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
190
191 if (pPartialRecord->cb)
192 {
193 /* There is a partial read in process. Continue with it. */
194 Assert (pPartialRecord->pu8);
195
196 LOGVBVABUFFER(("continue partial record cb = %d cbRecord 0x%08X, first = %d, free = %d\n",
197 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
198
199 if (cbRecord > pPartialRecord->cb)
200 {
201 /* New data has been added to the record. */
202 if (!vbvaPartialRead (pPartialRecord, cbRecord, pVBVA))
203 {
204 return false;
205 }
206 }
207
208 if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL))
209 {
210 /* The record is completed by guest. Return it to the caller. */
211 *ppHdr = (VBVACMDHDR *)pPartialRecord->pu8;
212 *pcbCmd = pPartialRecord->cb;
213
214 pPartialRecord->pu8 = NULL;
215 pPartialRecord->cb = 0;
216
217 /* Advance the record index. */
218 pVBVA->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
219
220 LOGVBVABUFFER(("partial done ok, data = %d, free = %d\n",
221 pVBVA->off32Data, pVBVA->off32Free));
222 }
223
224 return true;
225 }
226
227 /* A new record need to be processed. */
228 if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
229 {
230 /* Current record is being written by guest. '=' is important here,
231 * because the guest will do a FLUSH at this condition.
232 * This partial record is too large for the ring buffer and must
233 * be accumulated in an allocated buffer.
234 */
235 if (cbRecord >= pVBVA->cbData - pVBVA->cbPartialWriteThreshold)
236 {
237 /* Partial read must be started. */
238 if (!vbvaPartialRead (pPartialRecord, cbRecord, pVBVA))
239 {
240 return false;
241 }
242
243 LOGVBVABUFFER(("started partial record cb = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
244 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
245 }
246
247 return true;
248 }
249
250 /* Current record is complete. If it is not empty, process it. */
251 if (cbRecord)
252 {
253 /* The size of largest contiguous chunk in the ring biffer. */
254 uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
255
256 /* The pointer to data in the ring buffer. */
257 uint8_t *src = &pVBVA->au8Data[pVBVA->off32Data];
258
259 /* Fetch or point the data. */
260 if (u32BytesTillBoundary >= cbRecord)
261 {
262 /* The command does not cross buffer boundary. Return address in the buffer. */
263 *ppHdr = (VBVACMDHDR *)src;
264
265 /* Advance data offset. */
266 pVBVA->off32Data = (pVBVA->off32Data + cbRecord) % pVBVA->cbData;
267 }
268 else
269 {
270 /* The command crosses buffer boundary. Rare case, so not optimized. */
271 uint8_t *dst = (uint8_t *)RTMemAlloc (cbRecord);
272
273 if (!dst)
274 {
275 LogFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord));
276 pVBVA->off32Data = (pVBVA->off32Data + cbRecord) % pVBVA->cbData;
277 return false;
278 }
279
280 vbvaFetchBytes (pVBVA, dst, cbRecord);
281
282 *ppHdr = (VBVACMDHDR *)dst;
283
284 LOGVBVABUFFER(("Allocated from heap %p\n", dst));
285 }
286 }
287
288 *pcbCmd = cbRecord;
289
290 /* Advance the record index. */
291 pVBVA->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
292
293 LOGVBVABUFFER(("done ok, data = %d, free = %d\n",
294 pVBVA->off32Data, pVBVA->off32Free));
295
296 return true;
297}
298
299static void vbvaReleaseCmd (VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA, VBVACMDHDR *pHdr, uint32_t cbCmd)
300{
301 uint8_t *au8RingBuffer = &pVBVA->au8Data[0];
302
303 if ( (uint8_t *)pHdr >= au8RingBuffer
304 && (uint8_t *)pHdr < &au8RingBuffer[pVBVA->cbData])
305 {
306 /* The pointer is inside ring buffer. Must be continuous chunk. */
307 Assert (pVBVA->cbData - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);
308
309 /* Do nothing. */
310
311 Assert (!pPartialRecord->pu8 && pPartialRecord->cb == 0);
312 }
313 else
314 {
315 /* The pointer is outside. It is then an allocated copy. */
316 LOGVBVABUFFER(("Free heap %p\n", pHdr));
317
318 if ((uint8_t *)pHdr == pPartialRecord->pu8)
319 {
320 pPartialRecord->pu8 = NULL;
321 pPartialRecord->cb = 0;
322 }
323 else
324 {
325 Assert (!pPartialRecord->pu8 && pPartialRecord->cb == 0);
326 }
327
328 RTMemFree (pHdr);
329 }
330
331 return;
332}
333
334static int vbvaFlushProcess (unsigned uScreenId, PVGASTATE pVGAState, VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA)
335{
336 LOGVBVABUFFER(("uScreenId %d, indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
337 uScreenId, pVBVA->indexRecordFirst, pVBVA->indexRecordFree, pVBVA->off32Data, pVBVA->off32Free));
338 struct {
339 /* The rectangle that includes all dirty rectangles. */
340 int32_t xLeft;
341 int32_t xRight;
342 int32_t yTop;
343 int32_t yBottom;
344 } dirtyRect;
345 RT_ZERO(dirtyRect);
346
347 bool fUpdate = false; /* Whether there were any updates. */
348 bool fDirtyEmpty = true;
349
350 for (;;)
351 {
352 VBVACMDHDR *phdr = NULL;
353 uint32_t cbCmd = ~0;
354
355 /* Fetch the command data. */
356 if (!vbvaFetchCmd (pPartialRecord, pVBVA, &phdr, &cbCmd))
357 {
358 LogFunc(("unable to fetch command. off32Data = %d, off32Free = %d!!!\n",
359 pVBVA->off32Data, pVBVA->off32Free));
360
361 /* @todo old code disabled VBVA processing here. */
362 return VERR_NOT_SUPPORTED;
363 }
364
365 if (cbCmd == uint32_t(~0))
366 {
367 /* No more commands yet in the queue. */
368 break;
369 }
370
371 if (cbCmd != 0)
372 {
373 if (!fUpdate)
374 {
375 pVGAState->pDrv->pfnVBVAUpdateBegin (pVGAState->pDrv, uScreenId);
376 fUpdate = true;
377 }
378
379 /* Updates the rectangle and sends the command to the VRDP server. */
380 pVGAState->pDrv->pfnVBVAUpdateProcess (pVGAState->pDrv, uScreenId, phdr, cbCmd);
381
382 int32_t xRight = phdr->x + phdr->w;
383 int32_t yBottom = phdr->y + phdr->h;
384
385 /* These are global coords, relative to the primary screen. */
386
387 LOGVBVABUFFER(("cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
388 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));
389 LogRel3(("%s: update command cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
390 __PRETTY_FUNCTION__, cbCmd, phdr->x, phdr->y, phdr->w,
391 phdr->h));
392
393 /* Collect all rects into one. */
394 if (fDirtyEmpty)
395 {
396 /* This is the first rectangle to be added. */
397 dirtyRect.xLeft = phdr->x;
398 dirtyRect.yTop = phdr->y;
399 dirtyRect.xRight = xRight;
400 dirtyRect.yBottom = yBottom;
401 fDirtyEmpty = false;
402 }
403 else
404 {
405 /* Adjust region coordinates. */
406 if (dirtyRect.xLeft > phdr->x)
407 {
408 dirtyRect.xLeft = phdr->x;
409 }
410
411 if (dirtyRect.yTop > phdr->y)
412 {
413 dirtyRect.yTop = phdr->y;
414 }
415
416 if (dirtyRect.xRight < xRight)
417 {
418 dirtyRect.xRight = xRight;
419 }
420
421 if (dirtyRect.yBottom < yBottom)
422 {
423 dirtyRect.yBottom = yBottom;
424 }
425 }
426 }
427
428 vbvaReleaseCmd (pPartialRecord, pVBVA, phdr, cbCmd);
429 }
430
431 if (fUpdate)
432 {
433 if (dirtyRect.xRight - dirtyRect.xLeft)
434 {
435 LogRel3(("%s: sending update screen=%d, x=%d, y=%d, w=%d, h=%d\n",
436 __PRETTY_FUNCTION__, uScreenId, dirtyRect.xLeft,
437 dirtyRect.yTop, dirtyRect.xRight - dirtyRect.xLeft,
438 dirtyRect.yBottom - dirtyRect.yTop));
439 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, dirtyRect.xLeft, dirtyRect.yTop,
440 dirtyRect.xRight - dirtyRect.xLeft, dirtyRect.yBottom - dirtyRect.yTop);
441 }
442 else
443 {
444 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, 0, 0, 0, 0);
445 }
446 }
447
448 return VINF_SUCCESS;
449}
450
451static int vbvaFlush (PVGASTATE pVGAState, VBVACONTEXT *pCtx)
452{
453 unsigned uScreenId;
454
455 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
456 {
457 VBVAPARTIALRECORD *pPartialRecord = &pCtx->aViews[uScreenId].partialRecord;
458 VBVABUFFER *pVBVA = pCtx->aViews[uScreenId].pVBVA;
459
460 if (pVBVA)
461 {
462 vbvaFlushProcess (uScreenId, pVGAState, pPartialRecord, pVBVA);
463 }
464 }
465
466 /* @todo rc */
467 return VINF_SUCCESS;
468}
469
470static int vbvaResize (PVGASTATE pVGAState, VBVAVIEW *pView, const VBVAINFOSCREEN *pNewScreen)
471{
472 /* Verify pNewScreen. */
473 /* @todo */
474
475 /* Apply these changes. */
476 pView->screen = *pNewScreen;
477
478 uint8_t *pu8VRAM = pVGAState->vram_ptrR3 + pView->view.u32ViewOffset;
479
480 int rc = pVGAState->pDrv->pfnVBVAResize (pVGAState->pDrv, &pView->view, &pView->screen, pu8VRAM);
481
482 /* @todo process VINF_VGA_RESIZE_IN_PROGRESS? */
483
484 return rc;
485}
486
487static int vbvaEnable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCtx, VBVABUFFER *pVBVA, uint32_t u32Offset, bool fRestored)
488{
489 /* @todo old code did a UpdateDisplayAll at this place. */
490
491 int rc;
492
493 if (pVGAState->pDrv->pfnVBVAEnable)
494 {
495 pVBVA->hostFlags.u32HostEvents = 0;
496 pVBVA->hostFlags.u32SupportedOrders = 0;
497
498 rc = pVGAState->pDrv->pfnVBVAEnable (pVGAState->pDrv, uScreenId, &pVBVA->hostFlags, false);
499 }
500 else
501 {
502 rc = VERR_NOT_SUPPORTED;
503 }
504
505 if (RT_SUCCESS (rc))
506 {
507 /* pVBVA->hostFlags has been set up by pfnVBVAEnable. */
508 LogFlowFunc(("u32HostEvents 0x%08X, u32SupportedOrders 0x%08X\n",
509 pVBVA->hostFlags.u32HostEvents, pVBVA->hostFlags.u32SupportedOrders));
510
511 if (!fRestored)
512 {
513 /* @todo Actually this function must not touch the partialRecord structure at all,
514 * because initially it is a zero and when VBVA is disabled this should be set to zero.
515 * But I'm not sure that no code depends on zeroing partialRecord here.
516 * So for now (a quick fix for 4.1) just do not do this if the VM was restored,
517 * when partialRecord might be loaded already from the saved state.
518 */
519 pCtx->aViews[uScreenId].partialRecord.pu8 = NULL;
520 pCtx->aViews[uScreenId].partialRecord.cb = 0;
521 }
522
523 pCtx->aViews[uScreenId].pVBVA = pVBVA;
524 pCtx->aViews[uScreenId].u32VBVAOffset = u32Offset;
525 }
526
527 return rc;
528}
529
530static int vbvaDisable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCtx)
531{
532 /* Process any pending orders and empty the VBVA ring buffer. */
533 vbvaFlush (pVGAState, pCtx);
534
535 VBVAVIEW *pView = &pCtx->aViews[uScreenId];
536
537 if (pView->pVBVA)
538 {
539 pView->pVBVA->hostFlags.u32HostEvents = 0;
540 pView->pVBVA->hostFlags.u32SupportedOrders = 0;
541
542 pView->partialRecord.pu8 = NULL;
543 pView->partialRecord.cb = 0;
544
545 pView->pVBVA = NULL;
546 pView->u32VBVAOffset = HGSMIOFFSET_VOID;
547 }
548
549 pVGAState->pDrv->pfnVBVADisable (pVGAState->pDrv, uScreenId);
550 return VINF_SUCCESS;
551}
552
553bool VBVAIsEnabled(PVGASTATE pVGAState)
554{
555 PHGSMIINSTANCE pHGSMI = pVGAState->pHGSMI;
556 if (pHGSMI)
557 {
558 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pHGSMI);
559 if (pCtx)
560 {
561 if (pCtx->cViews)
562 {
563 VBVAVIEW * pView = &pCtx->aViews[0];
564 if (pView->pVBVA)
565 return true;
566 }
567 }
568 }
569 return false;
570}
571
572#ifdef DEBUG_sunlover
573void dumpMouseShapeInfo(const VBVAMOUSESHAPEINFO *pMouseShapeInfo)
574{
575 LogFlow(("fSet = %d, fVisible %d, fAlpha %d, @%d,%d %dx%d (%p, %d/%d)\n",
576 pMouseShapeInfo->fSet,
577 pMouseShapeInfo->fVisible,
578 pMouseShapeInfo->fAlpha,
579 pMouseShapeInfo->u32HotX,
580 pMouseShapeInfo->u32HotY,
581 pMouseShapeInfo->u32Width,
582 pMouseShapeInfo->u32Height,
583 pMouseShapeInfo->pu8Shape,
584 pMouseShapeInfo->cbShape,
585 pMouseShapeInfo->cbAllocated
586 ));
587}
588#endif
589
590static int vbvaUpdateMousePointerShape(PVGASTATE pVGAState, VBVAMOUSESHAPEINFO *pMouseShapeInfo, bool fShape, const uint8_t *pu8Shape)
591{
592 int rc;
593 LogFlowFunc(("pVGAState %p, pMouseShapeInfo %p, fShape %d, pu8Shape %p\n",
594 pVGAState, pMouseShapeInfo, fShape, pu8Shape));
595#ifdef DEBUG_sunlover
596 dumpMouseShapeInfo(pMouseShapeInfo);
597#endif
598
599 if (fShape && pu8Shape != NULL)
600 {
601 rc = pVGAState->pDrv->pfnVBVAMousePointerShape (pVGAState->pDrv,
602 pMouseShapeInfo->fVisible,
603 pMouseShapeInfo->fAlpha,
604 pMouseShapeInfo->u32HotX,
605 pMouseShapeInfo->u32HotY,
606 pMouseShapeInfo->u32Width,
607 pMouseShapeInfo->u32Height,
608 pu8Shape);
609 }
610 else
611 {
612 rc = pVGAState->pDrv->pfnVBVAMousePointerShape (pVGAState->pDrv,
613 pMouseShapeInfo->fVisible,
614 false,
615 0, 0,
616 0, 0,
617 NULL);
618 }
619
620 return rc;
621}
622
623static int vbvaMousePointerShape (PVGASTATE pVGAState, VBVACONTEXT *pCtx, const VBVAMOUSEPOINTERSHAPE *pShape, HGSMISIZE cbShape)
624{
625 bool fVisible = (pShape->fu32Flags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
626 bool fAlpha = (pShape->fu32Flags & VBOX_MOUSE_POINTER_ALPHA) != 0;
627 bool fShape = (pShape->fu32Flags & VBOX_MOUSE_POINTER_SHAPE) != 0;
628
629 HGSMISIZE cbPointerData = 0;
630
631 if (fShape)
632 {
633 if (pShape->u32Width > 8192 || pShape->u32Height > 8192)
634 {
635 Log(("vbvaMousePointerShape: unsupported size %ux%u\n",
636 pShape->u32Width, pShape->u32Height));
637 return VERR_INVALID_PARAMETER;
638 }
639
640 cbPointerData = ((((pShape->u32Width + 7) / 8) * pShape->u32Height + 3) & ~3)
641 + pShape->u32Width * 4 * pShape->u32Height;
642 }
643
644 if (cbPointerData > cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data))
645 {
646 Log(("vbvaMousePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
647 cbPointerData, cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data)));
648 return VERR_INVALID_PARAMETER;
649 }
650
651 /* Save mouse info it will be used to restore mouse pointer after restoring saved state. */
652 pCtx->mouseShapeInfo.fSet = true;
653 pCtx->mouseShapeInfo.fVisible = fVisible;
654 pCtx->mouseShapeInfo.fAlpha = fAlpha;
655 if (fShape)
656 {
657 /* Data related to shape. */
658 pCtx->mouseShapeInfo.u32HotX = pShape->u32HotX;
659 pCtx->mouseShapeInfo.u32HotY = pShape->u32HotY;
660 pCtx->mouseShapeInfo.u32Width = pShape->u32Width;
661 pCtx->mouseShapeInfo.u32Height = pShape->u32Height;
662
663 /* Reallocate memory buffer if necessary. */
664 if (cbPointerData > pCtx->mouseShapeInfo.cbAllocated)
665 {
666 RTMemFree (pCtx->mouseShapeInfo.pu8Shape);
667 pCtx->mouseShapeInfo.pu8Shape = NULL;
668 pCtx->mouseShapeInfo.cbShape = 0;
669
670 uint8_t *pu8Shape = (uint8_t *)RTMemAlloc (cbPointerData);
671 if (pu8Shape)
672 {
673 pCtx->mouseShapeInfo.pu8Shape = pu8Shape;
674 pCtx->mouseShapeInfo.cbAllocated = cbPointerData;
675 }
676 }
677
678 /* Copy shape bitmaps. */
679 if (pCtx->mouseShapeInfo.pu8Shape)
680 {
681 memcpy (pCtx->mouseShapeInfo.pu8Shape, &pShape->au8Data[0], cbPointerData);
682 pCtx->mouseShapeInfo.cbShape = cbPointerData;
683 }
684 }
685
686 if (pVGAState->pDrv->pfnVBVAMousePointerShape == NULL)
687 {
688 return VERR_NOT_SUPPORTED;
689 }
690
691 int rc = vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, fShape, &pShape->au8Data[0]);
692
693 return rc;
694}
695
696static unsigned vbvaViewFromOffset (PHGSMIINSTANCE pIns, VBVACONTEXT *pCtx, const void *pvBuffer)
697{
698 /* Check which view contains the buffer. */
699 HGSMIOFFSET offBuffer = HGSMIPointerToOffsetHost (pIns, pvBuffer);
700
701 if (offBuffer != HGSMIOFFSET_VOID)
702 {
703 unsigned uScreenId;
704
705 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
706 {
707 VBVAINFOVIEW *pView = &pCtx->aViews[uScreenId].view;
708
709 if ( pView->u32ViewSize > 0
710 && pView->u32ViewOffset <= offBuffer
711 && offBuffer <= pView->u32ViewOffset + pView->u32ViewSize - 1)
712 {
713 return pView->u32ViewIndex;
714 }
715 }
716 }
717
718 return ~0U;
719}
720
721#ifdef DEBUG_sunlover
722static void dumpctx(const VBVACONTEXT *pCtx)
723{
724 Log(("VBVACONTEXT dump: cViews %d\n", pCtx->cViews));
725
726 uint32_t iView;
727 for (iView = 0; iView < pCtx->cViews; iView++)
728 {
729 const VBVAVIEW *pView = &pCtx->aViews[iView];
730
731 Log((" view %d o 0x%x s 0x%x m 0x%x\n",
732 pView->view.u32ViewIndex,
733 pView->view.u32ViewOffset,
734 pView->view.u32ViewSize,
735 pView->view.u32MaxScreenSize));
736
737 Log((" screen %d @%d,%d s 0x%x l 0x%x %dx%d bpp %d f 0x%x\n",
738 pView->screen.u32ViewIndex,
739 pView->screen.i32OriginX,
740 pView->screen.i32OriginY,
741 pView->screen.u32StartOffset,
742 pView->screen.u32LineSize,
743 pView->screen.u32Width,
744 pView->screen.u32Height,
745 pView->screen.u16BitsPerPixel,
746 pView->screen.u16Flags));
747
748 Log((" VBVA o 0x%x p %p\n",
749 pView->u32VBVAOffset,
750 pView->pVBVA));
751
752 Log((" PR cb 0x%x p %p\n",
753 pView->partialRecord.cb,
754 pView->partialRecord.pu8));
755 }
756
757 dumpMouseShapeInfo(&pCtx->mouseShapeInfo);
758}
759#endif /* DEBUG_sunlover */
760
761#define VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC 0x12345678
762#define VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC 0x9abcdef0
763
764#ifdef VBOX_WITH_VIDEOHWACCEL
765static void vbvaVHWAHHCommandReinit(VBOXVHWACMD* pHdr, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay)
766{
767 memset(pHdr, 0, VBOXVHWACMD_HEADSIZE());
768 pHdr->cRefs = 1;
769 pHdr->iDisplay = iDisplay;
770 pHdr->rc = VERR_NOT_IMPLEMENTED;
771 pHdr->enmCmd = enmCmd;
772 pHdr->Flags = VBOXVHWACMD_FLAG_HH_CMD;
773}
774
775static VBOXVHWACMD* vbvaVHWAHHCommandCreate (PVGASTATE pVGAState, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay, VBOXVHWACMD_LENGTH cbCmd)
776{
777 VBOXVHWACMD* pHdr = (VBOXVHWACMD*)RTMemAllocZ(cbCmd + VBOXVHWACMD_HEADSIZE());
778 Assert(pHdr);
779 if (pHdr)
780 vbvaVHWAHHCommandReinit(pHdr, enmCmd, iDisplay);
781
782 return pHdr;
783}
784
785DECLINLINE(void) vbvaVHWAHHCommandRelease (VBOXVHWACMD* pCmd)
786{
787 uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs);
788 if(!cRefs)
789 {
790 RTMemFree(pCmd);
791 }
792}
793
794DECLINLINE(void) vbvaVHWAHHCommandRetain (VBOXVHWACMD* pCmd)
795{
796 ASMAtomicIncU32(&pCmd->cRefs);
797}
798
799static void vbvaVHWACommandComplete(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand)
800{
801 if (fAsyncCommand)
802 {
803 Assert(pCommand->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
804 vbvaVHWACommandCompleteAsync(&pVGAState->IVBVACallbacks, pCommand);
805 }
806 else
807 {
808 Log(("VGA Command <<< Sync rc %d %#p, %d\n", pCommand->rc, pCommand, pCommand->enmCmd));
809 pCommand->Flags &= (~VBOXVHWACMD_FLAG_HG_ASYNCH);
810 }
811
812}
813
814static void vbvaVHWACommandCompleteAllPending(PVGASTATE pVGAState, int rc)
815{
816 if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending))
817 return;
818
819 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
820
821 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
822
823 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
824 {
825 pIter->pCommand->rc = rc;
826 vbvaVHWACommandComplete(pVGAState, pIter->pCommand, true);
827
828 /* the command is submitted/processed, remove from the pend list */
829 RTListNodeRemove(&pIter->Node);
830 ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending);
831 RTMemFree(pIter);
832 }
833
834 PDMCritSectLeave(&pVGAState->CritSect);
835}
836
837static void vbvaVHWACommandClearAllPending(PVGASTATE pVGAState)
838{
839 if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending))
840 return;
841
842 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
843
844 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
845
846 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
847 {
848 RTListNodeRemove(&pIter->Node);
849 ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending);
850 RTMemFree(pIter);
851 }
852
853 PDMCritSectLeave(&pVGAState->CritSect);
854}
855
856static void vbvaVHWACommandPend(PVGASTATE pVGAState, PVBOXVHWACMD pCommand)
857{
858 int rc = VERR_BUFFER_OVERFLOW;
859
860 if (ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS)
861 {
862 VBOX_VHWA_PENDINGCMD *pPend = (VBOX_VHWA_PENDINGCMD*)RTMemAlloc(sizeof (*pPend));
863 if (pPend)
864 {
865 pCommand->Flags |= VBOXVHWACMD_FLAG_HG_ASYNCH;
866 pPend->pCommand = pCommand;
867 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
868 if (ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS)
869 {
870 RTListAppend(&pVGAState->pendingVhwaCommands.PendingList, &pPend->Node);
871 ASMAtomicIncU32(&pVGAState->pendingVhwaCommands.cPending);
872 PDMCritSectLeave(&pVGAState->CritSect);
873 return;
874 }
875 PDMCritSectLeave(&pVGAState->CritSect);
876 LogRel(("Pending command count has reached its threshold.. completing them all.."));
877 RTMemFree(pPend);
878 }
879 else
880 rc = VERR_NO_MEMORY;
881 }
882 else
883 LogRel(("Pending command count has reached its threshold, completing them all.."));
884
885 vbvaVHWACommandCompleteAllPending(pVGAState, rc);
886
887 pCommand->rc = rc;
888
889 vbvaVHWACommandComplete(pVGAState, pCommand, false);
890}
891
892static bool vbvaVHWACommandCanPend(PVBOXVHWACMD pCommand)
893{
894 switch (pCommand->enmCmd)
895 {
896 case VBOXVHWACMD_TYPE_HH_CONSTRUCT:
897 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN:
898 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND:
899 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM:
900 case VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM:
901 return false;
902 default:
903 return true;
904 }
905}
906
907static int vbvaVHWACommandSavePending(PVGASTATE pVGAState, PSSMHANDLE pSSM)
908{
909 int rc = SSMR3PutU32(pSSM, pVGAState->pendingVhwaCommands.cPending);
910 AssertRCReturn(rc, rc);
911 VBOX_VHWA_PENDINGCMD *pIter;
912 RTListForEach(&pVGAState->pendingVhwaCommands.PendingList, pIter, VBOX_VHWA_PENDINGCMD, Node)
913 {
914 rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pIter->pCommand) - ((uint8_t*)pVGAState->vram_ptrR3)));
915 AssertRCReturn(rc, rc);
916 }
917 return rc;
918}
919
920static int vbvaVHWACommandLoadPending(PVGASTATE pVGAState, PSSMHANDLE pSSM, uint32_t u32Version)
921{
922 if (u32Version < VGA_SAVEDSTATE_VERSION_WITH_PENDVHWA)
923 return VINF_SUCCESS;
924
925 int rc;
926 uint32_t u32;
927 rc = SSMR3GetU32(pSSM, &u32);
928 AssertRCReturn(rc, rc);
929 for (uint32_t i = 0; i < u32; ++i)
930 {
931 uint32_t off32;
932 rc = SSMR3GetU32(pSSM, &off32);
933 AssertRCReturn(rc, rc);
934 PVBOXVHWACMD pCommand = (PVBOXVHWACMD)(((uint8_t*)pVGAState->vram_ptrR3) + off32);
935 vbvaVHWACommandPend(pVGAState, pCommand);
936 }
937 return rc;
938}
939
940
941static bool vbvaVHWACommandSubmit(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand)
942{
943 unsigned id = (unsigned)pCommand->iDisplay;
944 bool fPend = false;
945
946 if (pVGAState->pDrv->pfnVHWACommandProcess)
947 {
948 Log(("VGA Command >>> %#p, %d\n", pCommand, pCommand->enmCmd));
949 int rc = pVGAState->pDrv->pfnVHWACommandProcess(pVGAState->pDrv, pCommand);
950 if (rc == VINF_CALLBACK_RETURN)
951 {
952 Log(("VGA Command --- Going Async %#p, %d\n", pCommand, pCommand->enmCmd));
953 return true; /* command will be completed asynchronously, return right away */
954 }
955 else if (rc == VERR_INVALID_STATE)
956 {
957 Log(("VGA Command --- Trying Pend %#p, %d\n", pCommand, pCommand->enmCmd));
958 fPend = vbvaVHWACommandCanPend(pCommand);
959 if (!fPend)
960 {
961 Log(("VGA Command --- Can NOT Pend %#p, %d\n", pCommand, pCommand->enmCmd));
962 pCommand->rc = rc;
963 }
964 else
965 Log(("VGA Command --- Can Pend %#p, %d\n", pCommand, pCommand->enmCmd));
966 }
967 else
968 {
969 Log(("VGA Command --- Going Complete Sync rc %d %#p, %d\n", rc, pCommand, pCommand->enmCmd));
970 pCommand->rc = rc;
971 }
972
973 /* the command was completed, take a special care about it (seee below) */
974 }
975 else
976 {
977 AssertFailed();
978 pCommand->rc = VERR_INVALID_STATE;
979 }
980
981 if (fPend)
982 return false;
983
984 vbvaVHWACommandComplete(pVGAState, pCommand, fAsyncCommand);
985
986 return true;
987}
988
989static bool vbvaVHWACheckPendingCommands(PVGASTATE pVGAState)
990{
991 if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending))
992 return true;
993
994 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
995
996 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
997
998 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
999 {
1000 if (!vbvaVHWACommandSubmit(pVGAState, pIter->pCommand, true))
1001 {
1002 PDMCritSectLeave(&pVGAState->CritSect);
1003 return false; /* the command should be pended still */
1004 }
1005
1006 /* the command is submitted/processed, remove from the pend list */
1007 RTListNodeRemove(&pIter->Node);
1008 ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending);
1009 RTMemFree(pIter);
1010 }
1011
1012 PDMCritSectLeave(&pVGAState->CritSect);
1013
1014 return true;
1015}
1016
1017void vbvaTimerCb(PVGASTATE pVGAState)
1018{
1019 vbvaVHWACheckPendingCommands(pVGAState);
1020}
1021static void vbvaVHWAHandleCommand(PVGASTATE pVGAState, PVBOXVHWACMD pCmd)
1022{
1023 if (vbvaVHWACheckPendingCommands(pVGAState))
1024 {
1025 if (vbvaVHWACommandSubmit(pVGAState, pCmd, false))
1026 return;
1027 }
1028
1029 vbvaVHWACommandPend(pVGAState, pCmd);
1030}
1031
1032static DECLCALLBACK(void) vbvaVHWAHHCommandSetEventCallback(void * pContext)
1033{
1034 RTSemEventSignal((RTSEMEVENT)pContext);
1035}
1036
1037static int vbvaVHWAHHCommandPost(PVGASTATE pVGAState, VBOXVHWACMD* pCmd)
1038{
1039 RTSEMEVENT hComplEvent;
1040 int rc = RTSemEventCreate(&hComplEvent);
1041 AssertRC(rc);
1042 if(RT_SUCCESS(rc))
1043 {
1044 /* ensure the cmd is not deleted until we process it */
1045 vbvaVHWAHHCommandRetain (pCmd);
1046 VBOXVHWA_HH_CALLBACK_SET(pCmd, vbvaVHWAHHCommandSetEventCallback, (void*)hComplEvent);
1047 vbvaVHWAHandleCommand(pVGAState, pCmd);
1048 if((ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_ASYNCH) != 0)
1049 {
1050 rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT);
1051 }
1052 else
1053 {
1054 /* the command is completed */
1055 }
1056
1057 AssertRC(rc);
1058 if(RT_SUCCESS(rc))
1059 {
1060 RTSemEventDestroy(hComplEvent);
1061 }
1062 vbvaVHWAHHCommandRelease(pCmd);
1063 }
1064 return rc;
1065}
1066
1067int vbvaVHWAConstruct (PVGASTATE pVGAState)
1068{
1069 pVGAState->pendingVhwaCommands.cPending = 0;
1070 RTListInit(&pVGAState->pendingVhwaCommands.PendingList);
1071
1072 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_CONSTRUCT, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
1073 Assert(pCmd);
1074 if(pCmd)
1075 {
1076 uint32_t iDisplay = 0;
1077 int rc = VINF_SUCCESS;
1078 VBOXVHWACMD_HH_CONSTRUCT * pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_CONSTRUCT);
1079
1080 do
1081 {
1082 memset(pBody, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
1083
1084 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1085 PVM pVM = PDMDevHlpGetVM(pDevIns);
1086
1087 pBody->pVM = pVM;
1088 pBody->pvVRAM = pVGAState->vram_ptrR3;
1089 pBody->cbVRAM = pVGAState->vram_size;
1090
1091 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
1092 AssertRC(rc);
1093 if(RT_SUCCESS(rc))
1094 {
1095 rc = pCmd->rc;
1096 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1097 if(rc == VERR_NOT_IMPLEMENTED)
1098 {
1099 /* @todo: set some flag in pVGAState indicating VHWA is not supported */
1100 /* VERR_NOT_IMPLEMENTED is not a failure, we just do not support it */
1101 rc = VINF_SUCCESS;
1102 }
1103
1104 if (!RT_SUCCESS(rc))
1105 break;
1106 }
1107 else
1108 break;
1109
1110 ++iDisplay;
1111 if (iDisplay >= pVGAState->cMonitors)
1112 break;
1113 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_CONSTRUCT, (int32_t)iDisplay);
1114 } while (true);
1115
1116 vbvaVHWAHHCommandRelease(pCmd);
1117
1118 return rc;
1119 }
1120 return VERR_OUT_OF_RESOURCES;
1121}
1122
1123int vbvaVHWAReset (PVGASTATE pVGAState)
1124{
1125 vbvaVHWACommandClearAllPending(pVGAState);
1126
1127 /* ensure we have all pending cmds processed and h->g cmds disabled */
1128 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_RESET, 0, 0);
1129 Assert(pCmd);
1130 if(pCmd)
1131 {
1132 int rc = VINF_SUCCESS;
1133 uint32_t iDisplay = 0;
1134
1135 do
1136 {
1137 rc =vbvaVHWAHHCommandPost(pVGAState, pCmd);
1138 AssertRC(rc);
1139 if(RT_SUCCESS(rc))
1140 {
1141 rc = pCmd->rc;
1142 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1143 if (rc == VERR_NOT_IMPLEMENTED)
1144 rc = VINF_SUCCESS;
1145 }
1146
1147 if (!RT_SUCCESS(rc))
1148 break;
1149
1150 ++iDisplay;
1151 if (iDisplay >= pVGAState->cMonitors)
1152 break;
1153 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_RESET, (int32_t)iDisplay);
1154
1155 } while (true);
1156
1157 vbvaVHWAHHCommandRelease(pCmd);
1158
1159 return rc;
1160 }
1161 return VERR_OUT_OF_RESOURCES;
1162}
1163
1164typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPRECB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext);
1165typedef FNVBOXVHWAHHCMDPRECB *PFNVBOXVHWAHHCMDPRECB;
1166
1167typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPOSTCB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext);
1168typedef FNVBOXVHWAHHCMDPOSTCB *PFNVBOXVHWAHHCMDPOSTCB;
1169
1170int vbvaVHWAHHPost(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, PFNVBOXVHWAHHCMDPRECB pfnPre, PFNVBOXVHWAHHCMDPOSTCB pfnPost, void *pvContext)
1171{
1172 const VBOXVHWACMD_TYPE enmType = pCmd->enmCmd;
1173 int rc = VINF_SUCCESS;
1174 uint32_t iDisplay = 0;
1175
1176 do
1177 {
1178 if (!pfnPre || pfnPre(pVGAState, pCmd, iDisplay, pvContext))
1179 {
1180 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
1181 AssertRC(rc);
1182 if (pfnPost)
1183 {
1184 if (!pfnPost(pVGAState, pCmd, iDisplay, rc, pvContext))
1185 {
1186 rc = VINF_SUCCESS;
1187 break;
1188 }
1189 rc = VINF_SUCCESS;
1190 }
1191 else if(RT_SUCCESS(rc))
1192 {
1193 rc = pCmd->rc;
1194 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1195 if(rc == VERR_NOT_IMPLEMENTED)
1196 {
1197 rc = VINF_SUCCESS;
1198 }
1199 }
1200
1201 if (!RT_SUCCESS(rc))
1202 break;
1203 }
1204
1205 ++iDisplay;
1206 if (iDisplay >= pVGAState->cMonitors)
1207 break;
1208 vbvaVHWAHHCommandReinit(pCmd, enmType, (int32_t)iDisplay);
1209 } while (true);
1210
1211 return rc;
1212}
1213
1214/* @todo call this also on reset? */
1215int vbvaVHWAEnable (PVGASTATE pVGAState, bool bEnable)
1216{
1217 const VBOXVHWACMD_TYPE enmType = bEnable ? VBOXVHWACMD_TYPE_HH_ENABLE : VBOXVHWACMD_TYPE_HH_DISABLE;
1218 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState,
1219 enmType,
1220 0, 0);
1221 Assert(pCmd);
1222 if(pCmd)
1223 {
1224 int rc = vbvaVHWAHHPost (pVGAState, pCmd, NULL, NULL, NULL);
1225 vbvaVHWAHHCommandRelease(pCmd);
1226 return rc;
1227 }
1228 return VERR_OUT_OF_RESOURCES;
1229}
1230
1231int vboxVBVASaveStatePrep (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1232{
1233 /* ensure we have no pending commands */
1234 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), false);
1235}
1236
1237int vboxVBVASaveStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1238{
1239 /* ensure we have no pending commands */
1240 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), true);
1241}
1242
1243int vbvaVHWACommandCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVHWACMD pCmd)
1244{
1245 int rc;
1246 Log(("VGA Command <<< Async rc %d %#p, %d\n", pCmd->rc, pCmd, pCmd->enmCmd));
1247
1248 if((pCmd->Flags & VBOXVHWACMD_FLAG_HH_CMD) == 0)
1249 {
1250 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
1251 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1252
1253 Assert(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
1254#ifdef VBOX_WITH_WDDM
1255 if (pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD)
1256 {
1257 rc = HGSMICompleteGuestCommand(pIns, pCmd, !!(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ));
1258 AssertRC(rc);
1259 }
1260 else
1261#endif
1262 {
1263 VBVAHOSTCMD *pHostCmd;
1264 int32_t iDisplay = pCmd->iDisplay;
1265
1266 if(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT)
1267 {
1268 rc = HGSMIHostCommandAlloc (pIns,
1269 (void**)&pHostCmd,
1270 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)),
1271 HGSMI_CH_VBVA,
1272 VBVAHG_EVENT);
1273 AssertRC(rc);
1274 if(RT_SUCCESS(rc))
1275 {
1276 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)));
1277 pHostCmd->iDstID = pCmd->iDisplay;
1278 pHostCmd->customOpCode = 0;
1279 VBVAHOSTCMDEVENT *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDEVENT);
1280 pBody->pEvent = pCmd->GuestVBVAReserved1;
1281 }
1282 }
1283 else
1284 {
1285 HGSMIOFFSET offCmd = HGSMIPointerToOffsetHost (pIns, pCmd);
1286 Assert(offCmd != HGSMIOFFSET_VOID);
1287 if(offCmd != HGSMIOFFSET_VOID)
1288 {
1289 rc = HGSMIHostCommandAlloc (pIns,
1290 (void**)&pHostCmd,
1291 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)),
1292 HGSMI_CH_VBVA,
1293 VBVAHG_DISPLAY_CUSTOM);
1294 AssertRC(rc);
1295 if(RT_SUCCESS(rc))
1296 {
1297 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)));
1298 pHostCmd->iDstID = pCmd->iDisplay;
1299 pHostCmd->customOpCode = VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE;
1300 VBVAHOSTCMDVHWACMDCOMPLETE *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDVHWACMDCOMPLETE);
1301 pBody->offCmd = offCmd;
1302 }
1303 }
1304 else
1305 {
1306 rc = VERR_INVALID_PARAMETER;
1307 }
1308 }
1309
1310 if(RT_SUCCESS(rc))
1311 {
1312 rc = HGSMIHostCommandProcessAndFreeAsynch(pIns, pHostCmd, (pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ) != 0);
1313 AssertRC(rc);
1314 if(RT_SUCCESS(rc))
1315 {
1316 return rc;
1317 }
1318 HGSMIHostCommandFree (pIns, pHostCmd);
1319 }
1320 }
1321 }
1322 else
1323 {
1324 PFNVBOXVHWA_HH_CALLBACK pfn = VBOXVHWA_HH_CALLBACK_GET(pCmd);
1325 if(pfn)
1326 {
1327 pfn(VBOXVHWA_HH_CALLBACK_GET_ARG(pCmd));
1328 }
1329 rc = VINF_SUCCESS;
1330 }
1331 return rc;
1332}
1333
1334typedef struct VBOXVBVASAVEDSTATECBDATA
1335{
1336 PSSMHANDLE pSSM;
1337 int rc;
1338 bool ab2DOn[VBOX_VIDEO_MAX_SCREENS];
1339} VBOXVBVASAVEDSTATECBDATA, *PVBOXVBVASAVEDSTATECBDATA;
1340
1341static DECLCALLBACK(bool) vboxVBVASaveStateBeginPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1342{
1343 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1344 if (RT_FAILURE(pData->rc))
1345 return false;
1346 if (RT_FAILURE(rc))
1347 {
1348 pData->rc = rc;
1349 return false;
1350 }
1351
1352 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1353 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1354 {
1355 pData->rc = VERR_INVALID_PARAMETER;
1356 return false;
1357 }
1358
1359 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1360 if (RT_SUCCESS(pCmd->rc))
1361 {
1362 pData->ab2DOn[iDisplay] = true;
1363 }
1364 else if (pCmd->rc != VERR_NOT_IMPLEMENTED)
1365 {
1366 pData->rc = pCmd->rc;
1367 return false;
1368 }
1369
1370 return true;
1371}
1372
1373static DECLCALLBACK(bool) vboxVBVASaveStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1374{
1375 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1376 if (RT_FAILURE(pData->rc))
1377 return false;
1378
1379 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1380 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1381 {
1382 pData->rc = VERR_INVALID_PARAMETER;
1383 return false;
1384 }
1385
1386 int rc;
1387
1388 if (pData->ab2DOn[iDisplay])
1389 {
1390 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC); AssertRC(rc);
1391 if (RT_FAILURE(rc))
1392 {
1393 pData->rc = rc;
1394 return false;
1395 }
1396 return true;
1397 }
1398
1399 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC); AssertRC(rc);
1400 if (RT_FAILURE(rc))
1401 {
1402 pData->rc = rc;
1403 return false;
1404 }
1405
1406 return false;
1407}
1408
1409static DECLCALLBACK(bool) vboxVBVASaveStateEndPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1410{
1411 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1412 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1413 if (pData->ab2DOn[iDisplay])
1414 {
1415 return true;
1416 }
1417
1418 return false;
1419}
1420
1421static DECLCALLBACK(bool) vboxVBVALoadStatePerformPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1422{
1423 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1424 if (RT_FAILURE(pData->rc))
1425 return false;
1426 if (RT_FAILURE(rc))
1427 {
1428 pData->rc = rc;
1429 return false;
1430 }
1431
1432 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1433 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1434 {
1435 pData->rc = VERR_INVALID_PARAMETER;
1436 return false;
1437 }
1438
1439 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1440 if (pCmd->rc == VERR_NOT_IMPLEMENTED)
1441 {
1442 pData->rc = SSMR3SkipToEndOfUnit(pData->pSSM);
1443 AssertRC(pData->rc);
1444 return false;
1445 }
1446 if (RT_FAILURE(pCmd->rc))
1447 {
1448 pData->rc = pCmd->rc;
1449 return false;
1450 }
1451
1452 return true;
1453}
1454
1455static DECLCALLBACK(bool) vboxVBVALoadStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1456{
1457 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1458 if (RT_FAILURE(pData->rc))
1459 return false;
1460
1461 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1462 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1463 {
1464 pData->rc = VERR_INVALID_PARAMETER;
1465 return false;
1466 }
1467
1468 int rc;
1469 uint32_t u32;
1470 rc = SSMR3GetU32(pData->pSSM, &u32); AssertRC(rc);
1471 if (RT_FAILURE(rc))
1472 {
1473 pData->rc = rc;
1474 return false;
1475 }
1476
1477 switch (u32)
1478 {
1479 case VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC:
1480 return true;
1481 case VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC:
1482 return false;
1483 default:
1484 pData->rc = VERR_INVALID_STATE;
1485 return false;
1486 }
1487}
1488#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
1489
1490int vboxVBVASaveDevStateExec (PVGASTATE pVGAState, PSSMHANDLE pSSM)
1491{
1492 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1493 int rc = HGSMIHostSaveStateExec (pIns, pSSM);
1494 if (RT_SUCCESS(rc))
1495 {
1496 /* Save VBVACONTEXT. */
1497 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1498
1499 if (!pCtx)
1500 {
1501 AssertFailed();
1502
1503 /* Still write a valid value to the SSM. */
1504 rc = SSMR3PutU32 (pSSM, 0);
1505 AssertRCReturn(rc, rc);
1506 }
1507 else
1508 {
1509#ifdef DEBUG_sunlover
1510 dumpctx(pCtx);
1511#endif
1512
1513 rc = SSMR3PutU32 (pSSM, pCtx->cViews);
1514 AssertRCReturn(rc, rc);
1515
1516 uint32_t iView;
1517 for (iView = 0; iView < pCtx->cViews; iView++)
1518 {
1519 VBVAVIEW *pView = &pCtx->aViews[iView];
1520
1521 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewIndex);
1522 AssertRCReturn(rc, rc);
1523 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewOffset);
1524 AssertRCReturn(rc, rc);
1525 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewSize);
1526 AssertRCReturn(rc, rc);
1527 rc = SSMR3PutU32 (pSSM, pView->view.u32MaxScreenSize);
1528 AssertRCReturn(rc, rc);
1529
1530 rc = SSMR3PutU32 (pSSM, pView->screen.u32ViewIndex);
1531 AssertRCReturn(rc, rc);
1532 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginX);
1533 AssertRCReturn(rc, rc);
1534 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginY);
1535 AssertRCReturn(rc, rc);
1536 rc = SSMR3PutU32 (pSSM, pView->screen.u32StartOffset);
1537 AssertRCReturn(rc, rc);
1538 rc = SSMR3PutU32 (pSSM, pView->screen.u32LineSize);
1539 AssertRCReturn(rc, rc);
1540 rc = SSMR3PutU32 (pSSM, pView->screen.u32Width);
1541 AssertRCReturn(rc, rc);
1542 rc = SSMR3PutU32 (pSSM, pView->screen.u32Height);
1543 AssertRCReturn(rc, rc);
1544 rc = SSMR3PutU16 (pSSM, pView->screen.u16BitsPerPixel);
1545 AssertRCReturn(rc, rc);
1546 rc = SSMR3PutU16 (pSSM, pView->screen.u16Flags);
1547 AssertRCReturn(rc, rc);
1548
1549 rc = SSMR3PutU32 (pSSM, pView->pVBVA? pView->u32VBVAOffset: HGSMIOFFSET_VOID);
1550 AssertRCReturn(rc, rc);
1551
1552 rc = SSMR3PutU32 (pSSM, pView->partialRecord.cb);
1553 AssertRCReturn(rc, rc);
1554
1555 if (pView->partialRecord.cb > 0)
1556 {
1557 rc = SSMR3PutMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1558 AssertRCReturn(rc, rc);
1559 }
1560 }
1561
1562 /* Save mouse pointer shape information. */
1563 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fSet);
1564 AssertRCReturn(rc, rc);
1565 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fVisible);
1566 AssertRCReturn(rc, rc);
1567 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fAlpha);
1568 AssertRCReturn(rc, rc);
1569 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotX);
1570 AssertRCReturn(rc, rc);
1571 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotY);
1572 AssertRCReturn(rc, rc);
1573 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Width);
1574 AssertRCReturn(rc, rc);
1575 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Height);
1576 AssertRCReturn(rc, rc);
1577 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.cbShape);
1578 AssertRCReturn(rc, rc);
1579 if (pCtx->mouseShapeInfo.cbShape)
1580 {
1581 rc = SSMR3PutMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1582 AssertRCReturn(rc, rc);
1583 }
1584
1585#ifdef VBOX_WITH_WDDM
1586 /* Size of some additional data. For future extensions. */
1587 rc = SSMR3PutU32 (pSSM, 4);
1588 AssertRCReturn(rc, rc);
1589 rc = SSMR3PutU32 (pSSM, pVGAState->fGuestCaps);
1590 AssertRCReturn(rc, rc);
1591#else
1592 /* Size of some additional data. For future extensions. */
1593 rc = SSMR3PutU32 (pSSM, 0);
1594 AssertRCReturn(rc, rc);
1595#endif
1596 }
1597 }
1598
1599 return rc;
1600}
1601
1602int vboxVBVASaveStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1603{
1604 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1605 int rc;
1606#ifdef VBOX_WITH_VIDEOHWACCEL
1607 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1608 VhwaData.pSSM = pSSM;
1609 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM); /* maximum cmd size */
1610 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN, 0, cbCmd);
1611 Assert(pCmd);
1612 if(pCmd)
1613 {
1614 vbvaVHWAHHPost (pVGAState, pCmd, NULL, vboxVBVASaveStateBeginPostCb, &VhwaData);
1615 rc = VhwaData.rc;
1616 AssertRC(rc);
1617 if (RT_SUCCESS(rc))
1618 {
1619#endif
1620 rc = vboxVBVASaveDevStateExec (pVGAState, pSSM);
1621 AssertRC(rc);
1622#ifdef VBOX_WITH_VIDEOHWACCEL
1623 if (RT_SUCCESS(rc))
1624 {
1625 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM, 0);
1626 VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM *pSave = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM);
1627 pSave->pSSM = pSSM;
1628 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStatePerformPreCb, NULL, &VhwaData);
1629 rc = VhwaData.rc;
1630 AssertRC(rc);
1631 if (RT_SUCCESS(rc))
1632 {
1633 rc = vbvaVHWACommandSavePending(pVGAState, pSSM);
1634 AssertRCReturn(rc, rc);
1635
1636 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND, 0);
1637 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStateEndPreCb, NULL, &VhwaData);
1638 rc = VhwaData.rc;
1639 AssertRC(rc);
1640 }
1641 }
1642 }
1643
1644 vbvaVHWAHHCommandRelease(pCmd);
1645 }
1646 else
1647 rc = VERR_OUT_OF_RESOURCES;
1648#else
1649 if (RT_SUCCESS(rc))
1650 {
1651 for (uint32_t i = 0; i < pVGAState->cMonitors; ++i)
1652 {
1653 rc = SSMR3PutU32 (pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC);
1654 AssertRCReturn(rc, rc);
1655 }
1656 }
1657#endif
1658 return rc;
1659}
1660
1661int vboxVBVALoadStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t u32Version)
1662{
1663 if (u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1664 {
1665 /* Nothing was saved. */
1666 return VINF_SUCCESS;
1667 }
1668
1669 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1670 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1671 int rc = HGSMIHostLoadStateExec (pIns, pSSM, u32Version);
1672 if (RT_SUCCESS(rc))
1673 {
1674 /* Load VBVACONTEXT. */
1675 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1676
1677 if (!pCtx)
1678 {
1679 /* This should not happen. */
1680 AssertFailed();
1681 rc = VERR_INVALID_PARAMETER;
1682 }
1683 else
1684 {
1685 uint32_t cViews = 0;
1686 rc = SSMR3GetU32 (pSSM, &cViews);
1687 AssertRCReturn(rc, rc);
1688
1689 uint32_t iView;
1690 for (iView = 0; iView < cViews; iView++)
1691 {
1692 VBVAVIEW *pView = &pCtx->aViews[iView];
1693
1694 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewIndex);
1695 AssertRCReturn(rc, rc);
1696 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewOffset);
1697 AssertRCReturn(rc, rc);
1698 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewSize);
1699 AssertRCReturn(rc, rc);
1700 rc = SSMR3GetU32 (pSSM, &pView->view.u32MaxScreenSize);
1701 AssertRCReturn(rc, rc);
1702
1703 rc = SSMR3GetU32 (pSSM, &pView->screen.u32ViewIndex);
1704 AssertRCReturn(rc, rc);
1705 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginX);
1706 AssertRCReturn(rc, rc);
1707 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginY);
1708 AssertRCReturn(rc, rc);
1709 rc = SSMR3GetU32 (pSSM, &pView->screen.u32StartOffset);
1710 AssertRCReturn(rc, rc);
1711 rc = SSMR3GetU32 (pSSM, &pView->screen.u32LineSize);
1712 AssertRCReturn(rc, rc);
1713 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Width);
1714 AssertRCReturn(rc, rc);
1715 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Height);
1716 AssertRCReturn(rc, rc);
1717 rc = SSMR3GetU16 (pSSM, &pView->screen.u16BitsPerPixel);
1718 AssertRCReturn(rc, rc);
1719 rc = SSMR3GetU16 (pSSM, &pView->screen.u16Flags);
1720 AssertRCReturn(rc, rc);
1721
1722 rc = SSMR3GetU32 (pSSM, &pView->u32VBVAOffset);
1723 AssertRCReturn(rc, rc);
1724
1725 rc = SSMR3GetU32 (pSSM, &pView->partialRecord.cb);
1726 AssertRCReturn(rc, rc);
1727
1728 if (pView->partialRecord.cb == 0)
1729 {
1730 pView->partialRecord.pu8 = NULL;
1731 }
1732 else
1733 {
1734 Assert(pView->partialRecord.pu8 == NULL); /* Should be it. */
1735
1736 uint8_t *pu8 = (uint8_t *)RTMemAlloc (pView->partialRecord.cb);
1737
1738 if (!pu8)
1739 {
1740 return VERR_NO_MEMORY;
1741 }
1742
1743 pView->partialRecord.pu8 = pu8;
1744
1745 rc = SSMR3GetMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1746 AssertRCReturn(rc, rc);
1747 }
1748
1749 if (pView->u32VBVAOffset == HGSMIOFFSET_VOID)
1750 {
1751 pView->pVBVA = NULL;
1752 }
1753 else
1754 {
1755 pView->pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, pView->u32VBVAOffset);
1756 }
1757 }
1758
1759 if (u32Version > VGA_SAVEDSTATE_VERSION_WITH_CONFIG)
1760 {
1761 /* Read mouse pointer shape information. */
1762 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fSet);
1763 AssertRCReturn(rc, rc);
1764 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fVisible);
1765 AssertRCReturn(rc, rc);
1766 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fAlpha);
1767 AssertRCReturn(rc, rc);
1768 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotX);
1769 AssertRCReturn(rc, rc);
1770 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotY);
1771 AssertRCReturn(rc, rc);
1772 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Width);
1773 AssertRCReturn(rc, rc);
1774 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Height);
1775 AssertRCReturn(rc, rc);
1776 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.cbShape);
1777 AssertRCReturn(rc, rc);
1778 if (pCtx->mouseShapeInfo.cbShape)
1779 {
1780 pCtx->mouseShapeInfo.pu8Shape = (uint8_t *)RTMemAlloc(pCtx->mouseShapeInfo.cbShape);
1781 if (pCtx->mouseShapeInfo.pu8Shape == NULL)
1782 {
1783 return VERR_NO_MEMORY;
1784 }
1785 pCtx->mouseShapeInfo.cbAllocated = pCtx->mouseShapeInfo.cbShape;
1786 rc = SSMR3GetMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1787 AssertRCReturn(rc, rc);
1788 }
1789 else
1790 {
1791 pCtx->mouseShapeInfo.pu8Shape = NULL;
1792 }
1793
1794 /* Size of some additional data. For future extensions. */
1795 uint32_t cbExtra = 0;
1796 rc = SSMR3GetU32 (pSSM, &cbExtra);
1797 AssertRCReturn(rc, rc);
1798#ifdef VBOX_WITH_WDDM
1799 if (cbExtra >= 4)
1800 {
1801 rc = SSMR3GetU32 (pSSM, &pVGAState->fGuestCaps);
1802 AssertRCReturn(rc, rc);
1803 cbExtra -= 4;
1804 }
1805#endif
1806 if (cbExtra > 0)
1807 {
1808 rc = SSMR3Skip(pSSM, cbExtra);
1809 AssertRCReturn(rc, rc);
1810 }
1811 }
1812
1813 pCtx->cViews = iView;
1814 LogFlowFunc(("%d views loaded\n", pCtx->cViews));
1815
1816 if (u32Version > VGA_SAVEDSTATE_VERSION_WDDM)
1817 {
1818#ifdef VBOX_WITH_VIDEOHWACCEL
1819 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM); /* maximum cmd size */
1820 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM, 0, cbCmd);
1821 Assert(pCmd);
1822 if(pCmd)
1823 {
1824 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1825 VhwaData.pSSM = pSSM;
1826 VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM *pLoad = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM);
1827 pLoad->pSSM = pSSM;
1828 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVALoadStatePerformPreCb, vboxVBVALoadStatePerformPostCb, &VhwaData);
1829 rc = VhwaData.rc;
1830 vbvaVHWAHHCommandRelease(pCmd);
1831 AssertRCReturn(rc, rc);
1832
1833 rc = vbvaVHWACommandLoadPending(pVGAState, pSSM, u32Version);
1834 AssertRCReturn(rc, rc);
1835 }
1836 else
1837 {
1838 rc = VERR_OUT_OF_RESOURCES;
1839 }
1840#else
1841 rc = SSMR3SkipToEndOfUnit(pSSM);
1842 AssertRCReturn(rc, rc);
1843#endif
1844 }
1845
1846#ifdef DEBUG_sunlover
1847 dumpctx(pCtx);
1848#endif
1849 }
1850 }
1851
1852 return rc;
1853}
1854
1855int vboxVBVALoadStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1856{
1857 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1858 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
1859
1860 if (pCtx)
1861 {
1862 uint32_t iView;
1863 for (iView = 0; iView < pCtx->cViews; iView++)
1864 {
1865 VBVAVIEW *pView = &pCtx->aViews[iView];
1866
1867 if (pView->pVBVA)
1868 {
1869 vbvaEnable (iView, pVGAState, pCtx, pView->pVBVA, pView->u32VBVAOffset, true /* fRestored */);
1870 vbvaResize (pVGAState, pView, &pView->screen);
1871 }
1872 }
1873
1874 if (pCtx->mouseShapeInfo.fSet)
1875 {
1876 vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, true, pCtx->mouseShapeInfo.pu8Shape);
1877 }
1878 }
1879
1880 return VINF_SUCCESS;
1881}
1882
1883void VBVARaiseIrq (PVGASTATE pVGAState, uint32_t fFlags)
1884{
1885 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1886 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
1887
1888 HGSMISetHostGuestFlags(pVGAState->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
1889 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1890
1891 PDMCritSectLeave(&pVGAState->CritSect);
1892}
1893
1894static DECLCALLBACK(int) vbvaRaiseIrqEMT(PVGASTATE pVGAState, uint32_t fFlags)
1895{
1896 VBVARaiseIrq(pVGAState, fFlags);
1897 return VINF_SUCCESS;
1898}
1899
1900void VBVARaiseIrqNoWait(PVGASTATE pVGAState, uint32_t fFlags)
1901{
1902 /* we can not use PDMDevHlpPCISetIrqNoWait here, because we need to set IRG host flag and raise IRQ atomically,
1903 * otherwise there might be a situation, when:
1904 * 1. Flag is set
1905 * 2. guest issues an IRQ clean request, that cleans up the flag and the interrupt
1906 * 3. IRQ is set */
1907 VMR3ReqCallNoWait(PDMDevHlpGetVM(pVGAState->pDevInsR3), VMCPUID_ANY, (PFNRT)vbvaRaiseIrqEMT, 2, pVGAState, fFlags);
1908}
1909
1910int VBVAInfoView(PVGASTATE pVGAState, VBVAINFOVIEW *pView)
1911{
1912 LogFlowFunc(("VBVA_INFO_VIEW: index %d, offset 0x%x, size 0x%x, max screen size 0x%x\n",
1913 pView->u32ViewIndex, pView->u32ViewOffset, pView->u32ViewSize, pView->u32MaxScreenSize));
1914
1915 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1916 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1917
1918 /* @todo verify view data. */
1919 if (pView->u32ViewIndex >= pCtx->cViews)
1920 {
1921 Log(("View index too large %d!!!\n",
1922 pView->u32ViewIndex));
1923 return VERR_INVALID_PARAMETER;
1924 }
1925
1926 pCtx->aViews[pView->u32ViewIndex].view = *pView;
1927
1928 return VINF_SUCCESS;
1929}
1930
1931int VBVAInfoScreen(PVGASTATE pVGAState, VBVAINFOSCREEN *pScreen)
1932{
1933 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1934 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1935 VBVAINFOVIEW *pView = &pCtx->aViews[pScreen->u32ViewIndex].view;
1936 /* Calculate the offset of the end of the screen so we can make
1937 * sure it is inside the view. I assume that screen rollover is not
1938 * implemented. */
1939 int64_t offEnd = (int64_t)pScreen->u32Height * pScreen->u32LineSize
1940 + pScreen->u32Width + pScreen->u32StartOffset;
1941 LogRel(("VBVA_INFO_SCREEN: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
1942 pScreen->u32ViewIndex, pScreen->i32OriginX, pScreen->i32OriginY,
1943 pScreen->u32Width, pScreen->u32Height,
1944 pScreen->u32LineSize, pScreen->u16BitsPerPixel, pScreen->u16Flags));
1945
1946 if ( pScreen->u32ViewIndex < RT_ELEMENTS (pCtx->aViews)
1947 && pScreen->u16BitsPerPixel <= 32
1948 && pScreen->u32Width <= UINT16_MAX
1949 && pScreen->u32Height <= UINT16_MAX
1950 && pScreen->u32LineSize <= UINT16_MAX * 4
1951 && offEnd < pView->u32MaxScreenSize)
1952 {
1953 vbvaResize (pVGAState, &pCtx->aViews[pScreen->u32ViewIndex], pScreen);
1954 return VINF_SUCCESS;
1955 }
1956
1957 LogRelFlow(("VBVA_INFO_SCREEN [%lu]: bad data: %lux%lu, line 0x%lx, BPP %u, start offset %lu, max screen size %lu\n",
1958 (unsigned long)pScreen->u32ViewIndex,
1959 (unsigned long)pScreen->u32Width,
1960 (unsigned long)pScreen->u32Height,
1961 (unsigned long)pScreen->u32LineSize,
1962 (unsigned long)pScreen->u16BitsPerPixel,
1963 (unsigned long)pScreen->u32StartOffset,
1964 (unsigned long)pView->u32MaxScreenSize));
1965 return VERR_INVALID_PARAMETER;
1966}
1967
1968int VBVAGetInfoViewAndScreen(PVGASTATE pVGAState, uint32_t u32ViewIndex, VBVAINFOVIEW *pView, VBVAINFOSCREEN *pScreen)
1969{
1970 if (u32ViewIndex >= pVGAState->cMonitors)
1971 return VERR_INVALID_PARAMETER;
1972
1973 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1974 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1975
1976 if (pView)
1977 *pView = pCtx->aViews[u32ViewIndex].view;
1978
1979 if (pScreen)
1980 *pScreen = pCtx->aViews[u32ViewIndex].screen;
1981
1982 return VINF_SUCCESS;
1983}
1984
1985
1986/*
1987 *
1988 * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
1989 *
1990 * VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
1991 * Read Write
1992 * Host port 0x3b0 to process completed
1993 * Guest port 0x3d0 control value? to process
1994 *
1995 */
1996
1997static DECLCALLBACK(void) vbvaNotifyGuest (void *pvCallback)
1998{
1999#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
2000 PVGASTATE pVGAState = (PVGASTATE)pvCallback;
2001 VBVARaiseIrqNoWait (pVGAState, 0);
2002#else
2003 NOREF(pvCallback);
2004 /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */
2005#endif
2006}
2007
2008/* The guest submitted a buffer. @todo Verify all guest data. */
2009static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
2010{
2011 int rc = VINF_SUCCESS;
2012
2013 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
2014 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
2015
2016 PVGASTATE pVGAState = (PVGASTATE)pvHandler;
2017 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
2018 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
2019
2020 switch (u16ChannelInfo)
2021 {
2022 case VBVA_CMDVBVA_SUBMIT:
2023 {
2024# ifdef VBOX_WITH_CRHGSMI
2025 rc = vboxCmdVBVACmdSubmit(pVGAState);
2026#endif
2027 break;
2028 }
2029 case VBVA_CMDVBVA_FLUSH:
2030 {
2031# ifdef VBOX_WITH_CRHGSMI
2032 rc =vboxCmdVBVACmdFlush(pVGAState);
2033#endif
2034 break;
2035 }
2036 case VBVA_CMDVBVA_CTL:
2037 {
2038#ifdef VBOX_WITH_CRHGSMI
2039 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXCMDVBVA_CTL))
2040 {
2041 Log(("buffer too small\n"));
2042#ifdef DEBUG_misha
2043 AssertMsgFailed(("buffer too small\n"));
2044#endif
2045 rc = VERR_INVALID_PARAMETER;
2046 break;
2047 }
2048 VBOXCMDVBVA_CTL *pCtl = (VBOXCMDVBVA_CTL*)VBoxSHGSMIBufferData((PVBOXSHGSMIHEADER)pvBuffer);
2049 rc = vboxCmdVBVACmdCtl(pVGAState, pCtl, cbBuffer - VBoxSHGSMIBufferHeaderSize());
2050#endif
2051 break;
2052 }
2053#ifdef VBOX_WITH_VDMA
2054 case VBVA_VDMA_CMD:
2055 {
2056 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMACBUF_DR))
2057 {
2058 rc = VERR_INVALID_PARAMETER;
2059 break;
2060 }
2061 PVBOXVDMACBUF_DR pCmd = (PVBOXVDMACBUF_DR)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
2062 vboxVDMACommand(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
2063 rc = VINF_SUCCESS;
2064 break;
2065 }
2066 case VBVA_VDMA_CTL:
2067 {
2068 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMA_CTL))
2069 {
2070 rc = VERR_INVALID_PARAMETER;
2071 break;
2072 }
2073 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
2074 vboxVDMAControl(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
2075 rc = VINF_SUCCESS;
2076 break;
2077 }
2078#endif
2079 case VBVA_QUERY_CONF32:
2080 {
2081 if (cbBuffer < sizeof (VBVACONF32))
2082 {
2083 rc = VERR_INVALID_PARAMETER;
2084 break;
2085 }
2086
2087 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
2088 LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n",
2089 pConf32->u32Index, pConf32->u32Value));
2090
2091 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
2092 {
2093 pConf32->u32Value = pCtx->cViews;
2094 }
2095 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
2096 {
2097 /* @todo a value calculated from the vram size */
2098 pConf32->u32Value = 64*_1K;
2099 }
2100 else
2101 {
2102 Log(("Unsupported VBVA_QUERY_CONF32 index %d!!!\n",
2103 pConf32->u32Index));
2104 rc = VERR_INVALID_PARAMETER;
2105 }
2106 } break;
2107
2108 case VBVA_SET_CONF32:
2109 {
2110 if (cbBuffer < sizeof (VBVACONF32))
2111 {
2112 rc = VERR_INVALID_PARAMETER;
2113 break;
2114 }
2115
2116 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
2117 LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n",
2118 pConf32->u32Index, pConf32->u32Value));
2119
2120 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
2121 {
2122 /* do nothing. this is a const. */
2123 }
2124 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
2125 {
2126 /* do nothing. this is a const. */
2127 }
2128 else
2129 {
2130 Log(("Unsupported VBVA_SET_CONF32 index %d!!!\n",
2131 pConf32->u32Index));
2132 rc = VERR_INVALID_PARAMETER;
2133 }
2134 } break;
2135
2136 case VBVA_INFO_VIEW:
2137 {
2138 if (cbBuffer < sizeof (VBVAINFOVIEW))
2139 {
2140 rc = VERR_INVALID_PARAMETER;
2141 break;
2142 }
2143
2144 /* Guest submits an array of VBVAINFOVIEW structures. */
2145 VBVAINFOVIEW *pView = (VBVAINFOVIEW *)pvBuffer;
2146
2147 for (;
2148 cbBuffer >= sizeof (VBVAINFOVIEW);
2149 pView++, cbBuffer -= sizeof (VBVAINFOVIEW))
2150 {
2151 VBVAINFOVIEW View = *pView;
2152 rc = VBVAInfoView(pVGAState, &View);
2153 if (RT_FAILURE(rc))
2154 break;
2155 }
2156 } break;
2157
2158 case VBVA_INFO_HEAP:
2159 {
2160 if (cbBuffer < sizeof (VBVAINFOHEAP))
2161 {
2162 rc = VERR_INVALID_PARAMETER;
2163 break;
2164 }
2165
2166 VBVAINFOHEAP *pHeap = (VBVAINFOHEAP *)pvBuffer;
2167 LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n",
2168 pHeap->u32HeapOffset, pHeap->u32HeapSize));
2169
2170 rc = HGSMISetupHostHeap (pIns, pHeap->u32HeapOffset, pHeap->u32HeapSize);
2171 } break;
2172
2173 case VBVA_FLUSH:
2174 {
2175 if (cbBuffer < sizeof (VBVAFLUSH))
2176 {
2177 rc = VERR_INVALID_PARAMETER;
2178 break;
2179 }
2180
2181 VBVAFLUSH *pFlush = (VBVAFLUSH *)pvBuffer;
2182 LogFlowFunc(("VBVA_FLUSH: u32Reserved 0x%x\n",
2183 pFlush->u32Reserved));
2184
2185 rc = vbvaFlush (pVGAState, pCtx);
2186 } break;
2187
2188 case VBVA_INFO_SCREEN:
2189 {
2190 if (cbBuffer < sizeof (VBVAINFOSCREEN))
2191 {
2192 rc = VERR_INVALID_PARAMETER;
2193 break;
2194 }
2195
2196 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)pvBuffer;
2197 VBVAINFOSCREEN Screen = *pScreen;
2198 rc = VBVAInfoScreen(pVGAState, &Screen);
2199 } break;
2200
2201 case VBVA_ENABLE:
2202 {
2203 if (cbBuffer < sizeof (VBVAENABLE))
2204 {
2205 rc = VERR_INVALID_PARAMETER;
2206 break;
2207 }
2208
2209 VBVAENABLE *pEnable = (VBVAENABLE *)pvBuffer;
2210 unsigned uScreenId;
2211 if (pEnable->u32Flags & VBVA_F_EXTENDED)
2212 {
2213 if (cbBuffer < sizeof (VBVAENABLE_EX))
2214 {
2215 rc = VERR_INVALID_PARAMETER;
2216 break;
2217 }
2218
2219 VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)pvBuffer;
2220 uScreenId = pEnableEx->u32ScreenId;
2221 }
2222 else
2223 {
2224 uScreenId = vbvaViewFromOffset (pIns, pCtx, pvBuffer);
2225 }
2226
2227 if (uScreenId == ~0U)
2228 {
2229 rc = VERR_INVALID_PARAMETER;
2230 break;
2231 }
2232
2233 LogFlowFunc(("VBVA_ENABLE[%d]: u32Flags 0x%x u32Offset 0x%x\n",
2234 uScreenId, pEnable->u32Flags, pEnable->u32Offset));
2235
2236 if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE)
2237 {
2238 /* Guest reported offset relative to view. */
2239 uint32_t u32Offset = pEnable->u32Offset;
2240 if (!(pEnable->u32Flags & VBVA_F_ABSOFFSET))
2241 {
2242 u32Offset += pCtx->aViews[uScreenId].view.u32ViewOffset;
2243 }
2244
2245 VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, u32Offset);
2246
2247 if (pVBVA)
2248 {
2249 /* Process any pending orders and empty the VBVA ring buffer. */
2250 vbvaFlush (pVGAState, pCtx);
2251
2252 rc = vbvaEnable (uScreenId, pVGAState, pCtx, pVBVA, u32Offset, false /* fRestored */);
2253 }
2254 else
2255 {
2256 Log(("Invalid VBVABUFFER offset 0x%x!!!\n",
2257 pEnable->u32Offset));
2258 rc = VERR_INVALID_PARAMETER;
2259 }
2260 }
2261 else if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE)
2262 {
2263 rc = vbvaDisable (uScreenId, pVGAState, pCtx);
2264 }
2265 else
2266 {
2267 Log(("Invalid VBVA_ENABLE flags 0x%x!!!\n",
2268 pEnable->u32Flags));
2269 rc = VERR_INVALID_PARAMETER;
2270 }
2271
2272 pEnable->i32Result = rc;
2273 } break;
2274
2275 case VBVA_MOUSE_POINTER_SHAPE:
2276 {
2277 if (cbBuffer < sizeof (VBVAMOUSEPOINTERSHAPE))
2278 {
2279 rc = VERR_INVALID_PARAMETER;
2280 break;
2281 }
2282
2283 VBVAMOUSEPOINTERSHAPE *pShape = (VBVAMOUSEPOINTERSHAPE *)pvBuffer;
2284
2285 LogFlowFunc(("VBVA_MOUSE_POINTER_SHAPE: i32Result 0x%x, fu32Flags 0x%x, hot spot %d,%d, size %dx%d\n",
2286 pShape->i32Result,
2287 pShape->fu32Flags,
2288 pShape->u32HotX,
2289 pShape->u32HotY,
2290 pShape->u32Width,
2291 pShape->u32Height));
2292
2293 rc = vbvaMousePointerShape (pVGAState, pCtx, pShape, cbBuffer);
2294
2295 pShape->i32Result = rc;
2296 } break;
2297
2298
2299#ifdef VBOX_WITH_VIDEOHWACCEL
2300 case VBVA_VHWA_CMD:
2301 {
2302 if (cbBuffer < sizeof (VBOXVHWACMD))
2303 {
2304 rc = VERR_INVALID_PARAMETER;
2305 break;
2306 }
2307 vbvaVHWAHandleCommand(pVGAState, (PVBOXVHWACMD)pvBuffer);
2308 rc = VINF_SUCCESS;
2309 break;
2310 } break;
2311#endif
2312
2313#ifdef VBOX_WITH_WDDM
2314 case VBVA_INFO_CAPS:
2315 {
2316 if (cbBuffer < sizeof (VBVACAPS))
2317 {
2318 rc = VERR_INVALID_PARAMETER;
2319 break;
2320 }
2321
2322 VBVACAPS *pCaps = (VBVACAPS*)pvBuffer;
2323 pVGAState->fGuestCaps = pCaps->fCaps;
2324 pCaps->rc = VINF_SUCCESS;
2325 } break;
2326#endif
2327 case VBVA_SCANLINE_CFG:
2328 {
2329 if (cbBuffer < sizeof (VBVASCANLINECFG))
2330 {
2331 rc = VERR_INVALID_PARAMETER;
2332 break;
2333 }
2334
2335 VBVASCANLINECFG *pCfg = (VBVASCANLINECFG*)pvBuffer;
2336 pVGAState->fScanLineCfg = pCfg->fFlags;
2337 pCfg->rc = VINF_SUCCESS;
2338 } break;
2339 default:
2340 Log(("Unsupported VBVA guest command %d!!!\n",
2341 u16ChannelInfo));
2342 break;
2343 }
2344
2345 return rc;
2346}
2347
2348/* When VBVA is paused, then VGA device is allowed to work but
2349 * no HGSMI etc state is changed.
2350 */
2351void VBVAPause(PVGASTATE pVGAState, bool fPause)
2352{
2353 if (!pVGAState || !pVGAState->pHGSMI)
2354 {
2355 return;
2356 }
2357
2358 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pVGAState->pHGSMI);
2359
2360 if (pCtx)
2361 {
2362 pCtx->fPaused = fPause;
2363 }
2364}
2365
2366void VBVAReset (PVGASTATE pVGAState)
2367{
2368 if (!pVGAState || !pVGAState->pHGSMI)
2369 {
2370 return;
2371 }
2372
2373 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2374
2375#ifdef VBOX_WITH_VIDEOHWACCEL
2376 vbvaVHWAReset (pVGAState);
2377#endif
2378
2379 uint32_t HgFlags = HGSMIReset (pVGAState->pHGSMI);
2380 if(HgFlags & HGSMIHOSTFLAGS_IRQ)
2381 {
2382 /* this means the IRQ is LEVEL_HIGH, need to reset it */
2383 PDMDevHlpPCISetIrq(pVGAState->pDevInsR3, 0, PDM_IRQ_LEVEL_LOW);
2384 }
2385
2386 if (pCtx)
2387 {
2388 vbvaFlush (pVGAState, pCtx);
2389
2390 unsigned uScreenId;
2391
2392 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
2393 {
2394 vbvaDisable (uScreenId, pVGAState, pCtx);
2395 }
2396
2397 pCtx->mouseShapeInfo.fSet = false;
2398 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2399 pCtx->mouseShapeInfo.pu8Shape = NULL;
2400 pCtx->mouseShapeInfo.cbAllocated = 0;
2401 pCtx->mouseShapeInfo.cbShape = 0;
2402 }
2403
2404}
2405
2406int VBVAUpdateDisplay (PVGASTATE pVGAState)
2407{
2408 int rc = VERR_NOT_SUPPORTED; /* Assuming that the VGA device will have to do updates. */
2409
2410 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2411
2412 if (pCtx)
2413 {
2414 if (!pCtx->fPaused)
2415 {
2416 rc = vbvaFlush (pVGAState, pCtx);
2417
2418 if (RT_SUCCESS (rc))
2419 {
2420 if (!pCtx->aViews[0].pVBVA)
2421 {
2422 /* VBVA is not enabled for the first view, so VGA device must do updates. */
2423 rc = VERR_NOT_SUPPORTED;
2424 }
2425 }
2426 }
2427 }
2428
2429 return rc;
2430}
2431
2432static HGSMICHANNELHANDLER sOldChannelHandler;
2433
2434int VBVAInit (PVGASTATE pVGAState)
2435{
2436 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
2437
2438 PVM pVM = PDMDevHlpGetVM(pDevIns);
2439
2440 int rc = HGSMICreate (&pVGAState->pHGSMI,
2441 pVM,
2442 "VBVA",
2443 0,
2444 pVGAState->vram_ptrR3,
2445 pVGAState->vram_size,
2446 vbvaNotifyGuest,
2447 pVGAState,
2448 sizeof (VBVACONTEXT));
2449
2450 if (RT_SUCCESS (rc))
2451 {
2452 rc = HGSMIHostChannelRegister (pVGAState->pHGSMI,
2453 HGSMI_CH_VBVA,
2454 vbvaChannelHandler,
2455 pVGAState,
2456 &sOldChannelHandler);
2457 if (RT_SUCCESS (rc))
2458 {
2459 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2460 pCtx->cViews = pVGAState->cMonitors;
2461 pCtx->fPaused = true;
2462 }
2463 }
2464
2465 return rc;
2466
2467}
2468
2469void VBVADestroy (PVGASTATE pVGAState)
2470{
2471 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2472
2473 if (pCtx)
2474 {
2475 pCtx->mouseShapeInfo.fSet = false;
2476 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2477 pCtx->mouseShapeInfo.pu8Shape = NULL;
2478 pCtx->mouseShapeInfo.cbAllocated = 0;
2479 pCtx->mouseShapeInfo.cbShape = 0;
2480 }
2481
2482 HGSMIDestroy (pVGAState->pHGSMI);
2483 pVGAState->pHGSMI = NULL;
2484}
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