VirtualBox

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

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

DevVGA: disable secondary screens when VBVA is disabled for them.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 81.3 KB
Line 
1/* $Id: DevVGA_VBVA.cpp 53044 2014-10-13 14:30:17Z 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 /* VBVA is working so disable the pause. */
527 pCtx->fPaused = false;
528 }
529
530 return rc;
531}
532
533static int vbvaDisable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCtx)
534{
535 /* Process any pending orders and empty the VBVA ring buffer. */
536 vbvaFlush (pVGAState, pCtx);
537
538 VBVAVIEW *pView = &pCtx->aViews[uScreenId];
539
540 if (uScreenId != 0)
541 {
542 /* Disable secondary screens. They only work in VBVA mode. */
543 VBVAINFOSCREEN screen;
544 RT_ZERO(screen);
545 screen.u16Flags = VBVA_SCREEN_F_DISABLED;
546 screen.u32ViewIndex = uScreenId;
547 vbvaResize(pVGAState, pView, &screen);
548 }
549
550 if (pView->pVBVA)
551 {
552 pView->pVBVA->hostFlags.u32HostEvents = 0;
553 pView->pVBVA->hostFlags.u32SupportedOrders = 0;
554
555 pView->partialRecord.pu8 = NULL;
556 pView->partialRecord.cb = 0;
557
558 pView->pVBVA = NULL;
559 pView->u32VBVAOffset = HGSMIOFFSET_VOID;
560 }
561
562 pVGAState->pDrv->pfnVBVADisable (pVGAState->pDrv, uScreenId);
563 return VINF_SUCCESS;
564}
565
566bool VBVAIsEnabled(PVGASTATE pVGAState)
567{
568 PHGSMIINSTANCE pHGSMI = pVGAState->pHGSMI;
569 if (pHGSMI)
570 {
571 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pHGSMI);
572 if (pCtx)
573 {
574 if (pCtx->cViews)
575 {
576 VBVAVIEW * pView = &pCtx->aViews[0];
577 if (pView->pVBVA)
578 return true;
579 }
580 }
581 }
582 return false;
583}
584
585#ifdef DEBUG_sunlover
586void dumpMouseShapeInfo(const VBVAMOUSESHAPEINFO *pMouseShapeInfo)
587{
588 LogFlow(("fSet = %d, fVisible %d, fAlpha %d, @%d,%d %dx%d (%p, %d/%d)\n",
589 pMouseShapeInfo->fSet,
590 pMouseShapeInfo->fVisible,
591 pMouseShapeInfo->fAlpha,
592 pMouseShapeInfo->u32HotX,
593 pMouseShapeInfo->u32HotY,
594 pMouseShapeInfo->u32Width,
595 pMouseShapeInfo->u32Height,
596 pMouseShapeInfo->pu8Shape,
597 pMouseShapeInfo->cbShape,
598 pMouseShapeInfo->cbAllocated
599 ));
600}
601#endif
602
603static int vbvaUpdateMousePointerShape(PVGASTATE pVGAState, VBVAMOUSESHAPEINFO *pMouseShapeInfo, bool fShape, const uint8_t *pu8Shape)
604{
605 int rc;
606 LogFlowFunc(("pVGAState %p, pMouseShapeInfo %p, fShape %d, pu8Shape %p\n",
607 pVGAState, pMouseShapeInfo, fShape, pu8Shape));
608#ifdef DEBUG_sunlover
609 dumpMouseShapeInfo(pMouseShapeInfo);
610#endif
611
612 if (fShape && pu8Shape != NULL)
613 {
614 rc = pVGAState->pDrv->pfnVBVAMousePointerShape (pVGAState->pDrv,
615 pMouseShapeInfo->fVisible,
616 pMouseShapeInfo->fAlpha,
617 pMouseShapeInfo->u32HotX,
618 pMouseShapeInfo->u32HotY,
619 pMouseShapeInfo->u32Width,
620 pMouseShapeInfo->u32Height,
621 pu8Shape);
622 }
623 else
624 {
625 rc = pVGAState->pDrv->pfnVBVAMousePointerShape (pVGAState->pDrv,
626 pMouseShapeInfo->fVisible,
627 false,
628 0, 0,
629 0, 0,
630 NULL);
631 }
632
633 return rc;
634}
635
636static int vbvaMousePointerShape (PVGASTATE pVGAState, VBVACONTEXT *pCtx, const VBVAMOUSEPOINTERSHAPE *pShape, HGSMISIZE cbShape)
637{
638 bool fVisible = (pShape->fu32Flags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
639 bool fAlpha = (pShape->fu32Flags & VBOX_MOUSE_POINTER_ALPHA) != 0;
640 bool fShape = (pShape->fu32Flags & VBOX_MOUSE_POINTER_SHAPE) != 0;
641
642 HGSMISIZE cbPointerData = 0;
643
644 if (fShape)
645 {
646 if (pShape->u32Width > 8192 || pShape->u32Height > 8192)
647 {
648 Log(("vbvaMousePointerShape: unsupported size %ux%u\n",
649 pShape->u32Width, pShape->u32Height));
650 return VERR_INVALID_PARAMETER;
651 }
652
653 cbPointerData = ((((pShape->u32Width + 7) / 8) * pShape->u32Height + 3) & ~3)
654 + pShape->u32Width * 4 * pShape->u32Height;
655 }
656
657 if (cbPointerData > cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data))
658 {
659 Log(("vbvaMousePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
660 cbPointerData, cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data)));
661 return VERR_INVALID_PARAMETER;
662 }
663
664 /* Save mouse info it will be used to restore mouse pointer after restoring saved state. */
665 pCtx->mouseShapeInfo.fSet = true;
666 pCtx->mouseShapeInfo.fVisible = fVisible;
667 pCtx->mouseShapeInfo.fAlpha = fAlpha;
668 if (fShape)
669 {
670 /* Data related to shape. */
671 pCtx->mouseShapeInfo.u32HotX = pShape->u32HotX;
672 pCtx->mouseShapeInfo.u32HotY = pShape->u32HotY;
673 pCtx->mouseShapeInfo.u32Width = pShape->u32Width;
674 pCtx->mouseShapeInfo.u32Height = pShape->u32Height;
675
676 /* Reallocate memory buffer if necessary. */
677 if (cbPointerData > pCtx->mouseShapeInfo.cbAllocated)
678 {
679 RTMemFree (pCtx->mouseShapeInfo.pu8Shape);
680 pCtx->mouseShapeInfo.pu8Shape = NULL;
681 pCtx->mouseShapeInfo.cbShape = 0;
682
683 uint8_t *pu8Shape = (uint8_t *)RTMemAlloc (cbPointerData);
684 if (pu8Shape)
685 {
686 pCtx->mouseShapeInfo.pu8Shape = pu8Shape;
687 pCtx->mouseShapeInfo.cbAllocated = cbPointerData;
688 }
689 }
690
691 /* Copy shape bitmaps. */
692 if (pCtx->mouseShapeInfo.pu8Shape)
693 {
694 memcpy (pCtx->mouseShapeInfo.pu8Shape, &pShape->au8Data[0], cbPointerData);
695 pCtx->mouseShapeInfo.cbShape = cbPointerData;
696 }
697 }
698
699 if (pVGAState->pDrv->pfnVBVAMousePointerShape == NULL)
700 {
701 return VERR_NOT_SUPPORTED;
702 }
703
704 int rc = vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, fShape, &pShape->au8Data[0]);
705
706 return rc;
707}
708
709static unsigned vbvaViewFromOffset (PHGSMIINSTANCE pIns, VBVACONTEXT *pCtx, const void *pvBuffer)
710{
711 /* Check which view contains the buffer. */
712 HGSMIOFFSET offBuffer = HGSMIPointerToOffsetHost (pIns, pvBuffer);
713
714 if (offBuffer != HGSMIOFFSET_VOID)
715 {
716 unsigned uScreenId;
717
718 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
719 {
720 VBVAINFOVIEW *pView = &pCtx->aViews[uScreenId].view;
721
722 if ( pView->u32ViewSize > 0
723 && pView->u32ViewOffset <= offBuffer
724 && offBuffer <= pView->u32ViewOffset + pView->u32ViewSize - 1)
725 {
726 return pView->u32ViewIndex;
727 }
728 }
729 }
730
731 return ~0U;
732}
733
734#ifdef DEBUG_sunlover
735static void dumpctx(const VBVACONTEXT *pCtx)
736{
737 Log(("VBVACONTEXT dump: cViews %d\n", pCtx->cViews));
738
739 uint32_t iView;
740 for (iView = 0; iView < pCtx->cViews; iView++)
741 {
742 const VBVAVIEW *pView = &pCtx->aViews[iView];
743
744 Log((" view %d o 0x%x s 0x%x m 0x%x\n",
745 pView->view.u32ViewIndex,
746 pView->view.u32ViewOffset,
747 pView->view.u32ViewSize,
748 pView->view.u32MaxScreenSize));
749
750 Log((" screen %d @%d,%d s 0x%x l 0x%x %dx%d bpp %d f 0x%x\n",
751 pView->screen.u32ViewIndex,
752 pView->screen.i32OriginX,
753 pView->screen.i32OriginY,
754 pView->screen.u32StartOffset,
755 pView->screen.u32LineSize,
756 pView->screen.u32Width,
757 pView->screen.u32Height,
758 pView->screen.u16BitsPerPixel,
759 pView->screen.u16Flags));
760
761 Log((" VBVA o 0x%x p %p\n",
762 pView->u32VBVAOffset,
763 pView->pVBVA));
764
765 Log((" PR cb 0x%x p %p\n",
766 pView->partialRecord.cb,
767 pView->partialRecord.pu8));
768 }
769
770 dumpMouseShapeInfo(&pCtx->mouseShapeInfo);
771}
772#endif /* DEBUG_sunlover */
773
774#define VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC 0x12345678
775#define VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC 0x9abcdef0
776
777#ifdef VBOX_WITH_VIDEOHWACCEL
778static void vbvaVHWAHHCommandReinit(VBOXVHWACMD* pHdr, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay)
779{
780 memset(pHdr, 0, VBOXVHWACMD_HEADSIZE());
781 pHdr->cRefs = 1;
782 pHdr->iDisplay = iDisplay;
783 pHdr->rc = VERR_NOT_IMPLEMENTED;
784 pHdr->enmCmd = enmCmd;
785 pHdr->Flags = VBOXVHWACMD_FLAG_HH_CMD;
786}
787
788static VBOXVHWACMD* vbvaVHWAHHCommandCreate (PVGASTATE pVGAState, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay, VBOXVHWACMD_LENGTH cbCmd)
789{
790 VBOXVHWACMD* pHdr = (VBOXVHWACMD*)RTMemAllocZ(cbCmd + VBOXVHWACMD_HEADSIZE());
791 Assert(pHdr);
792 if (pHdr)
793 vbvaVHWAHHCommandReinit(pHdr, enmCmd, iDisplay);
794
795 return pHdr;
796}
797
798DECLINLINE(void) vbvaVHWAHHCommandRelease (VBOXVHWACMD* pCmd)
799{
800 uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs);
801 if(!cRefs)
802 {
803 RTMemFree(pCmd);
804 }
805}
806
807DECLINLINE(void) vbvaVHWAHHCommandRetain (VBOXVHWACMD* pCmd)
808{
809 ASMAtomicIncU32(&pCmd->cRefs);
810}
811
812static void vbvaVHWACommandComplete(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand)
813{
814 if (fAsyncCommand)
815 {
816 Assert(pCommand->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
817 vbvaVHWACommandCompleteAsync(&pVGAState->IVBVACallbacks, pCommand);
818 }
819 else
820 {
821 Log(("VGA Command <<< Sync rc %d %#p, %d\n", pCommand->rc, pCommand, pCommand->enmCmd));
822 pCommand->Flags &= (~VBOXVHWACMD_FLAG_HG_ASYNCH);
823 }
824
825}
826
827static void vbvaVHWACommandCompleteAllPending(PVGASTATE pVGAState, int rc)
828{
829 if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending))
830 return;
831
832 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
833
834 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
835
836 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
837 {
838 pIter->pCommand->rc = rc;
839 vbvaVHWACommandComplete(pVGAState, pIter->pCommand, true);
840
841 /* the command is submitted/processed, remove from the pend list */
842 RTListNodeRemove(&pIter->Node);
843 ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending);
844 RTMemFree(pIter);
845 }
846
847 PDMCritSectLeave(&pVGAState->CritSect);
848}
849
850static void vbvaVHWACommandClearAllPending(PVGASTATE pVGAState)
851{
852 if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending))
853 return;
854
855 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
856
857 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
858
859 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
860 {
861 RTListNodeRemove(&pIter->Node);
862 ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending);
863 RTMemFree(pIter);
864 }
865
866 PDMCritSectLeave(&pVGAState->CritSect);
867}
868
869static void vbvaVHWACommandPend(PVGASTATE pVGAState, PVBOXVHWACMD pCommand)
870{
871 int rc = VERR_BUFFER_OVERFLOW;
872
873 if (ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS)
874 {
875 VBOX_VHWA_PENDINGCMD *pPend = (VBOX_VHWA_PENDINGCMD*)RTMemAlloc(sizeof (*pPend));
876 if (pPend)
877 {
878 pCommand->Flags |= VBOXVHWACMD_FLAG_HG_ASYNCH;
879 pPend->pCommand = pCommand;
880 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
881 if (ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS)
882 {
883 RTListAppend(&pVGAState->pendingVhwaCommands.PendingList, &pPend->Node);
884 ASMAtomicIncU32(&pVGAState->pendingVhwaCommands.cPending);
885 PDMCritSectLeave(&pVGAState->CritSect);
886 return;
887 }
888 PDMCritSectLeave(&pVGAState->CritSect);
889 LogRel(("Pending command count has reached its threshold.. completing them all.."));
890 RTMemFree(pPend);
891 }
892 else
893 rc = VERR_NO_MEMORY;
894 }
895 else
896 LogRel(("Pending command count has reached its threshold, completing them all.."));
897
898 vbvaVHWACommandCompleteAllPending(pVGAState, rc);
899
900 pCommand->rc = rc;
901
902 vbvaVHWACommandComplete(pVGAState, pCommand, false);
903}
904
905static bool vbvaVHWACommandCanPend(PVBOXVHWACMD pCommand)
906{
907 switch (pCommand->enmCmd)
908 {
909 case VBOXVHWACMD_TYPE_HH_CONSTRUCT:
910 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN:
911 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND:
912 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM:
913 case VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM:
914 return false;
915 default:
916 return true;
917 }
918}
919
920static int vbvaVHWACommandSavePending(PVGASTATE pVGAState, PSSMHANDLE pSSM)
921{
922 int rc = SSMR3PutU32(pSSM, pVGAState->pendingVhwaCommands.cPending);
923 AssertRCReturn(rc, rc);
924 VBOX_VHWA_PENDINGCMD *pIter;
925 RTListForEach(&pVGAState->pendingVhwaCommands.PendingList, pIter, VBOX_VHWA_PENDINGCMD, Node)
926 {
927 rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pIter->pCommand) - ((uint8_t*)pVGAState->vram_ptrR3)));
928 AssertRCReturn(rc, rc);
929 }
930 return rc;
931}
932
933static int vbvaVHWACommandLoadPending(PVGASTATE pVGAState, PSSMHANDLE pSSM, uint32_t u32Version)
934{
935 if (u32Version < VGA_SAVEDSTATE_VERSION_WITH_PENDVHWA)
936 return VINF_SUCCESS;
937
938 int rc;
939 uint32_t u32;
940 rc = SSMR3GetU32(pSSM, &u32);
941 AssertRCReturn(rc, rc);
942 for (uint32_t i = 0; i < u32; ++i)
943 {
944 uint32_t off32;
945 rc = SSMR3GetU32(pSSM, &off32);
946 AssertRCReturn(rc, rc);
947 PVBOXVHWACMD pCommand = (PVBOXVHWACMD)(((uint8_t*)pVGAState->vram_ptrR3) + off32);
948 vbvaVHWACommandPend(pVGAState, pCommand);
949 }
950 return rc;
951}
952
953
954static bool vbvaVHWACommandSubmit(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand)
955{
956 unsigned id = (unsigned)pCommand->iDisplay;
957 bool fPend = false;
958
959 if (pVGAState->pDrv->pfnVHWACommandProcess)
960 {
961 Log(("VGA Command >>> %#p, %d\n", pCommand, pCommand->enmCmd));
962 int rc = pVGAState->pDrv->pfnVHWACommandProcess(pVGAState->pDrv, pCommand);
963 if (rc == VINF_CALLBACK_RETURN)
964 {
965 Log(("VGA Command --- Going Async %#p, %d\n", pCommand, pCommand->enmCmd));
966 return true; /* command will be completed asynchronously, return right away */
967 }
968 else if (rc == VERR_INVALID_STATE)
969 {
970 Log(("VGA Command --- Trying Pend %#p, %d\n", pCommand, pCommand->enmCmd));
971 fPend = vbvaVHWACommandCanPend(pCommand);
972 if (!fPend)
973 {
974 Log(("VGA Command --- Can NOT Pend %#p, %d\n", pCommand, pCommand->enmCmd));
975 pCommand->rc = rc;
976 }
977 else
978 Log(("VGA Command --- Can Pend %#p, %d\n", pCommand, pCommand->enmCmd));
979 }
980 else
981 {
982 Log(("VGA Command --- Going Complete Sync rc %d %#p, %d\n", rc, pCommand, pCommand->enmCmd));
983 pCommand->rc = rc;
984 }
985
986 /* the command was completed, take a special care about it (seee below) */
987 }
988 else
989 {
990 AssertFailed();
991 pCommand->rc = VERR_INVALID_STATE;
992 }
993
994 if (fPend)
995 return false;
996
997 vbvaVHWACommandComplete(pVGAState, pCommand, fAsyncCommand);
998
999 return true;
1000}
1001
1002static bool vbvaVHWACheckPendingCommands(PVGASTATE pVGAState)
1003{
1004 if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending))
1005 return true;
1006
1007 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
1008
1009 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
1010
1011 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
1012 {
1013 if (!vbvaVHWACommandSubmit(pVGAState, pIter->pCommand, true))
1014 {
1015 PDMCritSectLeave(&pVGAState->CritSect);
1016 return false; /* the command should be pended still */
1017 }
1018
1019 /* the command is submitted/processed, remove from the pend list */
1020 RTListNodeRemove(&pIter->Node);
1021 ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending);
1022 RTMemFree(pIter);
1023 }
1024
1025 PDMCritSectLeave(&pVGAState->CritSect);
1026
1027 return true;
1028}
1029
1030void vbvaTimerCb(PVGASTATE pVGAState)
1031{
1032 vbvaVHWACheckPendingCommands(pVGAState);
1033}
1034static void vbvaVHWAHandleCommand(PVGASTATE pVGAState, PVBOXVHWACMD pCmd)
1035{
1036 if (vbvaVHWACheckPendingCommands(pVGAState))
1037 {
1038 if (vbvaVHWACommandSubmit(pVGAState, pCmd, false))
1039 return;
1040 }
1041
1042 vbvaVHWACommandPend(pVGAState, pCmd);
1043}
1044
1045static DECLCALLBACK(void) vbvaVHWAHHCommandSetEventCallback(void * pContext)
1046{
1047 RTSemEventSignal((RTSEMEVENT)pContext);
1048}
1049
1050static int vbvaVHWAHHCommandPost(PVGASTATE pVGAState, VBOXVHWACMD* pCmd)
1051{
1052 RTSEMEVENT hComplEvent;
1053 int rc = RTSemEventCreate(&hComplEvent);
1054 AssertRC(rc);
1055 if(RT_SUCCESS(rc))
1056 {
1057 /* ensure the cmd is not deleted until we process it */
1058 vbvaVHWAHHCommandRetain (pCmd);
1059 VBOXVHWA_HH_CALLBACK_SET(pCmd, vbvaVHWAHHCommandSetEventCallback, (void*)hComplEvent);
1060 vbvaVHWAHandleCommand(pVGAState, pCmd);
1061 if((ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_ASYNCH) != 0)
1062 {
1063 rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT);
1064 }
1065 else
1066 {
1067 /* the command is completed */
1068 }
1069
1070 AssertRC(rc);
1071 if(RT_SUCCESS(rc))
1072 {
1073 RTSemEventDestroy(hComplEvent);
1074 }
1075 vbvaVHWAHHCommandRelease(pCmd);
1076 }
1077 return rc;
1078}
1079
1080int vbvaVHWAConstruct (PVGASTATE pVGAState)
1081{
1082 pVGAState->pendingVhwaCommands.cPending = 0;
1083 RTListInit(&pVGAState->pendingVhwaCommands.PendingList);
1084
1085 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_CONSTRUCT, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
1086 Assert(pCmd);
1087 if(pCmd)
1088 {
1089 uint32_t iDisplay = 0;
1090 int rc = VINF_SUCCESS;
1091 VBOXVHWACMD_HH_CONSTRUCT * pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_CONSTRUCT);
1092
1093 do
1094 {
1095 memset(pBody, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
1096
1097 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1098 PVM pVM = PDMDevHlpGetVM(pDevIns);
1099
1100 pBody->pVM = pVM;
1101 pBody->pvVRAM = pVGAState->vram_ptrR3;
1102 pBody->cbVRAM = pVGAState->vram_size;
1103
1104 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
1105 AssertRC(rc);
1106 if(RT_SUCCESS(rc))
1107 {
1108 rc = pCmd->rc;
1109 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1110 if(rc == VERR_NOT_IMPLEMENTED)
1111 {
1112 /* @todo: set some flag in pVGAState indicating VHWA is not supported */
1113 /* VERR_NOT_IMPLEMENTED is not a failure, we just do not support it */
1114 rc = VINF_SUCCESS;
1115 }
1116
1117 if (!RT_SUCCESS(rc))
1118 break;
1119 }
1120 else
1121 break;
1122
1123 ++iDisplay;
1124 if (iDisplay >= pVGAState->cMonitors)
1125 break;
1126 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_CONSTRUCT, (int32_t)iDisplay);
1127 } while (true);
1128
1129 vbvaVHWAHHCommandRelease(pCmd);
1130
1131 return rc;
1132 }
1133 return VERR_OUT_OF_RESOURCES;
1134}
1135
1136int vbvaVHWAReset (PVGASTATE pVGAState)
1137{
1138 vbvaVHWACommandClearAllPending(pVGAState);
1139
1140 /* ensure we have all pending cmds processed and h->g cmds disabled */
1141 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_RESET, 0, 0);
1142 Assert(pCmd);
1143 if(pCmd)
1144 {
1145 int rc = VINF_SUCCESS;
1146 uint32_t iDisplay = 0;
1147
1148 do
1149 {
1150 rc =vbvaVHWAHHCommandPost(pVGAState, pCmd);
1151 AssertRC(rc);
1152 if(RT_SUCCESS(rc))
1153 {
1154 rc = pCmd->rc;
1155 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1156 if (rc == VERR_NOT_IMPLEMENTED)
1157 rc = VINF_SUCCESS;
1158 }
1159
1160 if (!RT_SUCCESS(rc))
1161 break;
1162
1163 ++iDisplay;
1164 if (iDisplay >= pVGAState->cMonitors)
1165 break;
1166 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_RESET, (int32_t)iDisplay);
1167
1168 } while (true);
1169
1170 vbvaVHWAHHCommandRelease(pCmd);
1171
1172 return rc;
1173 }
1174 return VERR_OUT_OF_RESOURCES;
1175}
1176
1177typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPRECB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext);
1178typedef FNVBOXVHWAHHCMDPRECB *PFNVBOXVHWAHHCMDPRECB;
1179
1180typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPOSTCB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext);
1181typedef FNVBOXVHWAHHCMDPOSTCB *PFNVBOXVHWAHHCMDPOSTCB;
1182
1183int vbvaVHWAHHPost(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, PFNVBOXVHWAHHCMDPRECB pfnPre, PFNVBOXVHWAHHCMDPOSTCB pfnPost, void *pvContext)
1184{
1185 const VBOXVHWACMD_TYPE enmType = pCmd->enmCmd;
1186 int rc = VINF_SUCCESS;
1187 uint32_t iDisplay = 0;
1188
1189 do
1190 {
1191 if (!pfnPre || pfnPre(pVGAState, pCmd, iDisplay, pvContext))
1192 {
1193 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
1194 AssertRC(rc);
1195 if (pfnPost)
1196 {
1197 if (!pfnPost(pVGAState, pCmd, iDisplay, rc, pvContext))
1198 {
1199 rc = VINF_SUCCESS;
1200 break;
1201 }
1202 rc = VINF_SUCCESS;
1203 }
1204 else if(RT_SUCCESS(rc))
1205 {
1206 rc = pCmd->rc;
1207 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1208 if(rc == VERR_NOT_IMPLEMENTED)
1209 {
1210 rc = VINF_SUCCESS;
1211 }
1212 }
1213
1214 if (!RT_SUCCESS(rc))
1215 break;
1216 }
1217
1218 ++iDisplay;
1219 if (iDisplay >= pVGAState->cMonitors)
1220 break;
1221 vbvaVHWAHHCommandReinit(pCmd, enmType, (int32_t)iDisplay);
1222 } while (true);
1223
1224 return rc;
1225}
1226
1227/* @todo call this also on reset? */
1228int vbvaVHWAEnable (PVGASTATE pVGAState, bool bEnable)
1229{
1230 const VBOXVHWACMD_TYPE enmType = bEnable ? VBOXVHWACMD_TYPE_HH_ENABLE : VBOXVHWACMD_TYPE_HH_DISABLE;
1231 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState,
1232 enmType,
1233 0, 0);
1234 Assert(pCmd);
1235 if(pCmd)
1236 {
1237 int rc = vbvaVHWAHHPost (pVGAState, pCmd, NULL, NULL, NULL);
1238 vbvaVHWAHHCommandRelease(pCmd);
1239 return rc;
1240 }
1241 return VERR_OUT_OF_RESOURCES;
1242}
1243
1244int vboxVBVASaveStatePrep (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1245{
1246 /* ensure we have no pending commands */
1247 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), false);
1248}
1249
1250int vboxVBVASaveStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1251{
1252 /* ensure we have no pending commands */
1253 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), true);
1254}
1255
1256int vbvaVHWACommandCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVHWACMD pCmd)
1257{
1258 int rc;
1259 Log(("VGA Command <<< Async rc %d %#p, %d\n", pCmd->rc, pCmd, pCmd->enmCmd));
1260
1261 if((pCmd->Flags & VBOXVHWACMD_FLAG_HH_CMD) == 0)
1262 {
1263 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
1264 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1265
1266 Assert(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
1267#ifdef VBOX_WITH_WDDM
1268 if (pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD)
1269 {
1270 rc = HGSMICompleteGuestCommand(pIns, pCmd, !!(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ));
1271 AssertRC(rc);
1272 }
1273 else
1274#endif
1275 {
1276 VBVAHOSTCMD *pHostCmd;
1277 int32_t iDisplay = pCmd->iDisplay;
1278
1279 if(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT)
1280 {
1281 rc = HGSMIHostCommandAlloc (pIns,
1282 (void**)&pHostCmd,
1283 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)),
1284 HGSMI_CH_VBVA,
1285 VBVAHG_EVENT);
1286 AssertRC(rc);
1287 if(RT_SUCCESS(rc))
1288 {
1289 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)));
1290 pHostCmd->iDstID = pCmd->iDisplay;
1291 pHostCmd->customOpCode = 0;
1292 VBVAHOSTCMDEVENT *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDEVENT);
1293 pBody->pEvent = pCmd->GuestVBVAReserved1;
1294 }
1295 }
1296 else
1297 {
1298 HGSMIOFFSET offCmd = HGSMIPointerToOffsetHost (pIns, pCmd);
1299 Assert(offCmd != HGSMIOFFSET_VOID);
1300 if(offCmd != HGSMIOFFSET_VOID)
1301 {
1302 rc = HGSMIHostCommandAlloc (pIns,
1303 (void**)&pHostCmd,
1304 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)),
1305 HGSMI_CH_VBVA,
1306 VBVAHG_DISPLAY_CUSTOM);
1307 AssertRC(rc);
1308 if(RT_SUCCESS(rc))
1309 {
1310 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)));
1311 pHostCmd->iDstID = pCmd->iDisplay;
1312 pHostCmd->customOpCode = VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE;
1313 VBVAHOSTCMDVHWACMDCOMPLETE *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDVHWACMDCOMPLETE);
1314 pBody->offCmd = offCmd;
1315 }
1316 }
1317 else
1318 {
1319 rc = VERR_INVALID_PARAMETER;
1320 }
1321 }
1322
1323 if(RT_SUCCESS(rc))
1324 {
1325 rc = HGSMIHostCommandProcessAndFreeAsynch(pIns, pHostCmd, (pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ) != 0);
1326 AssertRC(rc);
1327 if(RT_SUCCESS(rc))
1328 {
1329 return rc;
1330 }
1331 HGSMIHostCommandFree (pIns, pHostCmd);
1332 }
1333 }
1334 }
1335 else
1336 {
1337 PFNVBOXVHWA_HH_CALLBACK pfn = VBOXVHWA_HH_CALLBACK_GET(pCmd);
1338 if(pfn)
1339 {
1340 pfn(VBOXVHWA_HH_CALLBACK_GET_ARG(pCmd));
1341 }
1342 rc = VINF_SUCCESS;
1343 }
1344 return rc;
1345}
1346
1347typedef struct VBOXVBVASAVEDSTATECBDATA
1348{
1349 PSSMHANDLE pSSM;
1350 int rc;
1351 bool ab2DOn[VBOX_VIDEO_MAX_SCREENS];
1352} VBOXVBVASAVEDSTATECBDATA, *PVBOXVBVASAVEDSTATECBDATA;
1353
1354static DECLCALLBACK(bool) vboxVBVASaveStateBeginPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1355{
1356 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1357 if (RT_FAILURE(pData->rc))
1358 return false;
1359 if (RT_FAILURE(rc))
1360 {
1361 pData->rc = rc;
1362 return false;
1363 }
1364
1365 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1366 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1367 {
1368 pData->rc = VERR_INVALID_PARAMETER;
1369 return false;
1370 }
1371
1372 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1373 if (RT_SUCCESS(pCmd->rc))
1374 {
1375 pData->ab2DOn[iDisplay] = true;
1376 }
1377 else if (pCmd->rc != VERR_NOT_IMPLEMENTED)
1378 {
1379 pData->rc = pCmd->rc;
1380 return false;
1381 }
1382
1383 return true;
1384}
1385
1386static DECLCALLBACK(bool) vboxVBVASaveStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1387{
1388 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1389 if (RT_FAILURE(pData->rc))
1390 return false;
1391
1392 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1393 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1394 {
1395 pData->rc = VERR_INVALID_PARAMETER;
1396 return false;
1397 }
1398
1399 int rc;
1400
1401 if (pData->ab2DOn[iDisplay])
1402 {
1403 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC); AssertRC(rc);
1404 if (RT_FAILURE(rc))
1405 {
1406 pData->rc = rc;
1407 return false;
1408 }
1409 return true;
1410 }
1411
1412 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC); AssertRC(rc);
1413 if (RT_FAILURE(rc))
1414 {
1415 pData->rc = rc;
1416 return false;
1417 }
1418
1419 return false;
1420}
1421
1422static DECLCALLBACK(bool) vboxVBVASaveStateEndPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1423{
1424 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1425 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1426 if (pData->ab2DOn[iDisplay])
1427 {
1428 return true;
1429 }
1430
1431 return false;
1432}
1433
1434static DECLCALLBACK(bool) vboxVBVALoadStatePerformPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1435{
1436 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1437 if (RT_FAILURE(pData->rc))
1438 return false;
1439 if (RT_FAILURE(rc))
1440 {
1441 pData->rc = rc;
1442 return false;
1443 }
1444
1445 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1446 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1447 {
1448 pData->rc = VERR_INVALID_PARAMETER;
1449 return false;
1450 }
1451
1452 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1453 if (pCmd->rc == VERR_NOT_IMPLEMENTED)
1454 {
1455 pData->rc = SSMR3SkipToEndOfUnit(pData->pSSM);
1456 AssertRC(pData->rc);
1457 return false;
1458 }
1459 if (RT_FAILURE(pCmd->rc))
1460 {
1461 pData->rc = pCmd->rc;
1462 return false;
1463 }
1464
1465 return true;
1466}
1467
1468static DECLCALLBACK(bool) vboxVBVALoadStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1469{
1470 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1471 if (RT_FAILURE(pData->rc))
1472 return false;
1473
1474 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1475 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1476 {
1477 pData->rc = VERR_INVALID_PARAMETER;
1478 return false;
1479 }
1480
1481 int rc;
1482 uint32_t u32;
1483 rc = SSMR3GetU32(pData->pSSM, &u32); AssertRC(rc);
1484 if (RT_FAILURE(rc))
1485 {
1486 pData->rc = rc;
1487 return false;
1488 }
1489
1490 switch (u32)
1491 {
1492 case VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC:
1493 pData->ab2DOn[iDisplay] = true;
1494 return true;
1495 case VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC:
1496 pData->ab2DOn[iDisplay] = false;
1497 return false;
1498 default:
1499 pData->rc = VERR_INVALID_STATE;
1500 return false;
1501 }
1502}
1503#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
1504
1505int vboxVBVASaveDevStateExec (PVGASTATE pVGAState, PSSMHANDLE pSSM)
1506{
1507 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1508 int rc = HGSMIHostSaveStateExec (pIns, pSSM);
1509 if (RT_SUCCESS(rc))
1510 {
1511 /* Save VBVACONTEXT. */
1512 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1513
1514 if (!pCtx)
1515 {
1516 AssertFailed();
1517
1518 /* Still write a valid value to the SSM. */
1519 rc = SSMR3PutU32 (pSSM, 0);
1520 AssertRCReturn(rc, rc);
1521 }
1522 else
1523 {
1524#ifdef DEBUG_sunlover
1525 dumpctx(pCtx);
1526#endif
1527
1528 rc = SSMR3PutU32 (pSSM, pCtx->cViews);
1529 AssertRCReturn(rc, rc);
1530
1531 uint32_t iView;
1532 for (iView = 0; iView < pCtx->cViews; iView++)
1533 {
1534 VBVAVIEW *pView = &pCtx->aViews[iView];
1535
1536 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewIndex);
1537 AssertRCReturn(rc, rc);
1538 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewOffset);
1539 AssertRCReturn(rc, rc);
1540 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewSize);
1541 AssertRCReturn(rc, rc);
1542 rc = SSMR3PutU32 (pSSM, pView->view.u32MaxScreenSize);
1543 AssertRCReturn(rc, rc);
1544
1545 rc = SSMR3PutU32 (pSSM, pView->screen.u32ViewIndex);
1546 AssertRCReturn(rc, rc);
1547 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginX);
1548 AssertRCReturn(rc, rc);
1549 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginY);
1550 AssertRCReturn(rc, rc);
1551 rc = SSMR3PutU32 (pSSM, pView->screen.u32StartOffset);
1552 AssertRCReturn(rc, rc);
1553 rc = SSMR3PutU32 (pSSM, pView->screen.u32LineSize);
1554 AssertRCReturn(rc, rc);
1555 rc = SSMR3PutU32 (pSSM, pView->screen.u32Width);
1556 AssertRCReturn(rc, rc);
1557 rc = SSMR3PutU32 (pSSM, pView->screen.u32Height);
1558 AssertRCReturn(rc, rc);
1559 rc = SSMR3PutU16 (pSSM, pView->screen.u16BitsPerPixel);
1560 AssertRCReturn(rc, rc);
1561 rc = SSMR3PutU16 (pSSM, pView->screen.u16Flags);
1562 AssertRCReturn(rc, rc);
1563
1564 rc = SSMR3PutU32 (pSSM, pView->pVBVA? pView->u32VBVAOffset: HGSMIOFFSET_VOID);
1565 AssertRCReturn(rc, rc);
1566
1567 rc = SSMR3PutU32 (pSSM, pView->partialRecord.cb);
1568 AssertRCReturn(rc, rc);
1569
1570 if (pView->partialRecord.cb > 0)
1571 {
1572 rc = SSMR3PutMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1573 AssertRCReturn(rc, rc);
1574 }
1575 }
1576
1577 /* Save mouse pointer shape information. */
1578 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fSet);
1579 AssertRCReturn(rc, rc);
1580 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fVisible);
1581 AssertRCReturn(rc, rc);
1582 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fAlpha);
1583 AssertRCReturn(rc, rc);
1584 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotX);
1585 AssertRCReturn(rc, rc);
1586 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotY);
1587 AssertRCReturn(rc, rc);
1588 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Width);
1589 AssertRCReturn(rc, rc);
1590 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Height);
1591 AssertRCReturn(rc, rc);
1592 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.cbShape);
1593 AssertRCReturn(rc, rc);
1594 if (pCtx->mouseShapeInfo.cbShape)
1595 {
1596 rc = SSMR3PutMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1597 AssertRCReturn(rc, rc);
1598 }
1599
1600#ifdef VBOX_WITH_WDDM
1601 /* Size of some additional data. For future extensions. */
1602 rc = SSMR3PutU32 (pSSM, 4);
1603 AssertRCReturn(rc, rc);
1604 rc = SSMR3PutU32 (pSSM, pVGAState->fGuestCaps);
1605 AssertRCReturn(rc, rc);
1606#else
1607 /* Size of some additional data. For future extensions. */
1608 rc = SSMR3PutU32 (pSSM, 0);
1609 AssertRCReturn(rc, rc);
1610#endif
1611 }
1612 }
1613
1614 return rc;
1615}
1616
1617int vboxVBVASaveStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1618{
1619 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1620 int rc;
1621#ifdef VBOX_WITH_VIDEOHWACCEL
1622 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1623 VhwaData.pSSM = pSSM;
1624 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM); /* maximum cmd size */
1625 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN, 0, cbCmd);
1626 Assert(pCmd);
1627 if(pCmd)
1628 {
1629 vbvaVHWAHHPost (pVGAState, pCmd, NULL, vboxVBVASaveStateBeginPostCb, &VhwaData);
1630 rc = VhwaData.rc;
1631 AssertRC(rc);
1632 if (RT_SUCCESS(rc))
1633 {
1634#endif
1635 rc = vboxVBVASaveDevStateExec (pVGAState, pSSM);
1636 AssertRC(rc);
1637#ifdef VBOX_WITH_VIDEOHWACCEL
1638 if (RT_SUCCESS(rc))
1639 {
1640 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM, 0);
1641 VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM *pSave = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM);
1642 pSave->pSSM = pSSM;
1643 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStatePerformPreCb, NULL, &VhwaData);
1644 rc = VhwaData.rc;
1645 AssertRC(rc);
1646 if (RT_SUCCESS(rc))
1647 {
1648 rc = vbvaVHWACommandSavePending(pVGAState, pSSM);
1649 AssertRCReturn(rc, rc);
1650
1651 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND, 0);
1652 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStateEndPreCb, NULL, &VhwaData);
1653 rc = VhwaData.rc;
1654 AssertRC(rc);
1655 }
1656 }
1657 }
1658
1659 vbvaVHWAHHCommandRelease(pCmd);
1660 }
1661 else
1662 rc = VERR_OUT_OF_RESOURCES;
1663#else
1664 if (RT_SUCCESS(rc))
1665 {
1666 for (uint32_t i = 0; i < pVGAState->cMonitors; ++i)
1667 {
1668 rc = SSMR3PutU32 (pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC);
1669 AssertRCReturn(rc, rc);
1670 }
1671 }
1672
1673 /* no pending commands */
1674 SSMR3PutU32(pSSM, 0);
1675#endif
1676 return rc;
1677}
1678
1679int vboxVBVALoadStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t u32Version)
1680{
1681 if (u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1682 {
1683 /* Nothing was saved. */
1684 return VINF_SUCCESS;
1685 }
1686
1687 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1688 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1689 int rc = HGSMIHostLoadStateExec (pIns, pSSM, u32Version);
1690 if (RT_SUCCESS(rc))
1691 {
1692 /* Load VBVACONTEXT. */
1693 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1694
1695 if (!pCtx)
1696 {
1697 /* This should not happen. */
1698 AssertFailed();
1699 rc = VERR_INVALID_PARAMETER;
1700 }
1701 else
1702 {
1703 uint32_t cViews = 0;
1704 rc = SSMR3GetU32 (pSSM, &cViews);
1705 AssertRCReturn(rc, rc);
1706
1707 uint32_t iView;
1708 for (iView = 0; iView < cViews; iView++)
1709 {
1710 VBVAVIEW *pView = &pCtx->aViews[iView];
1711
1712 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewIndex);
1713 AssertRCReturn(rc, rc);
1714 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewOffset);
1715 AssertRCReturn(rc, rc);
1716 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewSize);
1717 AssertRCReturn(rc, rc);
1718 rc = SSMR3GetU32 (pSSM, &pView->view.u32MaxScreenSize);
1719 AssertRCReturn(rc, rc);
1720
1721 rc = SSMR3GetU32 (pSSM, &pView->screen.u32ViewIndex);
1722 AssertRCReturn(rc, rc);
1723 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginX);
1724 AssertRCReturn(rc, rc);
1725 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginY);
1726 AssertRCReturn(rc, rc);
1727 rc = SSMR3GetU32 (pSSM, &pView->screen.u32StartOffset);
1728 AssertRCReturn(rc, rc);
1729 rc = SSMR3GetU32 (pSSM, &pView->screen.u32LineSize);
1730 AssertRCReturn(rc, rc);
1731 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Width);
1732 AssertRCReturn(rc, rc);
1733 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Height);
1734 AssertRCReturn(rc, rc);
1735 rc = SSMR3GetU16 (pSSM, &pView->screen.u16BitsPerPixel);
1736 AssertRCReturn(rc, rc);
1737 rc = SSMR3GetU16 (pSSM, &pView->screen.u16Flags);
1738 AssertRCReturn(rc, rc);
1739
1740 rc = SSMR3GetU32 (pSSM, &pView->u32VBVAOffset);
1741 AssertRCReturn(rc, rc);
1742
1743 rc = SSMR3GetU32 (pSSM, &pView->partialRecord.cb);
1744 AssertRCReturn(rc, rc);
1745
1746 if (pView->partialRecord.cb == 0)
1747 {
1748 pView->partialRecord.pu8 = NULL;
1749 }
1750 else
1751 {
1752 Assert(pView->partialRecord.pu8 == NULL); /* Should be it. */
1753
1754 uint8_t *pu8 = (uint8_t *)RTMemAlloc (pView->partialRecord.cb);
1755
1756 if (!pu8)
1757 {
1758 return VERR_NO_MEMORY;
1759 }
1760
1761 pView->partialRecord.pu8 = pu8;
1762
1763 rc = SSMR3GetMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1764 AssertRCReturn(rc, rc);
1765 }
1766
1767 if (pView->u32VBVAOffset == HGSMIOFFSET_VOID)
1768 {
1769 pView->pVBVA = NULL;
1770 }
1771 else
1772 {
1773 pView->pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, pView->u32VBVAOffset);
1774 }
1775 }
1776
1777 if (u32Version > VGA_SAVEDSTATE_VERSION_WITH_CONFIG)
1778 {
1779 /* Read mouse pointer shape information. */
1780 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fSet);
1781 AssertRCReturn(rc, rc);
1782 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fVisible);
1783 AssertRCReturn(rc, rc);
1784 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fAlpha);
1785 AssertRCReturn(rc, rc);
1786 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotX);
1787 AssertRCReturn(rc, rc);
1788 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotY);
1789 AssertRCReturn(rc, rc);
1790 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Width);
1791 AssertRCReturn(rc, rc);
1792 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Height);
1793 AssertRCReturn(rc, rc);
1794 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.cbShape);
1795 AssertRCReturn(rc, rc);
1796 if (pCtx->mouseShapeInfo.cbShape)
1797 {
1798 pCtx->mouseShapeInfo.pu8Shape = (uint8_t *)RTMemAlloc(pCtx->mouseShapeInfo.cbShape);
1799 if (pCtx->mouseShapeInfo.pu8Shape == NULL)
1800 {
1801 return VERR_NO_MEMORY;
1802 }
1803 pCtx->mouseShapeInfo.cbAllocated = pCtx->mouseShapeInfo.cbShape;
1804 rc = SSMR3GetMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1805 AssertRCReturn(rc, rc);
1806 }
1807 else
1808 {
1809 pCtx->mouseShapeInfo.pu8Shape = NULL;
1810 }
1811
1812 /* Size of some additional data. For future extensions. */
1813 uint32_t cbExtra = 0;
1814 rc = SSMR3GetU32 (pSSM, &cbExtra);
1815 AssertRCReturn(rc, rc);
1816#ifdef VBOX_WITH_WDDM
1817 if (cbExtra >= 4)
1818 {
1819 rc = SSMR3GetU32 (pSSM, &pVGAState->fGuestCaps);
1820 AssertRCReturn(rc, rc);
1821 cbExtra -= 4;
1822 }
1823#endif
1824 if (cbExtra > 0)
1825 {
1826 rc = SSMR3Skip(pSSM, cbExtra);
1827 AssertRCReturn(rc, rc);
1828 }
1829 }
1830
1831 pCtx->cViews = iView;
1832 LogFlowFunc(("%d views loaded\n", pCtx->cViews));
1833
1834 if (u32Version > VGA_SAVEDSTATE_VERSION_WDDM)
1835 {
1836 bool fLoadCommands;
1837
1838 if (u32Version < VGA_SAVEDSTATE_VERSION_FIXED_PENDVHWA)
1839 {
1840 const char *pcszOsArch = SSMR3HandleHostOSAndArch(pSSM);
1841 Assert(pcszOsArch);
1842 fLoadCommands = !pcszOsArch || RTStrNCmp(pcszOsArch, RT_STR_TUPLE("solaris"));
1843 }
1844 else
1845 fLoadCommands = true;
1846
1847#ifdef VBOX_WITH_VIDEOHWACCEL
1848 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM); /* maximum cmd size */
1849 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM, 0, cbCmd);
1850 Assert(pCmd);
1851 if(pCmd)
1852 {
1853 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1854 VhwaData.pSSM = pSSM;
1855 VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM *pLoad = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM);
1856 pLoad->pSSM = pSSM;
1857 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVALoadStatePerformPreCb, vboxVBVALoadStatePerformPostCb, &VhwaData);
1858 rc = VhwaData.rc;
1859 vbvaVHWAHHCommandRelease(pCmd);
1860 AssertRCReturn(rc, rc);
1861
1862 if (fLoadCommands)
1863 {
1864 rc = vbvaVHWACommandLoadPending(pVGAState, pSSM, u32Version);
1865 AssertRCReturn(rc, rc);
1866 }
1867 }
1868 else
1869 {
1870 rc = VERR_OUT_OF_RESOURCES;
1871 }
1872#else
1873 uint32_t u32;
1874
1875 for (uint32_t i = 0; i < pVGAState->cMonitors; ++i)
1876 {
1877 rc = SSMR3GetU32(pSSM, &u32);
1878 AssertRCReturn(rc, rc);
1879
1880 if (u32 != VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC)
1881 {
1882 LogRel(("2D data while 2D is not supported\n"));
1883 return VERR_NOT_SUPPORTED;
1884 }
1885 }
1886
1887 if (fLoadCommands)
1888 {
1889 rc = SSMR3GetU32(pSSM, &u32);
1890 AssertRCReturn(rc, rc);
1891
1892 if (u32)
1893 {
1894 LogRel(("2D pending command while 2D is not supported\n"));
1895 return VERR_NOT_SUPPORTED;
1896 }
1897 }
1898#endif
1899 }
1900
1901#ifdef DEBUG_sunlover
1902 dumpctx(pCtx);
1903#endif
1904 }
1905 }
1906
1907 return rc;
1908}
1909
1910int vboxVBVALoadStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1911{
1912 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1913 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
1914
1915 if (pCtx)
1916 {
1917 uint32_t iView;
1918 for (iView = 0; iView < pCtx->cViews; iView++)
1919 {
1920 VBVAVIEW *pView = &pCtx->aViews[iView];
1921
1922 if (pView->pVBVA)
1923 {
1924#ifdef VBOX_WITH_CRHGSMI
1925 Assert(!vboxCmdVBVAIsEnabled(pVGAState));
1926#endif
1927 vbvaEnable (iView, pVGAState, pCtx, pView->pVBVA, pView->u32VBVAOffset, true /* fRestored */);
1928 vbvaResize (pVGAState, pView, &pView->screen);
1929 }
1930 }
1931
1932 if (pCtx->mouseShapeInfo.fSet)
1933 {
1934 vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, true, pCtx->mouseShapeInfo.pu8Shape);
1935 }
1936 }
1937
1938 return VINF_SUCCESS;
1939}
1940
1941void VBVARaiseIrq (PVGASTATE pVGAState, uint32_t fFlags)
1942{
1943 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1944 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
1945
1946 HGSMISetHostGuestFlags(pVGAState->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
1947 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1948
1949 PDMCritSectLeave(&pVGAState->CritSect);
1950}
1951
1952static DECLCALLBACK(int) vbvaRaiseIrqEMT(PVGASTATE pVGAState, uint32_t fFlags)
1953{
1954 VBVARaiseIrq(pVGAState, fFlags);
1955 return VINF_SUCCESS;
1956}
1957
1958void VBVARaiseIrqNoWait(PVGASTATE pVGAState, uint32_t fFlags)
1959{
1960 /* we can not use PDMDevHlpPCISetIrqNoWait here, because we need to set IRG host flag and raise IRQ atomically,
1961 * otherwise there might be a situation, when:
1962 * 1. Flag is set
1963 * 2. guest issues an IRQ clean request, that cleans up the flag and the interrupt
1964 * 3. IRQ is set */
1965 VMR3ReqCallNoWait(PDMDevHlpGetVM(pVGAState->pDevInsR3), VMCPUID_ANY, (PFNRT)vbvaRaiseIrqEMT, 2, pVGAState, fFlags);
1966}
1967
1968int VBVAInfoView(PVGASTATE pVGAState, VBVAINFOVIEW *pView)
1969{
1970 LogFlowFunc(("VBVA_INFO_VIEW: index %d, offset 0x%x, size 0x%x, max screen size 0x%x\n",
1971 pView->u32ViewIndex, pView->u32ViewOffset, pView->u32ViewSize, pView->u32MaxScreenSize));
1972
1973 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1974 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1975
1976 /* @todo verify view data. */
1977 if (pView->u32ViewIndex >= pCtx->cViews)
1978 {
1979 Log(("View index too large %d!!!\n",
1980 pView->u32ViewIndex));
1981 return VERR_INVALID_PARAMETER;
1982 }
1983
1984 pCtx->aViews[pView->u32ViewIndex].view = *pView;
1985
1986 return VINF_SUCCESS;
1987}
1988
1989int VBVAInfoScreen(PVGASTATE pVGAState, VBVAINFOSCREEN *pScreen)
1990{
1991 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1992 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1993 VBVAINFOVIEW *pView = &pCtx->aViews[pScreen->u32ViewIndex].view;
1994 /* Calculate the offset of the end of the screen so we can make
1995 * sure it is inside the view. I assume that screen rollover is not
1996 * implemented. */
1997 int64_t offEnd = (int64_t)pScreen->u32Height * pScreen->u32LineSize
1998 + pScreen->u32Width + pScreen->u32StartOffset;
1999 LogRel(("VBVA_INFO_SCREEN: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
2000 pScreen->u32ViewIndex, pScreen->i32OriginX, pScreen->i32OriginY,
2001 pScreen->u32Width, pScreen->u32Height,
2002 pScreen->u32LineSize, pScreen->u16BitsPerPixel, pScreen->u16Flags));
2003
2004 if ( pScreen->u32ViewIndex < RT_ELEMENTS (pCtx->aViews)
2005 && pScreen->u16BitsPerPixel <= 32
2006 && pScreen->u32Width <= UINT16_MAX
2007 && pScreen->u32Height <= UINT16_MAX
2008 && pScreen->u32LineSize <= UINT16_MAX * 4
2009 && offEnd < pView->u32MaxScreenSize)
2010 {
2011 vbvaResize (pVGAState, &pCtx->aViews[pScreen->u32ViewIndex], pScreen);
2012 return VINF_SUCCESS;
2013 }
2014
2015 LogRelFlow(("VBVA_INFO_SCREEN [%lu]: bad data: %lux%lu, line 0x%lx, BPP %u, start offset %lu, max screen size %lu\n",
2016 (unsigned long)pScreen->u32ViewIndex,
2017 (unsigned long)pScreen->u32Width,
2018 (unsigned long)pScreen->u32Height,
2019 (unsigned long)pScreen->u32LineSize,
2020 (unsigned long)pScreen->u16BitsPerPixel,
2021 (unsigned long)pScreen->u32StartOffset,
2022 (unsigned long)pView->u32MaxScreenSize));
2023 return VERR_INVALID_PARAMETER;
2024}
2025
2026int VBVAGetInfoViewAndScreen(PVGASTATE pVGAState, uint32_t u32ViewIndex, VBVAINFOVIEW *pView, VBVAINFOSCREEN *pScreen)
2027{
2028 if (u32ViewIndex >= pVGAState->cMonitors)
2029 return VERR_INVALID_PARAMETER;
2030
2031 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
2032 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
2033
2034 if (pView)
2035 *pView = pCtx->aViews[u32ViewIndex].view;
2036
2037 if (pScreen)
2038 *pScreen = pCtx->aViews[u32ViewIndex].screen;
2039
2040 return VINF_SUCCESS;
2041}
2042
2043
2044/*
2045 *
2046 * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
2047 *
2048 * VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
2049 * Read Write
2050 * Host port 0x3b0 to process completed
2051 * Guest port 0x3d0 control value? to process
2052 *
2053 */
2054
2055static DECLCALLBACK(void) vbvaNotifyGuest (void *pvCallback)
2056{
2057#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
2058 PVGASTATE pVGAState = (PVGASTATE)pvCallback;
2059 VBVARaiseIrqNoWait (pVGAState, 0);
2060#else
2061 NOREF(pvCallback);
2062 /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */
2063#endif
2064}
2065
2066/* The guest submitted a buffer. @todo Verify all guest data. */
2067static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
2068{
2069 int rc = VINF_SUCCESS;
2070
2071 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
2072 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
2073
2074 PVGASTATE pVGAState = (PVGASTATE)pvHandler;
2075 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
2076 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
2077
2078 switch (u16ChannelInfo)
2079 {
2080 case VBVA_CMDVBVA_SUBMIT:
2081 {
2082# ifdef VBOX_WITH_CRHGSMI
2083 rc = vboxCmdVBVACmdSubmit(pVGAState);
2084#endif
2085 break;
2086 }
2087 case VBVA_CMDVBVA_FLUSH:
2088 {
2089# ifdef VBOX_WITH_CRHGSMI
2090 rc =vboxCmdVBVACmdFlush(pVGAState);
2091#endif
2092 break;
2093 }
2094 case VBVA_CMDVBVA_CTL:
2095 {
2096#ifdef VBOX_WITH_CRHGSMI
2097 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXCMDVBVA_CTL))
2098 {
2099 Log(("buffer too small\n"));
2100#ifdef DEBUG_misha
2101 AssertMsgFailed(("buffer too small\n"));
2102#endif
2103 rc = VERR_INVALID_PARAMETER;
2104 break;
2105 }
2106 VBOXCMDVBVA_CTL *pCtl = (VBOXCMDVBVA_CTL*)VBoxSHGSMIBufferData((PVBOXSHGSMIHEADER)pvBuffer);
2107 rc = vboxCmdVBVACmdCtl(pVGAState, pCtl, cbBuffer - VBoxSHGSMIBufferHeaderSize());
2108#endif
2109 break;
2110 }
2111#ifdef VBOX_WITH_VDMA
2112 case VBVA_VDMA_CMD:
2113 {
2114 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMACBUF_DR))
2115 {
2116 rc = VERR_INVALID_PARAMETER;
2117 break;
2118 }
2119 PVBOXVDMACBUF_DR pCmd = (PVBOXVDMACBUF_DR)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
2120 vboxVDMACommand(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
2121 rc = VINF_SUCCESS;
2122 break;
2123 }
2124 case VBVA_VDMA_CTL:
2125 {
2126 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMA_CTL))
2127 {
2128 rc = VERR_INVALID_PARAMETER;
2129 break;
2130 }
2131 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
2132 vboxVDMAControl(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
2133 rc = VINF_SUCCESS;
2134 break;
2135 }
2136#endif
2137 case VBVA_QUERY_CONF32:
2138 {
2139 if (cbBuffer < sizeof (VBVACONF32))
2140 {
2141 rc = VERR_INVALID_PARAMETER;
2142 break;
2143 }
2144
2145 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
2146 LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n",
2147 pConf32->u32Index, pConf32->u32Value));
2148
2149 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
2150 {
2151 pConf32->u32Value = pCtx->cViews;
2152 }
2153 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
2154 {
2155 /* @todo a value calculated from the vram size */
2156 pConf32->u32Value = 64*_1K;
2157 }
2158 else
2159 {
2160 Log(("Unsupported VBVA_QUERY_CONF32 index %d!!!\n",
2161 pConf32->u32Index));
2162 rc = VERR_INVALID_PARAMETER;
2163 }
2164 } break;
2165
2166 case VBVA_SET_CONF32:
2167 {
2168 if (cbBuffer < sizeof (VBVACONF32))
2169 {
2170 rc = VERR_INVALID_PARAMETER;
2171 break;
2172 }
2173
2174 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
2175 LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n",
2176 pConf32->u32Index, pConf32->u32Value));
2177
2178 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
2179 {
2180 /* do nothing. this is a const. */
2181 }
2182 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
2183 {
2184 /* do nothing. this is a const. */
2185 }
2186 else
2187 {
2188 Log(("Unsupported VBVA_SET_CONF32 index %d!!!\n",
2189 pConf32->u32Index));
2190 rc = VERR_INVALID_PARAMETER;
2191 }
2192 } break;
2193
2194 case VBVA_INFO_VIEW:
2195 {
2196#ifdef VBOX_WITH_CRHGSMI
2197 if (vboxCmdVBVAIsEnabled(pVGAState))
2198 {
2199 AssertMsgFailed(("VBVA_INFO_VIEW is not acceptible for CmdVbva\n"));
2200 rc = VERR_INVALID_PARAMETER;
2201 break;
2202 }
2203#endif
2204
2205 if (cbBuffer < sizeof (VBVAINFOVIEW))
2206 {
2207 rc = VERR_INVALID_PARAMETER;
2208 break;
2209 }
2210
2211 /* Guest submits an array of VBVAINFOVIEW structures. */
2212 VBVAINFOVIEW *pView = (VBVAINFOVIEW *)pvBuffer;
2213
2214 for (;
2215 cbBuffer >= sizeof (VBVAINFOVIEW);
2216 pView++, cbBuffer -= sizeof (VBVAINFOVIEW))
2217 {
2218 VBVAINFOVIEW View = *pView;
2219 rc = VBVAInfoView(pVGAState, &View);
2220 if (RT_FAILURE(rc))
2221 break;
2222 }
2223 } break;
2224
2225 case VBVA_INFO_HEAP:
2226 {
2227 if (cbBuffer < sizeof (VBVAINFOHEAP))
2228 {
2229 rc = VERR_INVALID_PARAMETER;
2230 break;
2231 }
2232
2233 VBVAINFOHEAP *pHeap = (VBVAINFOHEAP *)pvBuffer;
2234 LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n",
2235 pHeap->u32HeapOffset, pHeap->u32HeapSize));
2236
2237 rc = HGSMISetupHostHeap (pIns, pHeap->u32HeapOffset, pHeap->u32HeapSize);
2238 } break;
2239
2240 case VBVA_FLUSH:
2241 {
2242 if (cbBuffer < sizeof (VBVAFLUSH))
2243 {
2244 rc = VERR_INVALID_PARAMETER;
2245 break;
2246 }
2247
2248 VBVAFLUSH *pFlush = (VBVAFLUSH *)pvBuffer;
2249 LogFlowFunc(("VBVA_FLUSH: u32Reserved 0x%x\n",
2250 pFlush->u32Reserved));
2251
2252 rc = vbvaFlush (pVGAState, pCtx);
2253 } break;
2254
2255 case VBVA_INFO_SCREEN:
2256 {
2257 if (cbBuffer < sizeof (VBVAINFOSCREEN))
2258 {
2259 rc = VERR_INVALID_PARAMETER;
2260 break;
2261 }
2262
2263#ifdef VBOX_WITH_CRHGSMI
2264 if (vboxCmdVBVAIsEnabled(pVGAState))
2265 {
2266 AssertMsgFailed(("VBVA_INFO_SCREEN is not acceptible for CmdVbva\n"));
2267 rc = VERR_INVALID_PARAMETER;
2268 break;
2269 }
2270#endif
2271
2272 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)pvBuffer;
2273 VBVAINFOSCREEN Screen = *pScreen;
2274 rc = VBVAInfoScreen(pVGAState, &Screen);
2275 } break;
2276
2277 case VBVA_ENABLE:
2278 {
2279#ifdef VBOX_WITH_CRHGSMI
2280 if (vboxCmdVBVAIsEnabled(pVGAState))
2281 {
2282 AssertMsgFailed(("VBVA_ENABLE is not acceptible for CmdVbva\n"));
2283 rc = VERR_INVALID_PARAMETER;
2284 break;
2285 }
2286#endif
2287
2288 if (cbBuffer < sizeof (VBVAENABLE))
2289 {
2290 rc = VERR_INVALID_PARAMETER;
2291 break;
2292 }
2293
2294 VBVAENABLE *pEnable = (VBVAENABLE *)pvBuffer;
2295 unsigned uScreenId;
2296 if (pEnable->u32Flags & VBVA_F_EXTENDED)
2297 {
2298 if (cbBuffer < sizeof (VBVAENABLE_EX))
2299 {
2300 rc = VERR_INVALID_PARAMETER;
2301 break;
2302 }
2303
2304 VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)pvBuffer;
2305 uScreenId = pEnableEx->u32ScreenId;
2306 }
2307 else
2308 {
2309 uScreenId = vbvaViewFromOffset (pIns, pCtx, pvBuffer);
2310 }
2311
2312 if (uScreenId == ~0U)
2313 {
2314 rc = VERR_INVALID_PARAMETER;
2315 break;
2316 }
2317
2318 LogFlowFunc(("VBVA_ENABLE[%d]: u32Flags 0x%x u32Offset 0x%x\n",
2319 uScreenId, pEnable->u32Flags, pEnable->u32Offset));
2320
2321 if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE)
2322 {
2323 /* Guest reported offset relative to view. */
2324 uint32_t u32Offset = pEnable->u32Offset;
2325 if (!(pEnable->u32Flags & VBVA_F_ABSOFFSET))
2326 {
2327 u32Offset += pCtx->aViews[uScreenId].view.u32ViewOffset;
2328 }
2329
2330 VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, u32Offset);
2331
2332 if (pVBVA)
2333 {
2334 /* Process any pending orders and empty the VBVA ring buffer. */
2335 vbvaFlush (pVGAState, pCtx);
2336
2337 rc = vbvaEnable (uScreenId, pVGAState, pCtx, pVBVA, u32Offset, false /* fRestored */);
2338 }
2339 else
2340 {
2341 Log(("Invalid VBVABUFFER offset 0x%x!!!\n",
2342 pEnable->u32Offset));
2343 rc = VERR_INVALID_PARAMETER;
2344 }
2345 }
2346 else if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE)
2347 {
2348 rc = vbvaDisable (uScreenId, pVGAState, pCtx);
2349 }
2350 else
2351 {
2352 Log(("Invalid VBVA_ENABLE flags 0x%x!!!\n",
2353 pEnable->u32Flags));
2354 rc = VERR_INVALID_PARAMETER;
2355 }
2356
2357 pEnable->i32Result = rc;
2358 } break;
2359
2360 case VBVA_MOUSE_POINTER_SHAPE:
2361 {
2362 if (cbBuffer < sizeof (VBVAMOUSEPOINTERSHAPE))
2363 {
2364 rc = VERR_INVALID_PARAMETER;
2365 break;
2366 }
2367
2368 VBVAMOUSEPOINTERSHAPE *pShape = (VBVAMOUSEPOINTERSHAPE *)pvBuffer;
2369
2370 LogFlowFunc(("VBVA_MOUSE_POINTER_SHAPE: i32Result 0x%x, fu32Flags 0x%x, hot spot %d,%d, size %dx%d\n",
2371 pShape->i32Result,
2372 pShape->fu32Flags,
2373 pShape->u32HotX,
2374 pShape->u32HotY,
2375 pShape->u32Width,
2376 pShape->u32Height));
2377
2378 rc = vbvaMousePointerShape (pVGAState, pCtx, pShape, cbBuffer);
2379
2380 pShape->i32Result = rc;
2381 } break;
2382
2383
2384#ifdef VBOX_WITH_VIDEOHWACCEL
2385 case VBVA_VHWA_CMD:
2386 {
2387 if (cbBuffer < sizeof (VBOXVHWACMD))
2388 {
2389 rc = VERR_INVALID_PARAMETER;
2390 break;
2391 }
2392 vbvaVHWAHandleCommand(pVGAState, (PVBOXVHWACMD)pvBuffer);
2393 rc = VINF_SUCCESS;
2394 break;
2395 } break;
2396#endif
2397
2398#ifdef VBOX_WITH_WDDM
2399 case VBVA_INFO_CAPS:
2400 {
2401 if (cbBuffer < sizeof (VBVACAPS))
2402 {
2403 rc = VERR_INVALID_PARAMETER;
2404 break;
2405 }
2406
2407 VBVACAPS *pCaps = (VBVACAPS*)pvBuffer;
2408 pVGAState->fGuestCaps = pCaps->fCaps;
2409 pCaps->rc = VINF_SUCCESS;
2410 } break;
2411#endif
2412 case VBVA_SCANLINE_CFG:
2413 {
2414 if (cbBuffer < sizeof (VBVASCANLINECFG))
2415 {
2416 rc = VERR_INVALID_PARAMETER;
2417 break;
2418 }
2419
2420 VBVASCANLINECFG *pCfg = (VBVASCANLINECFG*)pvBuffer;
2421 pVGAState->fScanLineCfg = pCfg->fFlags;
2422 pCfg->rc = VINF_SUCCESS;
2423 } break;
2424 default:
2425 Log(("Unsupported VBVA guest command %d!!!\n",
2426 u16ChannelInfo));
2427 break;
2428 }
2429
2430 return rc;
2431}
2432
2433/* When VBVA is paused, then VGA device is allowed to work but
2434 * no HGSMI etc state is changed.
2435 */
2436void VBVAPause(PVGASTATE pVGAState, bool fPause)
2437{
2438 if (!pVGAState || !pVGAState->pHGSMI)
2439 {
2440 return;
2441 }
2442
2443 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pVGAState->pHGSMI);
2444
2445 if (pCtx)
2446 {
2447 pCtx->fPaused = fPause;
2448 }
2449}
2450
2451void VBVAReset (PVGASTATE pVGAState)
2452{
2453 if (!pVGAState || !pVGAState->pHGSMI)
2454 {
2455 return;
2456 }
2457
2458 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2459
2460#ifdef VBOX_WITH_VIDEOHWACCEL
2461 vbvaVHWAReset (pVGAState);
2462#endif
2463
2464 uint32_t HgFlags = HGSMIReset (pVGAState->pHGSMI);
2465 if(HgFlags & HGSMIHOSTFLAGS_IRQ)
2466 {
2467 /* this means the IRQ is LEVEL_HIGH, need to reset it */
2468 PDMDevHlpPCISetIrq(pVGAState->pDevInsR3, 0, PDM_IRQ_LEVEL_LOW);
2469 }
2470
2471 if (pCtx)
2472 {
2473 vbvaFlush (pVGAState, pCtx);
2474
2475 unsigned uScreenId;
2476
2477 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
2478 {
2479 vbvaDisable (uScreenId, pVGAState, pCtx);
2480 }
2481
2482 pCtx->mouseShapeInfo.fSet = false;
2483 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2484 pCtx->mouseShapeInfo.pu8Shape = NULL;
2485 pCtx->mouseShapeInfo.cbAllocated = 0;
2486 pCtx->mouseShapeInfo.cbShape = 0;
2487 }
2488
2489}
2490
2491int VBVAUpdateDisplay (PVGASTATE pVGAState)
2492{
2493 int rc = VERR_NOT_SUPPORTED; /* Assuming that the VGA device will have to do updates. */
2494
2495 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2496
2497 if (pCtx)
2498 {
2499 if (!pCtx->fPaused)
2500 {
2501 rc = vbvaFlush (pVGAState, pCtx);
2502
2503 if (RT_SUCCESS (rc))
2504 {
2505 if (!pCtx->aViews[0].pVBVA)
2506 {
2507 /* VBVA is not enabled for the first view, so VGA device must do updates. */
2508 rc = VERR_NOT_SUPPORTED;
2509 }
2510 }
2511 }
2512 }
2513
2514 return rc;
2515}
2516
2517static HGSMICHANNELHANDLER sOldChannelHandler;
2518
2519int VBVAInit (PVGASTATE pVGAState)
2520{
2521 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
2522
2523 PVM pVM = PDMDevHlpGetVM(pDevIns);
2524
2525 int rc = HGSMICreate (&pVGAState->pHGSMI,
2526 pVM,
2527 "VBVA",
2528 0,
2529 pVGAState->vram_ptrR3,
2530 pVGAState->vram_size,
2531 vbvaNotifyGuest,
2532 pVGAState,
2533 sizeof (VBVACONTEXT));
2534
2535 if (RT_SUCCESS (rc))
2536 {
2537 rc = HGSMIHostChannelRegister (pVGAState->pHGSMI,
2538 HGSMI_CH_VBVA,
2539 vbvaChannelHandler,
2540 pVGAState,
2541 &sOldChannelHandler);
2542 if (RT_SUCCESS (rc))
2543 {
2544 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2545 pCtx->cViews = pVGAState->cMonitors;
2546 pCtx->fPaused = true;
2547 }
2548 }
2549
2550 return rc;
2551
2552}
2553
2554void VBVADestroy (PVGASTATE pVGAState)
2555{
2556 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2557
2558 if (pCtx)
2559 {
2560 pCtx->mouseShapeInfo.fSet = false;
2561 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2562 pCtx->mouseShapeInfo.pu8Shape = NULL;
2563 pCtx->mouseShapeInfo.cbAllocated = 0;
2564 pCtx->mouseShapeInfo.cbShape = 0;
2565 }
2566
2567 HGSMIDestroy (pVGAState->pHGSMI);
2568 pVGAState->pHGSMI = NULL;
2569}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette