VirtualBox

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

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

Devices/VGA_VBVA: use RT_STR_TUPLE()

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 80.9 KB
Line 
1/* $Id: DevVGA_VBVA.cpp 51730 2014-06-26 07:37:27Z 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 pData->ab2DOn[iDisplay] = true;
1481 return true;
1482 case VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC:
1483 pData->ab2DOn[iDisplay] = false;
1484 return false;
1485 default:
1486 pData->rc = VERR_INVALID_STATE;
1487 return false;
1488 }
1489}
1490#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
1491
1492int vboxVBVASaveDevStateExec (PVGASTATE pVGAState, PSSMHANDLE pSSM)
1493{
1494 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1495 int rc = HGSMIHostSaveStateExec (pIns, pSSM);
1496 if (RT_SUCCESS(rc))
1497 {
1498 /* Save VBVACONTEXT. */
1499 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1500
1501 if (!pCtx)
1502 {
1503 AssertFailed();
1504
1505 /* Still write a valid value to the SSM. */
1506 rc = SSMR3PutU32 (pSSM, 0);
1507 AssertRCReturn(rc, rc);
1508 }
1509 else
1510 {
1511#ifdef DEBUG_sunlover
1512 dumpctx(pCtx);
1513#endif
1514
1515 rc = SSMR3PutU32 (pSSM, pCtx->cViews);
1516 AssertRCReturn(rc, rc);
1517
1518 uint32_t iView;
1519 for (iView = 0; iView < pCtx->cViews; iView++)
1520 {
1521 VBVAVIEW *pView = &pCtx->aViews[iView];
1522
1523 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewIndex);
1524 AssertRCReturn(rc, rc);
1525 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewOffset);
1526 AssertRCReturn(rc, rc);
1527 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewSize);
1528 AssertRCReturn(rc, rc);
1529 rc = SSMR3PutU32 (pSSM, pView->view.u32MaxScreenSize);
1530 AssertRCReturn(rc, rc);
1531
1532 rc = SSMR3PutU32 (pSSM, pView->screen.u32ViewIndex);
1533 AssertRCReturn(rc, rc);
1534 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginX);
1535 AssertRCReturn(rc, rc);
1536 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginY);
1537 AssertRCReturn(rc, rc);
1538 rc = SSMR3PutU32 (pSSM, pView->screen.u32StartOffset);
1539 AssertRCReturn(rc, rc);
1540 rc = SSMR3PutU32 (pSSM, pView->screen.u32LineSize);
1541 AssertRCReturn(rc, rc);
1542 rc = SSMR3PutU32 (pSSM, pView->screen.u32Width);
1543 AssertRCReturn(rc, rc);
1544 rc = SSMR3PutU32 (pSSM, pView->screen.u32Height);
1545 AssertRCReturn(rc, rc);
1546 rc = SSMR3PutU16 (pSSM, pView->screen.u16BitsPerPixel);
1547 AssertRCReturn(rc, rc);
1548 rc = SSMR3PutU16 (pSSM, pView->screen.u16Flags);
1549 AssertRCReturn(rc, rc);
1550
1551 rc = SSMR3PutU32 (pSSM, pView->pVBVA? pView->u32VBVAOffset: HGSMIOFFSET_VOID);
1552 AssertRCReturn(rc, rc);
1553
1554 rc = SSMR3PutU32 (pSSM, pView->partialRecord.cb);
1555 AssertRCReturn(rc, rc);
1556
1557 if (pView->partialRecord.cb > 0)
1558 {
1559 rc = SSMR3PutMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1560 AssertRCReturn(rc, rc);
1561 }
1562 }
1563
1564 /* Save mouse pointer shape information. */
1565 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fSet);
1566 AssertRCReturn(rc, rc);
1567 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fVisible);
1568 AssertRCReturn(rc, rc);
1569 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fAlpha);
1570 AssertRCReturn(rc, rc);
1571 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotX);
1572 AssertRCReturn(rc, rc);
1573 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotY);
1574 AssertRCReturn(rc, rc);
1575 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Width);
1576 AssertRCReturn(rc, rc);
1577 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Height);
1578 AssertRCReturn(rc, rc);
1579 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.cbShape);
1580 AssertRCReturn(rc, rc);
1581 if (pCtx->mouseShapeInfo.cbShape)
1582 {
1583 rc = SSMR3PutMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1584 AssertRCReturn(rc, rc);
1585 }
1586
1587#ifdef VBOX_WITH_WDDM
1588 /* Size of some additional data. For future extensions. */
1589 rc = SSMR3PutU32 (pSSM, 4);
1590 AssertRCReturn(rc, rc);
1591 rc = SSMR3PutU32 (pSSM, pVGAState->fGuestCaps);
1592 AssertRCReturn(rc, rc);
1593#else
1594 /* Size of some additional data. For future extensions. */
1595 rc = SSMR3PutU32 (pSSM, 0);
1596 AssertRCReturn(rc, rc);
1597#endif
1598 }
1599 }
1600
1601 return rc;
1602}
1603
1604int vboxVBVASaveStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1605{
1606 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1607 int rc;
1608#ifdef VBOX_WITH_VIDEOHWACCEL
1609 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1610 VhwaData.pSSM = pSSM;
1611 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM); /* maximum cmd size */
1612 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN, 0, cbCmd);
1613 Assert(pCmd);
1614 if(pCmd)
1615 {
1616 vbvaVHWAHHPost (pVGAState, pCmd, NULL, vboxVBVASaveStateBeginPostCb, &VhwaData);
1617 rc = VhwaData.rc;
1618 AssertRC(rc);
1619 if (RT_SUCCESS(rc))
1620 {
1621#endif
1622 rc = vboxVBVASaveDevStateExec (pVGAState, pSSM);
1623 AssertRC(rc);
1624#ifdef VBOX_WITH_VIDEOHWACCEL
1625 if (RT_SUCCESS(rc))
1626 {
1627 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM, 0);
1628 VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM *pSave = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM);
1629 pSave->pSSM = pSSM;
1630 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStatePerformPreCb, NULL, &VhwaData);
1631 rc = VhwaData.rc;
1632 AssertRC(rc);
1633 if (RT_SUCCESS(rc))
1634 {
1635 rc = vbvaVHWACommandSavePending(pVGAState, pSSM);
1636 AssertRCReturn(rc, rc);
1637
1638 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND, 0);
1639 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStateEndPreCb, NULL, &VhwaData);
1640 rc = VhwaData.rc;
1641 AssertRC(rc);
1642 }
1643 }
1644 }
1645
1646 vbvaVHWAHHCommandRelease(pCmd);
1647 }
1648 else
1649 rc = VERR_OUT_OF_RESOURCES;
1650#else
1651 if (RT_SUCCESS(rc))
1652 {
1653 for (uint32_t i = 0; i < pVGAState->cMonitors; ++i)
1654 {
1655 rc = SSMR3PutU32 (pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC);
1656 AssertRCReturn(rc, rc);
1657 }
1658 }
1659
1660 /* no pending commands */
1661 SSMR3PutU32(pSSM, 0);
1662#endif
1663 return rc;
1664}
1665
1666int vboxVBVALoadStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t u32Version)
1667{
1668 if (u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1669 {
1670 /* Nothing was saved. */
1671 return VINF_SUCCESS;
1672 }
1673
1674 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1675 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1676 int rc = HGSMIHostLoadStateExec (pIns, pSSM, u32Version);
1677 if (RT_SUCCESS(rc))
1678 {
1679 /* Load VBVACONTEXT. */
1680 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1681
1682 if (!pCtx)
1683 {
1684 /* This should not happen. */
1685 AssertFailed();
1686 rc = VERR_INVALID_PARAMETER;
1687 }
1688 else
1689 {
1690 uint32_t cViews = 0;
1691 rc = SSMR3GetU32 (pSSM, &cViews);
1692 AssertRCReturn(rc, rc);
1693
1694 uint32_t iView;
1695 for (iView = 0; iView < cViews; iView++)
1696 {
1697 VBVAVIEW *pView = &pCtx->aViews[iView];
1698
1699 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewIndex);
1700 AssertRCReturn(rc, rc);
1701 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewOffset);
1702 AssertRCReturn(rc, rc);
1703 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewSize);
1704 AssertRCReturn(rc, rc);
1705 rc = SSMR3GetU32 (pSSM, &pView->view.u32MaxScreenSize);
1706 AssertRCReturn(rc, rc);
1707
1708 rc = SSMR3GetU32 (pSSM, &pView->screen.u32ViewIndex);
1709 AssertRCReturn(rc, rc);
1710 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginX);
1711 AssertRCReturn(rc, rc);
1712 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginY);
1713 AssertRCReturn(rc, rc);
1714 rc = SSMR3GetU32 (pSSM, &pView->screen.u32StartOffset);
1715 AssertRCReturn(rc, rc);
1716 rc = SSMR3GetU32 (pSSM, &pView->screen.u32LineSize);
1717 AssertRCReturn(rc, rc);
1718 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Width);
1719 AssertRCReturn(rc, rc);
1720 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Height);
1721 AssertRCReturn(rc, rc);
1722 rc = SSMR3GetU16 (pSSM, &pView->screen.u16BitsPerPixel);
1723 AssertRCReturn(rc, rc);
1724 rc = SSMR3GetU16 (pSSM, &pView->screen.u16Flags);
1725 AssertRCReturn(rc, rc);
1726
1727 rc = SSMR3GetU32 (pSSM, &pView->u32VBVAOffset);
1728 AssertRCReturn(rc, rc);
1729
1730 rc = SSMR3GetU32 (pSSM, &pView->partialRecord.cb);
1731 AssertRCReturn(rc, rc);
1732
1733 if (pView->partialRecord.cb == 0)
1734 {
1735 pView->partialRecord.pu8 = NULL;
1736 }
1737 else
1738 {
1739 Assert(pView->partialRecord.pu8 == NULL); /* Should be it. */
1740
1741 uint8_t *pu8 = (uint8_t *)RTMemAlloc (pView->partialRecord.cb);
1742
1743 if (!pu8)
1744 {
1745 return VERR_NO_MEMORY;
1746 }
1747
1748 pView->partialRecord.pu8 = pu8;
1749
1750 rc = SSMR3GetMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1751 AssertRCReturn(rc, rc);
1752 }
1753
1754 if (pView->u32VBVAOffset == HGSMIOFFSET_VOID)
1755 {
1756 pView->pVBVA = NULL;
1757 }
1758 else
1759 {
1760 pView->pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, pView->u32VBVAOffset);
1761 }
1762 }
1763
1764 if (u32Version > VGA_SAVEDSTATE_VERSION_WITH_CONFIG)
1765 {
1766 /* Read mouse pointer shape information. */
1767 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fSet);
1768 AssertRCReturn(rc, rc);
1769 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fVisible);
1770 AssertRCReturn(rc, rc);
1771 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fAlpha);
1772 AssertRCReturn(rc, rc);
1773 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotX);
1774 AssertRCReturn(rc, rc);
1775 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotY);
1776 AssertRCReturn(rc, rc);
1777 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Width);
1778 AssertRCReturn(rc, rc);
1779 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Height);
1780 AssertRCReturn(rc, rc);
1781 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.cbShape);
1782 AssertRCReturn(rc, rc);
1783 if (pCtx->mouseShapeInfo.cbShape)
1784 {
1785 pCtx->mouseShapeInfo.pu8Shape = (uint8_t *)RTMemAlloc(pCtx->mouseShapeInfo.cbShape);
1786 if (pCtx->mouseShapeInfo.pu8Shape == NULL)
1787 {
1788 return VERR_NO_MEMORY;
1789 }
1790 pCtx->mouseShapeInfo.cbAllocated = pCtx->mouseShapeInfo.cbShape;
1791 rc = SSMR3GetMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1792 AssertRCReturn(rc, rc);
1793 }
1794 else
1795 {
1796 pCtx->mouseShapeInfo.pu8Shape = NULL;
1797 }
1798
1799 /* Size of some additional data. For future extensions. */
1800 uint32_t cbExtra = 0;
1801 rc = SSMR3GetU32 (pSSM, &cbExtra);
1802 AssertRCReturn(rc, rc);
1803#ifdef VBOX_WITH_WDDM
1804 if (cbExtra >= 4)
1805 {
1806 rc = SSMR3GetU32 (pSSM, &pVGAState->fGuestCaps);
1807 AssertRCReturn(rc, rc);
1808 cbExtra -= 4;
1809 }
1810#endif
1811 if (cbExtra > 0)
1812 {
1813 rc = SSMR3Skip(pSSM, cbExtra);
1814 AssertRCReturn(rc, rc);
1815 }
1816 }
1817
1818 pCtx->cViews = iView;
1819 LogFlowFunc(("%d views loaded\n", pCtx->cViews));
1820
1821 if (u32Version > VGA_SAVEDSTATE_VERSION_WDDM)
1822 {
1823 bool fLoadCommands;
1824
1825 if (u32Version < VGA_SAVEDSTATE_VERSION_FIXED_PENDVHWA)
1826 {
1827 const char *pcszOsArch = SSMR3HandleHostOSAndArch(pSSM);
1828 Assert(pcszOsArch);
1829 fLoadCommands = !pcszOsArch || RTStrNCmp(pcszOsArch, RT_STR_TUPLE("solaris"));
1830 }
1831 else
1832 fLoadCommands = true;
1833
1834#ifdef VBOX_WITH_VIDEOHWACCEL
1835 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM); /* maximum cmd size */
1836 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM, 0, cbCmd);
1837 Assert(pCmd);
1838 if(pCmd)
1839 {
1840 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1841 VhwaData.pSSM = pSSM;
1842 VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM *pLoad = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM);
1843 pLoad->pSSM = pSSM;
1844 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVALoadStatePerformPreCb, vboxVBVALoadStatePerformPostCb, &VhwaData);
1845 rc = VhwaData.rc;
1846 vbvaVHWAHHCommandRelease(pCmd);
1847 AssertRCReturn(rc, rc);
1848
1849 if (fLoadCommands)
1850 {
1851 rc = vbvaVHWACommandLoadPending(pVGAState, pSSM, u32Version);
1852 AssertRCReturn(rc, rc);
1853 }
1854 }
1855 else
1856 {
1857 rc = VERR_OUT_OF_RESOURCES;
1858 }
1859#else
1860 uint32_t u32;
1861
1862 for (uint32_t i = 0; i < pVGAState->cMonitors; ++i)
1863 {
1864 rc = SSMR3GetU32(pSSM, &u32);
1865 AssertRCReturn(rc, rc);
1866
1867 if (u32 != VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC)
1868 {
1869 LogRel(("2D data while 2D is not supported\n"));
1870 return VERR_NOT_SUPPORTED;
1871 }
1872 }
1873
1874 if (fLoadCommands)
1875 {
1876 rc = SSMR3GetU32(pSSM, &u32);
1877 AssertRCReturn(rc, rc);
1878
1879 if (u32)
1880 {
1881 LogRel(("2D pending command while 2D is not supported\n"));
1882 return VERR_NOT_SUPPORTED;
1883 }
1884 }
1885#endif
1886 }
1887
1888#ifdef DEBUG_sunlover
1889 dumpctx(pCtx);
1890#endif
1891 }
1892 }
1893
1894 return rc;
1895}
1896
1897int vboxVBVALoadStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1898{
1899 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1900 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
1901
1902 if (pCtx)
1903 {
1904 uint32_t iView;
1905 for (iView = 0; iView < pCtx->cViews; iView++)
1906 {
1907 VBVAVIEW *pView = &pCtx->aViews[iView];
1908
1909 if (pView->pVBVA)
1910 {
1911#ifdef VBOX_WITH_CRHGSMI
1912 Assert(!vboxCmdVBVAIsEnabled(pVGAState));
1913#endif
1914 vbvaEnable (iView, pVGAState, pCtx, pView->pVBVA, pView->u32VBVAOffset, true /* fRestored */);
1915 vbvaResize (pVGAState, pView, &pView->screen);
1916 }
1917 }
1918
1919 if (pCtx->mouseShapeInfo.fSet)
1920 {
1921 vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, true, pCtx->mouseShapeInfo.pu8Shape);
1922 }
1923 }
1924
1925 return VINF_SUCCESS;
1926}
1927
1928void VBVARaiseIrq (PVGASTATE pVGAState, uint32_t fFlags)
1929{
1930 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1931 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
1932
1933 HGSMISetHostGuestFlags(pVGAState->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
1934 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1935
1936 PDMCritSectLeave(&pVGAState->CritSect);
1937}
1938
1939static DECLCALLBACK(int) vbvaRaiseIrqEMT(PVGASTATE pVGAState, uint32_t fFlags)
1940{
1941 VBVARaiseIrq(pVGAState, fFlags);
1942 return VINF_SUCCESS;
1943}
1944
1945void VBVARaiseIrqNoWait(PVGASTATE pVGAState, uint32_t fFlags)
1946{
1947 /* we can not use PDMDevHlpPCISetIrqNoWait here, because we need to set IRG host flag and raise IRQ atomically,
1948 * otherwise there might be a situation, when:
1949 * 1. Flag is set
1950 * 2. guest issues an IRQ clean request, that cleans up the flag and the interrupt
1951 * 3. IRQ is set */
1952 VMR3ReqCallNoWait(PDMDevHlpGetVM(pVGAState->pDevInsR3), VMCPUID_ANY, (PFNRT)vbvaRaiseIrqEMT, 2, pVGAState, fFlags);
1953}
1954
1955int VBVAInfoView(PVGASTATE pVGAState, VBVAINFOVIEW *pView)
1956{
1957 LogFlowFunc(("VBVA_INFO_VIEW: index %d, offset 0x%x, size 0x%x, max screen size 0x%x\n",
1958 pView->u32ViewIndex, pView->u32ViewOffset, pView->u32ViewSize, pView->u32MaxScreenSize));
1959
1960 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1961 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1962
1963 /* @todo verify view data. */
1964 if (pView->u32ViewIndex >= pCtx->cViews)
1965 {
1966 Log(("View index too large %d!!!\n",
1967 pView->u32ViewIndex));
1968 return VERR_INVALID_PARAMETER;
1969 }
1970
1971 pCtx->aViews[pView->u32ViewIndex].view = *pView;
1972
1973 return VINF_SUCCESS;
1974}
1975
1976int VBVAInfoScreen(PVGASTATE pVGAState, VBVAINFOSCREEN *pScreen)
1977{
1978 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1979 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1980 VBVAINFOVIEW *pView = &pCtx->aViews[pScreen->u32ViewIndex].view;
1981 /* Calculate the offset of the end of the screen so we can make
1982 * sure it is inside the view. I assume that screen rollover is not
1983 * implemented. */
1984 int64_t offEnd = (int64_t)pScreen->u32Height * pScreen->u32LineSize
1985 + pScreen->u32Width + pScreen->u32StartOffset;
1986 LogRel(("VBVA_INFO_SCREEN: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
1987 pScreen->u32ViewIndex, pScreen->i32OriginX, pScreen->i32OriginY,
1988 pScreen->u32Width, pScreen->u32Height,
1989 pScreen->u32LineSize, pScreen->u16BitsPerPixel, pScreen->u16Flags));
1990
1991 if ( pScreen->u32ViewIndex < RT_ELEMENTS (pCtx->aViews)
1992 && pScreen->u16BitsPerPixel <= 32
1993 && pScreen->u32Width <= UINT16_MAX
1994 && pScreen->u32Height <= UINT16_MAX
1995 && pScreen->u32LineSize <= UINT16_MAX * 4
1996 && offEnd < pView->u32MaxScreenSize)
1997 {
1998 vbvaResize (pVGAState, &pCtx->aViews[pScreen->u32ViewIndex], pScreen);
1999 return VINF_SUCCESS;
2000 }
2001
2002 LogRelFlow(("VBVA_INFO_SCREEN [%lu]: bad data: %lux%lu, line 0x%lx, BPP %u, start offset %lu, max screen size %lu\n",
2003 (unsigned long)pScreen->u32ViewIndex,
2004 (unsigned long)pScreen->u32Width,
2005 (unsigned long)pScreen->u32Height,
2006 (unsigned long)pScreen->u32LineSize,
2007 (unsigned long)pScreen->u16BitsPerPixel,
2008 (unsigned long)pScreen->u32StartOffset,
2009 (unsigned long)pView->u32MaxScreenSize));
2010 return VERR_INVALID_PARAMETER;
2011}
2012
2013int VBVAGetInfoViewAndScreen(PVGASTATE pVGAState, uint32_t u32ViewIndex, VBVAINFOVIEW *pView, VBVAINFOSCREEN *pScreen)
2014{
2015 if (u32ViewIndex >= pVGAState->cMonitors)
2016 return VERR_INVALID_PARAMETER;
2017
2018 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
2019 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
2020
2021 if (pView)
2022 *pView = pCtx->aViews[u32ViewIndex].view;
2023
2024 if (pScreen)
2025 *pScreen = pCtx->aViews[u32ViewIndex].screen;
2026
2027 return VINF_SUCCESS;
2028}
2029
2030
2031/*
2032 *
2033 * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
2034 *
2035 * VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
2036 * Read Write
2037 * Host port 0x3b0 to process completed
2038 * Guest port 0x3d0 control value? to process
2039 *
2040 */
2041
2042static DECLCALLBACK(void) vbvaNotifyGuest (void *pvCallback)
2043{
2044#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
2045 PVGASTATE pVGAState = (PVGASTATE)pvCallback;
2046 VBVARaiseIrqNoWait (pVGAState, 0);
2047#else
2048 NOREF(pvCallback);
2049 /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */
2050#endif
2051}
2052
2053/* The guest submitted a buffer. @todo Verify all guest data. */
2054static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
2055{
2056 int rc = VINF_SUCCESS;
2057
2058 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
2059 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
2060
2061 PVGASTATE pVGAState = (PVGASTATE)pvHandler;
2062 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
2063 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
2064
2065 switch (u16ChannelInfo)
2066 {
2067 case VBVA_CMDVBVA_SUBMIT:
2068 {
2069# ifdef VBOX_WITH_CRHGSMI
2070 rc = vboxCmdVBVACmdSubmit(pVGAState);
2071#endif
2072 break;
2073 }
2074 case VBVA_CMDVBVA_FLUSH:
2075 {
2076# ifdef VBOX_WITH_CRHGSMI
2077 rc =vboxCmdVBVACmdFlush(pVGAState);
2078#endif
2079 break;
2080 }
2081 case VBVA_CMDVBVA_CTL:
2082 {
2083#ifdef VBOX_WITH_CRHGSMI
2084 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXCMDVBVA_CTL))
2085 {
2086 Log(("buffer too small\n"));
2087#ifdef DEBUG_misha
2088 AssertMsgFailed(("buffer too small\n"));
2089#endif
2090 rc = VERR_INVALID_PARAMETER;
2091 break;
2092 }
2093 VBOXCMDVBVA_CTL *pCtl = (VBOXCMDVBVA_CTL*)VBoxSHGSMIBufferData((PVBOXSHGSMIHEADER)pvBuffer);
2094 rc = vboxCmdVBVACmdCtl(pVGAState, pCtl, cbBuffer - VBoxSHGSMIBufferHeaderSize());
2095#endif
2096 break;
2097 }
2098#ifdef VBOX_WITH_VDMA
2099 case VBVA_VDMA_CMD:
2100 {
2101 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMACBUF_DR))
2102 {
2103 rc = VERR_INVALID_PARAMETER;
2104 break;
2105 }
2106 PVBOXVDMACBUF_DR pCmd = (PVBOXVDMACBUF_DR)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
2107 vboxVDMACommand(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
2108 rc = VINF_SUCCESS;
2109 break;
2110 }
2111 case VBVA_VDMA_CTL:
2112 {
2113 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMA_CTL))
2114 {
2115 rc = VERR_INVALID_PARAMETER;
2116 break;
2117 }
2118 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
2119 vboxVDMAControl(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
2120 rc = VINF_SUCCESS;
2121 break;
2122 }
2123#endif
2124 case VBVA_QUERY_CONF32:
2125 {
2126 if (cbBuffer < sizeof (VBVACONF32))
2127 {
2128 rc = VERR_INVALID_PARAMETER;
2129 break;
2130 }
2131
2132 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
2133 LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n",
2134 pConf32->u32Index, pConf32->u32Value));
2135
2136 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
2137 {
2138 pConf32->u32Value = pCtx->cViews;
2139 }
2140 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
2141 {
2142 /* @todo a value calculated from the vram size */
2143 pConf32->u32Value = 64*_1K;
2144 }
2145 else
2146 {
2147 Log(("Unsupported VBVA_QUERY_CONF32 index %d!!!\n",
2148 pConf32->u32Index));
2149 rc = VERR_INVALID_PARAMETER;
2150 }
2151 } break;
2152
2153 case VBVA_SET_CONF32:
2154 {
2155 if (cbBuffer < sizeof (VBVACONF32))
2156 {
2157 rc = VERR_INVALID_PARAMETER;
2158 break;
2159 }
2160
2161 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
2162 LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n",
2163 pConf32->u32Index, pConf32->u32Value));
2164
2165 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
2166 {
2167 /* do nothing. this is a const. */
2168 }
2169 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
2170 {
2171 /* do nothing. this is a const. */
2172 }
2173 else
2174 {
2175 Log(("Unsupported VBVA_SET_CONF32 index %d!!!\n",
2176 pConf32->u32Index));
2177 rc = VERR_INVALID_PARAMETER;
2178 }
2179 } break;
2180
2181 case VBVA_INFO_VIEW:
2182 {
2183#ifdef VBOX_WITH_CRHGSMI
2184 if (vboxCmdVBVAIsEnabled(pVGAState))
2185 {
2186 AssertMsgFailed(("VBVA_INFO_VIEW is not acceptible for CmdVbva\n"));
2187 rc = VERR_INVALID_PARAMETER;
2188 break;
2189 }
2190#endif
2191
2192 if (cbBuffer < sizeof (VBVAINFOVIEW))
2193 {
2194 rc = VERR_INVALID_PARAMETER;
2195 break;
2196 }
2197
2198 /* Guest submits an array of VBVAINFOVIEW structures. */
2199 VBVAINFOVIEW *pView = (VBVAINFOVIEW *)pvBuffer;
2200
2201 for (;
2202 cbBuffer >= sizeof (VBVAINFOVIEW);
2203 pView++, cbBuffer -= sizeof (VBVAINFOVIEW))
2204 {
2205 VBVAINFOVIEW View = *pView;
2206 rc = VBVAInfoView(pVGAState, &View);
2207 if (RT_FAILURE(rc))
2208 break;
2209 }
2210 } break;
2211
2212 case VBVA_INFO_HEAP:
2213 {
2214 if (cbBuffer < sizeof (VBVAINFOHEAP))
2215 {
2216 rc = VERR_INVALID_PARAMETER;
2217 break;
2218 }
2219
2220 VBVAINFOHEAP *pHeap = (VBVAINFOHEAP *)pvBuffer;
2221 LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n",
2222 pHeap->u32HeapOffset, pHeap->u32HeapSize));
2223
2224 rc = HGSMISetupHostHeap (pIns, pHeap->u32HeapOffset, pHeap->u32HeapSize);
2225 } break;
2226
2227 case VBVA_FLUSH:
2228 {
2229 if (cbBuffer < sizeof (VBVAFLUSH))
2230 {
2231 rc = VERR_INVALID_PARAMETER;
2232 break;
2233 }
2234
2235 VBVAFLUSH *pFlush = (VBVAFLUSH *)pvBuffer;
2236 LogFlowFunc(("VBVA_FLUSH: u32Reserved 0x%x\n",
2237 pFlush->u32Reserved));
2238
2239 rc = vbvaFlush (pVGAState, pCtx);
2240 } break;
2241
2242 case VBVA_INFO_SCREEN:
2243 {
2244 if (cbBuffer < sizeof (VBVAINFOSCREEN))
2245 {
2246 rc = VERR_INVALID_PARAMETER;
2247 break;
2248 }
2249
2250#ifdef VBOX_WITH_CRHGSMI
2251 if (vboxCmdVBVAIsEnabled(pVGAState))
2252 {
2253 AssertMsgFailed(("VBVA_INFO_SCREEN is not acceptible for CmdVbva\n"));
2254 rc = VERR_INVALID_PARAMETER;
2255 break;
2256 }
2257#endif
2258
2259 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)pvBuffer;
2260 VBVAINFOSCREEN Screen = *pScreen;
2261 rc = VBVAInfoScreen(pVGAState, &Screen);
2262 } break;
2263
2264 case VBVA_ENABLE:
2265 {
2266#ifdef VBOX_WITH_CRHGSMI
2267 if (vboxCmdVBVAIsEnabled(pVGAState))
2268 {
2269 AssertMsgFailed(("VBVA_ENABLE is not acceptible for CmdVbva\n"));
2270 rc = VERR_INVALID_PARAMETER;
2271 break;
2272 }
2273#endif
2274
2275 if (cbBuffer < sizeof (VBVAENABLE))
2276 {
2277 rc = VERR_INVALID_PARAMETER;
2278 break;
2279 }
2280
2281 VBVAENABLE *pEnable = (VBVAENABLE *)pvBuffer;
2282 unsigned uScreenId;
2283 if (pEnable->u32Flags & VBVA_F_EXTENDED)
2284 {
2285 if (cbBuffer < sizeof (VBVAENABLE_EX))
2286 {
2287 rc = VERR_INVALID_PARAMETER;
2288 break;
2289 }
2290
2291 VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)pvBuffer;
2292 uScreenId = pEnableEx->u32ScreenId;
2293 }
2294 else
2295 {
2296 uScreenId = vbvaViewFromOffset (pIns, pCtx, pvBuffer);
2297 }
2298
2299 if (uScreenId == ~0U)
2300 {
2301 rc = VERR_INVALID_PARAMETER;
2302 break;
2303 }
2304
2305 LogFlowFunc(("VBVA_ENABLE[%d]: u32Flags 0x%x u32Offset 0x%x\n",
2306 uScreenId, pEnable->u32Flags, pEnable->u32Offset));
2307
2308 if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE)
2309 {
2310 /* Guest reported offset relative to view. */
2311 uint32_t u32Offset = pEnable->u32Offset;
2312 if (!(pEnable->u32Flags & VBVA_F_ABSOFFSET))
2313 {
2314 u32Offset += pCtx->aViews[uScreenId].view.u32ViewOffset;
2315 }
2316
2317 VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, u32Offset);
2318
2319 if (pVBVA)
2320 {
2321 /* Process any pending orders and empty the VBVA ring buffer. */
2322 vbvaFlush (pVGAState, pCtx);
2323
2324 rc = vbvaEnable (uScreenId, pVGAState, pCtx, pVBVA, u32Offset, false /* fRestored */);
2325 }
2326 else
2327 {
2328 Log(("Invalid VBVABUFFER offset 0x%x!!!\n",
2329 pEnable->u32Offset));
2330 rc = VERR_INVALID_PARAMETER;
2331 }
2332 }
2333 else if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE)
2334 {
2335 rc = vbvaDisable (uScreenId, pVGAState, pCtx);
2336 }
2337 else
2338 {
2339 Log(("Invalid VBVA_ENABLE flags 0x%x!!!\n",
2340 pEnable->u32Flags));
2341 rc = VERR_INVALID_PARAMETER;
2342 }
2343
2344 pEnable->i32Result = rc;
2345 } break;
2346
2347 case VBVA_MOUSE_POINTER_SHAPE:
2348 {
2349 if (cbBuffer < sizeof (VBVAMOUSEPOINTERSHAPE))
2350 {
2351 rc = VERR_INVALID_PARAMETER;
2352 break;
2353 }
2354
2355 VBVAMOUSEPOINTERSHAPE *pShape = (VBVAMOUSEPOINTERSHAPE *)pvBuffer;
2356
2357 LogFlowFunc(("VBVA_MOUSE_POINTER_SHAPE: i32Result 0x%x, fu32Flags 0x%x, hot spot %d,%d, size %dx%d\n",
2358 pShape->i32Result,
2359 pShape->fu32Flags,
2360 pShape->u32HotX,
2361 pShape->u32HotY,
2362 pShape->u32Width,
2363 pShape->u32Height));
2364
2365 rc = vbvaMousePointerShape (pVGAState, pCtx, pShape, cbBuffer);
2366
2367 pShape->i32Result = rc;
2368 } break;
2369
2370
2371#ifdef VBOX_WITH_VIDEOHWACCEL
2372 case VBVA_VHWA_CMD:
2373 {
2374 if (cbBuffer < sizeof (VBOXVHWACMD))
2375 {
2376 rc = VERR_INVALID_PARAMETER;
2377 break;
2378 }
2379 vbvaVHWAHandleCommand(pVGAState, (PVBOXVHWACMD)pvBuffer);
2380 rc = VINF_SUCCESS;
2381 break;
2382 } break;
2383#endif
2384
2385#ifdef VBOX_WITH_WDDM
2386 case VBVA_INFO_CAPS:
2387 {
2388 if (cbBuffer < sizeof (VBVACAPS))
2389 {
2390 rc = VERR_INVALID_PARAMETER;
2391 break;
2392 }
2393
2394 VBVACAPS *pCaps = (VBVACAPS*)pvBuffer;
2395 pVGAState->fGuestCaps = pCaps->fCaps;
2396 pCaps->rc = VINF_SUCCESS;
2397 } break;
2398#endif
2399 case VBVA_SCANLINE_CFG:
2400 {
2401 if (cbBuffer < sizeof (VBVASCANLINECFG))
2402 {
2403 rc = VERR_INVALID_PARAMETER;
2404 break;
2405 }
2406
2407 VBVASCANLINECFG *pCfg = (VBVASCANLINECFG*)pvBuffer;
2408 pVGAState->fScanLineCfg = pCfg->fFlags;
2409 pCfg->rc = VINF_SUCCESS;
2410 } break;
2411 default:
2412 Log(("Unsupported VBVA guest command %d!!!\n",
2413 u16ChannelInfo));
2414 break;
2415 }
2416
2417 return rc;
2418}
2419
2420/* When VBVA is paused, then VGA device is allowed to work but
2421 * no HGSMI etc state is changed.
2422 */
2423void VBVAPause(PVGASTATE pVGAState, bool fPause)
2424{
2425 if (!pVGAState || !pVGAState->pHGSMI)
2426 {
2427 return;
2428 }
2429
2430 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pVGAState->pHGSMI);
2431
2432 if (pCtx)
2433 {
2434 pCtx->fPaused = fPause;
2435 }
2436}
2437
2438void VBVAReset (PVGASTATE pVGAState)
2439{
2440 if (!pVGAState || !pVGAState->pHGSMI)
2441 {
2442 return;
2443 }
2444
2445 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2446
2447#ifdef VBOX_WITH_VIDEOHWACCEL
2448 vbvaVHWAReset (pVGAState);
2449#endif
2450
2451 uint32_t HgFlags = HGSMIReset (pVGAState->pHGSMI);
2452 if(HgFlags & HGSMIHOSTFLAGS_IRQ)
2453 {
2454 /* this means the IRQ is LEVEL_HIGH, need to reset it */
2455 PDMDevHlpPCISetIrq(pVGAState->pDevInsR3, 0, PDM_IRQ_LEVEL_LOW);
2456 }
2457
2458 if (pCtx)
2459 {
2460 vbvaFlush (pVGAState, pCtx);
2461
2462 unsigned uScreenId;
2463
2464 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
2465 {
2466 vbvaDisable (uScreenId, pVGAState, pCtx);
2467 }
2468
2469 pCtx->mouseShapeInfo.fSet = false;
2470 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2471 pCtx->mouseShapeInfo.pu8Shape = NULL;
2472 pCtx->mouseShapeInfo.cbAllocated = 0;
2473 pCtx->mouseShapeInfo.cbShape = 0;
2474 }
2475
2476}
2477
2478int VBVAUpdateDisplay (PVGASTATE pVGAState)
2479{
2480 int rc = VERR_NOT_SUPPORTED; /* Assuming that the VGA device will have to do updates. */
2481
2482 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2483
2484 if (pCtx)
2485 {
2486 if (!pCtx->fPaused)
2487 {
2488 rc = vbvaFlush (pVGAState, pCtx);
2489
2490 if (RT_SUCCESS (rc))
2491 {
2492 if (!pCtx->aViews[0].pVBVA)
2493 {
2494 /* VBVA is not enabled for the first view, so VGA device must do updates. */
2495 rc = VERR_NOT_SUPPORTED;
2496 }
2497 }
2498 }
2499 }
2500
2501 return rc;
2502}
2503
2504static HGSMICHANNELHANDLER sOldChannelHandler;
2505
2506int VBVAInit (PVGASTATE pVGAState)
2507{
2508 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
2509
2510 PVM pVM = PDMDevHlpGetVM(pDevIns);
2511
2512 int rc = HGSMICreate (&pVGAState->pHGSMI,
2513 pVM,
2514 "VBVA",
2515 0,
2516 pVGAState->vram_ptrR3,
2517 pVGAState->vram_size,
2518 vbvaNotifyGuest,
2519 pVGAState,
2520 sizeof (VBVACONTEXT));
2521
2522 if (RT_SUCCESS (rc))
2523 {
2524 rc = HGSMIHostChannelRegister (pVGAState->pHGSMI,
2525 HGSMI_CH_VBVA,
2526 vbvaChannelHandler,
2527 pVGAState,
2528 &sOldChannelHandler);
2529 if (RT_SUCCESS (rc))
2530 {
2531 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2532 pCtx->cViews = pVGAState->cMonitors;
2533 pCtx->fPaused = true;
2534 }
2535 }
2536
2537 return rc;
2538
2539}
2540
2541void VBVADestroy (PVGASTATE pVGAState)
2542{
2543 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2544
2545 if (pCtx)
2546 {
2547 pCtx->mouseShapeInfo.fSet = false;
2548 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2549 pCtx->mouseShapeInfo.pu8Shape = NULL;
2550 pCtx->mouseShapeInfo.cbAllocated = 0;
2551 pCtx->mouseShapeInfo.cbShape = 0;
2552 }
2553
2554 HGSMIDestroy (pVGAState->pHGSMI);
2555 pVGAState->pHGSMI = NULL;
2556}
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