VirtualBox

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

Last change on this file since 78339 was 77965, checked in by vboxsync, 6 years ago

Devices/Graphics: more preparations for drawing the pointer cursor in-device.
bugref:9376: Complete hardware cursor implementation in VMSVGA.
This change 1) moves the host cursor moved callback and the host cursor
capability change callback out of the VBVA part of the graphics device and
into the generic part, where they will presumably be implemented. It 2) also
stops reporting the host cursor position to the guest via VBVA (this was
always treated as optional by the Additions, and a position of (0, 0) treated
as no host support) and always reports that the host can handle hardware
cursor drawing, which is the case with all current front-ends and will be more
so when we can do drawing in the device.

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