VirtualBox

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

Last change on this file since 77807 was 77703, checked in by vboxsync, 6 years ago

BVGA,Display,FE/Qt: Don't flood the release log with screen updates message (Debian testing guest), changing the LogRel statements to LogRel2. Display will LogRel actual screen size, position, flag changes (but not VRAM address). Besides being extremely noisy it also slows down guest graphics as each release log message is flushed to the disk. PS. UI folks, we don't break log messages as this reduces the grep-ability.

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

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