VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 106.0 KB
RevLine 
[44876]1/* $Id: DevVGA_VBVA.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
[23118]2/** @file
[22622]3 * VirtualBox Video Acceleration (VBVA).
4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[22622]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[22622]26 */
27
[57358]28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[22622]32#define LOG_GROUP LOG_GROUP_DEV_VGA
[35346]33#include <VBox/vmm/pdmifs.h>
34#include <VBox/vmm/pdmdev.h>
35#include <VBox/vmm/pgm.h>
36#include <VBox/vmm/ssm.h>
[22622]37#include <VBox/VMMDev.h>
[71619]38#include <VBox/AssertGuest.h>
[65381]39#include <VBoxVideo.h>
[22622]40#include <iprt/alloc.h>
41#include <iprt/assert.h>
42#include <iprt/asm.h>
43#include <iprt/string.h>
44#include <iprt/param.h>
45#ifdef VBOX_WITH_VIDEOHWACCEL
46#include <iprt/semaphore.h>
47#endif
48
49#include "DevVGA.h"
50
51/* A very detailed logging. */
52#if 0 // def DEBUG_sunlover
53#define LOGVBVABUFFER(a) LogFlow(a)
54#else
[44876]55#define LOGVBVABUFFER(a) do {} while (0)
[22622]56#endif
57
[57358]58
59/*********************************************************************************************************************************
60* Structures and Typedefs *
61*********************************************************************************************************************************/
[34490]62typedef struct VBVAPARTIALRECORD
[22622]63{
64 uint8_t *pu8;
65 uint32_t cb;
66} VBVAPARTIALRECORD;
67
[56036]68typedef struct VBVADATA
69{
70 struct
71 {
[71619]72 VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *pVBVA; /**< Pointer to the guest memory with the VBVABUFFER. */
73 uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pu8Data; /**< For convenience, pointer to the guest ring buffer (VBVABUFFER::au8Data). */
[56036]74 } guest;
[71619]75 uint32_t u32VBVAOffset; /**< VBVABUFFER offset in the guest VRAM. */
76 VBVAPARTIALRECORD partialRecord; /**< Partial record temporary storage. */
77 uint32_t off32Data; /**< The offset where the data starts in the VBVABUFFER.
78 * The host code uses it instead of VBVABUFFER::off32Data. */
79 uint32_t indexRecordFirst; /**< Index of the first filled record in VBVABUFFER::aRecords. */
80 uint32_t cbPartialWriteThreshold; /**< Copy of VBVABUFFER::cbPartialWriteThreshold used by host code. */
81 uint32_t cbData; /**< Copy of VBVABUFFER::cbData used by host code. */
[56036]82} VBVADATA;
83
[34490]84typedef struct VBVAVIEW
[22622]85{
86 VBVAINFOVIEW view;
87 VBVAINFOSCREEN screen;
[56036]88 VBVADATA vbva;
[22622]89} VBVAVIEW;
90
[24714]91typedef struct VBVAMOUSESHAPEINFO
92{
93 bool fSet;
94 bool fVisible;
95 bool fAlpha;
96 uint32_t u32HotX;
97 uint32_t u32HotY;
98 uint32_t u32Width;
99 uint32_t u32Height;
100 uint32_t cbShape;
101 uint32_t cbAllocated;
102 uint8_t *pu8Shape;
103} VBVAMOUSESHAPEINFO;
104
[44876]105/** @todo saved state: save and restore VBVACONTEXT */
[34490]106typedef struct VBVACONTEXT
[22622]107{
108 uint32_t cViews;
[56036]109 VBVAVIEW aViews[VBOX_VIDEO_MAX_SCREENS];
[24714]110 VBVAMOUSESHAPEINFO mouseShapeInfo;
[50259]111 bool fPaused;
[53528]112 VBVAMODEHINT aModeHints[VBOX_VIDEO_MAX_SCREENS];
[22622]113} VBVACONTEXT;
114
[44876]115
[56036]116static void vbvaDataCleanup(VBVADATA *pVBVAData)
117{
118 if (pVBVAData->guest.pVBVA)
119 {
[71619]120 pVBVAData->guest.pVBVA->hostFlags.u32HostEvents = 0;
121 pVBVAData->guest.pVBVA->hostFlags.u32SupportedOrders = 0;
[56036]122 }
[56316]123
[83562]124 RTMemFreeZ(pVBVAData->partialRecord.pu8, pVBVAData->partialRecord.cb);
[44876]125
[56036]126 RT_ZERO(*pVBVAData);
127 pVBVAData->u32VBVAOffset = HGSMIOFFSET_VOID;
128}
129
[71619]130/** Copies @a cb bytes from the VBVA ring buffer to the @a pbDst.
[22622]131 * Used for partial records or for records which cross the ring boundary.
132 */
[71619]133static bool vbvaFetchBytes(VBVADATA *pVBVAData, uint8_t *pbDst, uint32_t cb)
[22622]134{
[56036]135 if (cb >= pVBVAData->cbData)
[22622]136 {
[56036]137 AssertMsgFailed(("cb = 0x%08X, ring buffer size 0x%08X", cb, pVBVAData->cbData));
138 return false;
[22622]139 }
140
[71619]141 const uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pbSrc = &pVBVAData->guest.pu8Data[pVBVAData->off32Data];
[56036]142 const uint32_t u32BytesTillBoundary = pVBVAData->cbData - pVBVAData->off32Data;
[71619]143 const int32_t i32Diff = cb - u32BytesTillBoundary;
[22622]144
145 if (i32Diff <= 0)
146 {
147 /* Chunk will not cross buffer boundary. */
[71619]148 RT_BCOPY_VOLATILE(pbDst, pbSrc, cb);
[22622]149 }
150 else
151 {
152 /* Chunk crosses buffer boundary. */
[71619]153 RT_BCOPY_VOLATILE(pbDst, pbSrc, u32BytesTillBoundary);
154 RT_BCOPY_VOLATILE(pbDst + u32BytesTillBoundary, &pVBVAData->guest.pu8Data[0], i32Diff);
[22622]155 }
156
[56036]157 /* Advance data offset and sync with guest. */
158 pVBVAData->off32Data = (pVBVAData->off32Data + cb) % pVBVAData->cbData;
159 pVBVAData->guest.pVBVA->off32Data = pVBVAData->off32Data;
160 return true;
[22622]161}
162
163
[56036]164static bool vbvaPartialRead(uint32_t cbRecord, VBVADATA *pVBVAData)
[22622]165{
[56036]166 VBVAPARTIALRECORD *pPartialRecord = &pVBVAData->partialRecord;
[22622]167 uint8_t *pu8New;
168
169 LOGVBVABUFFER(("vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
170 pPartialRecord->pu8, pPartialRecord->cb, cbRecord));
171
[56036]172 Assert(cbRecord > pPartialRecord->cb); /* Caller ensures this. */
173
174 const uint32_t cbChunk = cbRecord - pPartialRecord->cb;
175 if (cbChunk >= pVBVAData->cbData)
176 {
177 return false;
178 }
179
[22622]180 if (pPartialRecord->pu8)
181 {
[56036]182 Assert(pPartialRecord->cb);
183 pu8New = (uint8_t *)RTMemRealloc(pPartialRecord->pu8, cbRecord);
[22622]184 }
185 else
186 {
[56036]187 Assert(!pPartialRecord->cb);
188 pu8New = (uint8_t *)RTMemAlloc(cbRecord);
[22622]189 }
190
191 if (!pu8New)
192 {
193 /* Memory allocation failed, fail the function. */
194 Log(("vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
195 cbRecord));
196
197 return false;
198 }
199
200 /* Fetch data from the ring buffer. */
[56036]201 if (!vbvaFetchBytes(pVBVAData, pu8New + pPartialRecord->cb, cbChunk))
202 {
203 return false;
204 }
[22622]205
206 pPartialRecord->pu8 = pu8New;
207 pPartialRecord->cb = cbRecord;
208
209 return true;
210}
211
[71619]212/**
213 * For contiguous chunks just return the address in the buffer. For crossing
214 * boundary - allocate a buffer from heap.
[22622]215 */
[71619]216static bool vbvaFetchCmd(VBVADATA *pVBVAData, VBVACMDHDR RT_UNTRUSTED_VOLATILE_GUEST **ppHdr, uint32_t *pcbCmd)
[22622]217{
[56036]218 VBVAPARTIALRECORD *pPartialRecord = &pVBVAData->partialRecord;
219 uint32_t indexRecordFirst = pVBVAData->indexRecordFirst;
220 const uint32_t indexRecordFree = ASMAtomicReadU32(&pVBVAData->guest.pVBVA->indexRecordFree);
[22622]221
222 LOGVBVABUFFER(("first = %d, free = %d\n",
223 indexRecordFirst, indexRecordFree));
224
[56036]225 if (indexRecordFree >= RT_ELEMENTS(pVBVAData->guest.pVBVA->aRecords))
226 {
227 return false;
228 }
229
[22622]230 if (indexRecordFirst == indexRecordFree)
231 {
232 /* No records to process. Return without assigning output variables. */
233 return true;
234 }
235
[56036]236 uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVBVAData->guest.pVBVA->aRecords[indexRecordFirst].cbRecord);
[22622]237
[39887]238 LOGVBVABUFFER(("cbRecord = 0x%08X, pPartialRecord->cb = 0x%08X\n", cbRecordCurrent, pPartialRecord->cb));
[22622]239
[39887]240 uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
[22622]241
[56036]242 if (cbRecord > VBVA_MAX_RECORD_SIZE)
243 {
244 return false;
245 }
246
[22622]247 if (pPartialRecord->cb)
248 {
249 /* There is a partial read in process. Continue with it. */
250 Assert (pPartialRecord->pu8);
251
252 LOGVBVABUFFER(("continue partial record cb = %d cbRecord 0x%08X, first = %d, free = %d\n",
[39887]253 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
[22622]254
255 if (cbRecord > pPartialRecord->cb)
256 {
257 /* New data has been added to the record. */
[56036]258 if (!vbvaPartialRead(cbRecord, pVBVAData))
[22622]259 {
260 return false;
261 }
262 }
263
[39887]264 if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL))
[22622]265 {
266 /* The record is completed by guest. Return it to the caller. */
267 *ppHdr = (VBVACMDHDR *)pPartialRecord->pu8;
268 *pcbCmd = pPartialRecord->cb;
269
270 pPartialRecord->pu8 = NULL;
271 pPartialRecord->cb = 0;
272
[56036]273 /* Advance the record index and sync with guest. */
274 pVBVAData->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVAData->guest.pVBVA->aRecords);
275 pVBVAData->guest.pVBVA->indexRecordFirst = pVBVAData->indexRecordFirst;
[22622]276
277 LOGVBVABUFFER(("partial done ok, data = %d, free = %d\n",
[56036]278 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free));
[22622]279 }
280
281 return true;
282 }
283
284 /* A new record need to be processed. */
[39887]285 if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
[22622]286 {
287 /* Current record is being written by guest. '=' is important here,
288 * because the guest will do a FLUSH at this condition.
[33540]289 * This partial record is too large for the ring buffer and must
[22622]290 * be accumulated in an allocated buffer.
291 */
[56036]292 if (cbRecord >= pVBVAData->cbData - pVBVAData->cbPartialWriteThreshold)
[22622]293 {
294 /* Partial read must be started. */
[56036]295 if (!vbvaPartialRead(cbRecord, pVBVAData))
[22622]296 {
297 return false;
298 }
299
300 LOGVBVABUFFER(("started partial record cb = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
[39887]301 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
[22622]302 }
303
304 return true;
305 }
306
307 /* Current record is complete. If it is not empty, process it. */
[56036]308 if (cbRecord >= pVBVAData->cbData)
309 {
310 return false;
311 }
312
[22622]313 if (cbRecord)
314 {
[56036]315 /* The size of largest contiguous chunk in the ring buffer. */
316 uint32_t u32BytesTillBoundary = pVBVAData->cbData - pVBVAData->off32Data;
[22622]317
318 /* The pointer to data in the ring buffer. */
[71619]319 uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pbSrc = &pVBVAData->guest.pu8Data[pVBVAData->off32Data];
[22622]320
321 /* Fetch or point the data. */
322 if (u32BytesTillBoundary >= cbRecord)
323 {
324 /* The command does not cross buffer boundary. Return address in the buffer. */
[71619]325 *ppHdr = (VBVACMDHDR RT_UNTRUSTED_VOLATILE_GUEST *)pbSrc;
[22622]326
[58539]327 /* The data offset will be updated in vbvaReleaseCmd. */
[22622]328 }
329 else
330 {
331 /* The command crosses buffer boundary. Rare case, so not optimized. */
[71619]332 uint8_t *pbDst = (uint8_t *)RTMemAlloc(cbRecord);
333 if (!pbDst)
[22622]334 {
335 LogFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord));
336 return false;
337 }
338
[71619]339 vbvaFetchBytes(pVBVAData, pbDst, cbRecord);
[22622]340
[71619]341 *ppHdr = (VBVACMDHDR *)pbDst;
[22622]342
[71619]343 LOGVBVABUFFER(("Allocated from heap %p\n", pbDst));
[22622]344 }
345 }
346
347 *pcbCmd = cbRecord;
348
[56036]349 /* Advance the record index and sync with guest. */
350 pVBVAData->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVAData->guest.pVBVA->aRecords);
351 pVBVAData->guest.pVBVA->indexRecordFirst = pVBVAData->indexRecordFirst;
[22622]352
353 LOGVBVABUFFER(("done ok, data = %d, free = %d\n",
[56036]354 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free));
[22622]355
356 return true;
357}
358
[71619]359static void vbvaReleaseCmd(VBVADATA *pVBVAData, VBVACMDHDR RT_UNTRUSTED_VOLATILE_GUEST *pHdr, uint32_t cbCmd)
[22622]360{
[71619]361 VBVAPARTIALRECORD *pPartialRecord = &pVBVAData->partialRecord;
362 const uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pbRingBuffer = pVBVAData->guest.pu8Data;
[22622]363
[71619]364 if ( (uintptr_t)pHdr >= (uintptr_t)pbRingBuffer
365 && (uintptr_t)pHdr < (uintptr_t)&pbRingBuffer[pVBVAData->cbData])
[22622]366 {
367 /* The pointer is inside ring buffer. Must be continuous chunk. */
[71619]368 Assert(pVBVAData->cbData - (uint32_t)((uint8_t *)pHdr - pbRingBuffer) >= cbCmd);
[22622]369
[58539]370 /* Advance data offset and sync with guest. */
371 pVBVAData->off32Data = (pVBVAData->off32Data + cbCmd) % pVBVAData->cbData;
372 pVBVAData->guest.pVBVA->off32Data = pVBVAData->off32Data;
[22622]373
[58539]374 Assert(!pPartialRecord->pu8 && pPartialRecord->cb == 0);
[22622]375 }
376 else
377 {
378 /* The pointer is outside. It is then an allocated copy. */
379 LOGVBVABUFFER(("Free heap %p\n", pHdr));
380
381 if ((uint8_t *)pHdr == pPartialRecord->pu8)
382 {
383 pPartialRecord->pu8 = NULL;
384 pPartialRecord->cb = 0;
385 }
386 else
387 {
[56036]388 Assert(!pPartialRecord->pu8 && pPartialRecord->cb == 0);
[22622]389 }
390
[71619]391 RTMemFree((void *)pHdr);
[22622]392 }
393}
394
[82109]395static int vbvaFlushProcess(PVGASTATECC pThisCC, VBVADATA *pVBVAData, unsigned uScreenId)
[22622]396{
397 LOGVBVABUFFER(("uScreenId %d, indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
[72060]398 uScreenId, pVBVAData->indexRecordFirst, pVBVAData->guest.pVBVA->indexRecordFree,
399 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free));
[82109]400 struct
401 {
[22622]402 /* The rectangle that includes all dirty rectangles. */
403 int32_t xLeft;
404 int32_t xRight;
405 int32_t yTop;
406 int32_t yBottom;
407 } dirtyRect;
[32585]408 RT_ZERO(dirtyRect);
[23118]409
[22622]410 bool fUpdate = false; /* Whether there were any updates. */
[32585]411 bool fDirtyEmpty = true;
[22622]412
413 for (;;)
414 {
415 /* Fetch the command data. */
[71619]416 VBVACMDHDR RT_UNTRUSTED_VOLATILE_GUEST *pHdr = NULL;
417 uint32_t cbCmd = UINT32_MAX;
418 if (!vbvaFetchCmd(pVBVAData, &pHdr, &cbCmd))
[22622]419 {
420 LogFunc(("unable to fetch command. off32Data = %d, off32Free = %d!!!\n",
[71619]421 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free));
[22622]422 return VERR_NOT_SUPPORTED;
423 }
424
[72060]425 if (cbCmd == UINT32_MAX)
[22622]426 {
427 /* No more commands yet in the queue. */
428 break;
429 }
430
[56036]431 if (cbCmd < sizeof(VBVACMDHDR))
432 {
433 LogFunc(("short command. off32Data = %d, off32Free = %d, cbCmd %d!!!\n",
434 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free, cbCmd));
435
436 return VERR_NOT_SUPPORTED;
437 }
438
[22622]439 if (cbCmd != 0)
440 {
441 if (!fUpdate)
442 {
[82109]443 pThisCC->pDrv->pfnVBVAUpdateBegin(pThisCC->pDrv, uScreenId);
[22622]444 fUpdate = true;
445 }
446
447 /* Updates the rectangle and sends the command to the VRDP server. */
[82109]448 pThisCC->pDrv->pfnVBVAUpdateProcess(pThisCC->pDrv, uScreenId, pHdr, cbCmd);
[22622]449
[71619]450 int32_t xRight = pHdr->x + pHdr->w;
451 int32_t yBottom = pHdr->y + pHdr->h;
[22622]452
453 /* These are global coords, relative to the primary screen. */
454
[72060]455 LOGVBVABUFFER(("cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n", cbCmd, pHdr->x, pHdr->y, pHdr->w, pHdr->h));
[42409]456 LogRel3(("%s: update command cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
[71619]457 __FUNCTION__, cbCmd, pHdr->x, pHdr->y, pHdr->w, pHdr->h));
[22622]458
459 /* Collect all rects into one. */
[32585]460 if (fDirtyEmpty)
[22622]461 {
462 /* This is the first rectangle to be added. */
[71619]463 dirtyRect.xLeft = pHdr->x;
464 dirtyRect.yTop = pHdr->y;
[22622]465 dirtyRect.xRight = xRight;
466 dirtyRect.yBottom = yBottom;
[32585]467 fDirtyEmpty = false;
[22622]468 }
469 else
470 {
471 /* Adjust region coordinates. */
[71619]472 if (dirtyRect.xLeft > pHdr->x)
[22622]473 {
[71619]474 dirtyRect.xLeft = pHdr->x;
[22622]475 }
476
[71619]477 if (dirtyRect.yTop > pHdr->y)
[22622]478 {
[71619]479 dirtyRect.yTop = pHdr->y;
[22622]480 }
481
482 if (dirtyRect.xRight < xRight)
483 {
484 dirtyRect.xRight = xRight;
485 }
486
487 if (dirtyRect.yBottom < yBottom)
488 {
489 dirtyRect.yBottom = yBottom;
490 }
491 }
492 }
493
[71619]494 vbvaReleaseCmd(pVBVAData, pHdr, cbCmd);
[22622]495 }
496
497 if (fUpdate)
498 {
[32585]499 if (dirtyRect.xRight - dirtyRect.xLeft)
[22622]500 {
[42409]501 LogRel3(("%s: sending update screen=%d, x=%d, y=%d, w=%d, h=%d\n",
[56036]502 __FUNCTION__, uScreenId, dirtyRect.xLeft,
[42409]503 dirtyRect.yTop, dirtyRect.xRight - dirtyRect.xLeft,
504 dirtyRect.yBottom - dirtyRect.yTop));
[82109]505 pThisCC->pDrv->pfnVBVAUpdateEnd(pThisCC->pDrv, uScreenId, dirtyRect.xLeft, dirtyRect.yTop,
[56036]506 dirtyRect.xRight - dirtyRect.xLeft, dirtyRect.yBottom - dirtyRect.yTop);
[22622]507 }
508 else
509 {
[82109]510 pThisCC->pDrv->pfnVBVAUpdateEnd(pThisCC->pDrv, uScreenId, 0, 0, 0, 0);
[22622]511 }
512 }
513
514 return VINF_SUCCESS;
515}
516
[82109]517static int vbvaFlush(PVGASTATE pThis, PVGASTATECC pThisCC, VBVACONTEXT *pCtx)
[22622]518{
[56036]519 int rc = VINF_SUCCESS;
520
[22622]521 unsigned uScreenId;
522 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
523 {
[56036]524 VBVADATA *pVBVAData = &pCtx->aViews[uScreenId].vbva;
525 if (pVBVAData->guest.pVBVA)
[22622]526 {
[82109]527 rc = vbvaFlushProcess(pThisCC, pVBVAData, uScreenId);
[56036]528 if (RT_FAILURE(rc))
529 break;
[22622]530 }
531 }
532
[56036]533 if (RT_FAILURE(rc))
534 {
535 /* Turn off VBVA processing. */
[56992]536 LogRel(("VBVA: Disabling (%Rrc)\n", rc));
[82109]537 pThis->fGuestCaps = 0;
538 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
[56036]539 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
540 {
541 VBVADATA *pVBVAData = &pCtx->aViews[uScreenId].vbva;
542 if (pVBVAData->guest.pVBVA)
543 {
544 vbvaDataCleanup(pVBVAData);
[82109]545 pThisCC->pDrv->pfnVBVADisable(pThisCC->pDrv, uScreenId);
[56036]546 }
547 }
548 }
549
550 return rc;
[22622]551}
552
[82109]553static int vbvaResize(PVGASTATECC pThisCC, VBVAVIEW *pView, const VBVAINFOSCREEN *pNewScreen, bool fResetInputMapping)
[22622]554{
[56036]555 /* Callers ensure that pNewScreen contains valid data. */
[22622]556
557 /* Apply these changes. */
558 pView->screen = *pNewScreen;
559
[82109]560 uint8_t *pbVRam = pThisCC->pbVRam + pView->view.u32ViewOffset;
561 return pThisCC->pDrv->pfnVBVAResize(pThisCC->pDrv, &pView->view, &pView->screen, pbVRam, fResetInputMapping);
[22622]562}
563
[82109]564static int vbvaEnable(PVGASTATE pThis, PVGASTATECC pThisCC, VBVACONTEXT *pCtx, unsigned uScreenId,
[71619]565 VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *pVBVA, uint32_t u32Offset, bool fRestored)
[22622]566{
[71619]567 /*
568 * Copy into non-volatile memory and validate its content.
569 */
570 VBVABUFFER VbgaSafe;
571 RT_COPY_VOLATILE(VbgaSafe, *pVBVA);
572 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[22622]573
[71619]574 uint32_t const cbVBVABuffer = RT_UOFFSETOF(VBVABUFFER, au8Data) + VbgaSafe.cbData;
575 ASSERT_GUEST_RETURN( VbgaSafe.cbData <= UINT32_MAX - RT_UOFFSETOF(VBVABUFFER, au8Data)
[82109]576 && cbVBVABuffer <= pThis->vram_size
577 && u32Offset <= pThis->vram_size - cbVBVABuffer,
[71619]578 VERR_INVALID_PARAMETER);
[56785]579 if (!fRestored)
580 {
[71619]581 ASSERT_GUEST_RETURN(VbgaSafe.off32Data == 0, VERR_INVALID_PARAMETER);
582 ASSERT_GUEST_RETURN(VbgaSafe.off32Free == 0, VERR_INVALID_PARAMETER);
583 ASSERT_GUEST_RETURN(VbgaSafe.indexRecordFirst == 0, VERR_INVALID_PARAMETER);
584 ASSERT_GUEST_RETURN(VbgaSafe.indexRecordFree == 0, VERR_INVALID_PARAMETER);
[56785]585 }
[71619]586 ASSERT_GUEST_RETURN( VbgaSafe.cbPartialWriteThreshold < VbgaSafe.cbData
587 && VbgaSafe.cbPartialWriteThreshold != 0,
588 VERR_INVALID_PARAMETER);
589 RT_UNTRUSTED_VALIDATED_FENCE();
[56785]590
[71619]591 /*
592 * Okay, try do the job.
593 */
594 int rc;
[82109]595 if (pThisCC->pDrv->pfnVBVAEnable)
[56036]596 {
[71619]597 pVBVA->hostFlags.u32HostEvents = 0;
598 pVBVA->hostFlags.u32SupportedOrders = 0;
[82109]599 rc = pThisCC->pDrv->pfnVBVAEnable(pThisCC->pDrv, uScreenId, &pVBVA->hostFlags);
[71619]600 if (RT_SUCCESS(rc))
601 {
602 /* pVBVA->hostFlags has been set up by pfnVBVAEnable. */
603 LogFlowFunc(("u32HostEvents=0x%08x u32SupportedOrders=0x%08x\n",
604 pVBVA->hostFlags.u32HostEvents, pVBVA->hostFlags.u32SupportedOrders));
[22622]605
[71619]606 VBVADATA *pVBVAData = &pCtx->aViews[uScreenId].vbva;
607 pVBVAData->guest.pVBVA = pVBVA;
608 pVBVAData->guest.pu8Data = &pVBVA->au8Data[0];
609 pVBVAData->u32VBVAOffset = u32Offset;
610 pVBVAData->off32Data = VbgaSafe.off32Data;
611 pVBVAData->indexRecordFirst = VbgaSafe.indexRecordFirst;
612 pVBVAData->cbPartialWriteThreshold = VbgaSafe.cbPartialWriteThreshold;
613 pVBVAData->cbData = VbgaSafe.cbData;
[22622]614
[71619]615 if (!fRestored)
616 {
617 /** @todo Actually this function must not touch the partialRecord structure at all,
618 * because initially it is a zero and when VBVA is disabled this should be set to zero.
619 * But I'm not sure that no code depends on zeroing partialRecord here.
620 * So for now (a quick fix for 4.1) just do not do this if the VM was restored,
621 * when partialRecord might be loaded already from the saved state.
622 */
623 pVBVAData->partialRecord.pu8 = NULL;
624 pVBVAData->partialRecord.cb = 0;
625 }
[56036]626
[71619]627 /* VBVA is working so disable the pause. */
628 pCtx->fPaused = false;
[39887]629 }
[22622]630 }
[71619]631 else
632 rc = VERR_NOT_SUPPORTED;
[22622]633 return rc;
634}
635
[82109]636static int vbvaDisable(PVGASTATE pThis, PVGASTATECC pThisCC, VBVACONTEXT *pCtx, unsigned idScreen)
[22622]637{
638 /* Process any pending orders and empty the VBVA ring buffer. */
[82109]639 vbvaFlush(pThis, pThisCC, pCtx);
[22622]640
[82109]641 AssertReturn(idScreen < RT_ELEMENTS(pCtx->aViews), VERR_OUT_OF_RANGE);
642 VBVADATA *pVBVAData = &pCtx->aViews[idScreen].vbva;
[56036]643 vbvaDataCleanup(pVBVAData);
[22622]644
[82109]645 if (idScreen == 0)
[56814]646 {
[82109]647 pThis->fGuestCaps = 0;
648 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
[56814]649 }
[82109]650 pThisCC->pDrv->pfnVBVADisable(pThisCC->pDrv, idScreen);
[22622]651 return VINF_SUCCESS;
652}
653
[82109]654#ifdef UNUSED_FUNCTION
655bool VBVAIsEnabled(PVGASTATECC pThisCC)
[28379]656{
[82109]657 PHGSMIINSTANCE pHGSMI = pThisCC->pHGSMI;
[28379]658 if (pHGSMI)
659 {
660 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pHGSMI);
661 if (pCtx)
662 {
663 if (pCtx->cViews)
664 {
665 VBVAVIEW * pView = &pCtx->aViews[0];
[56036]666 if (pView->vbva.guest.pVBVA)
[28379]667 return true;
668 }
669 }
670 }
671 return false;
672}
[82109]673#endif
[28379]674
[24714]675#ifdef DEBUG_sunlover
676void dumpMouseShapeInfo(const VBVAMOUSESHAPEINFO *pMouseShapeInfo)
677{
678 LogFlow(("fSet = %d, fVisible %d, fAlpha %d, @%d,%d %dx%d (%p, %d/%d)\n",
679 pMouseShapeInfo->fSet,
680 pMouseShapeInfo->fVisible,
681 pMouseShapeInfo->fAlpha,
682 pMouseShapeInfo->u32HotX,
683 pMouseShapeInfo->u32HotY,
684 pMouseShapeInfo->u32Width,
685 pMouseShapeInfo->u32Height,
686 pMouseShapeInfo->pu8Shape,
687 pMouseShapeInfo->cbShape,
688 pMouseShapeInfo->cbAllocated
689 ));
690}
691#endif
692
[82109]693static int vbvaUpdateMousePointerShape(PVGASTATECC pThisCC, VBVAMOUSESHAPEINFO *pMouseShapeInfo, bool fShape)
[24714]694{
[82109]695 LogFlowFunc(("pThisCC %p, pMouseShapeInfo %p, fShape %d\n", pThisCC, pMouseShapeInfo, fShape));
[24714]696#ifdef DEBUG_sunlover
697 dumpMouseShapeInfo(pMouseShapeInfo);
698#endif
699
[82109]700 if (pThisCC->pDrv->pfnVBVAMousePointerShape == NULL)
[56036]701 return VERR_NOT_SUPPORTED;
702
703 int rc;
704 if (fShape && pMouseShapeInfo->pu8Shape != NULL)
[82109]705 rc = pThisCC->pDrv->pfnVBVAMousePointerShape(pThisCC->pDrv,
706 pMouseShapeInfo->fVisible,
707 pMouseShapeInfo->fAlpha,
708 pMouseShapeInfo->u32HotX,
709 pMouseShapeInfo->u32HotY,
710 pMouseShapeInfo->u32Width,
711 pMouseShapeInfo->u32Height,
712 pMouseShapeInfo->pu8Shape);
[24714]713 else
[82109]714 rc = pThisCC->pDrv->pfnVBVAMousePointerShape(pThisCC->pDrv,
715 pMouseShapeInfo->fVisible,
716 false,
717 0, 0,
718 0, 0,
719 NULL);
[24714]720 return rc;
721}
722
[82109]723static int vbvaMousePointerShape(PVGASTATECC pThisCC, VBVACONTEXT *pCtx,
[71590]724 const VBVAMOUSEPOINTERSHAPE RT_UNTRUSTED_VOLATILE_GUEST *pShape, HGSMISIZE cbShape)
[22622]725{
[71622]726 /*
727 * Make non-volatile copy of the shape header and validate it.
728 */
729 VBVAMOUSEPOINTERSHAPE SafeShape;
730 RT_COPY_VOLATILE(SafeShape, *pShape);
731 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[22622]732
[56036]733 LogFlowFunc(("VBVA_MOUSE_POINTER_SHAPE: i32Result 0x%x, fu32Flags 0x%x, hot spot %d,%d, size %dx%d\n",
[71622]734 SafeShape.i32Result, SafeShape.fu32Flags, SafeShape.u32HotX, SafeShape.u32HotY, SafeShape.u32Width, SafeShape.u32Height));
[56036]735
[71622]736 const bool fVisible = RT_BOOL(SafeShape.fu32Flags & VBOX_MOUSE_POINTER_VISIBLE);
737 const bool fAlpha = RT_BOOL(SafeShape.fu32Flags & VBOX_MOUSE_POINTER_ALPHA);
738 const bool fShape = RT_BOOL(SafeShape.fu32Flags & VBOX_MOUSE_POINTER_SHAPE);
[56036]739
[22622]740 HGSMISIZE cbPointerData = 0;
741 if (fShape)
742 {
[71622]743 static const uint32_t s_cxMax = 2048; //used to be: 8192;
744 static const uint32_t s_cyMax = 2048; //used to be: 8192;
745 ASSERT_GUEST_MSG_RETURN( SafeShape.u32Width <= s_cxMax
746 || SafeShape.u32Height <= s_cyMax,
747 ("Too large: %ux%u, max %ux%x\n", SafeShape.u32Width, SafeShape.u32Height, s_cxMax, s_cyMax),
748 VERR_INVALID_PARAMETER);
[49427]749
[71622]750 cbPointerData = ((((SafeShape.u32Width + 7) / 8) * SafeShape.u32Height + 3) & ~3)
751 + SafeShape.u32Width * 4 * SafeShape.u32Height;
[23118]752
[71622]753 ASSERT_GUEST_MSG_RETURN(cbPointerData <= cbShape - RT_UOFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data),
754 ("Insufficent pointer data: Expected %#x, got %#x\n",
755 cbPointerData, cbShape - RT_UOFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data) ),
756 VERR_INVALID_PARAMETER);
[22622]757 }
[71622]758 RT_UNTRUSTED_VALIDATED_FENCE();
[22622]759
[71622]760 /*
761 * Do the job.
762 */
[24714]763 /* Save mouse info it will be used to restore mouse pointer after restoring saved state. */
764 pCtx->mouseShapeInfo.fSet = true;
765 pCtx->mouseShapeInfo.fVisible = fVisible;
766 if (fShape)
[22622]767 {
[24940]768 /* Data related to shape. */
[71622]769 pCtx->mouseShapeInfo.u32HotX = SafeShape.u32HotX;
770 pCtx->mouseShapeInfo.u32HotY = SafeShape.u32HotY;
771 pCtx->mouseShapeInfo.u32Width = SafeShape.u32Width;
772 pCtx->mouseShapeInfo.u32Height = SafeShape.u32Height;
[59307]773 pCtx->mouseShapeInfo.fAlpha = fAlpha;
[24940]774
[24714]775 /* Reallocate memory buffer if necessary. */
776 if (cbPointerData > pCtx->mouseShapeInfo.cbAllocated)
777 {
[83562]778 RTMemFreeZ(pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbAllocated);
[24714]779 pCtx->mouseShapeInfo.pu8Shape = NULL;
780 pCtx->mouseShapeInfo.cbShape = 0;
[22622]781
[71626]782 uint8_t *pu8Shape = (uint8_t *)RTMemAlloc(cbPointerData);
[24714]783 if (pu8Shape)
784 {
785 pCtx->mouseShapeInfo.pu8Shape = pu8Shape;
786 pCtx->mouseShapeInfo.cbAllocated = cbPointerData;
787 }
788 }
[22622]789
[24714]790 /* Copy shape bitmaps. */
791 if (pCtx->mouseShapeInfo.pu8Shape)
792 {
[71622]793 RT_BCOPY_VOLATILE(pCtx->mouseShapeInfo.pu8Shape, &pShape->au8Data[0], cbPointerData);
[24714]794 pCtx->mouseShapeInfo.cbShape = cbPointerData;
795 }
[22622]796 }
[24714]797
[82109]798 return vbvaUpdateMousePointerShape(pThisCC, &pCtx->mouseShapeInfo, fShape);
[22622]799}
800
[71590]801static uint32_t vbvaViewFromBufferPtr(PHGSMIINSTANCE pIns, const VBVACONTEXT *pCtx,
802 const void RT_UNTRUSTED_VOLATILE_GUEST *pvBuffer)
[22622]803{
804 /* Check which view contains the buffer. */
[56036]805 HGSMIOFFSET offBuffer = HGSMIPointerToOffsetHost(pIns, pvBuffer);
[22622]806 if (offBuffer != HGSMIOFFSET_VOID)
807 {
808 unsigned uScreenId;
809 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
810 {
[56036]811 const VBVAINFOVIEW *pView = &pCtx->aViews[uScreenId].view;
[71619]812 if ((uint32_t)(offBuffer - pView->u32ViewOffset) < pView->u32ViewSize)
[22622]813 return pView->u32ViewIndex;
814 }
815 }
[62928]816 return UINT32_MAX;
[22622]817}
818
819#ifdef DEBUG_sunlover
820static void dumpctx(const VBVACONTEXT *pCtx)
821{
822 Log(("VBVACONTEXT dump: cViews %d\n", pCtx->cViews));
823
824 uint32_t iView;
825 for (iView = 0; iView < pCtx->cViews; iView++)
826 {
827 const VBVAVIEW *pView = &pCtx->aViews[iView];
828
829 Log((" view %d o 0x%x s 0x%x m 0x%x\n",
830 pView->view.u32ViewIndex,
831 pView->view.u32ViewOffset,
832 pView->view.u32ViewSize,
833 pView->view.u32MaxScreenSize));
834
835 Log((" screen %d @%d,%d s 0x%x l 0x%x %dx%d bpp %d f 0x%x\n",
836 pView->screen.u32ViewIndex,
837 pView->screen.i32OriginX,
838 pView->screen.i32OriginY,
839 pView->screen.u32StartOffset,
840 pView->screen.u32LineSize,
841 pView->screen.u32Width,
842 pView->screen.u32Height,
[23118]843 pView->screen.u16BitsPerPixel,
[22622]844 pView->screen.u16Flags));
845
846 Log((" VBVA o 0x%x p %p\n",
[56431]847 pView->vbva.u32VBVAOffset,
[56036]848 pView->vbva.guest.pVBVA));
[22622]849
850 Log((" PR cb 0x%x p %p\n",
[56431]851 pView->vbva.partialRecord.cb,
852 pView->vbva.partialRecord.pu8));
[22622]853 }
[24714]854
855 dumpMouseShapeInfo(&pCtx->mouseShapeInfo);
[22622]856}
857#endif /* DEBUG_sunlover */
858
[34140]859#define VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC 0x12345678
860#define VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC 0x9abcdef0
[22622]861
862#ifdef VBOX_WITH_VIDEOHWACCEL
[82109]863
[27839]864static void vbvaVHWAHHCommandReinit(VBOXVHWACMD* pHdr, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay)
[22622]865{
[27839]866 memset(pHdr, 0, VBOXVHWACMD_HEADSIZE());
867 pHdr->cRefs = 1;
868 pHdr->iDisplay = iDisplay;
869 pHdr->rc = VERR_NOT_IMPLEMENTED;
870 pHdr->enmCmd = enmCmd;
871 pHdr->Flags = VBOXVHWACMD_FLAG_HH_CMD;
872}
873
[62928]874static VBOXVHWACMD *vbvaVHWAHHCommandCreate(VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay, VBOXVHWACMD_LENGTH cbCmd)
[27839]875{
[62928]876 VBOXVHWACMD *pHdr = (VBOXVHWACMD *)RTMemAllocZ(cbCmd + VBOXVHWACMD_HEADSIZE());
[22622]877 Assert(pHdr);
878 if (pHdr)
[27839]879 vbvaVHWAHHCommandReinit(pHdr, enmCmd, iDisplay);
[22622]880
881 return pHdr;
882}
883
[62928]884DECLINLINE(void) vbvaVHWAHHCommandRelease(VBOXVHWACMD *pCmd)
[22622]885{
886 uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs);
[62928]887 if (!cRefs)
[22622]888 RTMemFree(pCmd);
889}
890
[62928]891DECLINLINE(void) vbvaVHWAHHCommandRetain(VBOXVHWACMD *pCmd)
[22622]892{
893 ASMAtomicIncU32(&pCmd->cRefs);
894}
895
[82109]896static void vbvaVHWACommandComplete(PVGASTATECC pThisCC, VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCommand, bool fAsyncCommand)
[22622]897{
[49420]898 if (fAsyncCommand)
899 {
900 Assert(pCommand->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
[82109]901 vbvaR3VHWACommandCompleteAsync(&pThisCC->IVBVACallbacks, pCommand);
[49420]902 }
903 else
904 {
905 Log(("VGA Command <<< Sync rc %d %#p, %d\n", pCommand->rc, pCommand, pCommand->enmCmd));
[62928]906 pCommand->Flags &= ~VBOXVHWACMD_FLAG_HG_ASYNCH;
[49420]907 }
908
909}
910
[82109]911static void vbvaVHWACommandCompleteAllPending(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, int rc)
[49420]912{
[82109]913 if (!ASMAtomicUoReadU32(&pThis->pendingVhwaCommands.cPending))
[49420]914 return;
915
[90447]916 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
917 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
[49434]918
[62928]919 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
[82109]920 RTListForEachSafe(&pThis->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
[49420]921 {
922 pIter->pCommand->rc = rc;
[82109]923 vbvaVHWACommandComplete(pThisCC, pIter->pCommand, true);
[49420]924
925 /* the command is submitted/processed, remove from the pend list */
926 RTListNodeRemove(&pIter->Node);
[82109]927 ASMAtomicDecU32(&pThis->pendingVhwaCommands.cPending);
[49420]928 RTMemFree(pIter);
929 }
[49434]930
[82109]931 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
[49420]932}
933
[82109]934static void vbvaVHWACommandClearAllPending(PPDMDEVINS pDevIns, PVGASTATE pThis)
[49420]935{
[82109]936 if (!ASMAtomicUoReadU32(&pThis->pendingVhwaCommands.cPending))
[49420]937 return;
938
[90447]939 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
940 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
[49434]941
[62928]942 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
[82109]943 RTListForEachSafe(&pThis->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
[49420]944 {
945 RTListNodeRemove(&pIter->Node);
[82109]946 ASMAtomicDecU32(&pThis->pendingVhwaCommands.cPending);
[49420]947 RTMemFree(pIter);
948 }
[49434]949
[82109]950 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
[49420]951}
952
[82109]953static void vbvaVHWACommandPend(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
954 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCommand)
[49420]955{
956 int rc = VERR_BUFFER_OVERFLOW;
957
[82109]958 if (ASMAtomicUoReadU32(&pThis->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS)
[49420]959 {
[62928]960 VBOX_VHWA_PENDINGCMD *pPend = (VBOX_VHWA_PENDINGCMD *)RTMemAlloc(sizeof(*pPend));
[49420]961 if (pPend)
962 {
963 pCommand->Flags |= VBOXVHWACMD_FLAG_HG_ASYNCH;
964 pPend->pCommand = pCommand;
[90447]965
966 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
967 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
968
[82109]969 if (ASMAtomicUoReadU32(&pThis->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS)
[49434]970 {
[82109]971 RTListAppend(&pThis->pendingVhwaCommands.PendingList, &pPend->Node);
972 ASMAtomicIncU32(&pThis->pendingVhwaCommands.cPending);
973 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
[49434]974 return;
975 }
[82109]976 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
[56097]977 LogRel(("VBVA: Pending command count has reached its threshold.. completing them all.."));
[49434]978 RTMemFree(pPend);
[49420]979 }
980 else
981 rc = VERR_NO_MEMORY;
982 }
983 else
[56097]984 LogRel(("VBVA: Pending command count has reached its threshold, completing them all.."));
[49420]985
[82109]986 vbvaVHWACommandCompleteAllPending(pDevIns, pThis, pThisCC, rc);
[49420]987
988 pCommand->rc = rc;
989
[82109]990 vbvaVHWACommandComplete(pThisCC, pCommand, false);
[49420]991}
992
[71590]993static bool vbvaVHWACommandCanPend(VBOXVHWACMD_TYPE enmCmd)
[49420]994{
[71590]995 switch (enmCmd)
[49420]996 {
997 case VBOXVHWACMD_TYPE_HH_CONSTRUCT:
998 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN:
999 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND:
1000 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM:
1001 case VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM:
1002 return false;
1003 default:
1004 return true;
1005 }
1006}
1007
[82109]1008static int vbvaVHWACommandSavePending(PCPDMDEVHLPR3 pHlp, PVGASTATE pThis, PVGASTATECC pThisCC, PSSMHANDLE pSSM)
[49420]1009{
[82109]1010 int rc = pHlp->pfnSSMPutU32(pSSM, pThis->pendingVhwaCommands.cPending);
[49420]1011 AssertRCReturn(rc, rc);
[62928]1012
[49420]1013 VBOX_VHWA_PENDINGCMD *pIter;
[82109]1014 RTListForEach(&pThis->pendingVhwaCommands.PendingList, pIter, VBOX_VHWA_PENDINGCMD, Node)
[49420]1015 {
[82109]1016 AssertContinue((uintptr_t)pIter->pCommand - (uintptr_t)pThisCC->pbVRam < pThis->vram_size);
1017 rc = pHlp->pfnSSMPutU32(pSSM, (uint32_t)(((uint8_t *)pIter->pCommand) - ((uint8_t *)pThisCC->pbVRam)));
[49420]1018 AssertRCReturn(rc, rc);
1019 }
1020 return rc;
1021}
1022
[82109]1023static int vbvaVHWACommandLoadPending(PPDMDEVINS pDevIns, PCPDMDEVHLPR3 pHlp, PVGASTATE pThis, PVGASTATECC pThisCC,
1024 PSSMHANDLE pSSM, uint32_t u32Version)
[49420]1025{
1026 if (u32Version < VGA_SAVEDSTATE_VERSION_WITH_PENDVHWA)
1027 return VINF_SUCCESS;
1028
1029 uint32_t u32;
[82048]1030 int rc = pHlp->pfnSSMGetU32(pSSM, &u32);
[49420]1031 AssertRCReturn(rc, rc);
1032 for (uint32_t i = 0; i < u32; ++i)
1033 {
1034 uint32_t off32;
[82048]1035 rc = pHlp->pfnSSMGetU32(pSSM, &off32);
[49420]1036 AssertRCReturn(rc, rc);
[71590]1037 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCommand
[82109]1038 = (VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *)((uint8_t volatile *)pThisCC->pbVRam + off32);
1039 vbvaVHWACommandPend(pDevIns, pThis, pThisCC, pCommand);
[49420]1040 }
1041 return rc;
1042}
1043
1044
[71626]1045/** Worker for vbvaVHWACommandSubmit. */
[82109]1046static bool vbvaVHWACommandSubmitInner(PVGASTATE pThis, PVGASTATECC pThisCC,
1047 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCommand, bool *pfPending)
[49420]1048{
[71626]1049 *pfPending = false;
1050
1051 /*
1052 * Read the command type and validate it and our driver state.
1053 */
[71590]1054 VBOXVHWACMD_TYPE enmCmd = pCommand->enmCmd;
[71626]1055 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[71590]1056
[82109]1057 bool fGuestCmd = (uintptr_t)pCommand - (uintptr_t)pThisCC->pbVRam < pThis->vram_size;
[71626]1058 ASSERT_GUEST_LOGREL_MSG_STMT_RETURN( !fGuestCmd
1059 || ( enmCmd != VBOXVHWACMD_TYPE_HH_CONSTRUCT
1060 && enmCmd != VBOXVHWACMD_TYPE_HH_RESET
1061 && enmCmd != VBOXVHWACMD_TYPE_HH_DISABLE
1062 && enmCmd != VBOXVHWACMD_TYPE_HH_ENABLE
1063 && enmCmd != VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN
1064 && enmCmd != VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND
1065 && enmCmd != VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM
1066 && enmCmd != VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM),
1067 ("enmCmd=%d\n", enmCmd),
1068 pCommand->rc = VERR_INVALID_PARAMETER,
1069 true);
[82109]1070 ASSERT_GUEST_STMT_RETURN(pThisCC->pDrv->pfnVHWACommandProcess, pCommand->rc = VERR_INVALID_STATE, true);
[71626]1071 RT_UNTRUSTED_VALIDATED_FENCE();
1072
1073 /*
1074 * Call the driver to process the command.
1075 */
1076 Log(("VGA Command >>> %#p, %d\n", pCommand, enmCmd));
[82109]1077 int rc = pThisCC->pDrv->pfnVHWACommandProcess(pThisCC->pDrv, enmCmd, fGuestCmd, pCommand);
[71626]1078 if (rc == VINF_CALLBACK_RETURN)
[49420]1079 {
[71626]1080 Log(("VGA Command --- Going Async %#p, %d\n", pCommand, enmCmd));
1081 *pfPending = true;
1082 return true; /* Command will be completed asynchronously by the driver and need not be put in the pending list. */
1083 }
1084
1085 if (rc == VERR_INVALID_STATE)
1086 {
1087 Log(("VGA Command --- Trying Pend %#p, %d\n", pCommand, enmCmd));
1088 if (vbvaVHWACommandCanPend(enmCmd))
[49420]1089 {
[71626]1090 Log(("VGA Command --- Can Pend %#p, %d\n", pCommand, enmCmd));
1091 *pfPending = true;
1092 return false; /* put on pending list so it can be retried?? */
[49420]1093 }
1094
[71626]1095 Log(("VGA Command --- Can NOT Pend %#p, %d\n", pCommand, enmCmd));
[49420]1096 }
[24779]1097 else
[71626]1098 Log(("VGA Command --- Going Complete Sync rc %d %#p, %d\n", rc, pCommand, enmCmd));
[49420]1099
[71626]1100 /* the command was completed, take a special care about it (see caller) */
1101 pCommand->rc = rc;
1102 return true;
1103}
[49420]1104
1105
[82109]1106static bool vbvaVHWACommandSubmit(PVGASTATE pThis, PVGASTATECC pThisCC,
1107 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCommand, bool fAsyncCommand)
[71626]1108{
1109 bool fPending = false;
[82109]1110 bool fRet = vbvaVHWACommandSubmitInner(pThis, pThisCC, pCommand, &fPending);
[71626]1111 if (!fPending)
[82109]1112 vbvaVHWACommandComplete(pThisCC, pCommand, fAsyncCommand);
[71626]1113 return fRet;
[22622]1114}
1115
[71626]1116
1117/**
1118 * @returns false if commands are pending, otherwise true.
1119 */
[82109]1120static bool vbvaVHWACheckPendingCommands(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
[49420]1121{
[82109]1122 if (!ASMAtomicUoReadU32(&pThis->pendingVhwaCommands.cPending))
[49420]1123 return true;
1124
[90447]1125 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
1126 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
[49434]1127
[64766]1128 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
[82109]1129 RTListForEachSafe(&pThis->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
[49420]1130 {
[82109]1131 if (!vbvaVHWACommandSubmit(pThis, pThisCC, pIter->pCommand, true))
[49434]1132 {
[82109]1133 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
[71626]1134 return false; /* the command should be still pending */
[49434]1135 }
[49420]1136
1137 /* the command is submitted/processed, remove from the pend list */
1138 RTListNodeRemove(&pIter->Node);
[82109]1139 ASMAtomicDecU32(&pThis->pendingVhwaCommands.cPending);
[49420]1140 RTMemFree(pIter);
1141 }
1142
[82109]1143 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
[49434]1144
[49420]1145 return true;
1146}
1147
[82109]1148void vbvaTimerCb(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
[49420]1149{
[82109]1150 vbvaVHWACheckPendingCommands(pDevIns, pThis, pThisCC);
[49420]1151}
[71626]1152
[82109]1153static void vbvaVHWAHandleCommand(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
1154 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCmd)
[49420]1155{
[82109]1156 if (vbvaVHWACheckPendingCommands(pDevIns, pThis, pThisCC))
[49420]1157 {
[82109]1158 if (vbvaVHWACommandSubmit(pThis, pThisCC, pCmd, false))
[49420]1159 return;
1160 }
1161
[82109]1162 vbvaVHWACommandPend(pDevIns, pThis, pThisCC, pCmd);
[49420]1163}
1164
[24925]1165static DECLCALLBACK(void) vbvaVHWAHHCommandSetEventCallback(void * pContext)
1166{
1167 RTSemEventSignal((RTSEMEVENT)pContext);
1168}
1169
[82109]1170static int vbvaVHWAHHCommandPost(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, VBOXVHWACMD *pCmd)
[22622]1171{
1172 RTSEMEVENT hComplEvent;
1173 int rc = RTSemEventCreate(&hComplEvent);
[24095]1174 AssertRC(rc);
[71626]1175 if (RT_SUCCESS(rc))
[22622]1176 {
1177 /* ensure the cmd is not deleted until we process it */
[71626]1178 vbvaVHWAHHCommandRetain(pCmd);
1179
1180 VBOXVHWA_HH_CALLBACK_SET(pCmd, vbvaVHWAHHCommandSetEventCallback, (void *)hComplEvent);
[82109]1181 vbvaVHWAHandleCommand(pDevIns, pThis, pThisCC, pCmd);
[22622]1182
[71626]1183 if ((ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_ASYNCH) != 0)
1184 rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT); /** @todo Why the NoResume and event leaking here? */
1185 /* else: the command is completed */
1186
[24095]1187 AssertRC(rc);
[71626]1188 if (RT_SUCCESS(rc))
[22622]1189 RTSemEventDestroy(hComplEvent);
[71626]1190
[22622]1191 vbvaVHWAHHCommandRelease(pCmd);
1192 }
1193 return rc;
1194}
1195
[82109]1196int vbvaVHWAConstruct(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
[22622]1197{
[82109]1198 pThis->pendingVhwaCommands.cPending = 0;
1199 RTListInit(&pThis->pendingVhwaCommands.PendingList);
[49434]1200
[62928]1201 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(VBOXVHWACMD_TYPE_HH_CONSTRUCT, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
[22622]1202 Assert(pCmd);
1203 if(pCmd)
1204 {
[27839]1205 uint32_t iDisplay = 0;
1206 int rc = VINF_SUCCESS;
[71592]1207 VBOXVHWACMD_HH_CONSTRUCT *pBody = VBOXVHWACMD_BODY_HOST_HEAP(pCmd, VBOXVHWACMD_HH_CONSTRUCT);
[22622]1208
[82109]1209 for (;;)
[27839]1210 {
1211 memset(pBody, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
[22622]1212
[27839]1213 PVM pVM = PDMDevHlpGetVM(pDevIns);
[22622]1214
[27839]1215 pBody->pVM = pVM;
[82109]1216 pBody->pvVRAM = pThisCC->pbVRam;
1217 pBody->cbVRAM = pThis->vram_size;
[27839]1218
[82109]1219 rc = vbvaVHWAHHCommandPost(pDevIns, pThis, pThisCC, pCmd);
[71592]1220 ASMCompilerBarrier();
1221
[27839]1222 AssertRC(rc);
[71592]1223 if (RT_SUCCESS(rc))
[22622]1224 {
[27839]1225 rc = pCmd->rc;
1226 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1227 if(rc == VERR_NOT_IMPLEMENTED)
1228 {
[82109]1229 /** @todo set some flag in pThis indicating VHWA is not supported */
[27839]1230 /* VERR_NOT_IMPLEMENTED is not a failure, we just do not support it */
1231 rc = VINF_SUCCESS;
1232 }
1233
1234 if (!RT_SUCCESS(rc))
1235 break;
[22622]1236 }
[27839]1237 else
1238 break;
[24163]1239
[27839]1240 ++iDisplay;
[82109]1241 if (iDisplay >= pThis->cMonitors)
[27839]1242 break;
1243 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_CONSTRUCT, (int32_t)iDisplay);
[82109]1244 }
[27839]1245
[24163]1246 vbvaVHWAHHCommandRelease(pCmd);
1247
[22622]1248 return rc;
1249 }
1250 return VERR_OUT_OF_RESOURCES;
1251}
1252
[82109]1253static int vbvaVHWAReset(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
[24053]1254{
[82109]1255 vbvaVHWACommandClearAllPending(pDevIns, pThis);
[49420]1256
[24053]1257 /* ensure we have all pending cmds processed and h->g cmds disabled */
[62928]1258 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(VBOXVHWACMD_TYPE_HH_RESET, 0, 0);
[24053]1259 Assert(pCmd);
[71626]1260 if (pCmd)
[24053]1261 {
[27839]1262 int rc = VINF_SUCCESS;
1263 uint32_t iDisplay = 0;
1264
1265 do
[24053]1266 {
[82109]1267 rc = vbvaVHWAHHCommandPost(pDevIns, pThis, pThisCC, pCmd);
[27839]1268 AssertRC(rc);
1269 if(RT_SUCCESS(rc))
1270 {
1271 rc = pCmd->rc;
1272 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1273 if (rc == VERR_NOT_IMPLEMENTED)
1274 rc = VINF_SUCCESS;
1275 }
[24163]1276
[27839]1277 if (!RT_SUCCESS(rc))
1278 break;
1279
1280 ++iDisplay;
[82109]1281 if (iDisplay >= pThis->cMonitors)
[27839]1282 break;
1283 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_RESET, (int32_t)iDisplay);
1284
1285 } while (true);
1286
[24163]1287 vbvaVHWAHHCommandRelease(pCmd);
1288
[24053]1289 return rc;
1290 }
1291 return VERR_OUT_OF_RESOURCES;
1292}
1293
[85121]1294typedef DECLCALLBACKTYPE(bool, FNVBOXVHWAHHCMDPRECB,(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, VBOXVHWACMD *pCmd,
1295 uint32_t iDisplay, void *pvContext));
[34140]1296typedef FNVBOXVHWAHHCMDPRECB *PFNVBOXVHWAHHCMDPRECB;
1297
[85121]1298typedef DECLCALLBACKTYPE(bool, FNVBOXVHWAHHCMDPOSTCB,(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, VBOXVHWACMD *pCmd,
1299 uint32_t iDisplay, int rc, void *pvContext));
[34140]1300typedef FNVBOXVHWAHHCMDPOSTCB *PFNVBOXVHWAHHCMDPOSTCB;
1301
[82109]1302static int vbvaVHWAHHPost(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, VBOXVHWACMD *pCmd,
1303 PFNVBOXVHWAHHCMDPRECB pfnPre, PFNVBOXVHWAHHCMDPOSTCB pfnPost, void *pvContext)
[22622]1304{
[34140]1305 const VBOXVHWACMD_TYPE enmType = pCmd->enmCmd;
1306 int rc = VINF_SUCCESS;
1307 uint32_t iDisplay = 0;
1308
1309 do
[22622]1310 {
[82109]1311 if (!pfnPre || pfnPre(pDevIns, pThis, pThisCC, pCmd, iDisplay, pvContext))
[22622]1312 {
[82109]1313 rc = vbvaVHWAHHCommandPost(pDevIns, pThis, pThisCC, pCmd);
[27839]1314 AssertRC(rc);
[34140]1315 if (pfnPost)
[22622]1316 {
[82109]1317 if (!pfnPost(pDevIns, pThis, pThisCC, pCmd, iDisplay, rc, pvContext))
[34140]1318 {
1319 rc = VINF_SUCCESS;
1320 break;
1321 }
1322 rc = VINF_SUCCESS;
1323 }
1324 else if(RT_SUCCESS(rc))
1325 {
[27839]1326 rc = pCmd->rc;
1327 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1328 if(rc == VERR_NOT_IMPLEMENTED)
1329 {
1330 rc = VINF_SUCCESS;
1331 }
[22622]1332 }
[24163]1333
[27839]1334 if (!RT_SUCCESS(rc))
1335 break;
[34140]1336 }
[27839]1337
[34140]1338 ++iDisplay;
[82109]1339 if (iDisplay >= pThis->cMonitors)
[34140]1340 break;
1341 vbvaVHWAHHCommandReinit(pCmd, enmType, (int32_t)iDisplay);
1342 } while (true);
[27839]1343
[34140]1344 return rc;
1345}
[27839]1346
[63562]1347/** @todo call this also on reset? */
[82109]1348static int vbvaVHWAEnable(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, bool bEnable)
[34140]1349{
1350 const VBOXVHWACMD_TYPE enmType = bEnable ? VBOXVHWACMD_TYPE_HH_ENABLE : VBOXVHWACMD_TYPE_HH_DISABLE;
[62928]1351 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(enmType, 0, 0);
[34140]1352 Assert(pCmd);
1353 if(pCmd)
1354 {
[82109]1355 int rc = vbvaVHWAHHPost(pDevIns, pThis, pThisCC, pCmd, NULL, NULL, NULL);
[24163]1356 vbvaVHWAHHCommandRelease(pCmd);
[22622]1357 return rc;
1358 }
1359 return VERR_OUT_OF_RESOURCES;
1360}
1361
[62928]1362int vboxVBVASaveStatePrep(PPDMDEVINS pDevIns)
[22622]1363{
1364 /* ensure we have no pending commands */
[82109]1365 return vbvaVHWAEnable(pDevIns, PDMDEVINS_2_DATA(pDevIns, PVGASTATE), PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC), false);
[22622]1366}
1367
[62928]1368int vboxVBVASaveStateDone(PPDMDEVINS pDevIns)
[34129]1369{
1370 /* ensure we have no pending commands */
[82109]1371 return vbvaVHWAEnable(pDevIns, PDMDEVINS_2_DATA(pDevIns, PVGASTATE), PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC), true);
[34129]1372}
1373
[82109]1374
[71626]1375/**
1376 * @interface_method_impl{PDMIDISPLAYVBVACALLBACKS,pfnVHWACommandCompleteAsync}
1377 */
[82088]1378DECLCALLBACK(int) vbvaR3VHWACommandCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface,
1379 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCmd)
[22622]1380{
[82109]1381 PVGASTATECC pThisCC = RT_FROM_MEMBER(pInterface, VGASTATECC, IVBVACallbacks);
1382 PPDMDEVINS pDevIns = pThisCC->pDevIns;
1383 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
[22622]1384 int rc;
[82109]1385
[49420]1386 Log(("VGA Command <<< Async rc %d %#p, %d\n", pCmd->rc, pCmd, pCmd->enmCmd));
1387
[82109]1388 if ((uintptr_t)pCmd - (uintptr_t)pThisCC->pbVRam < pThis->vram_size)
[22622]1389 {
[82109]1390 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
[71626]1391 Assert(!(pCmd->Flags & VBOXVHWACMD_FLAG_HH_CMD));
[22622]1392 Assert(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
[32622]1393#ifdef VBOX_WITH_WDDM
[82109]1394 if (pThis->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD)
[22622]1395 {
[29742]1396 rc = HGSMICompleteGuestCommand(pIns, pCmd, !!(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ));
[24095]1397 AssertRC(rc);
[22622]1398 }
1399 else
[29742]1400#endif
[22622]1401 {
[71590]1402 VBVAHOSTCMD RT_UNTRUSTED_VOLATILE_GUEST *pHostCmd = NULL; /* Shut up MSC. */
[62928]1403 if (pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT)
[22622]1404 {
[62928]1405 rc = HGSMIHostCommandAlloc(pIns,
[71590]1406 (void RT_UNTRUSTED_VOLATILE_GUEST **)&pHostCmd,
[62928]1407 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)),
1408 HGSMI_CH_VBVA,
1409 VBVAHG_EVENT);
[24095]1410 AssertRC(rc);
[62928]1411 if (RT_SUCCESS(rc))
[22622]1412 {
[71590]1413 memset((void *)pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)));
[22622]1414 pHostCmd->iDstID = pCmd->iDisplay;
[29742]1415 pHostCmd->customOpCode = 0;
[71592]1416 VBVAHOSTCMDEVENT RT_UNTRUSTED_VOLATILE_GUEST *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDEVENT);
[29742]1417 pBody->pEvent = pCmd->GuestVBVAReserved1;
[22622]1418 }
1419 }
1420 else
1421 {
[62928]1422 HGSMIOFFSET offCmd = HGSMIPointerToOffsetHost(pIns, pCmd);
[29742]1423 Assert(offCmd != HGSMIOFFSET_VOID);
[62928]1424 if (offCmd != HGSMIOFFSET_VOID)
[29742]1425 {
[62928]1426 rc = HGSMIHostCommandAlloc(pIns,
[71590]1427 (void RT_UNTRUSTED_VOLATILE_GUEST **)&pHostCmd,
[62928]1428 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)),
1429 HGSMI_CH_VBVA,
1430 VBVAHG_DISPLAY_CUSTOM);
[29742]1431 AssertRC(rc);
[62928]1432 if (RT_SUCCESS(rc))
[29742]1433 {
[71590]1434 memset((void *)pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)));
[29742]1435 pHostCmd->iDstID = pCmd->iDisplay;
1436 pHostCmd->customOpCode = VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE;
[71592]1437 VBVAHOSTCMDVHWACMDCOMPLETE RT_UNTRUSTED_VOLATILE_GUEST *pBody
1438 = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDVHWACMDCOMPLETE);
[29742]1439 pBody->offCmd = offCmd;
1440 }
1441 }
1442 else
1443 rc = VERR_INVALID_PARAMETER;
[22622]1444 }
1445
[62928]1446 if (RT_SUCCESS(rc))
[22622]1447 {
[55560]1448 rc = HGSMIHostCommandSubmitAndFreeAsynch(pIns, pHostCmd, RT_BOOL(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ));
[29742]1449 AssertRC(rc);
[62928]1450 if (RT_SUCCESS(rc))
[29742]1451 return rc;
[62928]1452
[29742]1453 HGSMIHostCommandFree (pIns, pHostCmd);
[22622]1454 }
1455 }
1456 }
1457 else
1458 {
[71626]1459 Assert(pCmd->Flags & VBOXVHWACMD_FLAG_HH_CMD);
[24925]1460 PFNVBOXVHWA_HH_CALLBACK pfn = VBOXVHWA_HH_CALLBACK_GET(pCmd);
[62928]1461 if (pfn)
[24925]1462 pfn(VBOXVHWA_HH_CALLBACK_GET_ARG(pCmd));
[22622]1463 rc = VINF_SUCCESS;
1464 }
1465 return rc;
1466}
[34140]1467
1468typedef struct VBOXVBVASAVEDSTATECBDATA
1469{
1470 PSSMHANDLE pSSM;
1471 int rc;
1472 bool ab2DOn[VBOX_VIDEO_MAX_SCREENS];
1473} VBOXVBVASAVEDSTATECBDATA, *PVBOXVBVASAVEDSTATECBDATA;
1474
[82109]1475/**
1476 * @callback_method_impl{FNVBOXVHWAHHCMDPOSTCB}
1477 */
1478static DECLCALLBACK(bool) vboxVBVASaveStateBeginPostCb(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
1479 VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
[34140]1480{
[82109]1481 RT_NOREF(pDevIns, pThis, pThisCC, pCmd);
[34140]1482 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1483 if (RT_FAILURE(pData->rc))
1484 return false;
1485 if (RT_FAILURE(rc))
1486 {
1487 pData->rc = rc;
1488 return false;
1489 }
1490
1491 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1492 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1493 {
1494 pData->rc = VERR_INVALID_PARAMETER;
1495 return false;
1496 }
1497
1498 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1499 if (RT_SUCCESS(pCmd->rc))
1500 {
1501 pData->ab2DOn[iDisplay] = true;
1502 }
1503 else if (pCmd->rc != VERR_NOT_IMPLEMENTED)
1504 {
1505 pData->rc = pCmd->rc;
1506 return false;
1507 }
1508
1509 return true;
1510}
1511
[82109]1512/**
1513 * @callback_method_impl{FNVBOXVHWAHHCMDPRECB}
1514 */
1515static DECLCALLBACK(bool) vboxVBVASaveStatePerformPreCb(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
1516 VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
[34140]1517{
[82109]1518 RT_NOREF(pThis, pThisCC, pCmd);
[34140]1519 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1520 if (RT_FAILURE(pData->rc))
1521 return false;
1522
1523 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1524 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1525 {
1526 pData->rc = VERR_INVALID_PARAMETER;
1527 return false;
1528 }
1529
1530 int rc;
[82109]1531 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
[34140]1532
1533 if (pData->ab2DOn[iDisplay])
1534 {
[82048]1535 rc = pHlp->pfnSSMPutU32(pData->pSSM, VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC); AssertRC(rc);
[34140]1536 if (RT_FAILURE(rc))
1537 {
1538 pData->rc = rc;
1539 return false;
1540 }
1541 return true;
1542 }
1543
[82048]1544 rc = pHlp->pfnSSMPutU32(pData->pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC); AssertRC(rc);
[34140]1545 if (RT_FAILURE(rc))
1546 {
1547 pData->rc = rc;
1548 return false;
1549 }
1550
1551 return false;
1552}
1553
[82109]1554/**
1555 * @callback_method_impl{FNVBOXVHWAHHCMDPOSTCB}
1556 */
1557static DECLCALLBACK(bool) vboxVBVASaveStateEndPreCb(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
1558 VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
[34140]1559{
[82109]1560 RT_NOREF(pDevIns, pThis, pThisCC, pCmd);
[34140]1561 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1562 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1563 if (pData->ab2DOn[iDisplay])
1564 return true;
1565 return false;
1566}
1567
[82109]1568/**
1569 * @callback_method_impl{FNVBOXVHWAHHCMDPOSTCB}
1570 */
1571static DECLCALLBACK(bool) vboxVBVALoadStatePerformPostCb(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
1572 VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
[34140]1573{
[82109]1574 RT_NOREF(pThis, pThisCC, pCmd);
[34140]1575 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1576 if (RT_FAILURE(pData->rc))
1577 return false;
1578 if (RT_FAILURE(rc))
1579 {
1580 pData->rc = rc;
1581 return false;
1582 }
1583
1584 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1585 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1586 {
1587 pData->rc = VERR_INVALID_PARAMETER;
1588 return false;
1589 }
1590
[82109]1591 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
[34140]1592 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1593 if (pCmd->rc == VERR_NOT_IMPLEMENTED)
1594 {
[82048]1595 pData->rc = pHlp->pfnSSMSkipToEndOfUnit(pData->pSSM);
[34140]1596 AssertRC(pData->rc);
1597 return false;
1598 }
1599 if (RT_FAILURE(pCmd->rc))
1600 {
1601 pData->rc = pCmd->rc;
1602 return false;
1603 }
1604
1605 return true;
1606}
1607
[82109]1608/**
1609 * @callback_method_impl{FNVBOXVHWAHHCMDPOSTCB}
1610 */
1611static DECLCALLBACK(bool) vboxVBVALoadStatePerformPreCb(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
1612 VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
[34140]1613{
[82109]1614 RT_NOREF(pThis, pThisCC, pCmd);
[34140]1615 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1616 if (RT_FAILURE(pData->rc))
1617 return false;
1618
1619 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1620 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1621 {
1622 pData->rc = VERR_INVALID_PARAMETER;
1623 return false;
1624 }
1625
[82109]1626 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
[34140]1627 int rc;
1628 uint32_t u32;
[82048]1629 rc = pHlp->pfnSSMGetU32(pData->pSSM, &u32); AssertRC(rc);
[34140]1630 if (RT_FAILURE(rc))
1631 {
1632 pData->rc = rc;
1633 return false;
1634 }
1635
1636 switch (u32)
1637 {
1638 case VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC:
[51631]1639 pData->ab2DOn[iDisplay] = true;
[34140]1640 return true;
1641 case VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC:
[51631]1642 pData->ab2DOn[iDisplay] = false;
[34140]1643 return false;
1644 default:
1645 pData->rc = VERR_INVALID_STATE;
1646 return false;
1647 }
1648}
1649
[82109]1650#endif /* VBOX_WITH_VIDEOHWACCEL */
1651
1652static int vboxVBVASaveDevStateExec(PCPDMDEVHLPR3 pHlp, PVGASTATE pThis, PVGASTATECC pThisCC, PSSMHANDLE pSSM)
[34140]1653{
[82109]1654 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
[82048]1655 int rc = HGSMIHostSaveStateExec(pHlp, pIns, pSSM);
[34140]1656 if (RT_SUCCESS(rc))
1657 {
[56969]1658 VGA_SAVED_STATE_PUT_MARKER(pSSM, 2);
1659
[34140]1660 /* Save VBVACONTEXT. */
1661 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1662
1663 if (!pCtx)
1664 {
1665 AssertFailed();
1666
1667 /* Still write a valid value to the SSM. */
[82048]1668 rc = pHlp->pfnSSMPutU32 (pSSM, 0);
[34140]1669 AssertRCReturn(rc, rc);
1670 }
1671 else
1672 {
1673#ifdef DEBUG_sunlover
1674 dumpctx(pCtx);
[22622]1675#endif
1676
[82048]1677 rc = pHlp->pfnSSMPutU32 (pSSM, pCtx->cViews);
[34140]1678 AssertRCReturn(rc, rc);
[22622]1679
[34140]1680 uint32_t iView;
1681 for (iView = 0; iView < pCtx->cViews; iView++)
1682 {
1683 VBVAVIEW *pView = &pCtx->aViews[iView];
1684
[82048]1685 rc = pHlp->pfnSSMPutU32(pSSM, pView->view.u32ViewIndex);
[34140]1686 AssertRCReturn(rc, rc);
[82048]1687 rc = pHlp->pfnSSMPutU32(pSSM, pView->view.u32ViewOffset);
[34140]1688 AssertRCReturn(rc, rc);
[82048]1689 rc = pHlp->pfnSSMPutU32(pSSM, pView->view.u32ViewSize);
[34140]1690 AssertRCReturn(rc, rc);
[82048]1691 rc = pHlp->pfnSSMPutU32(pSSM, pView->view.u32MaxScreenSize);
[34140]1692 AssertRCReturn(rc, rc);
1693
[82048]1694 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32ViewIndex);
[34140]1695 AssertRCReturn(rc, rc);
[82048]1696 rc = pHlp->pfnSSMPutS32(pSSM, pView->screen.i32OriginX);
[34140]1697 AssertRCReturn(rc, rc);
[82048]1698 rc = pHlp->pfnSSMPutS32(pSSM, pView->screen.i32OriginY);
[34140]1699 AssertRCReturn(rc, rc);
[82048]1700 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32StartOffset);
[34140]1701 AssertRCReturn(rc, rc);
[82048]1702 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32LineSize);
[34140]1703 AssertRCReturn(rc, rc);
[82048]1704 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32Width);
[34140]1705 AssertRCReturn(rc, rc);
[82048]1706 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32Height);
[34140]1707 AssertRCReturn(rc, rc);
[82048]1708 rc = pHlp->pfnSSMPutU16(pSSM, pView->screen.u16BitsPerPixel);
[34140]1709 AssertRCReturn(rc, rc);
[82048]1710 rc = pHlp->pfnSSMPutU16(pSSM, pView->screen.u16Flags);
[34140]1711 AssertRCReturn(rc, rc);
1712
[82048]1713 rc = pHlp->pfnSSMPutU32(pSSM, pView->vbva.guest.pVBVA? pView->vbva.u32VBVAOffset: HGSMIOFFSET_VOID);
[34140]1714 AssertRCReturn(rc, rc);
1715
[82048]1716 rc = pHlp->pfnSSMPutU32(pSSM, pView->vbva.partialRecord.cb);
[34140]1717 AssertRCReturn(rc, rc);
1718
[56036]1719 if (pView->vbva.partialRecord.cb > 0)
[34140]1720 {
[82048]1721 rc = pHlp->pfnSSMPutMem(pSSM, pView->vbva.partialRecord.pu8, pView->vbva.partialRecord.cb);
[34140]1722 AssertRCReturn(rc, rc);
1723 }
1724 }
1725
1726 /* Save mouse pointer shape information. */
[82048]1727 rc = pHlp->pfnSSMPutBool(pSSM, pCtx->mouseShapeInfo.fSet);
[34140]1728 AssertRCReturn(rc, rc);
[82048]1729 rc = pHlp->pfnSSMPutBool(pSSM, pCtx->mouseShapeInfo.fVisible);
[34140]1730 AssertRCReturn(rc, rc);
[82048]1731 rc = pHlp->pfnSSMPutBool(pSSM, pCtx->mouseShapeInfo.fAlpha);
[34140]1732 AssertRCReturn(rc, rc);
[82048]1733 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.u32HotX);
[34140]1734 AssertRCReturn(rc, rc);
[82048]1735 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.u32HotY);
[34140]1736 AssertRCReturn(rc, rc);
[82048]1737 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.u32Width);
[34140]1738 AssertRCReturn(rc, rc);
[82048]1739 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.u32Height);
[34140]1740 AssertRCReturn(rc, rc);
[82048]1741 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.cbShape);
[34140]1742 AssertRCReturn(rc, rc);
1743 if (pCtx->mouseShapeInfo.cbShape)
1744 {
[82048]1745 rc = pHlp->pfnSSMPutMem(pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
[34140]1746 AssertRCReturn(rc, rc);
1747 }
1748
[34188]1749#ifdef VBOX_WITH_WDDM
[34140]1750 /* Size of some additional data. For future extensions. */
[82048]1751 rc = pHlp->pfnSSMPutU32(pSSM, 4);
[34188]1752 AssertRCReturn(rc, rc);
[82109]1753 rc = pHlp->pfnSSMPutU32(pSSM, pThis->fGuestCaps);
[34188]1754 AssertRCReturn(rc, rc);
1755#else
1756 /* Size of some additional data. For future extensions. */
[82048]1757 rc = pHlp->pfnSSMPutU32(pSSM, 0);
[34140]1758 AssertRCReturn(rc, rc);
[34188]1759#endif
[82048]1760 rc = pHlp->pfnSSMPutU32(pSSM, RT_ELEMENTS(pCtx->aModeHints));
[53528]1761 AssertRCReturn(rc, rc);
[82048]1762 rc = pHlp->pfnSSMPutU32(pSSM, sizeof(VBVAMODEHINT));
[53528]1763 AssertRCReturn(rc, rc);
1764 for (unsigned i = 0; i < RT_ELEMENTS(pCtx->aModeHints); ++i)
1765 {
[82048]1766 rc = pHlp->pfnSSMPutMem(pSSM, &pCtx->aModeHints[i], sizeof(VBVAMODEHINT));
[53528]1767 AssertRCReturn(rc, rc);
1768 }
[34140]1769 }
1770 }
1771
1772 return rc;
1773}
1774
[82048]1775int vboxVBVASaveStateExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
[34140]1776{
[82109]1777 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1778 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
1779 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
[34140]1780 int rc;
1781#ifdef VBOX_WITH_VIDEOHWACCEL
1782 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1783 VhwaData.pSSM = pSSM;
1784 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM); /* maximum cmd size */
[62928]1785 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN, 0, cbCmd);
[34140]1786 Assert(pCmd);
[82109]1787 if (pCmd)
[34140]1788 {
[82109]1789 vbvaVHWAHHPost(pDevIns, pThis, pThisCC, pCmd, NULL, vboxVBVASaveStateBeginPostCb, &VhwaData);
[34140]1790 rc = VhwaData.rc;
1791 AssertRC(rc);
1792 if (RT_SUCCESS(rc))
1793 {
1794#endif
[82109]1795 rc = vboxVBVASaveDevStateExec(pHlp, pThis, pThisCC, pSSM);
[34140]1796 AssertRC(rc);
1797#ifdef VBOX_WITH_VIDEOHWACCEL
1798 if (RT_SUCCESS(rc))
1799 {
1800 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM, 0);
[71592]1801 VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM *pSave = VBOXVHWACMD_BODY_HOST_HEAP(pCmd, VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM);
[34140]1802 pSave->pSSM = pSSM;
[82109]1803 vbvaVHWAHHPost(pDevIns, pThis, pThisCC, pCmd, vboxVBVASaveStatePerformPreCb, NULL, &VhwaData);
[34140]1804 rc = VhwaData.rc;
1805 AssertRC(rc);
1806 if (RT_SUCCESS(rc))
1807 {
[82109]1808 rc = vbvaVHWACommandSavePending(pHlp, pThis, pThisCC, pSSM);
[49420]1809 AssertRCReturn(rc, rc);
1810
[34140]1811 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND, 0);
[82109]1812 vbvaVHWAHHPost(pDevIns, pThis, pThisCC, pCmd, vboxVBVASaveStateEndPreCb, NULL, &VhwaData);
[34140]1813 rc = VhwaData.rc;
1814 AssertRC(rc);
1815 }
1816 }
1817 }
1818
1819 vbvaVHWAHHCommandRelease(pCmd);
1820 }
[34203]1821 else
1822 rc = VERR_OUT_OF_RESOURCES;
[34140]1823#else
[34203]1824 if (RT_SUCCESS(rc))
[34140]1825 {
[82109]1826 for (uint32_t i = 0; i < pThis->cMonitors; ++i)
[34203]1827 {
[82048]1828 rc = pHlp->pfnSSMPutU32(pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC);
[34203]1829 AssertRCReturn(rc, rc);
1830 }
[34140]1831 }
[51631]1832
1833 /* no pending commands */
[82048]1834 pHlp->pfnSSMPutU32(pSSM, 0);
[34140]1835#endif
[34203]1836 return rc;
[34140]1837}
1838
[82048]1839int vboxVBVALoadStateExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion)
[34140]1840{
[56969]1841 if (uVersion < VGA_SAVEDSTATE_VERSION_HGSMI)
[34140]1842 {
1843 /* Nothing was saved. */
1844 return VINF_SUCCESS;
1845 }
1846
[82109]1847 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1848 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
1849 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1850 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
[82048]1851 int rc = HGSMIHostLoadStateExec(pHlp, pIns, pSSM, uVersion);
[34140]1852 if (RT_SUCCESS(rc))
1853 {
[56969]1854 VGA_SAVED_STATE_GET_MARKER_RETURN_ON_MISMATCH(pSSM, uVersion, 2);
1855
[34140]1856 /* Load VBVACONTEXT. */
1857 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1858
1859 if (!pCtx)
1860 {
1861 /* This should not happen. */
1862 AssertFailed();
1863 rc = VERR_INVALID_PARAMETER;
1864 }
1865 else
1866 {
1867 uint32_t cViews = 0;
[82048]1868 rc = pHlp->pfnSSMGetU32 (pSSM, &cViews);
[34140]1869 AssertRCReturn(rc, rc);
1870
1871 uint32_t iView;
1872 for (iView = 0; iView < cViews; iView++)
1873 {
1874 VBVAVIEW *pView = &pCtx->aViews[iView];
1875
[82048]1876 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32ViewIndex);
[34140]1877 AssertRCReturn(rc, rc);
[82048]1878 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32ViewOffset);
[34140]1879 AssertRCReturn(rc, rc);
[82048]1880 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32ViewSize);
[34140]1881 AssertRCReturn(rc, rc);
[82048]1882 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32MaxScreenSize);
[34140]1883 AssertRCReturn(rc, rc);
1884
[82048]1885 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32ViewIndex);
[34140]1886 AssertRCReturn(rc, rc);
[82048]1887 rc = pHlp->pfnSSMGetS32 (pSSM, &pView->screen.i32OriginX);
[34140]1888 AssertRCReturn(rc, rc);
[82048]1889 rc = pHlp->pfnSSMGetS32 (pSSM, &pView->screen.i32OriginY);
[34140]1890 AssertRCReturn(rc, rc);
[82048]1891 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32StartOffset);
[34140]1892 AssertRCReturn(rc, rc);
[82048]1893 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32LineSize);
[34140]1894 AssertRCReturn(rc, rc);
[82048]1895 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32Width);
[34140]1896 AssertRCReturn(rc, rc);
[82048]1897 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32Height);
[34140]1898 AssertRCReturn(rc, rc);
[82048]1899 rc = pHlp->pfnSSMGetU16 (pSSM, &pView->screen.u16BitsPerPixel);
[34140]1900 AssertRCReturn(rc, rc);
[82048]1901 rc = pHlp->pfnSSMGetU16 (pSSM, &pView->screen.u16Flags);
[34140]1902 AssertRCReturn(rc, rc);
1903
[82048]1904 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->vbva.u32VBVAOffset);
[34140]1905 AssertRCReturn(rc, rc);
1906
[82048]1907 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->vbva.partialRecord.cb);
[34140]1908 AssertRCReturn(rc, rc);
1909
[56036]1910 if (pView->vbva.partialRecord.cb == 0)
[34140]1911 {
[56036]1912 pView->vbva.partialRecord.pu8 = NULL;
[34140]1913 }
1914 else
1915 {
[56036]1916 Assert(pView->vbva.partialRecord.pu8 == NULL); /* Should be it. */
[34140]1917
[56036]1918 uint8_t *pu8 = (uint8_t *)RTMemAlloc(pView->vbva.partialRecord.cb);
[34140]1919
1920 if (!pu8)
1921 {
1922 return VERR_NO_MEMORY;
1923 }
1924
[56036]1925 pView->vbva.partialRecord.pu8 = pu8;
[34140]1926
[82048]1927 rc = pHlp->pfnSSMGetMem (pSSM, pView->vbva.partialRecord.pu8, pView->vbva.partialRecord.cb);
[34140]1928 AssertRCReturn(rc, rc);
1929 }
1930
[56036]1931 if (pView->vbva.u32VBVAOffset == HGSMIOFFSET_VOID)
[34140]1932 {
[56036]1933 pView->vbva.guest.pVBVA = NULL;
[34140]1934 }
1935 else
1936 {
[56036]1937 pView->vbva.guest.pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost(pIns, pView->vbva.u32VBVAOffset);
[34140]1938 }
1939 }
1940
[56969]1941 if (uVersion > VGA_SAVEDSTATE_VERSION_WITH_CONFIG)
[34140]1942 {
1943 /* Read mouse pointer shape information. */
[82048]1944 rc = pHlp->pfnSSMGetBool (pSSM, &pCtx->mouseShapeInfo.fSet);
[34140]1945 AssertRCReturn(rc, rc);
[82048]1946 rc = pHlp->pfnSSMGetBool (pSSM, &pCtx->mouseShapeInfo.fVisible);
[34140]1947 AssertRCReturn(rc, rc);
[82048]1948 rc = pHlp->pfnSSMGetBool (pSSM, &pCtx->mouseShapeInfo.fAlpha);
[34140]1949 AssertRCReturn(rc, rc);
[82048]1950 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotX);
[34140]1951 AssertRCReturn(rc, rc);
[82048]1952 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotY);
[34140]1953 AssertRCReturn(rc, rc);
[82048]1954 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32Width);
[34140]1955 AssertRCReturn(rc, rc);
[82048]1956 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32Height);
[34140]1957 AssertRCReturn(rc, rc);
[82048]1958 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.cbShape);
[34140]1959 AssertRCReturn(rc, rc);
1960 if (pCtx->mouseShapeInfo.cbShape)
1961 {
1962 pCtx->mouseShapeInfo.pu8Shape = (uint8_t *)RTMemAlloc(pCtx->mouseShapeInfo.cbShape);
1963 if (pCtx->mouseShapeInfo.pu8Shape == NULL)
1964 {
1965 return VERR_NO_MEMORY;
1966 }
1967 pCtx->mouseShapeInfo.cbAllocated = pCtx->mouseShapeInfo.cbShape;
[82048]1968 rc = pHlp->pfnSSMGetMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
[34140]1969 AssertRCReturn(rc, rc);
1970 }
1971 else
1972 {
1973 pCtx->mouseShapeInfo.pu8Shape = NULL;
1974 }
1975
1976 /* Size of some additional data. For future extensions. */
1977 uint32_t cbExtra = 0;
[82048]1978 rc = pHlp->pfnSSMGetU32 (pSSM, &cbExtra);
[34140]1979 AssertRCReturn(rc, rc);
[34188]1980#ifdef VBOX_WITH_WDDM
1981 if (cbExtra >= 4)
1982 {
[82109]1983 rc = pHlp->pfnSSMGetU32 (pSSM, &pThis->fGuestCaps);
[34188]1984 AssertRCReturn(rc, rc);
[82109]1985 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
[34188]1986 cbExtra -= 4;
1987 }
1988#endif
[34140]1989 if (cbExtra > 0)
1990 {
[82048]1991 rc = pHlp->pfnSSMSkip(pSSM, cbExtra);
[34140]1992 AssertRCReturn(rc, rc);
1993 }
[53535]1994
[56969]1995 if (uVersion >= VGA_SAVEDSTATE_VERSION_MODE_HINTS)
[53529]1996 {
[53535]1997 uint32_t cModeHints, cbModeHints;
[82048]1998 rc = pHlp->pfnSSMGetU32 (pSSM, &cModeHints);
[53529]1999 AssertRCReturn(rc, rc);
[82048]2000 rc = pHlp->pfnSSMGetU32 (pSSM, &cbModeHints);
[53535]2001 AssertRCReturn(rc, rc);
2002 memset(&pCtx->aModeHints, ~0, sizeof(pCtx->aModeHints));
2003 unsigned iHint;
2004 for (iHint = 0; iHint < cModeHints; ++iHint)
2005 {
2006 if ( cbModeHints <= sizeof(VBVAMODEHINT)
2007 && iHint < RT_ELEMENTS(pCtx->aModeHints))
[82048]2008 rc = pHlp->pfnSSMGetMem(pSSM, &pCtx->aModeHints[iHint],
[53535]2009 cbModeHints);
2010 else
[82048]2011 rc = pHlp->pfnSSMSkip(pSSM, cbModeHints);
[53535]2012 AssertRCReturn(rc, rc);
2013 }
[53529]2014 }
[34140]2015 }
2016
2017 pCtx->cViews = iView;
2018 LogFlowFunc(("%d views loaded\n", pCtx->cViews));
2019
[56969]2020 if (uVersion > VGA_SAVEDSTATE_VERSION_WDDM)
[34140]2021 {
[51648]2022 bool fLoadCommands;
2023
[56969]2024 if (uVersion < VGA_SAVEDSTATE_VERSION_FIXED_PENDVHWA)
[51648]2025 {
[82048]2026 const char *pcszOsArch = pHlp->pfnSSMHandleHostOSAndArch(pSSM);
[51648]2027 Assert(pcszOsArch);
[51730]2028 fLoadCommands = !pcszOsArch || RTStrNCmp(pcszOsArch, RT_STR_TUPLE("solaris"));
[51648]2029 }
2030 else
2031 fLoadCommands = true;
2032
[34140]2033#ifdef VBOX_WITH_VIDEOHWACCEL
2034 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM); /* maximum cmd size */
[62928]2035 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM, 0, cbCmd);
[34140]2036 Assert(pCmd);
2037 if(pCmd)
2038 {
2039 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
2040 VhwaData.pSSM = pSSM;
[71592]2041 VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM *pLoad = VBOXVHWACMD_BODY_HOST_HEAP(pCmd, VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM);
[34140]2042 pLoad->pSSM = pSSM;
[82109]2043 vbvaVHWAHHPost(pDevIns, pThis, pThisCC, pCmd, vboxVBVALoadStatePerformPreCb,
2044 vboxVBVALoadStatePerformPostCb, &VhwaData);
[34140]2045 rc = VhwaData.rc;
2046 vbvaVHWAHHCommandRelease(pCmd);
[49420]2047 AssertRCReturn(rc, rc);
2048
[51631]2049 if (fLoadCommands)
2050 {
[82109]2051 rc = vbvaVHWACommandLoadPending(pDevIns, pHlp, pThis, pThisCC, pSSM, uVersion);
[51631]2052 AssertRCReturn(rc, rc);
2053 }
[34140]2054 }
2055 else
2056 {
2057 rc = VERR_OUT_OF_RESOURCES;
2058 }
2059#else
[51631]2060 uint32_t u32;
2061
[82109]2062 for (uint32_t i = 0; i < pThis->cMonitors; ++i)
[51631]2063 {
[82048]2064 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
[51631]2065 AssertRCReturn(rc, rc);
2066
2067 if (u32 != VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC)
2068 {
[56097]2069 LogRel(("VBVA: 2D data while 2D is not supported\n"));
[51631]2070 return VERR_NOT_SUPPORTED;
2071 }
2072 }
2073
[51648]2074 if (fLoadCommands)
[51631]2075 {
[82048]2076 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
[51631]2077 AssertRCReturn(rc, rc);
2078
[51633]2079 if (u32)
2080 {
[56097]2081 LogRel(("VBVA: 2D pending command while 2D is not supported\n"));
[51633]2082 return VERR_NOT_SUPPORTED;
2083 }
[51631]2084 }
[34140]2085#endif
2086 }
2087
2088#ifdef DEBUG_sunlover
2089 dumpctx(pCtx);
2090#endif
2091 }
2092 }
2093
2094 return rc;
2095}
2096
[62928]2097int vboxVBVALoadStateDone(PPDMDEVINS pDevIns)
[34140]2098{
[82109]2099 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
2100 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
2101 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
[34140]2102 if (pCtx)
2103 {
2104 uint32_t iView;
2105 for (iView = 0; iView < pCtx->cViews; iView++)
2106 {
2107 VBVAVIEW *pView = &pCtx->aViews[iView];
[56036]2108 if (pView->vbva.guest.pVBVA)
[34140]2109 {
[82109]2110 int rc = vbvaEnable(pThis, pThisCC, pCtx, iView, pView->vbva.guest.pVBVA,
2111 pView->vbva.u32VBVAOffset, true /* fRestored */);
[56797]2112 if (RT_SUCCESS(rc))
[82109]2113 vbvaResize(pThisCC, pView, &pView->screen, false);
[56797]2114 else
2115 LogRel(("VBVA: can not restore: %Rrc\n", rc));
[34140]2116 }
2117 }
2118
2119 if (pCtx->mouseShapeInfo.fSet)
[82109]2120 vbvaUpdateMousePointerShape(pThisCC, &pCtx->mouseShapeInfo, true);
[34140]2121 }
2122
2123 return VINF_SUCCESS;
2124}
2125
[82109]2126void VBVARaiseIrq(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, uint32_t fFlags)
[41636]2127{
[90447]2128 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSectIRQ, VERR_SEM_BUSY);
2129 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSectIRQ, rcLock);
[56041]2130
[82109]2131 const uint32_t fu32CurrentGuestFlags = HGSMIGetHostGuestFlags(pThisCC->pHGSMI);
[61973]2132 if ((fu32CurrentGuestFlags & HGSMIHOSTFLAGS_IRQ) == 0)
[60465]2133 {
[61973]2134 /* No IRQ set yet. */
[82109]2135 Assert(pThis->fu32PendingGuestFlags == 0);
[61973]2136
[82109]2137 HGSMISetHostGuestFlags(pThisCC->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
[61973]2138
2139 /* If VM is not running, the IRQ will be set in VBVAOnResume. */
2140 const VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
2141 if ( enmVMState == VMSTATE_RUNNING
2142 || enmVMState == VMSTATE_RUNNING_LS)
2143 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
[60465]2144 }
[61973]2145 else
2146 {
2147 /* IRQ already set, remember the new flags. */
[82109]2148 pThis->fu32PendingGuestFlags |= HGSMIHOSTFLAGS_IRQ | fFlags;
[61973]2149 }
[41636]2150
[82109]2151 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSectIRQ);
[51324]2152}
2153
[82109]2154void VBVAOnResume(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
[60465]2155{
[90447]2156 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSectIRQ, VERR_SEM_BUSY);
2157 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSectIRQ, rcLock);
[60465]2158
[82109]2159 if (HGSMIGetHostGuestFlags(pThisCC->pHGSMI) & HGSMIHOSTFLAGS_IRQ)
[61973]2160 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
2161
[82050]2162 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSectIRQ);
[60465]2163}
2164
[82109]2165static int vbvaHandleQueryConf32(PVGASTATECC pThisCC, VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *pConf32)
[56036]2166{
[71619]2167 uint32_t const idxQuery = pConf32->u32Index;
2168 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
2169 LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n", idxQuery, pConf32->u32Value));
[56036]2170
[82109]2171 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
[71619]2172 uint32_t uValue;
2173 if (idxQuery == VBOX_VBVA_CONF32_MONITOR_COUNT)
2174 uValue = pCtx->cViews;
2175 else if (idxQuery == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
2176 uValue = _64K; /** @todo a value calculated from the vram size */
2177 else if ( idxQuery == VBOX_VBVA_CONF32_MODE_HINT_REPORTING
2178 || idxQuery == VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING)
2179 uValue = VINF_SUCCESS;
2180 else if (idxQuery == VBOX_VBVA_CONF32_CURSOR_CAPABILITIES)
[77965]2181 uValue = VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE;
[71619]2182 else if (idxQuery == VBOX_VBVA_CONF32_SCREEN_FLAGS)
2183 uValue = VBVA_SCREEN_F_ACTIVE
2184 | VBVA_SCREEN_F_DISABLED
2185 | VBVA_SCREEN_F_BLANK
2186 | VBVA_SCREEN_F_BLANK2;
2187 else if (idxQuery == VBOX_VBVA_CONF32_MAX_RECORD_SIZE)
2188 uValue = VBVA_MAX_RECORD_SIZE;
[71656]2189 else if (idxQuery == UINT32_MAX)
2190 uValue = UINT32_MAX; /* Older GA uses this for sanity checking. See testQueryConf in HGSMIBase.cpp on branches. */
[56036]2191 else
[71619]2192 ASSERT_GUEST_MSG_FAILED_RETURN(("Invalid index %#x\n", idxQuery), VERR_INVALID_PARAMETER);
[56036]2193
[71619]2194 pConf32->u32Value = uValue;
2195 return VINF_SUCCESS;
[56036]2196}
2197
[71619]2198static int vbvaHandleSetConf32(VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *pConf32)
[56036]2199{
[71619]2200 uint32_t const idxQuery = pConf32->u32Index;
2201 uint32_t const uValue = pConf32->u32Value;
2202 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
2203 LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n", idxQuery, uValue));
[56036]2204
[71619]2205 if (idxQuery == VBOX_VBVA_CONF32_MONITOR_COUNT)
2206 { /* do nothing. this is a const. */ }
2207 else if (idxQuery == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
2208 { /* do nothing. this is a const. */ }
[56036]2209 else
[71619]2210 ASSERT_GUEST_MSG_FAILED_RETURN(("Invalid index %#x (value=%u)\n", idxQuery, uValue), VERR_INVALID_PARAMETER);
[56036]2211
[71620]2212 RT_NOREF_PV(uValue);
[71619]2213 return VINF_SUCCESS;
[56036]2214}
2215
[82109]2216static int vbvaHandleInfoHeap(PVGASTATECC pThisCC, const VBVAINFOHEAP RT_UNTRUSTED_VOLATILE_GUEST *pInfoHeap)
[56036]2217{
[71619]2218 uint32_t const offHeap = pInfoHeap->u32HeapOffset;
2219 uint32_t const cbHeap = pInfoHeap->u32HeapSize;
2220 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
2221 LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n", offHeap, cbHeap));
[56036]2222
[82109]2223 return HGSMIHostHeapSetup(pThisCC->pHGSMI, offHeap, cbHeap);
[56036]2224}
2225
[82109]2226static int vbvaInfoView(PVGASTATE pThis, PVGASTATER3 pThisCC, const VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_GUEST *pView)
[51121]2227{
[71590]2228 VBVAINFOVIEW view;
[71619]2229 RT_COPY_VOLATILE(view, *pView);
2230 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[56036]2231
[55844]2232 LogFlowFunc(("VBVA_INFO_VIEW: u32ViewIndex %d, u32ViewOffset 0x%x, u32ViewSize 0x%x, u32MaxScreenSize 0x%x\n",
[56036]2233 view.u32ViewIndex, view.u32ViewOffset, view.u32ViewSize, view.u32MaxScreenSize));
[49507]2234
[82109]2235 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
[71619]2236 ASSERT_GUEST_LOGREL_MSG_RETURN( view.u32ViewIndex < pCtx->cViews
[82109]2237 && view.u32ViewOffset <= pThis->vram_size
2238 && view.u32ViewSize <= pThis->vram_size
2239 && view.u32ViewOffset <= pThis->vram_size - view.u32ViewSize
[71619]2240 && view.u32MaxScreenSize <= view.u32ViewSize,
2241 ("index %d(%d), offset 0x%x, size 0x%x, max 0x%x, vram size 0x%x\n",
2242 view.u32ViewIndex, pCtx->cViews, view.u32ViewOffset, view.u32ViewSize,
[82109]2243 view.u32MaxScreenSize, pThis->vram_size),
[71619]2244 VERR_INVALID_PARAMETER);
2245 RT_UNTRUSTED_VALIDATED_FENCE();
[51121]2246
[71619]2247 pCtx->aViews[view.u32ViewIndex].view = view;
2248 return VINF_SUCCESS;
[51121]2249}
2250
[82109]2251static int vbvaInfoScreen(PVGASTATECC pThisCC, const VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_GUEST *pScreen)
[51121]2252{
[71619]2253 /*
2254 * Copy input into non-volatile buffer.
2255 */
[71590]2256 VBVAINFOSCREEN screen;
[71619]2257 RT_COPY_VOLATILE(screen, *pScreen);
2258 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[77703]2259 LogRel2(("VBVA: InfoScreen: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
2260 screen.u32ViewIndex, screen.i32OriginX, screen.i32OriginY,
2261 screen.u32Width, screen.u32Height,
2262 screen.u32LineSize, screen.u16BitsPerPixel, screen.u16Flags));
[51121]2263
[71619]2264 /*
2265 * Validate input.
2266 */
[56036]2267 /* Allow screen.u16BitsPerPixel == 0 because legacy guest code used it for screen blanking. */
[82109]2268 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
[71619]2269 ASSERT_GUEST_LOGREL_MSG_RETURN(screen.u32ViewIndex < pCtx->cViews,
2270 ("Screen index %#x is out of bound (cViews=%#x)\n", screen.u32ViewIndex, pCtx->cViews),
2271 VERR_INVALID_PARAMETER);
2272 ASSERT_GUEST_LOGREL_MSG_RETURN( screen.u16BitsPerPixel <= 32
2273 && screen.u32Width <= UINT16_MAX
2274 && screen.u32Height <= UINT16_MAX
2275 && screen.u32LineSize <= UINT16_MAX * UINT32_C(4),
2276 ("One or more values out of range: u16BitsPerPixel=%#x u32Width=%#x u32Height=%#x u32LineSize=%#x\n",
2277 screen.u16BitsPerPixel, screen.u32Width, screen.u32Height, screen.u32LineSize),
2278 VERR_INVALID_PARAMETER);
2279 RT_UNTRUSTED_VALIDATED_FENCE();
[55844]2280
[71619]2281 const VBVAINFOVIEW *pView = &pCtx->aViews[screen.u32ViewIndex].view;
2282 const uint32_t cbPerPixel = (screen.u16BitsPerPixel + 7) / 8;
2283 ASSERT_GUEST_LOGREL_MSG_RETURN(screen.u32Width <= screen.u32LineSize / (cbPerPixel ? cbPerPixel : 1),
2284 ("u32Width=%#x u32LineSize=%3x cbPerPixel=%#x\n",
2285 screen.u32Width, screen.u32LineSize, cbPerPixel),
2286 VERR_INVALID_PARAMETER);
[51121]2287
[71619]2288 const uint64_t u64ScreenSize = (uint64_t)screen.u32LineSize * screen.u32Height;
2289
2290 ASSERT_GUEST_LOGREL_MSG_RETURN( screen.u32StartOffset <= pView->u32ViewSize
2291 && u64ScreenSize <= pView->u32MaxScreenSize
2292 && screen.u32StartOffset <= pView->u32ViewSize - (uint32_t)u64ScreenSize,
2293 ("u32StartOffset=%#x u32ViewSize=%#x u64ScreenSize=%#RX64 u32MaxScreenSize=%#x\n",
[71620]2294 screen.u32StartOffset, pView->u32ViewSize, u64ScreenSize, pView->u32MaxScreenSize),
[71619]2295 VERR_INVALID_PARAMETER);
2296 RT_UNTRUSTED_VALIDATED_FENCE();
2297
2298 /*
2299 * Do the job.
2300 */
[82109]2301 vbvaResize(pThisCC, &pCtx->aViews[screen.u32ViewIndex], &screen, true);
[71619]2302 return VINF_SUCCESS;
[51121]2303}
2304
[82109]2305#ifdef UNUSED_FUNCTION
2306int VBVAGetInfoViewAndScreen(PVGASTATE pThis, PVGASTATECC pThisCC, uint32_t u32ViewIndex, VBVAINFOVIEW *pView, VBVAINFOSCREEN *pScreen)
[51260]2307{
[82109]2308 if (u32ViewIndex >= pThis->cMonitors)
[51260]2309 return VERR_INVALID_PARAMETER;
[51121]2310
[82109]2311 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
[51260]2312 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
2313
2314 if (pView)
2315 *pView = pCtx->aViews[u32ViewIndex].view;
2316
2317 if (pScreen)
2318 *pScreen = pCtx->aViews[u32ViewIndex].screen;
2319
2320 return VINF_SUCCESS;
2321}
[82109]2322#endif
[51260]2323
[82109]2324static int vbvaHandleEnable(PVGASTATE pThis, PVGASTATER3 pThisCC, uint32_t fEnableFlags, uint32_t offEnable, uint32_t idScreen)
[56036]2325{
[71619]2326 LogFlowFunc(("VBVA_ENABLE[%u]: fEnableFlags=0x%x offEnable=%#x\n", idScreen, fEnableFlags, offEnable));
[82109]2327 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
[71619]2328 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pIns);
[51260]2329
[71619]2330 /*
2331 * Validate input.
2332 */
2333 ASSERT_GUEST_LOGREL_MSG_RETURN(idScreen < pCtx->cViews, ("idScreen=%#x cViews=%#x\n", idScreen, pCtx->cViews), VERR_INVALID_PARAMETER);
2334 ASSERT_GUEST_LOGREL_MSG_RETURN( (fEnableFlags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE
2335 || (fEnableFlags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE,
2336 ("fEnableFlags=%#x\n", fEnableFlags),
2337 VERR_INVALID_PARAMETER);
2338 if (fEnableFlags & VBVA_F_ENABLE)
[56036]2339 {
[82109]2340 ASSERT_GUEST_LOGREL_MSG_RETURN(offEnable < pThis->vram_size,
2341 ("offEnable=%#x vram_size=%#x\n", offEnable, pThis->vram_size),
[71619]2342 VERR_INVALID_PARAMETER);
2343 if (fEnableFlags & VBVA_F_ABSOFFSET)
2344 /* Offset from VRAM start. */
[82109]2345 ASSERT_GUEST_LOGREL_MSG_RETURN( pThis->vram_size >= RT_UOFFSETOF(VBVABUFFER, au8Data)
2346 && offEnable <= pThis->vram_size - RT_UOFFSETOF(VBVABUFFER, au8Data),
2347 ("offEnable=%#x vram_size=%#x\n", offEnable, pThis->vram_size),
[71619]2348 VERR_INVALID_PARAMETER);
[56036]2349 else
2350 {
[71619]2351 /* Offset from the view start. We'd be using idScreen here to fence required. */
2352 RT_UNTRUSTED_VALIDATED_FENCE();
2353 const VBVAINFOVIEW *pView = &pCtx->aViews[idScreen].view;
[82109]2354 ASSERT_GUEST_LOGREL_MSG_RETURN( pThis->vram_size - offEnable >= pView->u32ViewOffset
[71619]2355 && pView->u32ViewSize >= RT_UOFFSETOF(VBVABUFFER, au8Data)
2356 && offEnable <= pView->u32ViewSize - RT_UOFFSETOF(VBVABUFFER, au8Data),
2357 ("offEnable=%#x vram_size=%#x view: %#x LB %#x\n",
[82109]2358 offEnable, pThis->vram_size, pView->u32ViewOffset, pView->u32ViewSize),
[71619]2359 VERR_INVALID_PARAMETER);
2360 offEnable += pView->u32ViewOffset;
[56036]2361 }
[71619]2362 ASSERT_GUEST_LOGREL_MSG_RETURN(HGSMIIsOffsetValid(pIns, offEnable),
2363 ("offEnable=%#x area %#x LB %#x\n",
2364 offEnable, HGSMIGetAreaOffset(pIns), HGSMIGetAreaSize(pIns)),
2365 VERR_INVALID_PARAMETER);
2366 }
2367 RT_UNTRUSTED_VALIDATED_FENCE();
[56036]2368
[71619]2369 /*
2370 * Execute.
2371 */
2372 int rc = VINF_SUCCESS;
2373 if (fEnableFlags & VBVA_F_ENABLE)
2374 {
2375 VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *pVBVA
2376 = (VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *)HGSMIOffsetToPointerHost(pIns, offEnable);
2377 ASSERT_GUEST_LOGREL_RETURN(pVBVA, VERR_INVALID_PARAMETER); /* already check above, but let's be careful. */
[56036]2378
[71619]2379 /* Process any pending orders and empty the VBVA ring buffer. */
[82109]2380 vbvaFlush(pThis, pThisCC, pCtx);
[56797]2381
[82109]2382 rc = vbvaEnable(pThis, pThisCC, pCtx, idScreen, pVBVA, offEnable, false /* fRestored */);
[56797]2383 if (RT_FAILURE(rc))
[56799]2384 LogRelMax(8, ("VBVA: can not enable: %Rrc\n", rc));
[56036]2385 }
2386 else
[82109]2387 rc = vbvaDisable(pThis, pThisCC, pCtx, idScreen);
[56036]2388 return rc;
2389}
2390
[82109]2391static int vbvaHandleQueryModeHints(PVGASTATECC pThisCC, VBVAQUERYMODEHINTS volatile *pQueryModeHints, HGSMISIZE cbBuffer)
[56036]2392{
[82109]2393 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
[70604]2394 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pIns);
[56036]2395
[71626]2396 /*
2397 * Copy and validate the request.
2398 */
[70604]2399 uint16_t const cHintsQueried = pQueryModeHints->cHintsQueried;
2400 uint16_t const cbHintStructureGuest = pQueryModeHints->cbHintStructureGuest;
[71626]2401 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[56036]2402
[56097]2403 LogRelFlowFunc(("VBVA: HandleQueryModeHints: cHintsQueried=%RU16, cbHintStructureGuest=%RU16\n",
[70604]2404 cHintsQueried, cbHintStructureGuest));
[71626]2405 ASSERT_GUEST_RETURN(cbBuffer >= sizeof(VBVAQUERYMODEHINTS) + (uint32_t)cHintsQueried * cbHintStructureGuest,
2406 VERR_INVALID_PARAMETER);
2407 RT_UNTRUSTED_VALIDATED_FENCE();
[56036]2408
[71626]2409 /*
2410 * Produce the requested data.
2411 */
[70604]2412 uint8_t *pbHint = (uint8_t *)(pQueryModeHints + 1);
[56036]2413 memset(pbHint, ~0, cbBuffer - sizeof(VBVAQUERYMODEHINTS));
2414
[70604]2415 for (unsigned iHint = 0; iHint < cHintsQueried && iHint < VBOX_VIDEO_MAX_SCREENS; ++iHint)
[56036]2416 {
[70604]2417 memcpy(pbHint, &pCtx->aModeHints[iHint], RT_MIN(cbHintStructureGuest, sizeof(VBVAMODEHINT)));
2418 pbHint += cbHintStructureGuest;
[59169]2419 Assert((uintptr_t)(pbHint - (uint8_t *)pQueryModeHints) <= cbBuffer);
[56036]2420 }
2421
2422 return VINF_SUCCESS;
2423}
2424
[22622]2425/*
2426 *
2427 * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
2428 *
[23793]2429 * VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
2430 * Read Write
2431 * Host port 0x3b0 to process completed
2432 * Guest port 0x3d0 control value? to process
[22622]2433 *
2434 */
2435
[82109]2436static DECLCALLBACK(void) vbvaNotifyGuest(void *pvCallback)
[22622]2437{
[32877]2438#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
[82109]2439 PPDMDEVINS pDevIns = (PPDMDEVINS)pvCallback;
2440 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
2441 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
2442 VBVARaiseIrq(pDevIns, pThis, pThisCC, 0);
[22622]2443#else
2444 NOREF(pvCallback);
2445 /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */
2446#endif
2447}
2448
[70604]2449/**
2450 * The guest submitted a command buffer (hit VGA_PORT_HGSMI_GUEST).
[56036]2451 *
[70604]2452 * Verify the buffer size and invoke corresponding handler.
2453 *
[58170]2454 * @return VBox status code.
[56036]2455 * @param pvHandler The VBVA channel context.
2456 * @param u16ChannelInfo Command code.
[70604]2457 * @param pvBuffer HGSMI buffer with command data. Considered volatile!
[56036]2458 * @param cbBuffer Size of command data.
[70604]2459 *
2460 * @thread EMT
[56036]2461 */
[71590]2462static DECLCALLBACK(int) vbvaChannelHandler(void *pvHandler, uint16_t u16ChannelInfo,
2463 void RT_UNTRUSTED_VOLATILE_GUEST *pvBuffer, HGSMISIZE cbBuffer)
[22622]2464{
2465 int rc = VINF_SUCCESS;
2466
[70604]2467 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n", pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
[22622]2468
[82109]2469 PPDMDEVINS pDevIns = (PPDMDEVINS)pvHandler;
2470 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
2471 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
2472 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
2473 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pIns);
[22622]2474
2475 switch (u16ChannelInfo)
2476 {
[32877]2477#ifdef VBOX_WITH_VDMA
[26833]2478 case VBVA_VDMA_CMD:
[70596]2479 if (cbBuffer >= VBoxSHGSMIBufferHeaderSize() + sizeof(VBOXVDMACBUF_DR))
[39603]2480 {
[71612]2481 VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_GUEST *pCmd
2482 = (VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_GUEST *)VBoxSHGSMIBufferData((VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
[82109]2483 vboxVDMACommand(pThisCC->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
[70596]2484 rc = VINF_SUCCESS;
2485 }
2486 else
[39603]2487 rc = VERR_INVALID_PARAMETER;
[70596]2488 break;
[56036]2489
[26833]2490 case VBVA_VDMA_CTL:
[70596]2491 if (cbBuffer >= VBoxSHGSMIBufferHeaderSize() + sizeof(VBOXVDMA_CTL))
[39603]2492 {
[71612]2493 VBOXVDMA_CTL RT_UNTRUSTED_VOLATILE_GUEST *pCmd
2494 = (VBOXVDMA_CTL RT_UNTRUSTED_VOLATILE_GUEST *)VBoxSHGSMIBufferData((VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
[82109]2495 vboxVDMAControl(pThisCC->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
[70596]2496 }
2497 else
[39603]2498 rc = VERR_INVALID_PARAMETER;
[70596]2499 break;
[56036]2500#endif /* VBOX_WITH_VDMA */
2501
[22622]2502 case VBVA_QUERY_CONF32:
[70604]2503 if (cbBuffer >= sizeof(VBVACONF32))
[82109]2504 rc = vbvaHandleQueryConf32(pThisCC, (VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
[70604]2505 else
[22622]2506 rc = VERR_INVALID_PARAMETER;
[70604]2507 break;
[22622]2508
2509 case VBVA_SET_CONF32:
[70604]2510 if (cbBuffer >= sizeof(VBVACONF32))
[71619]2511 rc = vbvaHandleSetConf32((VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
[70604]2512 else
[22622]2513 rc = VERR_INVALID_PARAMETER;
[70604]2514 break;
[22622]2515
2516 case VBVA_INFO_VIEW:
[55844]2517 /* Expect at least one VBVAINFOVIEW structure. */
[70604]2518 rc = VERR_INVALID_PARAMETER;
2519 if (cbBuffer >= sizeof(VBVAINFOVIEW))
[22622]2520 {
[70604]2521 /* Guest submits an array of VBVAINFOVIEW structures. */
[71590]2522 const VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_GUEST *pView = (VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
[70604]2523 for (;
2524 cbBuffer >= sizeof(VBVAINFOVIEW);
2525 ++pView, cbBuffer -= sizeof(VBVAINFOVIEW))
2526 {
[82109]2527 rc = vbvaInfoView(pThis, pThisCC, pView);
[70604]2528 if (RT_FAILURE(rc))
2529 break;
2530 }
[22622]2531 }
[70604]2532 break;
[22622]2533
2534 case VBVA_INFO_HEAP:
[70604]2535 if (cbBuffer >= sizeof(VBVAINFOHEAP))
[82109]2536 rc = vbvaHandleInfoHeap(pThisCC, (VBVAINFOHEAP RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
[70604]2537 else
[22622]2538 rc = VERR_INVALID_PARAMETER;
[70604]2539 break;
[22622]2540
2541 case VBVA_FLUSH:
[70604]2542 if (cbBuffer >= sizeof(VBVAFLUSH))
[82109]2543 rc = vbvaFlush(pThis, pThisCC, pCtx);
[70604]2544 else
[22622]2545 rc = VERR_INVALID_PARAMETER;
[70604]2546 break;
[22622]2547
2548 case VBVA_INFO_SCREEN:
[70604]2549 rc = VERR_INVALID_PARAMETER;
2550 if (cbBuffer >= sizeof(VBVAINFOSCREEN))
[82109]2551 rc = vbvaInfoScreen(pThisCC, (VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
[70604]2552 break;
[22622]2553
2554 case VBVA_ENABLE:
[70604]2555 rc = VERR_INVALID_PARAMETER;
2556 if (cbBuffer >= sizeof(VBVAENABLE))
[22622]2557 {
[71590]2558 VBVAENABLE RT_UNTRUSTED_VOLATILE_GUEST *pVbvaEnable = (VBVAENABLE RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
[71619]2559 uint32_t const fEnableFlags = pVbvaEnable->u32Flags;
2560 uint32_t const offEnable = pVbvaEnable->u32Offset;
[71607]2561 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[22622]2562
[71619]2563 uint32_t idScreen;
2564 if (fEnableFlags & VBVA_F_EXTENDED)
[28228]2565 {
[71619]2566 ASSERT_GUEST_STMT_BREAK(cbBuffer >= sizeof(VBVAENABLE_EX), rc = VERR_INVALID_PARAMETER);
2567 idScreen = ((VBVAENABLE_EX RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer)->u32ScreenId;
2568 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[28228]2569 }
[70604]2570 else
[71619]2571 idScreen = vbvaViewFromBufferPtr(pIns, pCtx, pvBuffer);
[22622]2572
[82109]2573 rc = vbvaHandleEnable(pThis, pThisCC, fEnableFlags, offEnable, idScreen);
[70604]2574 pVbvaEnable->i32Result = rc;
[28228]2575 }
[70604]2576 break;
[28228]2577
[22622]2578 case VBVA_MOUSE_POINTER_SHAPE:
[70604]2579 if (cbBuffer >= sizeof(VBVAMOUSEPOINTERSHAPE))
[22622]2580 {
[71619]2581 VBVAMOUSEPOINTERSHAPE RT_UNTRUSTED_VOLATILE_GUEST *pShape
2582 = (VBVAMOUSEPOINTERSHAPE RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
[82109]2583 rc = vbvaMousePointerShape(pThisCC, pCtx, pShape, cbBuffer);
[70604]2584 pShape->i32Result = rc;
2585 }
2586 else
[22622]2587 rc = VERR_INVALID_PARAMETER;
[70604]2588 break;
[22622]2589
2590
2591#ifdef VBOX_WITH_VIDEOHWACCEL
2592 case VBVA_VHWA_CMD:
[70604]2593 if (cbBuffer >= VBOXVHWACMD_HEADSIZE())
[49420]2594 {
[82109]2595 vbvaVHWAHandleCommand(pDevIns, pThis, pThisCC, (VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
[70604]2596 rc = VINF_SUCCESS;
2597 }
2598 else
[49420]2599 rc = VERR_INVALID_PARAMETER;
[70604]2600 break;
2601#endif
[22622]2602
[32622]2603#ifdef VBOX_WITH_WDDM
[29742]2604 case VBVA_INFO_CAPS:
[70604]2605 if (cbBuffer >= sizeof(VBVACAPS))
[29742]2606 {
[71590]2607 VBVACAPS RT_UNTRUSTED_VOLATILE_GUEST *pCaps = (VBVACAPS RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
[82109]2608 pThis->fGuestCaps = pCaps->fCaps;
[71607]2609 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
2610
[82109]2611 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
[70604]2612 pCaps->rc = rc = VINF_SUCCESS;
2613 }
2614 else
[29742]2615 rc = VERR_INVALID_PARAMETER;
[70604]2616 break;
2617#endif
[29742]2618
[41636]2619 case VBVA_SCANLINE_CFG:
[70604]2620 if (cbBuffer >= sizeof(VBVASCANLINECFG))
[41636]2621 {
[71590]2622 VBVASCANLINECFG RT_UNTRUSTED_VOLATILE_GUEST *pCfg = (VBVASCANLINECFG RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
[82109]2623 pThis->fScanLineCfg = pCfg->fFlags;
[71607]2624 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
2625
[70604]2626 pCfg->rc = rc = VINF_SUCCESS;
2627 }
2628 else
[41636]2629 rc = VERR_INVALID_PARAMETER;
[70604]2630 break;
[41636]2631
[53528]2632 case VBVA_QUERY_MODE_HINTS:
[70604]2633 if (cbBuffer >= sizeof(VBVAQUERYMODEHINTS))
[53528]2634 {
[71626]2635 VBVAQUERYMODEHINTS RT_UNTRUSTED_VOLATILE_GUEST *pQueryModeHints
2636 = (VBVAQUERYMODEHINTS RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
[82109]2637 rc = vbvaHandleQueryModeHints(pThisCC, pQueryModeHints, cbBuffer);
[70604]2638 pQueryModeHints->rc = rc;
2639 }
2640 else
[53528]2641 rc = VERR_INVALID_PARAMETER;
[70604]2642 break;
[56036]2643
[53965]2644 case VBVA_REPORT_INPUT_MAPPING:
[70604]2645 if (cbBuffer >= sizeof(VBVAREPORTINPUTMAPPING))
[53965]2646 {
[71590]2647 VBVAREPORTINPUTMAPPING inputMapping;
2648 {
2649 VBVAREPORTINPUTMAPPING RT_UNTRUSTED_VOLATILE_GUEST *pInputMapping
2650 = (VBVAREPORTINPUTMAPPING RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
[71626]2651 inputMapping.x = pInputMapping->x;
2652 inputMapping.y = pInputMapping->y;
[71590]2653 inputMapping.cx = pInputMapping->cx;
2654 inputMapping.cy = pInputMapping->cy;
2655 }
[71607]2656 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[71590]2657
[70604]2658 LogRelFlowFunc(("VBVA: ChannelHandler: VBVA_REPORT_INPUT_MAPPING: x=%RI32, y=%RI32, cx=%RU32, cy=%RU32\n",
2659 inputMapping.x, inputMapping.y, inputMapping.cx, inputMapping.cy));
[82109]2660 pThisCC->pDrv->pfnVBVAInputMappingUpdate(pThisCC->pDrv,
[70604]2661 inputMapping.x, inputMapping.y,
2662 inputMapping.cx, inputMapping.cy);
2663 rc = VINF_SUCCESS;
2664 }
2665 else
[53965]2666 rc = VERR_INVALID_PARAMETER;
[70604]2667 break;
[56036]2668
[53965]2669 case VBVA_CURSOR_POSITION:
[70604]2670 if (cbBuffer >= sizeof(VBVACURSORPOSITION))
[53965]2671 {
[71590]2672 VBVACURSORPOSITION RT_UNTRUSTED_VOLATILE_GUEST *pReport = (VBVACURSORPOSITION RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
2673 VBVACURSORPOSITION Report;
2674 Report.fReportPosition = pReport->fReportPosition;
2675 Report.x = pReport->x;
2676 Report.y = pReport->y;
[71607]2677 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
[56036]2678
[77130]2679 LogRelFlowFunc(("VBVA: ChannelHandler: VBVA_CURSOR_POSITION: fReportPosition=%RTbool, Id=%RU32, x=%RU32, y=%RU32\n",
2680 RT_BOOL(Report.fReportPosition), vbvaViewFromBufferPtr(pIns, pCtx, pvBuffer), Report.x, Report.y));
[56036]2681
[82109]2682 pThisCC->pDrv->pfnVBVAReportCursorPosition(pThisCC->pDrv, RT_BOOL(Report.fReportPosition), vbvaViewFromBufferPtr(pIns, pCtx, pvBuffer), Report.x, Report.y);
[77965]2683 /* This was only ever briefly used by the guest, and a value
2684 * of zero in both was taken to mean "ignore". */
2685 pReport->x = 0;
2686 pReport->y = 0;
[70604]2687 rc = VINF_SUCCESS;
2688 }
2689 else
2690 rc = VERR_INVALID_PARAMETER;
2691 break;
[56036]2692
[22622]2693 default:
[70604]2694 Log(("Unsupported VBVA guest command %d (%#x)!!!\n", u16ChannelInfo, u16ChannelInfo));
[22622]2695 break;
2696 }
2697
2698 return rc;
2699}
2700
[82109]2701/** When VBVA is paused, the VGA device is allowed to work but
[50259]2702 * no HGSMI etc state is changed.
2703 */
[82109]2704static void vbvaPause(PVGASTATECC pThisCC, bool fPause)
[50259]2705{
[82109]2706 if (!pThisCC || !pThisCC->pHGSMI)
[50259]2707 return;
2708
[82109]2709 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
[50259]2710 if (pCtx)
2711 pCtx->fPaused = fPause;
2712}
2713
[82109]2714bool VBVAIsPaused(PVGASTATECC pThisCC)
[60369]2715{
[82109]2716 if (pThisCC && pThisCC->pHGSMI)
[60369]2717 {
[82109]2718 const VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
[60369]2719 if (pCtx && pCtx->cViews)
2720 {
2721 /* If VBVA is enabled at all. */
2722 const VBVAVIEW *pView = &pCtx->aViews[0];
2723 if (pView->vbva.guest.pVBVA)
2724 return pCtx->fPaused;
2725 }
2726 }
2727 /* VBVA is disabled. */
2728 return true;
2729}
2730
[82109]2731void VBVAOnVBEChanged(PVGASTATE pThis, PVGASTATECC pThisCC)
[60369]2732{
2733 /* The guest does not depend on host handling the VBE registers. */
[82109]2734 if (pThis->fGuestCaps & VBVACAPS_USE_VBVA_ONLY)
[60369]2735 return;
2736
[82109]2737 vbvaPause(pThisCC, (pThis->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) == 0);
[60369]2738}
2739
[82109]2740void VBVAReset(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
[22622]2741{
[82109]2742 if (!pThis || !pThisCC->pHGSMI)
[22622]2743 return;
2744
[82109]2745 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
[22622]2746
[24053]2747#ifdef VBOX_WITH_VIDEOHWACCEL
[82109]2748 vbvaVHWAReset(pDevIns, pThis, pThisCC);
[24053]2749#endif
2750
[82109]2751 HGSMIReset(pThisCC->pHGSMI);
[61976]2752 /* Make sure the IRQ is reset. */
[82109]2753 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_LOW);
2754 pThis->fu32PendingGuestFlags = 0;
[24053]2755
[22622]2756 if (pCtx)
2757 {
[82109]2758 vbvaFlush(pThis, pThisCC, pCtx);
[22622]2759
[82109]2760 for (unsigned idScreen = 0; idScreen < pCtx->cViews; idScreen++)
2761 vbvaDisable(pThis, pThisCC, pCtx, idScreen);
[22622]2762
[24714]2763 pCtx->mouseShapeInfo.fSet = false;
[83562]2764 RTMemFreeZ(pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbAllocated);
[24714]2765 pCtx->mouseShapeInfo.pu8Shape = NULL;
2766 pCtx->mouseShapeInfo.cbAllocated = 0;
2767 pCtx->mouseShapeInfo.cbShape = 0;
[22622]2768 }
[24053]2769
[22622]2770}
2771
[82109]2772int VBVAUpdateDisplay(PVGASTATE pThis, PVGASTATECC pThisCC)
[22622]2773{
2774 int rc = VERR_NOT_SUPPORTED; /* Assuming that the VGA device will have to do updates. */
2775
[82109]2776 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
[22622]2777 if (pCtx)
2778 {
[50259]2779 if (!pCtx->fPaused)
2780 {
[82109]2781 rc = vbvaFlush(pThis, pThisCC, pCtx);
2782 if (RT_SUCCESS(rc))
[22622]2783 {
[56036]2784 if (!pCtx->aViews[0].vbva.guest.pVBVA)
[50259]2785 {
2786 /* VBVA is not enabled for the first view, so VGA device must do updates. */
2787 rc = VERR_NOT_SUPPORTED;
2788 }
[22622]2789 }
2790 }
2791 }
2792
2793 return rc;
2794}
2795
[82109]2796static int vbvaSendModeHintWorker(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
2797 uint32_t cx, uint32_t cy, uint32_t cBPP, uint32_t iDisplay, uint32_t dx,
[53528]2798 uint32_t dy, uint32_t fEnabled,
2799 uint32_t fNotifyGuest)
2800{
[82109]2801 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
[53528]2802 /** @note See Display::setVideoModeHint: "It is up to the guest to decide
2803 * whether the hint is valid. Therefore don't do any VRAM sanity checks
2804 * here! */
[54168]2805 if (iDisplay >= RT_MIN(pThis->cMonitors, RT_ELEMENTS(pCtx->aModeHints)))
[53528]2806 return VERR_OUT_OF_RANGE;
2807 pCtx->aModeHints[iDisplay].magic = VBVAMODEHINT_MAGIC;
2808 pCtx->aModeHints[iDisplay].cx = cx;
2809 pCtx->aModeHints[iDisplay].cy = cy;
2810 pCtx->aModeHints[iDisplay].cBPP = cBPP;
2811 pCtx->aModeHints[iDisplay].dx = dx;
2812 pCtx->aModeHints[iDisplay].dy = dy;
2813 pCtx->aModeHints[iDisplay].fEnabled = fEnabled;
[54162]2814 if (fNotifyGuest && pThis->fGuestCaps & VBVACAPS_IRQ && pThis->fGuestCaps & VBVACAPS_VIDEO_MODE_HINTS)
[82109]2815 VBVARaiseIrq(pDevIns, pThis, pThisCC, HGSMIHOSTFLAGS_HOTPLUG);
[53528]2816 return VINF_SUCCESS;
2817}
2818
2819
[82088]2820/**
2821 * @interface_method_impl{PDMIDISPLAYPORT,pfnSendModeHint}
2822 */
2823DECLCALLBACK(int) vbvaR3PortSendModeHint(PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy, uint32_t cBPP,
2824 uint32_t iDisplay, uint32_t dx, uint32_t dy, uint32_t fEnabled, uint32_t fNotifyGuest)
[53528]2825{
[82109]2826 PVGASTATECC pThisCC = RT_FROM_MEMBER(pInterface, VGASTATECC, IPort);
2827 PPDMDEVINS pDevIns = pThisCC->pDevIns;
2828 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
2829 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
[90447]2830 AssertRCReturn(rc, rc);
[53528]2831
[82109]2832 rc = vbvaSendModeHintWorker(pDevIns, pThis, pThisCC, cx, cy, cBPP, iDisplay, dx, dy, fEnabled, fNotifyGuest);
[82088]2833
[82109]2834 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
[53528]2835 return rc;
2836}
2837
[82109]2838int VBVAInit(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
[22622]2839{
[82109]2840 int rc = HGSMICreate(&pThisCC->pHGSMI,
[91942]2841 pDevIns,
[70596]2842 "VBVA",
2843 0,
[82109]2844 pThisCC->pbVRam,
2845 pThis->vram_size,
[70596]2846 vbvaNotifyGuest,
[82109]2847 pDevIns,
[70596]2848 sizeof(VBVACONTEXT));
2849 if (RT_SUCCESS(rc))
[22622]2850 {
[82109]2851 rc = HGSMIHostChannelRegister(pThisCC->pHGSMI,
[70596]2852 HGSMI_CH_VBVA,
2853 vbvaChannelHandler,
[82109]2854 pDevIns);
[70596]2855 if (RT_SUCCESS(rc))
[22622]2856 {
[82109]2857 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
2858 pCtx->cViews = pThis->cMonitors;
[50259]2859 pCtx->fPaused = true;
[54594]2860 memset(pCtx->aModeHints, ~0, sizeof(pCtx->aModeHints));
[22622]2861 }
2862 }
2863
2864 return rc;
2865
2866}
2867
[82109]2868void VBVADestroy(PVGASTATECC pThisCC)
[22622]2869{
[82109]2870 PHGSMIINSTANCE pHgsmi = pThisCC->pHGSMI;
[70370]2871 if (pHgsmi)
[24714]2872 {
[70370]2873 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pHgsmi);
[24714]2874 pCtx->mouseShapeInfo.fSet = false;
[83562]2875 RTMemFreeZ(pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbAllocated);
[24714]2876 pCtx->mouseShapeInfo.pu8Shape = NULL;
2877 pCtx->mouseShapeInfo.cbAllocated = 0;
2878 pCtx->mouseShapeInfo.cbShape = 0;
[70370]2879
2880 HGSMIDestroy(pHgsmi);
[82109]2881 pThisCC->pHGSMI = NULL;
[24714]2882 }
[70370]2883}
[24714]2884
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use