VirtualBox

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

Last change on this file since 108721 was 108721, checked in by vboxsync, 3 weeks ago

Removed 2D video acceleration (aka VAHW / VBOX_WITH_VIDEOHWACCEL) [SSM fix, wasn't properly documented / #ifdef'ed before]. bugref:10756

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 75.6 KB
Line 
1/* $Id: DevVGA_VBVA.cpp 108721 2025-03-24 16:50:43Z vboxsync $ */
2/** @file
3 * VirtualBox Video Acceleration (VBVA).
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DEV_VGA
33#include <VBox/vmm/pdmifs.h>
34#include <VBox/vmm/pdmdev.h>
35#include <VBox/vmm/pgm.h>
36#include <VBox/vmm/ssm.h>
37#include <VBox/VMMDev.h>
38#include <VBox/AssertGuest.h>
39#include <VBoxVideo.h>
40#include <iprt/alloc.h>
41#include <iprt/assert.h>
42#include <iprt/asm.h>
43#include <iprt/string.h>
44#include <iprt/param.h>
45
46#include "DevVGA.h"
47
48/* A very detailed logging. */
49#if 0 // def DEBUG_sunlover
50#define LOGVBVABUFFER(a) LogFlow(a)
51#else
52#define LOGVBVABUFFER(a) do {} while (0)
53#endif
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59typedef struct VBVAPARTIALRECORD
60{
61 uint8_t *pu8;
62 uint32_t cb;
63} VBVAPARTIALRECORD;
64
65typedef struct VBVADATA
66{
67 struct
68 {
69 VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *pVBVA; /**< Pointer to the guest memory with the VBVABUFFER. */
70 uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pu8Data; /**< For convenience, pointer to the guest ring buffer (VBVABUFFER::au8Data). */
71 } guest;
72 uint32_t u32VBVAOffset; /**< VBVABUFFER offset in the guest VRAM. */
73 VBVAPARTIALRECORD partialRecord; /**< Partial record temporary storage. */
74 uint32_t off32Data; /**< The offset where the data starts in the VBVABUFFER.
75 * The host code uses it instead of VBVABUFFER::off32Data. */
76 uint32_t indexRecordFirst; /**< Index of the first filled record in VBVABUFFER::aRecords. */
77 uint32_t cbPartialWriteThreshold; /**< Copy of VBVABUFFER::cbPartialWriteThreshold used by host code. */
78 uint32_t cbData; /**< Copy of VBVABUFFER::cbData used by host code. */
79} VBVADATA;
80
81typedef struct VBVAVIEW
82{
83 VBVAINFOVIEW view;
84 VBVAINFOSCREEN screen;
85 VBVADATA vbva;
86} VBVAVIEW;
87
88typedef struct VBVAMOUSESHAPEINFO
89{
90 bool fSet;
91 bool fVisible;
92 bool fAlpha;
93 uint32_t u32HotX;
94 uint32_t u32HotY;
95 uint32_t u32Width;
96 uint32_t u32Height;
97 uint32_t cbShape;
98 uint32_t cbAllocated;
99 uint8_t *pu8Shape;
100} VBVAMOUSESHAPEINFO;
101
102/** @todo saved state: save and restore VBVACONTEXT */
103typedef struct VBVACONTEXT
104{
105 uint32_t cViews;
106 VBVAVIEW aViews[VBOX_VIDEO_MAX_SCREENS];
107 VBVAMOUSESHAPEINFO mouseShapeInfo;
108 bool fPaused;
109 VBVAMODEHINT aModeHints[VBOX_VIDEO_MAX_SCREENS];
110} VBVACONTEXT;
111
112
113static void vbvaDataCleanup(VBVADATA *pVBVAData)
114{
115 if (pVBVAData->guest.pVBVA)
116 {
117 pVBVAData->guest.pVBVA->hostFlags.u32HostEvents = 0;
118 pVBVAData->guest.pVBVA->hostFlags.u32SupportedOrders = 0;
119 }
120
121 RTMemFreeZ(pVBVAData->partialRecord.pu8, pVBVAData->partialRecord.cb);
122
123 RT_ZERO(*pVBVAData);
124 pVBVAData->u32VBVAOffset = HGSMIOFFSET_VOID;
125}
126
127/** Copies @a cb bytes from the VBVA ring buffer to the @a pbDst.
128 * Used for partial records or for records which cross the ring boundary.
129 */
130static bool vbvaFetchBytes(VBVADATA *pVBVAData, uint8_t *pbDst, uint32_t cb)
131{
132 if (cb >= pVBVAData->cbData)
133 {
134 AssertMsgFailed(("cb = 0x%08X, ring buffer size 0x%08X", cb, pVBVAData->cbData));
135 return false;
136 }
137
138 const uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pbSrc = &pVBVAData->guest.pu8Data[pVBVAData->off32Data];
139 const uint32_t u32BytesTillBoundary = pVBVAData->cbData - pVBVAData->off32Data;
140 const int32_t i32Diff = cb - u32BytesTillBoundary;
141
142 if (i32Diff <= 0)
143 {
144 /* Chunk will not cross buffer boundary. */
145 RT_BCOPY_VOLATILE(pbDst, pbSrc, cb);
146 }
147 else
148 {
149 /* Chunk crosses buffer boundary. */
150 RT_BCOPY_VOLATILE(pbDst, pbSrc, u32BytesTillBoundary);
151 RT_BCOPY_VOLATILE(pbDst + u32BytesTillBoundary, &pVBVAData->guest.pu8Data[0], i32Diff);
152 }
153
154 /* Advance data offset and sync with guest. */
155 pVBVAData->off32Data = (pVBVAData->off32Data + cb) % pVBVAData->cbData;
156 pVBVAData->guest.pVBVA->off32Data = pVBVAData->off32Data;
157 return true;
158}
159
160
161static bool vbvaPartialRead(uint32_t cbRecord, VBVADATA *pVBVAData)
162{
163 VBVAPARTIALRECORD *pPartialRecord = &pVBVAData->partialRecord;
164 uint8_t *pu8New;
165
166 LOGVBVABUFFER(("vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
167 pPartialRecord->pu8, pPartialRecord->cb, cbRecord));
168
169 Assert(cbRecord > pPartialRecord->cb); /* Caller ensures this. */
170
171 const uint32_t cbChunk = cbRecord - pPartialRecord->cb;
172 if (cbChunk >= pVBVAData->cbData)
173 {
174 return false;
175 }
176
177 if (pPartialRecord->pu8)
178 {
179 Assert(pPartialRecord->cb);
180 pu8New = (uint8_t *)RTMemRealloc(pPartialRecord->pu8, cbRecord);
181 }
182 else
183 {
184 Assert(!pPartialRecord->cb);
185 pu8New = (uint8_t *)RTMemAlloc(cbRecord);
186 }
187
188 if (!pu8New)
189 {
190 /* Memory allocation failed, fail the function. */
191 Log(("vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
192 cbRecord));
193
194 return false;
195 }
196
197 /* Fetch data from the ring buffer. */
198 if (!vbvaFetchBytes(pVBVAData, pu8New + pPartialRecord->cb, cbChunk))
199 {
200 return false;
201 }
202
203 pPartialRecord->pu8 = pu8New;
204 pPartialRecord->cb = cbRecord;
205
206 return true;
207}
208
209/**
210 * For contiguous chunks just return the address in the buffer. For crossing
211 * boundary - allocate a buffer from heap.
212 */
213static bool vbvaFetchCmd(VBVADATA *pVBVAData, VBVACMDHDR RT_UNTRUSTED_VOLATILE_GUEST **ppHdr, uint32_t *pcbCmd)
214{
215 VBVAPARTIALRECORD *pPartialRecord = &pVBVAData->partialRecord;
216 uint32_t indexRecordFirst = pVBVAData->indexRecordFirst;
217 const uint32_t indexRecordFree = ASMAtomicReadU32(&pVBVAData->guest.pVBVA->indexRecordFree);
218
219 LOGVBVABUFFER(("first = %d, free = %d\n",
220 indexRecordFirst, indexRecordFree));
221
222 if (indexRecordFree >= RT_ELEMENTS(pVBVAData->guest.pVBVA->aRecords))
223 {
224 return false;
225 }
226
227 if (indexRecordFirst == indexRecordFree)
228 {
229 /* No records to process. Return without assigning output variables. */
230 return true;
231 }
232
233 uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVBVAData->guest.pVBVA->aRecords[indexRecordFirst].cbRecord);
234
235 LOGVBVABUFFER(("cbRecord = 0x%08X, pPartialRecord->cb = 0x%08X\n", cbRecordCurrent, pPartialRecord->cb));
236
237 uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
238
239 if (cbRecord > VBVA_MAX_RECORD_SIZE)
240 {
241 return false;
242 }
243
244 if (pPartialRecord->cb)
245 {
246 /* There is a partial read in process. Continue with it. */
247 Assert (pPartialRecord->pu8);
248
249 LOGVBVABUFFER(("continue partial record cb = %d cbRecord 0x%08X, first = %d, free = %d\n",
250 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
251
252 if (cbRecord > pPartialRecord->cb)
253 {
254 /* New data has been added to the record. */
255 if (!vbvaPartialRead(cbRecord, pVBVAData))
256 {
257 return false;
258 }
259 }
260
261 if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL))
262 {
263 /* The record is completed by guest. Return it to the caller. */
264 *ppHdr = (VBVACMDHDR *)pPartialRecord->pu8;
265 *pcbCmd = pPartialRecord->cb;
266
267 pPartialRecord->pu8 = NULL;
268 pPartialRecord->cb = 0;
269
270 /* Advance the record index and sync with guest. */
271 pVBVAData->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVAData->guest.pVBVA->aRecords);
272 pVBVAData->guest.pVBVA->indexRecordFirst = pVBVAData->indexRecordFirst;
273
274 LOGVBVABUFFER(("partial done ok, data = %d, free = %d\n",
275 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free));
276 }
277
278 return true;
279 }
280
281 /* A new record need to be processed. */
282 if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
283 {
284 /* Current record is being written by guest. '=' is important here,
285 * because the guest will do a FLUSH at this condition.
286 * This partial record is too large for the ring buffer and must
287 * be accumulated in an allocated buffer.
288 */
289 if (cbRecord >= pVBVAData->cbData - pVBVAData->cbPartialWriteThreshold)
290 {
291 /* Partial read must be started. */
292 if (!vbvaPartialRead(cbRecord, pVBVAData))
293 {
294 return false;
295 }
296
297 LOGVBVABUFFER(("started partial record cb = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
298 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
299 }
300
301 return true;
302 }
303
304 /* Current record is complete. If it is not empty, process it. */
305 if (cbRecord >= pVBVAData->cbData)
306 {
307 return false;
308 }
309
310 if (cbRecord)
311 {
312 /* The size of largest contiguous chunk in the ring buffer. */
313 uint32_t u32BytesTillBoundary = pVBVAData->cbData - pVBVAData->off32Data;
314
315 /* The pointer to data in the ring buffer. */
316 uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pbSrc = &pVBVAData->guest.pu8Data[pVBVAData->off32Data];
317
318 /* Fetch or point the data. */
319 if (u32BytesTillBoundary >= cbRecord)
320 {
321 /* The command does not cross buffer boundary. Return address in the buffer. */
322 *ppHdr = (VBVACMDHDR RT_UNTRUSTED_VOLATILE_GUEST *)pbSrc;
323
324 /* The data offset will be updated in vbvaReleaseCmd. */
325 }
326 else
327 {
328 /* The command crosses buffer boundary. Rare case, so not optimized. */
329 uint8_t *pbDst = (uint8_t *)RTMemAlloc(cbRecord);
330 if (!pbDst)
331 {
332 LogFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord));
333 return false;
334 }
335
336 vbvaFetchBytes(pVBVAData, pbDst, cbRecord);
337
338 *ppHdr = (VBVACMDHDR *)pbDst;
339
340 LOGVBVABUFFER(("Allocated from heap %p\n", pbDst));
341 }
342 }
343
344 *pcbCmd = cbRecord;
345
346 /* Advance the record index and sync with guest. */
347 pVBVAData->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVAData->guest.pVBVA->aRecords);
348 pVBVAData->guest.pVBVA->indexRecordFirst = pVBVAData->indexRecordFirst;
349
350 LOGVBVABUFFER(("done ok, data = %d, free = %d\n",
351 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free));
352
353 return true;
354}
355
356static void vbvaReleaseCmd(VBVADATA *pVBVAData, VBVACMDHDR RT_UNTRUSTED_VOLATILE_GUEST *pHdr, uint32_t cbCmd)
357{
358 VBVAPARTIALRECORD *pPartialRecord = &pVBVAData->partialRecord;
359 const uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pbRingBuffer = pVBVAData->guest.pu8Data;
360
361 if ( (uintptr_t)pHdr >= (uintptr_t)pbRingBuffer
362 && (uintptr_t)pHdr < (uintptr_t)&pbRingBuffer[pVBVAData->cbData])
363 {
364 /* The pointer is inside ring buffer. Must be continuous chunk. */
365 Assert(pVBVAData->cbData - (uint32_t)((uint8_t *)pHdr - pbRingBuffer) >= cbCmd);
366
367 /* Advance data offset and sync with guest. */
368 pVBVAData->off32Data = (pVBVAData->off32Data + cbCmd) % pVBVAData->cbData;
369 pVBVAData->guest.pVBVA->off32Data = pVBVAData->off32Data;
370
371 Assert(!pPartialRecord->pu8 && pPartialRecord->cb == 0);
372 }
373 else
374 {
375 /* The pointer is outside. It is then an allocated copy. */
376 LOGVBVABUFFER(("Free heap %p\n", pHdr));
377
378 if ((uint8_t *)pHdr == pPartialRecord->pu8)
379 {
380 pPartialRecord->pu8 = NULL;
381 pPartialRecord->cb = 0;
382 }
383 else
384 {
385 Assert(!pPartialRecord->pu8 && pPartialRecord->cb == 0);
386 }
387
388 RTMemFree((void *)pHdr);
389 }
390}
391
392static int vbvaFlushProcess(PVGASTATECC pThisCC, VBVADATA *pVBVAData, unsigned uScreenId)
393{
394 LOGVBVABUFFER(("uScreenId %d, indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
395 uScreenId, pVBVAData->indexRecordFirst, pVBVAData->guest.pVBVA->indexRecordFree,
396 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free));
397 struct
398 {
399 /* The rectangle that includes all dirty rectangles. */
400 int32_t xLeft;
401 int32_t xRight;
402 int32_t yTop;
403 int32_t yBottom;
404 } dirtyRect;
405 RT_ZERO(dirtyRect);
406
407 bool fUpdate = false; /* Whether there were any updates. */
408 bool fDirtyEmpty = true;
409
410 for (;;)
411 {
412 /* Fetch the command data. */
413 VBVACMDHDR RT_UNTRUSTED_VOLATILE_GUEST *pHdr = NULL;
414 uint32_t cbCmd = UINT32_MAX;
415 if (!vbvaFetchCmd(pVBVAData, &pHdr, &cbCmd))
416 {
417 LogFunc(("unable to fetch command. off32Data = %d, off32Free = %d!!!\n",
418 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free));
419 return VERR_NOT_SUPPORTED;
420 }
421
422 if (cbCmd == UINT32_MAX)
423 {
424 /* No more commands yet in the queue. */
425 break;
426 }
427
428 if (cbCmd < sizeof(VBVACMDHDR))
429 {
430 LogFunc(("short command. off32Data = %d, off32Free = %d, cbCmd %d!!!\n",
431 pVBVAData->off32Data, pVBVAData->guest.pVBVA->off32Free, cbCmd));
432
433 return VERR_NOT_SUPPORTED;
434 }
435
436 if (!fUpdate)
437 {
438 pThisCC->pDrv->pfnVBVAUpdateBegin(pThisCC->pDrv, uScreenId);
439 fUpdate = true;
440 }
441
442 /* Updates the rectangle and sends the command to the VRDP server. */
443 pThisCC->pDrv->pfnVBVAUpdateProcess(pThisCC->pDrv, uScreenId, pHdr, cbCmd);
444
445 int32_t xRight = pHdr->x + pHdr->w;
446 int32_t yBottom = pHdr->y + pHdr->h;
447
448 /* These are global coords, relative to the primary screen. */
449
450 LOGVBVABUFFER(("cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n", cbCmd, pHdr->x, pHdr->y, pHdr->w, pHdr->h));
451 LogRel3(("%s: update command cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
452 __FUNCTION__, cbCmd, pHdr->x, pHdr->y, pHdr->w, pHdr->h));
453
454 /* Collect all rects into one. */
455 if (fDirtyEmpty)
456 {
457 /* This is the first rectangle to be added. */
458 dirtyRect.xLeft = pHdr->x;
459 dirtyRect.yTop = pHdr->y;
460 dirtyRect.xRight = xRight;
461 dirtyRect.yBottom = yBottom;
462 fDirtyEmpty = false;
463 }
464 else
465 {
466 /* Adjust region coordinates. */
467 if (dirtyRect.xLeft > pHdr->x)
468 {
469 dirtyRect.xLeft = pHdr->x;
470 }
471
472 if (dirtyRect.yTop > pHdr->y)
473 {
474 dirtyRect.yTop = pHdr->y;
475 }
476
477 if (dirtyRect.xRight < xRight)
478 {
479 dirtyRect.xRight = xRight;
480 }
481
482 if (dirtyRect.yBottom < yBottom)
483 {
484 dirtyRect.yBottom = yBottom;
485 }
486 }
487
488 vbvaReleaseCmd(pVBVAData, pHdr, cbCmd);
489 }
490
491 if (fUpdate)
492 {
493 if (dirtyRect.xRight - dirtyRect.xLeft)
494 {
495 LogRel3(("%s: sending update screen=%d, x=%d, y=%d, w=%d, h=%d\n",
496 __FUNCTION__, uScreenId, dirtyRect.xLeft,
497 dirtyRect.yTop, dirtyRect.xRight - dirtyRect.xLeft,
498 dirtyRect.yBottom - dirtyRect.yTop));
499 pThisCC->pDrv->pfnVBVAUpdateEnd(pThisCC->pDrv, uScreenId, dirtyRect.xLeft, dirtyRect.yTop,
500 dirtyRect.xRight - dirtyRect.xLeft, dirtyRect.yBottom - dirtyRect.yTop);
501 }
502 else
503 {
504 pThisCC->pDrv->pfnVBVAUpdateEnd(pThisCC->pDrv, uScreenId, 0, 0, 0, 0);
505 }
506 }
507
508 return VINF_SUCCESS;
509}
510
511static int vbvaFlush(PVGASTATE pThis, PVGASTATECC pThisCC, VBVACONTEXT *pCtx)
512{
513 int rc = VINF_SUCCESS;
514
515 unsigned uScreenId;
516 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
517 {
518 VBVADATA *pVBVAData = &pCtx->aViews[uScreenId].vbva;
519 if (pVBVAData->guest.pVBVA)
520 {
521 rc = vbvaFlushProcess(pThisCC, pVBVAData, uScreenId);
522 if (RT_FAILURE(rc))
523 break;
524 }
525 }
526
527 if (RT_FAILURE(rc))
528 {
529 /* Turn off VBVA processing. */
530 LogRel(("VBVA: Disabling (%Rrc)\n", rc));
531 pThis->fGuestCaps = 0;
532 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
533 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
534 {
535 VBVADATA *pVBVAData = &pCtx->aViews[uScreenId].vbva;
536 if (pVBVAData->guest.pVBVA)
537 {
538 vbvaDataCleanup(pVBVAData);
539 pThisCC->pDrv->pfnVBVADisable(pThisCC->pDrv, uScreenId);
540 }
541 }
542 }
543
544 return rc;
545}
546
547static int vbvaResize(PVGASTATECC pThisCC, VBVAVIEW *pView, const VBVAINFOSCREEN *pNewScreen, bool fResetInputMapping)
548{
549 /* Callers ensure that pNewScreen contains valid data. */
550
551 /* Apply these changes. */
552 pView->screen = *pNewScreen;
553
554 uint8_t *pbVRam = pThisCC->pbVRam + pView->view.u32ViewOffset;
555 return pThisCC->pDrv->pfnVBVAResize(pThisCC->pDrv, &pView->view, &pView->screen, pbVRam, fResetInputMapping);
556}
557
558static int vbvaEnable(PVGASTATE pThis, PVGASTATECC pThisCC, VBVACONTEXT *pCtx, unsigned uScreenId,
559 VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *pVBVA, uint32_t u32Offset, bool fRestored)
560{
561 /*
562 * Copy into non-volatile memory and validate its content.
563 */
564 VBVABUFFER VbgaSafe;
565 RT_COPY_VOLATILE(VbgaSafe, *pVBVA);
566 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
567
568 uint32_t const cbVBVABuffer = RT_UOFFSETOF(VBVABUFFER, au8Data) + VbgaSafe.cbData;
569 ASSERT_GUEST_RETURN( VbgaSafe.cbData <= UINT32_MAX - RT_UOFFSETOF(VBVABUFFER, au8Data)
570 && cbVBVABuffer <= pThis->vram_size
571 && u32Offset <= pThis->vram_size - cbVBVABuffer,
572 VERR_INVALID_PARAMETER);
573 if (!fRestored)
574 {
575 ASSERT_GUEST_RETURN(VbgaSafe.off32Data == 0, VERR_INVALID_PARAMETER);
576 ASSERT_GUEST_RETURN(VbgaSafe.off32Free == 0, VERR_INVALID_PARAMETER);
577 ASSERT_GUEST_RETURN(VbgaSafe.indexRecordFirst == 0, VERR_INVALID_PARAMETER);
578 ASSERT_GUEST_RETURN(VbgaSafe.indexRecordFree == 0, VERR_INVALID_PARAMETER);
579 }
580 ASSERT_GUEST_RETURN( VbgaSafe.cbPartialWriteThreshold < VbgaSafe.cbData
581 && VbgaSafe.cbPartialWriteThreshold != 0,
582 VERR_INVALID_PARAMETER);
583 RT_UNTRUSTED_VALIDATED_FENCE();
584
585 /*
586 * Okay, try do the job.
587 */
588 int rc;
589 if (pThisCC->pDrv->pfnVBVAEnable)
590 {
591 pVBVA->hostFlags.u32HostEvents = 0;
592 pVBVA->hostFlags.u32SupportedOrders = 0;
593 rc = pThisCC->pDrv->pfnVBVAEnable(pThisCC->pDrv, uScreenId, &pVBVA->hostFlags);
594 if (RT_SUCCESS(rc))
595 {
596 /* pVBVA->hostFlags has been set up by pfnVBVAEnable. */
597 LogFlowFunc(("u32HostEvents=0x%08x u32SupportedOrders=0x%08x\n",
598 pVBVA->hostFlags.u32HostEvents, pVBVA->hostFlags.u32SupportedOrders));
599
600 VBVADATA *pVBVAData = &pCtx->aViews[uScreenId].vbva;
601 pVBVAData->guest.pVBVA = pVBVA;
602 pVBVAData->guest.pu8Data = &pVBVA->au8Data[0];
603 pVBVAData->u32VBVAOffset = u32Offset;
604 pVBVAData->off32Data = VbgaSafe.off32Data;
605 pVBVAData->indexRecordFirst = VbgaSafe.indexRecordFirst;
606 pVBVAData->cbPartialWriteThreshold = VbgaSafe.cbPartialWriteThreshold;
607 pVBVAData->cbData = VbgaSafe.cbData;
608
609 if (!fRestored)
610 {
611 /** @todo Actually this function must not touch the partialRecord structure at all,
612 * because initially it is a zero and when VBVA is disabled this should be set to zero.
613 * But I'm not sure that no code depends on zeroing partialRecord here.
614 * So for now (a quick fix for 4.1) just do not do this if the VM was restored,
615 * when partialRecord might be loaded already from the saved state.
616 */
617 pVBVAData->partialRecord.pu8 = NULL;
618 pVBVAData->partialRecord.cb = 0;
619 }
620
621 /* VBVA is working so disable the pause. */
622 pCtx->fPaused = false;
623 }
624 }
625 else
626 rc = VERR_NOT_SUPPORTED;
627 return rc;
628}
629
630static int vbvaDisable(PVGASTATE pThis, PVGASTATECC pThisCC, VBVACONTEXT *pCtx, unsigned idScreen)
631{
632 /* Process any pending orders and empty the VBVA ring buffer. */
633 vbvaFlush(pThis, pThisCC, pCtx);
634
635 AssertReturn(idScreen < RT_ELEMENTS(pCtx->aViews), VERR_OUT_OF_RANGE);
636 VBVADATA *pVBVAData = &pCtx->aViews[idScreen].vbva;
637 vbvaDataCleanup(pVBVAData);
638
639 if (idScreen == 0)
640 {
641 pThis->fGuestCaps = 0;
642 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
643 }
644 pThisCC->pDrv->pfnVBVADisable(pThisCC->pDrv, idScreen);
645 return VINF_SUCCESS;
646}
647
648#ifdef UNUSED_FUNCTION
649bool VBVAIsEnabled(PVGASTATECC pThisCC)
650{
651 PHGSMIINSTANCE pHGSMI = pThisCC->pHGSMI;
652 if (pHGSMI)
653 {
654 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pHGSMI);
655 if (pCtx)
656 {
657 if (pCtx->cViews)
658 {
659 VBVAVIEW * pView = &pCtx->aViews[0];
660 if (pView->vbva.guest.pVBVA)
661 return true;
662 }
663 }
664 }
665 return false;
666}
667#endif
668
669#ifdef DEBUG_sunlover
670void dumpMouseShapeInfo(const VBVAMOUSESHAPEINFO *pMouseShapeInfo)
671{
672 LogFlow(("fSet = %d, fVisible %d, fAlpha %d, @%d,%d %dx%d (%p, %d/%d)\n",
673 pMouseShapeInfo->fSet,
674 pMouseShapeInfo->fVisible,
675 pMouseShapeInfo->fAlpha,
676 pMouseShapeInfo->u32HotX,
677 pMouseShapeInfo->u32HotY,
678 pMouseShapeInfo->u32Width,
679 pMouseShapeInfo->u32Height,
680 pMouseShapeInfo->pu8Shape,
681 pMouseShapeInfo->cbShape,
682 pMouseShapeInfo->cbAllocated
683 ));
684}
685#endif
686
687static int vbvaUpdateMousePointerShape(PVGASTATECC pThisCC, VBVAMOUSESHAPEINFO *pMouseShapeInfo, bool fShape)
688{
689 LogFlowFunc(("pThisCC %p, pMouseShapeInfo %p, fShape %d\n", pThisCC, pMouseShapeInfo, fShape));
690#ifdef DEBUG_sunlover
691 dumpMouseShapeInfo(pMouseShapeInfo);
692#endif
693
694 if (pThisCC->pDrv->pfnVBVAMousePointerShape == NULL)
695 return VERR_NOT_SUPPORTED;
696
697 int rc;
698 if (fShape && pMouseShapeInfo->pu8Shape != NULL)
699 rc = pThisCC->pDrv->pfnVBVAMousePointerShape(pThisCC->pDrv,
700 pMouseShapeInfo->fVisible,
701 pMouseShapeInfo->fAlpha,
702 pMouseShapeInfo->u32HotX,
703 pMouseShapeInfo->u32HotY,
704 pMouseShapeInfo->u32Width,
705 pMouseShapeInfo->u32Height,
706 pMouseShapeInfo->pu8Shape);
707 else
708 rc = pThisCC->pDrv->pfnVBVAMousePointerShape(pThisCC->pDrv,
709 pMouseShapeInfo->fVisible,
710 false,
711 0, 0,
712 0, 0,
713 NULL);
714 return rc;
715}
716
717static int vbvaMousePointerShape(PVGASTATECC pThisCC, 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 RTMemFreeZ(pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbAllocated);
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(pThisCC, &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
856static int vboxVBVASaveDevStateExec(PCPDMDEVHLPR3 pHlp, PVGASTATE pThis, PVGASTATECC pThisCC, PSSMHANDLE pSSM)
857{
858 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
859 int rc = HGSMIHostSaveStateExec(pHlp, pIns, pSSM);
860 if (RT_SUCCESS(rc))
861 {
862 VGA_SAVED_STATE_PUT_MARKER(pSSM, 2);
863
864 /* Save VBVACONTEXT. */
865 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
866
867 if (!pCtx)
868 {
869 AssertFailed();
870
871 /* Still write a valid value to the SSM. */
872 rc = pHlp->pfnSSMPutU32 (pSSM, 0);
873 AssertRCReturn(rc, rc);
874 }
875 else
876 {
877#ifdef DEBUG_sunlover
878 dumpctx(pCtx);
879#endif
880
881 rc = pHlp->pfnSSMPutU32 (pSSM, pCtx->cViews);
882 AssertRCReturn(rc, rc);
883
884 uint32_t iView;
885 for (iView = 0; iView < pCtx->cViews; iView++)
886 {
887 VBVAVIEW *pView = &pCtx->aViews[iView];
888
889 rc = pHlp->pfnSSMPutU32(pSSM, pView->view.u32ViewIndex);
890 AssertRCReturn(rc, rc);
891 rc = pHlp->pfnSSMPutU32(pSSM, pView->view.u32ViewOffset);
892 AssertRCReturn(rc, rc);
893 rc = pHlp->pfnSSMPutU32(pSSM, pView->view.u32ViewSize);
894 AssertRCReturn(rc, rc);
895 rc = pHlp->pfnSSMPutU32(pSSM, pView->view.u32MaxScreenSize);
896 AssertRCReturn(rc, rc);
897
898 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32ViewIndex);
899 AssertRCReturn(rc, rc);
900 rc = pHlp->pfnSSMPutS32(pSSM, pView->screen.i32OriginX);
901 AssertRCReturn(rc, rc);
902 rc = pHlp->pfnSSMPutS32(pSSM, pView->screen.i32OriginY);
903 AssertRCReturn(rc, rc);
904 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32StartOffset);
905 AssertRCReturn(rc, rc);
906 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32LineSize);
907 AssertRCReturn(rc, rc);
908 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32Width);
909 AssertRCReturn(rc, rc);
910 rc = pHlp->pfnSSMPutU32(pSSM, pView->screen.u32Height);
911 AssertRCReturn(rc, rc);
912 rc = pHlp->pfnSSMPutU16(pSSM, pView->screen.u16BitsPerPixel);
913 AssertRCReturn(rc, rc);
914 rc = pHlp->pfnSSMPutU16(pSSM, pView->screen.u16Flags);
915 AssertRCReturn(rc, rc);
916
917 rc = pHlp->pfnSSMPutU32(pSSM, pView->vbva.guest.pVBVA? pView->vbva.u32VBVAOffset: HGSMIOFFSET_VOID);
918 AssertRCReturn(rc, rc);
919
920 rc = pHlp->pfnSSMPutU32(pSSM, pView->vbva.partialRecord.cb);
921 AssertRCReturn(rc, rc);
922
923 if (pView->vbva.partialRecord.cb > 0)
924 {
925 rc = pHlp->pfnSSMPutMem(pSSM, pView->vbva.partialRecord.pu8, pView->vbva.partialRecord.cb);
926 AssertRCReturn(rc, rc);
927 }
928 }
929
930 /* Save mouse pointer shape information. */
931 rc = pHlp->pfnSSMPutBool(pSSM, pCtx->mouseShapeInfo.fSet);
932 AssertRCReturn(rc, rc);
933 rc = pHlp->pfnSSMPutBool(pSSM, pCtx->mouseShapeInfo.fVisible);
934 AssertRCReturn(rc, rc);
935 rc = pHlp->pfnSSMPutBool(pSSM, pCtx->mouseShapeInfo.fAlpha);
936 AssertRCReturn(rc, rc);
937 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.u32HotX);
938 AssertRCReturn(rc, rc);
939 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.u32HotY);
940 AssertRCReturn(rc, rc);
941 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.u32Width);
942 AssertRCReturn(rc, rc);
943 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.u32Height);
944 AssertRCReturn(rc, rc);
945 rc = pHlp->pfnSSMPutU32(pSSM, pCtx->mouseShapeInfo.cbShape);
946 AssertRCReturn(rc, rc);
947 if (pCtx->mouseShapeInfo.cbShape)
948 {
949 rc = pHlp->pfnSSMPutMem(pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
950 AssertRCReturn(rc, rc);
951 }
952
953#ifdef VBOX_WITH_WDDM
954 /* Size of some additional data. For future extensions. */
955 rc = pHlp->pfnSSMPutU32(pSSM, 4);
956 AssertRCReturn(rc, rc);
957 rc = pHlp->pfnSSMPutU32(pSSM, pThis->fGuestCaps);
958 AssertRCReturn(rc, rc);
959#else
960 /* Size of some additional data. For future extensions. */
961 rc = pHlp->pfnSSMPutU32(pSSM, 0);
962 AssertRCReturn(rc, rc);
963#endif
964 rc = pHlp->pfnSSMPutU32(pSSM, RT_ELEMENTS(pCtx->aModeHints));
965 AssertRCReturn(rc, rc);
966 rc = pHlp->pfnSSMPutU32(pSSM, sizeof(VBVAMODEHINT));
967 AssertRCReturn(rc, rc);
968 for (unsigned i = 0; i < RT_ELEMENTS(pCtx->aModeHints); ++i)
969 {
970 rc = pHlp->pfnSSMPutMem(pSSM, &pCtx->aModeHints[i], sizeof(VBVAMODEHINT));
971 AssertRCReturn(rc, rc);
972 }
973 }
974 }
975
976 return rc;
977}
978
979int vboxVBVASaveStateExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
980{
981 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
982 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
983 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
984
985 return vboxVBVASaveDevStateExec(pHlp, pThis, pThisCC, pSSM);
986}
987
988int vboxVBVALoadStateExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion)
989{
990 if (uVersion < VGA_SAVEDSTATE_VERSION_HGSMI)
991 {
992 /* Nothing was saved. */
993 return VINF_SUCCESS;
994 }
995
996 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
997 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
998 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
999 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1000 int rc = HGSMIHostLoadStateExec(pHlp, pIns, pSSM, uVersion);
1001 if (RT_SUCCESS(rc))
1002 {
1003 VGA_SAVED_STATE_GET_MARKER_RETURN_ON_MISMATCH(pSSM, uVersion, 2);
1004
1005 /* Load VBVACONTEXT. */
1006 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1007
1008 if (!pCtx)
1009 {
1010 /* This should not happen. */
1011 AssertFailed();
1012 rc = VERR_INVALID_PARAMETER;
1013 }
1014 else
1015 {
1016 uint32_t cViews = 0;
1017 rc = pHlp->pfnSSMGetU32 (pSSM, &cViews);
1018 AssertRCReturn(rc, rc);
1019
1020 uint32_t iView;
1021 for (iView = 0; iView < cViews; iView++)
1022 {
1023 VBVAVIEW *pView = &pCtx->aViews[iView];
1024
1025 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32ViewIndex);
1026 AssertRCReturn(rc, rc);
1027 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32ViewOffset);
1028 AssertRCReturn(rc, rc);
1029 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32ViewSize);
1030 AssertRCReturn(rc, rc);
1031 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32MaxScreenSize);
1032 AssertRCReturn(rc, rc);
1033
1034 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32ViewIndex);
1035 AssertRCReturn(rc, rc);
1036 rc = pHlp->pfnSSMGetS32 (pSSM, &pView->screen.i32OriginX);
1037 AssertRCReturn(rc, rc);
1038 rc = pHlp->pfnSSMGetS32 (pSSM, &pView->screen.i32OriginY);
1039 AssertRCReturn(rc, rc);
1040 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32StartOffset);
1041 AssertRCReturn(rc, rc);
1042 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32LineSize);
1043 AssertRCReturn(rc, rc);
1044 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32Width);
1045 AssertRCReturn(rc, rc);
1046 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32Height);
1047 AssertRCReturn(rc, rc);
1048 rc = pHlp->pfnSSMGetU16 (pSSM, &pView->screen.u16BitsPerPixel);
1049 AssertRCReturn(rc, rc);
1050 rc = pHlp->pfnSSMGetU16 (pSSM, &pView->screen.u16Flags);
1051 AssertRCReturn(rc, rc);
1052
1053 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->vbva.u32VBVAOffset);
1054 AssertRCReturn(rc, rc);
1055
1056 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->vbva.partialRecord.cb);
1057 AssertRCReturn(rc, rc);
1058
1059 if (pView->vbva.partialRecord.cb == 0)
1060 {
1061 pView->vbva.partialRecord.pu8 = NULL;
1062 }
1063 else
1064 {
1065 Assert(pView->vbva.partialRecord.pu8 == NULL); /* Should be it. */
1066
1067 uint8_t *pu8 = (uint8_t *)RTMemAlloc(pView->vbva.partialRecord.cb);
1068
1069 if (!pu8)
1070 {
1071 return VERR_NO_MEMORY;
1072 }
1073
1074 pView->vbva.partialRecord.pu8 = pu8;
1075
1076 rc = pHlp->pfnSSMGetMem (pSSM, pView->vbva.partialRecord.pu8, pView->vbva.partialRecord.cb);
1077 AssertRCReturn(rc, rc);
1078 }
1079
1080 if (pView->vbva.u32VBVAOffset == HGSMIOFFSET_VOID)
1081 {
1082 pView->vbva.guest.pVBVA = NULL;
1083 }
1084 else
1085 {
1086 pView->vbva.guest.pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost(pIns, pView->vbva.u32VBVAOffset);
1087 }
1088 }
1089
1090 if (uVersion > VGA_SAVEDSTATE_VERSION_WITH_CONFIG)
1091 {
1092 /* Read mouse pointer shape information. */
1093 rc = pHlp->pfnSSMGetBool (pSSM, &pCtx->mouseShapeInfo.fSet);
1094 AssertRCReturn(rc, rc);
1095 rc = pHlp->pfnSSMGetBool (pSSM, &pCtx->mouseShapeInfo.fVisible);
1096 AssertRCReturn(rc, rc);
1097 rc = pHlp->pfnSSMGetBool (pSSM, &pCtx->mouseShapeInfo.fAlpha);
1098 AssertRCReturn(rc, rc);
1099 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotX);
1100 AssertRCReturn(rc, rc);
1101 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotY);
1102 AssertRCReturn(rc, rc);
1103 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32Width);
1104 AssertRCReturn(rc, rc);
1105 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32Height);
1106 AssertRCReturn(rc, rc);
1107 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.cbShape);
1108 AssertRCReturn(rc, rc);
1109 if (pCtx->mouseShapeInfo.cbShape)
1110 {
1111 pCtx->mouseShapeInfo.pu8Shape = (uint8_t *)RTMemAlloc(pCtx->mouseShapeInfo.cbShape);
1112 if (pCtx->mouseShapeInfo.pu8Shape == NULL)
1113 {
1114 return VERR_NO_MEMORY;
1115 }
1116 pCtx->mouseShapeInfo.cbAllocated = pCtx->mouseShapeInfo.cbShape;
1117 rc = pHlp->pfnSSMGetMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1118 AssertRCReturn(rc, rc);
1119 }
1120 else
1121 {
1122 pCtx->mouseShapeInfo.pu8Shape = NULL;
1123 }
1124
1125 /* Size of some additional data. For future extensions. */
1126 uint32_t cbExtra = 0;
1127 rc = pHlp->pfnSSMGetU32 (pSSM, &cbExtra);
1128 AssertRCReturn(rc, rc);
1129#ifdef VBOX_WITH_WDDM
1130 if (cbExtra >= 4)
1131 {
1132 rc = pHlp->pfnSSMGetU32 (pSSM, &pThis->fGuestCaps);
1133 AssertRCReturn(rc, rc);
1134 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
1135 cbExtra -= 4;
1136 }
1137#endif
1138 if (cbExtra > 0)
1139 {
1140 rc = pHlp->pfnSSMSkip(pSSM, cbExtra);
1141 AssertRCReturn(rc, rc);
1142 }
1143
1144 if (uVersion >= VGA_SAVEDSTATE_VERSION_MODE_HINTS)
1145 {
1146 uint32_t cModeHints, cbModeHints;
1147 rc = pHlp->pfnSSMGetU32 (pSSM, &cModeHints);
1148 AssertRCReturn(rc, rc);
1149 rc = pHlp->pfnSSMGetU32 (pSSM, &cbModeHints);
1150 AssertRCReturn(rc, rc);
1151 memset(&pCtx->aModeHints, ~0, sizeof(pCtx->aModeHints));
1152 unsigned iHint;
1153 for (iHint = 0; iHint < cModeHints; ++iHint)
1154 {
1155 if ( cbModeHints <= sizeof(VBVAMODEHINT)
1156 && iHint < RT_ELEMENTS(pCtx->aModeHints))
1157 rc = pHlp->pfnSSMGetMem(pSSM, &pCtx->aModeHints[iHint],
1158 cbModeHints);
1159 else
1160 rc = pHlp->pfnSSMSkip(pSSM, cbModeHints);
1161 AssertRCReturn(rc, rc);
1162 }
1163 }
1164 }
1165
1166 pCtx->cViews = iView;
1167 LogFlowFunc(("%d views loaded\n", pCtx->cViews));
1168
1169 if (uVersion > VGA_SAVEDSTATE_VERSION_WDDM)
1170 {
1171 /* Skip loading VHWA (2D Video Hardware Acceleration) state from older saved states. */
1172 if (uVersion < VGA_SAVEDSTATE_VERSION_VHWA_REMOVED)
1173 {
1174 bool fLoadCommands;
1175 if (uVersion < VGA_SAVEDSTATE_VERSION_FIXED_PENDVHWA)
1176 {
1177 const char *pcszOsArch = pHlp->pfnSSMHandleHostOSAndArch(pSSM);
1178 AssertPtr(pcszOsArch);
1179 fLoadCommands = !pcszOsArch || RTStrNCmp(pcszOsArch, RT_STR_TUPLE("solaris"));
1180 }
1181 else
1182 fLoadCommands = true;
1183
1184 uint32_t u32;
1185 for (uint32_t i = 0; i < pThis->cMonitors; ++i)
1186 {
1187 rc = pHlp->pfnSSMGetU32(pSSM, &u32); /* VHWA [un]available magic. */
1188 AssertRCReturn(rc, rc);
1189 }
1190
1191 /* Pending VHWA commands. */
1192 if (fLoadCommands)
1193 {
1194 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
1195 AssertRCReturn(rc, rc);
1196 for (uint32_t i = 0; i < u32; ++i)
1197 {
1198 rc = pHlp->pfnSSMSkip(pSSM, sizeof(uint32_t));
1199 AssertRCReturn(rc, rc);
1200 }
1201 }
1202 }
1203 }
1204
1205#ifdef DEBUG_sunlover
1206 dumpctx(pCtx);
1207#endif
1208 }
1209 }
1210
1211 return rc;
1212}
1213
1214int vboxVBVALoadStateDone(PPDMDEVINS pDevIns)
1215{
1216 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1217 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
1218 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1219 if (pCtx)
1220 {
1221 uint32_t iView;
1222 for (iView = 0; iView < pCtx->cViews; iView++)
1223 {
1224 VBVAVIEW *pView = &pCtx->aViews[iView];
1225 if (pView->vbva.guest.pVBVA)
1226 {
1227 int rc = vbvaEnable(pThis, pThisCC, pCtx, iView, pView->vbva.guest.pVBVA,
1228 pView->vbva.u32VBVAOffset, true /* fRestored */);
1229 if (RT_SUCCESS(rc))
1230 vbvaResize(pThisCC, pView, &pView->screen, false);
1231 else
1232 LogRel(("VBVA: can not restore: %Rrc\n", rc));
1233 }
1234 }
1235
1236 if (pCtx->mouseShapeInfo.fSet)
1237 vbvaUpdateMousePointerShape(pThisCC, &pCtx->mouseShapeInfo, true);
1238 }
1239
1240 return VINF_SUCCESS;
1241}
1242
1243void VBVARaiseIrq(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, uint32_t fFlags)
1244{
1245 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSectIRQ, VERR_SEM_BUSY);
1246 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSectIRQ, rcLock);
1247
1248 const uint32_t fu32CurrentGuestFlags = HGSMIGetHostGuestFlags(pThisCC->pHGSMI);
1249 if ((fu32CurrentGuestFlags & HGSMIHOSTFLAGS_IRQ) == 0)
1250 {
1251 /* No IRQ set yet. */
1252 Assert(pThis->fu32PendingGuestFlags == 0);
1253
1254 HGSMISetHostGuestFlags(pThisCC->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
1255
1256 /* If VM is not running, the IRQ will be set in VBVAOnResume. */
1257 const VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
1258 if ( enmVMState == VMSTATE_RUNNING
1259 || enmVMState == VMSTATE_RUNNING_LS)
1260 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1261 }
1262 else
1263 {
1264 /* IRQ already set, remember the new flags. */
1265 pThis->fu32PendingGuestFlags |= HGSMIHOSTFLAGS_IRQ | fFlags;
1266 }
1267
1268 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSectIRQ);
1269}
1270
1271void VBVAOnResume(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
1272{
1273 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSectIRQ, VERR_SEM_BUSY);
1274 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSectIRQ, rcLock);
1275
1276 if (HGSMIGetHostGuestFlags(pThisCC->pHGSMI) & HGSMIHOSTFLAGS_IRQ)
1277 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1278
1279 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSectIRQ);
1280}
1281
1282static int vbvaHandleQueryConf32(PVGASTATECC pThisCC, VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *pConf32)
1283{
1284 uint32_t const idxQuery = pConf32->u32Index;
1285 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1286 LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n", idxQuery, pConf32->u32Value));
1287
1288 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1289 uint32_t uValue;
1290 if (idxQuery == VBOX_VBVA_CONF32_MONITOR_COUNT)
1291 uValue = pCtx->cViews;
1292 else if (idxQuery == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
1293 uValue = _64K; /** @todo a value calculated from the vram size */
1294 else if ( idxQuery == VBOX_VBVA_CONF32_MODE_HINT_REPORTING
1295 || idxQuery == VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING)
1296 uValue = VINF_SUCCESS;
1297 else if (idxQuery == VBOX_VBVA_CONF32_CURSOR_CAPABILITIES)
1298 uValue = VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE;
1299 else if (idxQuery == VBOX_VBVA_CONF32_SCREEN_FLAGS)
1300 uValue = VBVA_SCREEN_F_ACTIVE
1301 | VBVA_SCREEN_F_DISABLED
1302 | VBVA_SCREEN_F_BLANK
1303 | VBVA_SCREEN_F_BLANK2;
1304 else if (idxQuery == VBOX_VBVA_CONF32_MAX_RECORD_SIZE)
1305 uValue = VBVA_MAX_RECORD_SIZE;
1306 else if (idxQuery == UINT32_MAX)
1307 uValue = UINT32_MAX; /* Older GA uses this for sanity checking. See testQueryConf in HGSMIBase.cpp on branches. */
1308 else
1309 ASSERT_GUEST_MSG_FAILED_RETURN(("Invalid index %#x\n", idxQuery), VERR_INVALID_PARAMETER);
1310
1311 pConf32->u32Value = uValue;
1312 return VINF_SUCCESS;
1313}
1314
1315static int vbvaHandleSetConf32(VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *pConf32)
1316{
1317 uint32_t const idxQuery = pConf32->u32Index;
1318 uint32_t const uValue = pConf32->u32Value;
1319 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1320 LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n", idxQuery, uValue));
1321
1322 if (idxQuery == VBOX_VBVA_CONF32_MONITOR_COUNT)
1323 { /* do nothing. this is a const. */ }
1324 else if (idxQuery == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
1325 { /* do nothing. this is a const. */ }
1326 else
1327 ASSERT_GUEST_MSG_FAILED_RETURN(("Invalid index %#x (value=%u)\n", idxQuery, uValue), VERR_INVALID_PARAMETER);
1328
1329 RT_NOREF_PV(uValue);
1330 return VINF_SUCCESS;
1331}
1332
1333static int vbvaHandleInfoHeap(PVGASTATECC pThisCC, const VBVAINFOHEAP RT_UNTRUSTED_VOLATILE_GUEST *pInfoHeap)
1334{
1335 uint32_t const offHeap = pInfoHeap->u32HeapOffset;
1336 uint32_t const cbHeap = pInfoHeap->u32HeapSize;
1337 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1338 LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n", offHeap, cbHeap));
1339
1340 return HGSMIHostHeapSetup(pThisCC->pHGSMI, offHeap, cbHeap);
1341}
1342
1343static int vbvaInfoView(PVGASTATE pThis, PVGASTATER3 pThisCC, const VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_GUEST *pView)
1344{
1345 VBVAINFOVIEW view;
1346 RT_COPY_VOLATILE(view, *pView);
1347 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1348
1349 LogFlowFunc(("VBVA_INFO_VIEW: u32ViewIndex %d, u32ViewOffset 0x%x, u32ViewSize 0x%x, u32MaxScreenSize 0x%x\n",
1350 view.u32ViewIndex, view.u32ViewOffset, view.u32ViewSize, view.u32MaxScreenSize));
1351
1352 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1353 ASSERT_GUEST_LOGREL_MSG_RETURN( view.u32ViewIndex < pCtx->cViews
1354 && view.u32ViewOffset <= pThis->vram_size
1355 && view.u32ViewSize <= pThis->vram_size
1356 && view.u32ViewOffset <= pThis->vram_size - view.u32ViewSize
1357 && view.u32MaxScreenSize <= view.u32ViewSize,
1358 ("index %d(%d), offset 0x%x, size 0x%x, max 0x%x, vram size 0x%x\n",
1359 view.u32ViewIndex, pCtx->cViews, view.u32ViewOffset, view.u32ViewSize,
1360 view.u32MaxScreenSize, pThis->vram_size),
1361 VERR_INVALID_PARAMETER);
1362 RT_UNTRUSTED_VALIDATED_FENCE();
1363
1364 pCtx->aViews[view.u32ViewIndex].view = view;
1365 return VINF_SUCCESS;
1366}
1367
1368static int vbvaInfoScreen(PVGASTATECC pThisCC, const VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_GUEST *pScreen)
1369{
1370 /*
1371 * Copy input into non-volatile buffer.
1372 */
1373 VBVAINFOSCREEN screen;
1374 RT_COPY_VOLATILE(screen, *pScreen);
1375 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1376 LogRel2(("VBVA: InfoScreen: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
1377 screen.u32ViewIndex, screen.i32OriginX, screen.i32OriginY,
1378 screen.u32Width, screen.u32Height,
1379 screen.u32LineSize, screen.u16BitsPerPixel, screen.u16Flags));
1380
1381 /*
1382 * Validate input.
1383 */
1384 /* Allow screen.u16BitsPerPixel == 0 because legacy guest code used it for screen blanking. */
1385 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1386 ASSERT_GUEST_LOGREL_MSG_RETURN(screen.u32ViewIndex < pCtx->cViews,
1387 ("Screen index %#x is out of bound (cViews=%#x)\n", screen.u32ViewIndex, pCtx->cViews),
1388 VERR_INVALID_PARAMETER);
1389 ASSERT_GUEST_LOGREL_MSG_RETURN( screen.u16BitsPerPixel <= 32
1390 && screen.u32Width <= UINT16_MAX
1391 && screen.u32Height <= UINT16_MAX
1392 && screen.u32LineSize <= UINT16_MAX * UINT32_C(4),
1393 ("One or more values out of range: u16BitsPerPixel=%#x u32Width=%#x u32Height=%#x u32LineSize=%#x\n",
1394 screen.u16BitsPerPixel, screen.u32Width, screen.u32Height, screen.u32LineSize),
1395 VERR_INVALID_PARAMETER);
1396 RT_UNTRUSTED_VALIDATED_FENCE();
1397
1398 const VBVAINFOVIEW *pView = &pCtx->aViews[screen.u32ViewIndex].view;
1399 const uint32_t cbPerPixel = (screen.u16BitsPerPixel + 7) / 8;
1400 ASSERT_GUEST_LOGREL_MSG_RETURN(screen.u32Width <= screen.u32LineSize / (cbPerPixel ? cbPerPixel : 1),
1401 ("u32Width=%#x u32LineSize=%3x cbPerPixel=%#x\n",
1402 screen.u32Width, screen.u32LineSize, cbPerPixel),
1403 VERR_INVALID_PARAMETER);
1404
1405 const uint64_t u64ScreenSize = (uint64_t)screen.u32LineSize * screen.u32Height;
1406
1407 ASSERT_GUEST_LOGREL_MSG_RETURN( screen.u32StartOffset <= pView->u32ViewSize
1408 && u64ScreenSize <= pView->u32MaxScreenSize
1409 && screen.u32StartOffset <= pView->u32ViewSize - (uint32_t)u64ScreenSize,
1410 ("u32StartOffset=%#x u32ViewSize=%#x u64ScreenSize=%#RX64 u32MaxScreenSize=%#x\n",
1411 screen.u32StartOffset, pView->u32ViewSize, u64ScreenSize, pView->u32MaxScreenSize),
1412 VERR_INVALID_PARAMETER);
1413 RT_UNTRUSTED_VALIDATED_FENCE();
1414
1415 /*
1416 * Do the job.
1417 */
1418 vbvaResize(pThisCC, &pCtx->aViews[screen.u32ViewIndex], &screen, true);
1419 return VINF_SUCCESS;
1420}
1421
1422#ifdef UNUSED_FUNCTION
1423int VBVAGetInfoViewAndScreen(PVGASTATE pThis, PVGASTATECC pThisCC, uint32_t u32ViewIndex, VBVAINFOVIEW *pView, VBVAINFOSCREEN *pScreen)
1424{
1425 if (u32ViewIndex >= pThis->cMonitors)
1426 return VERR_INVALID_PARAMETER;
1427
1428 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1429 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1430
1431 if (pView)
1432 *pView = pCtx->aViews[u32ViewIndex].view;
1433
1434 if (pScreen)
1435 *pScreen = pCtx->aViews[u32ViewIndex].screen;
1436
1437 return VINF_SUCCESS;
1438}
1439#endif
1440
1441static int vbvaHandleEnable(PVGASTATE pThis, PVGASTATER3 pThisCC, uint32_t fEnableFlags, uint32_t offEnable, uint32_t idScreen)
1442{
1443 LogFlowFunc(("VBVA_ENABLE[%u]: fEnableFlags=0x%x offEnable=%#x\n", idScreen, fEnableFlags, offEnable));
1444 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1445 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pIns);
1446
1447 /*
1448 * Validate input.
1449 */
1450 ASSERT_GUEST_LOGREL_MSG_RETURN(idScreen < pCtx->cViews, ("idScreen=%#x cViews=%#x\n", idScreen, pCtx->cViews), VERR_INVALID_PARAMETER);
1451 ASSERT_GUEST_LOGREL_MSG_RETURN( (fEnableFlags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE
1452 || (fEnableFlags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE,
1453 ("fEnableFlags=%#x\n", fEnableFlags),
1454 VERR_INVALID_PARAMETER);
1455 if (fEnableFlags & VBVA_F_ENABLE)
1456 {
1457 ASSERT_GUEST_LOGREL_MSG_RETURN(offEnable < pThis->vram_size,
1458 ("offEnable=%#x vram_size=%#x\n", offEnable, pThis->vram_size),
1459 VERR_INVALID_PARAMETER);
1460 if (fEnableFlags & VBVA_F_ABSOFFSET)
1461 /* Offset from VRAM start. */
1462 ASSERT_GUEST_LOGREL_MSG_RETURN( pThis->vram_size >= RT_UOFFSETOF(VBVABUFFER, au8Data)
1463 && offEnable <= pThis->vram_size - RT_UOFFSETOF(VBVABUFFER, au8Data),
1464 ("offEnable=%#x vram_size=%#x\n", offEnable, pThis->vram_size),
1465 VERR_INVALID_PARAMETER);
1466 else
1467 {
1468 /* Offset from the view start. We'd be using idScreen here to fence required. */
1469 RT_UNTRUSTED_VALIDATED_FENCE();
1470 const VBVAINFOVIEW *pView = &pCtx->aViews[idScreen].view;
1471 ASSERT_GUEST_LOGREL_MSG_RETURN( pThis->vram_size - offEnable >= pView->u32ViewOffset
1472 && pView->u32ViewSize >= RT_UOFFSETOF(VBVABUFFER, au8Data)
1473 && offEnable <= pView->u32ViewSize - RT_UOFFSETOF(VBVABUFFER, au8Data),
1474 ("offEnable=%#x vram_size=%#x view: %#x LB %#x\n",
1475 offEnable, pThis->vram_size, pView->u32ViewOffset, pView->u32ViewSize),
1476 VERR_INVALID_PARAMETER);
1477 offEnable += pView->u32ViewOffset;
1478 }
1479 ASSERT_GUEST_LOGREL_MSG_RETURN(HGSMIIsOffsetValid(pIns, offEnable),
1480 ("offEnable=%#x area %#x LB %#x\n",
1481 offEnable, HGSMIGetAreaOffset(pIns), HGSMIGetAreaSize(pIns)),
1482 VERR_INVALID_PARAMETER);
1483 }
1484 RT_UNTRUSTED_VALIDATED_FENCE();
1485
1486 /*
1487 * Execute.
1488 */
1489 int rc = VINF_SUCCESS;
1490 if (fEnableFlags & VBVA_F_ENABLE)
1491 {
1492 VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *pVBVA
1493 = (VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *)HGSMIOffsetToPointerHost(pIns, offEnable);
1494 ASSERT_GUEST_LOGREL_RETURN(pVBVA, VERR_INVALID_PARAMETER); /* already check above, but let's be careful. */
1495
1496 /* Process any pending orders and empty the VBVA ring buffer. */
1497 vbvaFlush(pThis, pThisCC, pCtx);
1498
1499 rc = vbvaEnable(pThis, pThisCC, pCtx, idScreen, pVBVA, offEnable, false /* fRestored */);
1500 if (RT_FAILURE(rc))
1501 LogRelMax(8, ("VBVA: can not enable: %Rrc\n", rc));
1502 }
1503 else
1504 rc = vbvaDisable(pThis, pThisCC, pCtx, idScreen);
1505 return rc;
1506}
1507
1508static int vbvaHandleQueryModeHints(PVGASTATECC pThisCC, VBVAQUERYMODEHINTS volatile *pQueryModeHints, HGSMISIZE cbBuffer)
1509{
1510 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1511 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pIns);
1512
1513 /*
1514 * Copy and validate the request.
1515 */
1516 uint16_t const cHintsQueried = pQueryModeHints->cHintsQueried;
1517 uint16_t const cbHintStructureGuest = pQueryModeHints->cbHintStructureGuest;
1518 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1519
1520 LogRelFlowFunc(("VBVA: HandleQueryModeHints: cHintsQueried=%RU16, cbHintStructureGuest=%RU16\n",
1521 cHintsQueried, cbHintStructureGuest));
1522 ASSERT_GUEST_RETURN(cbBuffer >= sizeof(VBVAQUERYMODEHINTS) + (uint32_t)cHintsQueried * cbHintStructureGuest,
1523 VERR_INVALID_PARAMETER);
1524 RT_UNTRUSTED_VALIDATED_FENCE();
1525
1526 /*
1527 * Produce the requested data.
1528 */
1529 uint8_t *pbHint = (uint8_t *)(pQueryModeHints + 1);
1530 memset(pbHint, ~0, cbBuffer - sizeof(VBVAQUERYMODEHINTS));
1531
1532 for (unsigned iHint = 0; iHint < cHintsQueried && iHint < VBOX_VIDEO_MAX_SCREENS; ++iHint)
1533 {
1534 memcpy(pbHint, &pCtx->aModeHints[iHint], RT_MIN(cbHintStructureGuest, sizeof(VBVAMODEHINT)));
1535 pbHint += cbHintStructureGuest;
1536 Assert((uintptr_t)(pbHint - (uint8_t *)pQueryModeHints) <= cbBuffer);
1537 }
1538
1539 return VINF_SUCCESS;
1540}
1541
1542/*
1543 *
1544 * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
1545 *
1546 * VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
1547 * Read Write
1548 * Host port 0x3b0 to process completed
1549 * Guest port 0x3d0 control value? to process
1550 *
1551 */
1552
1553static DECLCALLBACK(void) vbvaNotifyGuest(void *pvCallback)
1554{
1555#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
1556 PPDMDEVINS pDevIns = (PPDMDEVINS)pvCallback;
1557 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1558 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
1559 VBVARaiseIrq(pDevIns, pThis, pThisCC, 0);
1560#else
1561 NOREF(pvCallback);
1562 /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */
1563#endif
1564}
1565
1566/**
1567 * The guest submitted a command buffer (hit VGA_PORT_HGSMI_GUEST).
1568 *
1569 * Verify the buffer size and invoke corresponding handler.
1570 *
1571 * @return VBox status code.
1572 * @param pvHandler The VBVA channel context.
1573 * @param u16ChannelInfo Command code.
1574 * @param pvBuffer HGSMI buffer with command data. Considered volatile!
1575 * @param cbBuffer Size of command data.
1576 *
1577 * @thread EMT
1578 */
1579static DECLCALLBACK(int) vbvaChannelHandler(void *pvHandler, uint16_t u16ChannelInfo,
1580 void RT_UNTRUSTED_VOLATILE_GUEST *pvBuffer, HGSMISIZE cbBuffer)
1581{
1582 int rc = VINF_SUCCESS;
1583
1584 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n", pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
1585
1586 PPDMDEVINS pDevIns = (PPDMDEVINS)pvHandler;
1587 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1588 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
1589 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1590 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pIns);
1591
1592 switch (u16ChannelInfo)
1593 {
1594#ifdef VBOX_WITH_VDMA
1595 case VBVA_VDMA_CMD:
1596 if (cbBuffer >= VBoxSHGSMIBufferHeaderSize() + sizeof(VBOXVDMACBUF_DR))
1597 {
1598 VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_GUEST *pCmd
1599 = (VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_GUEST *)VBoxSHGSMIBufferData((VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1600 vboxVDMACommand(pThisCC->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1601 rc = VINF_SUCCESS;
1602 }
1603 else
1604 rc = VERR_INVALID_PARAMETER;
1605 break;
1606
1607 case VBVA_VDMA_CTL:
1608 if (cbBuffer >= VBoxSHGSMIBufferHeaderSize() + sizeof(VBOXVDMA_CTL))
1609 {
1610 VBOXVDMA_CTL RT_UNTRUSTED_VOLATILE_GUEST *pCmd
1611 = (VBOXVDMA_CTL RT_UNTRUSTED_VOLATILE_GUEST *)VBoxSHGSMIBufferData((VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1612 vboxVDMAControl(pThisCC->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1613 }
1614 else
1615 rc = VERR_INVALID_PARAMETER;
1616 break;
1617#endif /* VBOX_WITH_VDMA */
1618
1619 case VBVA_QUERY_CONF32:
1620 if (cbBuffer >= sizeof(VBVACONF32))
1621 rc = vbvaHandleQueryConf32(pThisCC, (VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1622 else
1623 rc = VERR_INVALID_PARAMETER;
1624 break;
1625
1626 case VBVA_SET_CONF32:
1627 if (cbBuffer >= sizeof(VBVACONF32))
1628 rc = vbvaHandleSetConf32((VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1629 else
1630 rc = VERR_INVALID_PARAMETER;
1631 break;
1632
1633 case VBVA_INFO_VIEW:
1634 /* Expect at least one VBVAINFOVIEW structure. */
1635 rc = VERR_INVALID_PARAMETER;
1636 if (cbBuffer >= sizeof(VBVAINFOVIEW))
1637 {
1638 /* Guest submits an array of VBVAINFOVIEW structures. */
1639 const VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_GUEST *pView = (VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1640 for (;
1641 cbBuffer >= sizeof(VBVAINFOVIEW);
1642 ++pView, cbBuffer -= sizeof(VBVAINFOVIEW))
1643 {
1644 rc = vbvaInfoView(pThis, pThisCC, pView);
1645 if (RT_FAILURE(rc))
1646 break;
1647 }
1648 }
1649 break;
1650
1651 case VBVA_INFO_HEAP:
1652 if (cbBuffer >= sizeof(VBVAINFOHEAP))
1653 rc = vbvaHandleInfoHeap(pThisCC, (VBVAINFOHEAP RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1654 else
1655 rc = VERR_INVALID_PARAMETER;
1656 break;
1657
1658 case VBVA_FLUSH:
1659 if (cbBuffer >= sizeof(VBVAFLUSH))
1660 rc = vbvaFlush(pThis, pThisCC, pCtx);
1661 else
1662 rc = VERR_INVALID_PARAMETER;
1663 break;
1664
1665 case VBVA_INFO_SCREEN:
1666 rc = VERR_INVALID_PARAMETER;
1667 if (cbBuffer >= sizeof(VBVAINFOSCREEN))
1668 rc = vbvaInfoScreen(pThisCC, (VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1669 break;
1670
1671 case VBVA_ENABLE:
1672 rc = VERR_INVALID_PARAMETER;
1673 if (cbBuffer >= sizeof(VBVAENABLE))
1674 {
1675 VBVAENABLE RT_UNTRUSTED_VOLATILE_GUEST *pVbvaEnable = (VBVAENABLE RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1676 uint32_t const fEnableFlags = pVbvaEnable->u32Flags;
1677 uint32_t const offEnable = pVbvaEnable->u32Offset;
1678 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1679
1680 uint32_t idScreen;
1681 if (fEnableFlags & VBVA_F_EXTENDED)
1682 {
1683 ASSERT_GUEST_STMT_BREAK(cbBuffer >= sizeof(VBVAENABLE_EX), rc = VERR_INVALID_PARAMETER);
1684 idScreen = ((VBVAENABLE_EX RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer)->u32ScreenId;
1685 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1686 }
1687 else
1688 idScreen = vbvaViewFromBufferPtr(pIns, pCtx, pvBuffer);
1689
1690 rc = vbvaHandleEnable(pThis, pThisCC, fEnableFlags, offEnable, idScreen);
1691 pVbvaEnable->i32Result = rc;
1692 }
1693 break;
1694
1695 case VBVA_MOUSE_POINTER_SHAPE:
1696 if (cbBuffer >= sizeof(VBVAMOUSEPOINTERSHAPE))
1697 {
1698 VBVAMOUSEPOINTERSHAPE RT_UNTRUSTED_VOLATILE_GUEST *pShape
1699 = (VBVAMOUSEPOINTERSHAPE RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1700 rc = vbvaMousePointerShape(pThisCC, pCtx, pShape, cbBuffer);
1701 pShape->i32Result = rc;
1702 }
1703 else
1704 rc = VERR_INVALID_PARAMETER;
1705 break;
1706
1707#ifdef VBOX_WITH_WDDM
1708 case VBVA_INFO_CAPS:
1709 if (cbBuffer >= sizeof(VBVACAPS))
1710 {
1711 VBVACAPS RT_UNTRUSTED_VOLATILE_GUEST *pCaps = (VBVACAPS RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1712 pThis->fGuestCaps = pCaps->fCaps;
1713 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1714
1715 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
1716 pCaps->rc = rc = VINF_SUCCESS;
1717 }
1718 else
1719 rc = VERR_INVALID_PARAMETER;
1720 break;
1721#endif
1722
1723 case VBVA_SCANLINE_CFG:
1724 if (cbBuffer >= sizeof(VBVASCANLINECFG))
1725 {
1726 VBVASCANLINECFG RT_UNTRUSTED_VOLATILE_GUEST *pCfg = (VBVASCANLINECFG RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1727 pThis->fScanLineCfg = pCfg->fFlags;
1728 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1729
1730 pCfg->rc = rc = VINF_SUCCESS;
1731 }
1732 else
1733 rc = VERR_INVALID_PARAMETER;
1734 break;
1735
1736 case VBVA_QUERY_MODE_HINTS:
1737 if (cbBuffer >= sizeof(VBVAQUERYMODEHINTS))
1738 {
1739 VBVAQUERYMODEHINTS RT_UNTRUSTED_VOLATILE_GUEST *pQueryModeHints
1740 = (VBVAQUERYMODEHINTS RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1741 rc = vbvaHandleQueryModeHints(pThisCC, pQueryModeHints, cbBuffer);
1742 pQueryModeHints->rc = rc;
1743 }
1744 else
1745 rc = VERR_INVALID_PARAMETER;
1746 break;
1747
1748 case VBVA_REPORT_INPUT_MAPPING:
1749 if (cbBuffer >= sizeof(VBVAREPORTINPUTMAPPING))
1750 {
1751 VBVAREPORTINPUTMAPPING inputMapping;
1752 {
1753 VBVAREPORTINPUTMAPPING RT_UNTRUSTED_VOLATILE_GUEST *pInputMapping
1754 = (VBVAREPORTINPUTMAPPING RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1755 inputMapping.x = pInputMapping->x;
1756 inputMapping.y = pInputMapping->y;
1757 inputMapping.cx = pInputMapping->cx;
1758 inputMapping.cy = pInputMapping->cy;
1759 }
1760 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1761
1762 LogRelFlowFunc(("VBVA: ChannelHandler: VBVA_REPORT_INPUT_MAPPING: x=%RI32, y=%RI32, cx=%RU32, cy=%RU32\n",
1763 inputMapping.x, inputMapping.y, inputMapping.cx, inputMapping.cy));
1764 pThisCC->pDrv->pfnVBVAInputMappingUpdate(pThisCC->pDrv,
1765 inputMapping.x, inputMapping.y,
1766 inputMapping.cx, inputMapping.cy);
1767 rc = VINF_SUCCESS;
1768 }
1769 else
1770 rc = VERR_INVALID_PARAMETER;
1771 break;
1772
1773 case VBVA_CURSOR_POSITION:
1774 if (cbBuffer >= sizeof(VBVACURSORPOSITION))
1775 {
1776 VBVACURSORPOSITION RT_UNTRUSTED_VOLATILE_GUEST *pReport = (VBVACURSORPOSITION RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1777 VBVACURSORPOSITION Report;
1778 Report.fReportPosition = pReport->fReportPosition;
1779 Report.x = pReport->x;
1780 Report.y = pReport->y;
1781 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1782
1783 LogRelFlowFunc(("VBVA: ChannelHandler: VBVA_CURSOR_POSITION: fReportPosition=%RTbool, Id=%RU32, x=%RU32, y=%RU32\n",
1784 RT_BOOL(Report.fReportPosition), vbvaViewFromBufferPtr(pIns, pCtx, pvBuffer), Report.x, Report.y));
1785
1786 pThisCC->pDrv->pfnVBVAReportCursorPosition(pThisCC->pDrv, RT_BOOL(Report.fReportPosition), vbvaViewFromBufferPtr(pIns, pCtx, pvBuffer), Report.x, Report.y);
1787 /* This was only ever briefly used by the guest, and a value
1788 * of zero in both was taken to mean "ignore". */
1789 pReport->x = 0;
1790 pReport->y = 0;
1791 rc = VINF_SUCCESS;
1792 }
1793 else
1794 rc = VERR_INVALID_PARAMETER;
1795 break;
1796
1797 default:
1798 Log(("Unsupported VBVA guest command %d (%#x)!!!\n", u16ChannelInfo, u16ChannelInfo));
1799 break;
1800 }
1801
1802 return rc;
1803}
1804
1805/** When VBVA is paused, the VGA device is allowed to work but
1806 * no HGSMI etc state is changed.
1807 */
1808static void vbvaPause(PVGASTATECC pThisCC, bool fPause)
1809{
1810 if (!pThisCC || !pThisCC->pHGSMI)
1811 return;
1812
1813 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1814 if (pCtx)
1815 pCtx->fPaused = fPause;
1816}
1817
1818bool VBVAIsPaused(PVGASTATECC pThisCC)
1819{
1820 if (pThisCC && pThisCC->pHGSMI)
1821 {
1822 const VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1823 if (pCtx && pCtx->cViews)
1824 {
1825 /* If VBVA is enabled at all. */
1826 const VBVAVIEW *pView = &pCtx->aViews[0];
1827 if (pView->vbva.guest.pVBVA)
1828 return pCtx->fPaused;
1829 }
1830 }
1831 /* VBVA is disabled. */
1832 return true;
1833}
1834
1835void VBVAOnVBEChanged(PVGASTATE pThis, PVGASTATECC pThisCC)
1836{
1837 /* The guest does not depend on host handling the VBE registers. */
1838 if (pThis->fGuestCaps & VBVACAPS_USE_VBVA_ONLY)
1839 return;
1840
1841 vbvaPause(pThisCC, (pThis->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) == 0);
1842}
1843
1844void VBVAReset(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
1845{
1846 if (!pThis || !pThisCC->pHGSMI)
1847 return;
1848
1849 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1850
1851 HGSMIReset(pThisCC->pHGSMI);
1852 /* Make sure the IRQ is reset. */
1853 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_LOW);
1854 pThis->fu32PendingGuestFlags = 0;
1855
1856 if (pCtx)
1857 {
1858 vbvaFlush(pThis, pThisCC, pCtx);
1859
1860 for (unsigned idScreen = 0; idScreen < pCtx->cViews; idScreen++)
1861 vbvaDisable(pThis, pThisCC, pCtx, idScreen);
1862
1863 pCtx->mouseShapeInfo.fSet = false;
1864 RTMemFreeZ(pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbAllocated);
1865 pCtx->mouseShapeInfo.pu8Shape = NULL;
1866 pCtx->mouseShapeInfo.cbAllocated = 0;
1867 pCtx->mouseShapeInfo.cbShape = 0;
1868 }
1869
1870}
1871
1872int VBVAUpdateDisplay(PVGASTATE pThis, PVGASTATECC pThisCC)
1873{
1874 int rc = VERR_NOT_SUPPORTED; /* Assuming that the VGA device will have to do updates. */
1875
1876 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1877 if (pCtx)
1878 {
1879 if (!pCtx->fPaused)
1880 {
1881 rc = vbvaFlush(pThis, pThisCC, pCtx);
1882 if (RT_SUCCESS(rc))
1883 {
1884 if (!pCtx->aViews[0].vbva.guest.pVBVA)
1885 {
1886 /* VBVA is not enabled for the first view, so VGA device must do updates. */
1887 rc = VERR_NOT_SUPPORTED;
1888 }
1889 }
1890 }
1891 }
1892
1893 return rc;
1894}
1895
1896static int vbvaSendModeHintWorker(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
1897 uint32_t cx, uint32_t cy, uint32_t cBPP, uint32_t iDisplay, uint32_t dx,
1898 uint32_t dy, uint32_t fEnabled,
1899 uint32_t fNotifyGuest)
1900{
1901 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1902 /** @note See Display::setVideoModeHint: "It is up to the guest to decide
1903 * whether the hint is valid. Therefore don't do any VRAM sanity checks
1904 * here! */
1905 if (iDisplay >= RT_MIN(pThis->cMonitors, RT_ELEMENTS(pCtx->aModeHints)))
1906 return VERR_OUT_OF_RANGE;
1907 pCtx->aModeHints[iDisplay].magic = VBVAMODEHINT_MAGIC;
1908 pCtx->aModeHints[iDisplay].cx = cx;
1909 pCtx->aModeHints[iDisplay].cy = cy;
1910 pCtx->aModeHints[iDisplay].cBPP = cBPP;
1911 pCtx->aModeHints[iDisplay].dx = dx;
1912 pCtx->aModeHints[iDisplay].dy = dy;
1913 pCtx->aModeHints[iDisplay].fEnabled = fEnabled;
1914 if (fNotifyGuest && pThis->fGuestCaps & VBVACAPS_IRQ && pThis->fGuestCaps & VBVACAPS_VIDEO_MODE_HINTS)
1915 VBVARaiseIrq(pDevIns, pThis, pThisCC, HGSMIHOSTFLAGS_HOTPLUG);
1916 return VINF_SUCCESS;
1917}
1918
1919
1920/**
1921 * @interface_method_impl{PDMIDISPLAYPORT,pfnSendModeHint}
1922 */
1923DECLCALLBACK(int) vbvaR3PortSendModeHint(PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy, uint32_t cBPP,
1924 uint32_t iDisplay, uint32_t dx, uint32_t dy, uint32_t fEnabled, uint32_t fNotifyGuest)
1925{
1926 PVGASTATECC pThisCC = RT_FROM_MEMBER(pInterface, VGASTATECC, IPort);
1927 PPDMDEVINS pDevIns = pThisCC->pDevIns;
1928 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1929 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
1930 AssertRCReturn(rc, rc);
1931
1932 rc = vbvaSendModeHintWorker(pDevIns, pThis, pThisCC, cx, cy, cBPP, iDisplay, dx, dy, fEnabled, fNotifyGuest);
1933
1934 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
1935 return rc;
1936}
1937
1938int VBVAInit(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
1939{
1940 int rc = HGSMICreate(&pThisCC->pHGSMI,
1941 pDevIns,
1942 "VBVA",
1943 0,
1944 pThisCC->pbVRam,
1945 pThis->vram_size,
1946 vbvaNotifyGuest,
1947 pDevIns,
1948 sizeof(VBVACONTEXT));
1949 if (RT_SUCCESS(rc))
1950 {
1951 rc = HGSMIHostChannelRegister(pThisCC->pHGSMI,
1952 HGSMI_CH_VBVA,
1953 vbvaChannelHandler,
1954 pDevIns);
1955 if (RT_SUCCESS(rc))
1956 {
1957 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1958 pCtx->cViews = pThis->cMonitors;
1959 pCtx->fPaused = true;
1960 memset(pCtx->aModeHints, ~0, sizeof(pCtx->aModeHints));
1961 }
1962 }
1963
1964 return rc;
1965
1966}
1967
1968void VBVADestroy(PVGASTATECC pThisCC)
1969{
1970 PHGSMIINSTANCE pHgsmi = pThisCC->pHGSMI;
1971 if (pHgsmi)
1972 {
1973 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pHgsmi);
1974 pCtx->mouseShapeInfo.fSet = false;
1975 RTMemFreeZ(pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbAllocated);
1976 pCtx->mouseShapeInfo.pu8Shape = NULL;
1977 pCtx->mouseShapeInfo.cbAllocated = 0;
1978 pCtx->mouseShapeInfo.cbShape = 0;
1979
1980 HGSMIDestroy(pHgsmi);
1981 pThisCC->pHGSMI = NULL;
1982 }
1983}
1984
Note: See TracBrowser for help on using the repository browser.

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