VirtualBox

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

Last change on this file since 108641 was 108641, checked in by vboxsync, 4 weeks ago

Removed 2D video acceleration (aka VHWA / VBOX_WITH_VIDEOHWACCEL). bugref:10756

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 75.9 KB
Line 
1/* $Id: DevVGA_VBVA.cpp 108641 2025-03-20 12:48:42Z 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 int rc = vboxVBVASaveDevStateExec(pHlp, pThis, pThisCC, pSSM);
986 if (RT_SUCCESS(rc))
987 {
988 for (uint32_t i = 0; i < pThis->cMonitors; ++i)
989 {
990 rc = pHlp->pfnSSMPutU32(pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC);
991 AssertRCReturn(rc, rc);
992 }
993 }
994
995 /* no pending commands */
996 pHlp->pfnSSMPutU32(pSSM, 0);
997
998 return rc;
999}
1000
1001int vboxVBVALoadStateExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion)
1002{
1003 if (uVersion < VGA_SAVEDSTATE_VERSION_HGSMI)
1004 {
1005 /* Nothing was saved. */
1006 return VINF_SUCCESS;
1007 }
1008
1009 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1010 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
1011 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1012 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1013 int rc = HGSMIHostLoadStateExec(pHlp, pIns, pSSM, uVersion);
1014 if (RT_SUCCESS(rc))
1015 {
1016 VGA_SAVED_STATE_GET_MARKER_RETURN_ON_MISMATCH(pSSM, uVersion, 2);
1017
1018 /* Load VBVACONTEXT. */
1019 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1020
1021 if (!pCtx)
1022 {
1023 /* This should not happen. */
1024 AssertFailed();
1025 rc = VERR_INVALID_PARAMETER;
1026 }
1027 else
1028 {
1029 uint32_t cViews = 0;
1030 rc = pHlp->pfnSSMGetU32 (pSSM, &cViews);
1031 AssertRCReturn(rc, rc);
1032
1033 uint32_t iView;
1034 for (iView = 0; iView < cViews; iView++)
1035 {
1036 VBVAVIEW *pView = &pCtx->aViews[iView];
1037
1038 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32ViewIndex);
1039 AssertRCReturn(rc, rc);
1040 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32ViewOffset);
1041 AssertRCReturn(rc, rc);
1042 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32ViewSize);
1043 AssertRCReturn(rc, rc);
1044 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->view.u32MaxScreenSize);
1045 AssertRCReturn(rc, rc);
1046
1047 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32ViewIndex);
1048 AssertRCReturn(rc, rc);
1049 rc = pHlp->pfnSSMGetS32 (pSSM, &pView->screen.i32OriginX);
1050 AssertRCReturn(rc, rc);
1051 rc = pHlp->pfnSSMGetS32 (pSSM, &pView->screen.i32OriginY);
1052 AssertRCReturn(rc, rc);
1053 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32StartOffset);
1054 AssertRCReturn(rc, rc);
1055 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32LineSize);
1056 AssertRCReturn(rc, rc);
1057 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32Width);
1058 AssertRCReturn(rc, rc);
1059 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->screen.u32Height);
1060 AssertRCReturn(rc, rc);
1061 rc = pHlp->pfnSSMGetU16 (pSSM, &pView->screen.u16BitsPerPixel);
1062 AssertRCReturn(rc, rc);
1063 rc = pHlp->pfnSSMGetU16 (pSSM, &pView->screen.u16Flags);
1064 AssertRCReturn(rc, rc);
1065
1066 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->vbva.u32VBVAOffset);
1067 AssertRCReturn(rc, rc);
1068
1069 rc = pHlp->pfnSSMGetU32 (pSSM, &pView->vbva.partialRecord.cb);
1070 AssertRCReturn(rc, rc);
1071
1072 if (pView->vbva.partialRecord.cb == 0)
1073 {
1074 pView->vbva.partialRecord.pu8 = NULL;
1075 }
1076 else
1077 {
1078 Assert(pView->vbva.partialRecord.pu8 == NULL); /* Should be it. */
1079
1080 uint8_t *pu8 = (uint8_t *)RTMemAlloc(pView->vbva.partialRecord.cb);
1081
1082 if (!pu8)
1083 {
1084 return VERR_NO_MEMORY;
1085 }
1086
1087 pView->vbva.partialRecord.pu8 = pu8;
1088
1089 rc = pHlp->pfnSSMGetMem (pSSM, pView->vbva.partialRecord.pu8, pView->vbva.partialRecord.cb);
1090 AssertRCReturn(rc, rc);
1091 }
1092
1093 if (pView->vbva.u32VBVAOffset == HGSMIOFFSET_VOID)
1094 {
1095 pView->vbva.guest.pVBVA = NULL;
1096 }
1097 else
1098 {
1099 pView->vbva.guest.pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost(pIns, pView->vbva.u32VBVAOffset);
1100 }
1101 }
1102
1103 if (uVersion > VGA_SAVEDSTATE_VERSION_WITH_CONFIG)
1104 {
1105 /* Read mouse pointer shape information. */
1106 rc = pHlp->pfnSSMGetBool (pSSM, &pCtx->mouseShapeInfo.fSet);
1107 AssertRCReturn(rc, rc);
1108 rc = pHlp->pfnSSMGetBool (pSSM, &pCtx->mouseShapeInfo.fVisible);
1109 AssertRCReturn(rc, rc);
1110 rc = pHlp->pfnSSMGetBool (pSSM, &pCtx->mouseShapeInfo.fAlpha);
1111 AssertRCReturn(rc, rc);
1112 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotX);
1113 AssertRCReturn(rc, rc);
1114 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotY);
1115 AssertRCReturn(rc, rc);
1116 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32Width);
1117 AssertRCReturn(rc, rc);
1118 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.u32Height);
1119 AssertRCReturn(rc, rc);
1120 rc = pHlp->pfnSSMGetU32 (pSSM, &pCtx->mouseShapeInfo.cbShape);
1121 AssertRCReturn(rc, rc);
1122 if (pCtx->mouseShapeInfo.cbShape)
1123 {
1124 pCtx->mouseShapeInfo.pu8Shape = (uint8_t *)RTMemAlloc(pCtx->mouseShapeInfo.cbShape);
1125 if (pCtx->mouseShapeInfo.pu8Shape == NULL)
1126 {
1127 return VERR_NO_MEMORY;
1128 }
1129 pCtx->mouseShapeInfo.cbAllocated = pCtx->mouseShapeInfo.cbShape;
1130 rc = pHlp->pfnSSMGetMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1131 AssertRCReturn(rc, rc);
1132 }
1133 else
1134 {
1135 pCtx->mouseShapeInfo.pu8Shape = NULL;
1136 }
1137
1138 /* Size of some additional data. For future extensions. */
1139 uint32_t cbExtra = 0;
1140 rc = pHlp->pfnSSMGetU32 (pSSM, &cbExtra);
1141 AssertRCReturn(rc, rc);
1142#ifdef VBOX_WITH_WDDM
1143 if (cbExtra >= 4)
1144 {
1145 rc = pHlp->pfnSSMGetU32 (pSSM, &pThis->fGuestCaps);
1146 AssertRCReturn(rc, rc);
1147 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
1148 cbExtra -= 4;
1149 }
1150#endif
1151 if (cbExtra > 0)
1152 {
1153 rc = pHlp->pfnSSMSkip(pSSM, cbExtra);
1154 AssertRCReturn(rc, rc);
1155 }
1156
1157 if (uVersion >= VGA_SAVEDSTATE_VERSION_MODE_HINTS)
1158 {
1159 uint32_t cModeHints, cbModeHints;
1160 rc = pHlp->pfnSSMGetU32 (pSSM, &cModeHints);
1161 AssertRCReturn(rc, rc);
1162 rc = pHlp->pfnSSMGetU32 (pSSM, &cbModeHints);
1163 AssertRCReturn(rc, rc);
1164 memset(&pCtx->aModeHints, ~0, sizeof(pCtx->aModeHints));
1165 unsigned iHint;
1166 for (iHint = 0; iHint < cModeHints; ++iHint)
1167 {
1168 if ( cbModeHints <= sizeof(VBVAMODEHINT)
1169 && iHint < RT_ELEMENTS(pCtx->aModeHints))
1170 rc = pHlp->pfnSSMGetMem(pSSM, &pCtx->aModeHints[iHint],
1171 cbModeHints);
1172 else
1173 rc = pHlp->pfnSSMSkip(pSSM, cbModeHints);
1174 AssertRCReturn(rc, rc);
1175 }
1176 }
1177 }
1178
1179 pCtx->cViews = iView;
1180 LogFlowFunc(("%d views loaded\n", pCtx->cViews));
1181
1182 if (uVersion > VGA_SAVEDSTATE_VERSION_WDDM)
1183 {
1184 /* Skip loading VHWA (2D Video Hardware Acceleration) state from older saved states. */
1185 if (uVersion < VGA_SAVEDSTATE_VERSION_VHWA_REMOVED)
1186 {
1187 bool fLoadCommands;
1188 if (uVersion < VGA_SAVEDSTATE_VERSION_FIXED_PENDVHWA)
1189 {
1190 const char *pcszOsArch = pHlp->pfnSSMHandleHostOSAndArch(pSSM);
1191 AssertPtr(pcszOsArch);
1192 fLoadCommands = !pcszOsArch || RTStrNCmp(pcszOsArch, RT_STR_TUPLE("solaris"));
1193 }
1194 else
1195 fLoadCommands = true;
1196
1197 uint32_t u32;
1198 for (uint32_t i = 0; i < pThis->cMonitors; ++i)
1199 {
1200 rc = pHlp->pfnSSMGetU32(pSSM, &u32); /* VHWA [un]available magic. */
1201 AssertRCReturn(rc, rc);
1202 }
1203
1204 /* Pending VHWA commands. */
1205 if (fLoadCommands)
1206 {
1207 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
1208 AssertRCReturn(rc, rc);
1209 for (uint32_t i = 0; i < u32; ++i)
1210 {
1211 rc = pHlp->pfnSSMSkip(pSSM, sizeof(uint32_t));
1212 AssertRCReturn(rc, rc);
1213 }
1214 }
1215 }
1216 }
1217
1218#ifdef DEBUG_sunlover
1219 dumpctx(pCtx);
1220#endif
1221 }
1222 }
1223
1224 return rc;
1225}
1226
1227int vboxVBVALoadStateDone(PPDMDEVINS pDevIns)
1228{
1229 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1230 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
1231 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1232 if (pCtx)
1233 {
1234 uint32_t iView;
1235 for (iView = 0; iView < pCtx->cViews; iView++)
1236 {
1237 VBVAVIEW *pView = &pCtx->aViews[iView];
1238 if (pView->vbva.guest.pVBVA)
1239 {
1240 int rc = vbvaEnable(pThis, pThisCC, pCtx, iView, pView->vbva.guest.pVBVA,
1241 pView->vbva.u32VBVAOffset, true /* fRestored */);
1242 if (RT_SUCCESS(rc))
1243 vbvaResize(pThisCC, pView, &pView->screen, false);
1244 else
1245 LogRel(("VBVA: can not restore: %Rrc\n", rc));
1246 }
1247 }
1248
1249 if (pCtx->mouseShapeInfo.fSet)
1250 vbvaUpdateMousePointerShape(pThisCC, &pCtx->mouseShapeInfo, true);
1251 }
1252
1253 return VINF_SUCCESS;
1254}
1255
1256void VBVARaiseIrq(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, uint32_t fFlags)
1257{
1258 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSectIRQ, VERR_SEM_BUSY);
1259 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSectIRQ, rcLock);
1260
1261 const uint32_t fu32CurrentGuestFlags = HGSMIGetHostGuestFlags(pThisCC->pHGSMI);
1262 if ((fu32CurrentGuestFlags & HGSMIHOSTFLAGS_IRQ) == 0)
1263 {
1264 /* No IRQ set yet. */
1265 Assert(pThis->fu32PendingGuestFlags == 0);
1266
1267 HGSMISetHostGuestFlags(pThisCC->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
1268
1269 /* If VM is not running, the IRQ will be set in VBVAOnResume. */
1270 const VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
1271 if ( enmVMState == VMSTATE_RUNNING
1272 || enmVMState == VMSTATE_RUNNING_LS)
1273 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1274 }
1275 else
1276 {
1277 /* IRQ already set, remember the new flags. */
1278 pThis->fu32PendingGuestFlags |= HGSMIHOSTFLAGS_IRQ | fFlags;
1279 }
1280
1281 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSectIRQ);
1282}
1283
1284void VBVAOnResume(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
1285{
1286 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSectIRQ, VERR_SEM_BUSY);
1287 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSectIRQ, rcLock);
1288
1289 if (HGSMIGetHostGuestFlags(pThisCC->pHGSMI) & HGSMIHOSTFLAGS_IRQ)
1290 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1291
1292 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSectIRQ);
1293}
1294
1295static int vbvaHandleQueryConf32(PVGASTATECC pThisCC, VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *pConf32)
1296{
1297 uint32_t const idxQuery = pConf32->u32Index;
1298 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1299 LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n", idxQuery, pConf32->u32Value));
1300
1301 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1302 uint32_t uValue;
1303 if (idxQuery == VBOX_VBVA_CONF32_MONITOR_COUNT)
1304 uValue = pCtx->cViews;
1305 else if (idxQuery == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
1306 uValue = _64K; /** @todo a value calculated from the vram size */
1307 else if ( idxQuery == VBOX_VBVA_CONF32_MODE_HINT_REPORTING
1308 || idxQuery == VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING)
1309 uValue = VINF_SUCCESS;
1310 else if (idxQuery == VBOX_VBVA_CONF32_CURSOR_CAPABILITIES)
1311 uValue = VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE;
1312 else if (idxQuery == VBOX_VBVA_CONF32_SCREEN_FLAGS)
1313 uValue = VBVA_SCREEN_F_ACTIVE
1314 | VBVA_SCREEN_F_DISABLED
1315 | VBVA_SCREEN_F_BLANK
1316 | VBVA_SCREEN_F_BLANK2;
1317 else if (idxQuery == VBOX_VBVA_CONF32_MAX_RECORD_SIZE)
1318 uValue = VBVA_MAX_RECORD_SIZE;
1319 else if (idxQuery == UINT32_MAX)
1320 uValue = UINT32_MAX; /* Older GA uses this for sanity checking. See testQueryConf in HGSMIBase.cpp on branches. */
1321 else
1322 ASSERT_GUEST_MSG_FAILED_RETURN(("Invalid index %#x\n", idxQuery), VERR_INVALID_PARAMETER);
1323
1324 pConf32->u32Value = uValue;
1325 return VINF_SUCCESS;
1326}
1327
1328static int vbvaHandleSetConf32(VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *pConf32)
1329{
1330 uint32_t const idxQuery = pConf32->u32Index;
1331 uint32_t const uValue = pConf32->u32Value;
1332 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1333 LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n", idxQuery, uValue));
1334
1335 if (idxQuery == VBOX_VBVA_CONF32_MONITOR_COUNT)
1336 { /* do nothing. this is a const. */ }
1337 else if (idxQuery == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
1338 { /* do nothing. this is a const. */ }
1339 else
1340 ASSERT_GUEST_MSG_FAILED_RETURN(("Invalid index %#x (value=%u)\n", idxQuery, uValue), VERR_INVALID_PARAMETER);
1341
1342 RT_NOREF_PV(uValue);
1343 return VINF_SUCCESS;
1344}
1345
1346static int vbvaHandleInfoHeap(PVGASTATECC pThisCC, const VBVAINFOHEAP RT_UNTRUSTED_VOLATILE_GUEST *pInfoHeap)
1347{
1348 uint32_t const offHeap = pInfoHeap->u32HeapOffset;
1349 uint32_t const cbHeap = pInfoHeap->u32HeapSize;
1350 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1351 LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n", offHeap, cbHeap));
1352
1353 return HGSMIHostHeapSetup(pThisCC->pHGSMI, offHeap, cbHeap);
1354}
1355
1356static int vbvaInfoView(PVGASTATE pThis, PVGASTATER3 pThisCC, const VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_GUEST *pView)
1357{
1358 VBVAINFOVIEW view;
1359 RT_COPY_VOLATILE(view, *pView);
1360 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1361
1362 LogFlowFunc(("VBVA_INFO_VIEW: u32ViewIndex %d, u32ViewOffset 0x%x, u32ViewSize 0x%x, u32MaxScreenSize 0x%x\n",
1363 view.u32ViewIndex, view.u32ViewOffset, view.u32ViewSize, view.u32MaxScreenSize));
1364
1365 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1366 ASSERT_GUEST_LOGREL_MSG_RETURN( view.u32ViewIndex < pCtx->cViews
1367 && view.u32ViewOffset <= pThis->vram_size
1368 && view.u32ViewSize <= pThis->vram_size
1369 && view.u32ViewOffset <= pThis->vram_size - view.u32ViewSize
1370 && view.u32MaxScreenSize <= view.u32ViewSize,
1371 ("index %d(%d), offset 0x%x, size 0x%x, max 0x%x, vram size 0x%x\n",
1372 view.u32ViewIndex, pCtx->cViews, view.u32ViewOffset, view.u32ViewSize,
1373 view.u32MaxScreenSize, pThis->vram_size),
1374 VERR_INVALID_PARAMETER);
1375 RT_UNTRUSTED_VALIDATED_FENCE();
1376
1377 pCtx->aViews[view.u32ViewIndex].view = view;
1378 return VINF_SUCCESS;
1379}
1380
1381static int vbvaInfoScreen(PVGASTATECC pThisCC, const VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_GUEST *pScreen)
1382{
1383 /*
1384 * Copy input into non-volatile buffer.
1385 */
1386 VBVAINFOSCREEN screen;
1387 RT_COPY_VOLATILE(screen, *pScreen);
1388 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1389 LogRel2(("VBVA: InfoScreen: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
1390 screen.u32ViewIndex, screen.i32OriginX, screen.i32OriginY,
1391 screen.u32Width, screen.u32Height,
1392 screen.u32LineSize, screen.u16BitsPerPixel, screen.u16Flags));
1393
1394 /*
1395 * Validate input.
1396 */
1397 /* Allow screen.u16BitsPerPixel == 0 because legacy guest code used it for screen blanking. */
1398 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1399 ASSERT_GUEST_LOGREL_MSG_RETURN(screen.u32ViewIndex < pCtx->cViews,
1400 ("Screen index %#x is out of bound (cViews=%#x)\n", screen.u32ViewIndex, pCtx->cViews),
1401 VERR_INVALID_PARAMETER);
1402 ASSERT_GUEST_LOGREL_MSG_RETURN( screen.u16BitsPerPixel <= 32
1403 && screen.u32Width <= UINT16_MAX
1404 && screen.u32Height <= UINT16_MAX
1405 && screen.u32LineSize <= UINT16_MAX * UINT32_C(4),
1406 ("One or more values out of range: u16BitsPerPixel=%#x u32Width=%#x u32Height=%#x u32LineSize=%#x\n",
1407 screen.u16BitsPerPixel, screen.u32Width, screen.u32Height, screen.u32LineSize),
1408 VERR_INVALID_PARAMETER);
1409 RT_UNTRUSTED_VALIDATED_FENCE();
1410
1411 const VBVAINFOVIEW *pView = &pCtx->aViews[screen.u32ViewIndex].view;
1412 const uint32_t cbPerPixel = (screen.u16BitsPerPixel + 7) / 8;
1413 ASSERT_GUEST_LOGREL_MSG_RETURN(screen.u32Width <= screen.u32LineSize / (cbPerPixel ? cbPerPixel : 1),
1414 ("u32Width=%#x u32LineSize=%3x cbPerPixel=%#x\n",
1415 screen.u32Width, screen.u32LineSize, cbPerPixel),
1416 VERR_INVALID_PARAMETER);
1417
1418 const uint64_t u64ScreenSize = (uint64_t)screen.u32LineSize * screen.u32Height;
1419
1420 ASSERT_GUEST_LOGREL_MSG_RETURN( screen.u32StartOffset <= pView->u32ViewSize
1421 && u64ScreenSize <= pView->u32MaxScreenSize
1422 && screen.u32StartOffset <= pView->u32ViewSize - (uint32_t)u64ScreenSize,
1423 ("u32StartOffset=%#x u32ViewSize=%#x u64ScreenSize=%#RX64 u32MaxScreenSize=%#x\n",
1424 screen.u32StartOffset, pView->u32ViewSize, u64ScreenSize, pView->u32MaxScreenSize),
1425 VERR_INVALID_PARAMETER);
1426 RT_UNTRUSTED_VALIDATED_FENCE();
1427
1428 /*
1429 * Do the job.
1430 */
1431 vbvaResize(pThisCC, &pCtx->aViews[screen.u32ViewIndex], &screen, true);
1432 return VINF_SUCCESS;
1433}
1434
1435#ifdef UNUSED_FUNCTION
1436int VBVAGetInfoViewAndScreen(PVGASTATE pThis, PVGASTATECC pThisCC, uint32_t u32ViewIndex, VBVAINFOVIEW *pView, VBVAINFOSCREEN *pScreen)
1437{
1438 if (u32ViewIndex >= pThis->cMonitors)
1439 return VERR_INVALID_PARAMETER;
1440
1441 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1442 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1443
1444 if (pView)
1445 *pView = pCtx->aViews[u32ViewIndex].view;
1446
1447 if (pScreen)
1448 *pScreen = pCtx->aViews[u32ViewIndex].screen;
1449
1450 return VINF_SUCCESS;
1451}
1452#endif
1453
1454static int vbvaHandleEnable(PVGASTATE pThis, PVGASTATER3 pThisCC, uint32_t fEnableFlags, uint32_t offEnable, uint32_t idScreen)
1455{
1456 LogFlowFunc(("VBVA_ENABLE[%u]: fEnableFlags=0x%x offEnable=%#x\n", idScreen, fEnableFlags, offEnable));
1457 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1458 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pIns);
1459
1460 /*
1461 * Validate input.
1462 */
1463 ASSERT_GUEST_LOGREL_MSG_RETURN(idScreen < pCtx->cViews, ("idScreen=%#x cViews=%#x\n", idScreen, pCtx->cViews), VERR_INVALID_PARAMETER);
1464 ASSERT_GUEST_LOGREL_MSG_RETURN( (fEnableFlags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE
1465 || (fEnableFlags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE,
1466 ("fEnableFlags=%#x\n", fEnableFlags),
1467 VERR_INVALID_PARAMETER);
1468 if (fEnableFlags & VBVA_F_ENABLE)
1469 {
1470 ASSERT_GUEST_LOGREL_MSG_RETURN(offEnable < pThis->vram_size,
1471 ("offEnable=%#x vram_size=%#x\n", offEnable, pThis->vram_size),
1472 VERR_INVALID_PARAMETER);
1473 if (fEnableFlags & VBVA_F_ABSOFFSET)
1474 /* Offset from VRAM start. */
1475 ASSERT_GUEST_LOGREL_MSG_RETURN( pThis->vram_size >= RT_UOFFSETOF(VBVABUFFER, au8Data)
1476 && offEnable <= pThis->vram_size - RT_UOFFSETOF(VBVABUFFER, au8Data),
1477 ("offEnable=%#x vram_size=%#x\n", offEnable, pThis->vram_size),
1478 VERR_INVALID_PARAMETER);
1479 else
1480 {
1481 /* Offset from the view start. We'd be using idScreen here to fence required. */
1482 RT_UNTRUSTED_VALIDATED_FENCE();
1483 const VBVAINFOVIEW *pView = &pCtx->aViews[idScreen].view;
1484 ASSERT_GUEST_LOGREL_MSG_RETURN( pThis->vram_size - offEnable >= pView->u32ViewOffset
1485 && pView->u32ViewSize >= RT_UOFFSETOF(VBVABUFFER, au8Data)
1486 && offEnable <= pView->u32ViewSize - RT_UOFFSETOF(VBVABUFFER, au8Data),
1487 ("offEnable=%#x vram_size=%#x view: %#x LB %#x\n",
1488 offEnable, pThis->vram_size, pView->u32ViewOffset, pView->u32ViewSize),
1489 VERR_INVALID_PARAMETER);
1490 offEnable += pView->u32ViewOffset;
1491 }
1492 ASSERT_GUEST_LOGREL_MSG_RETURN(HGSMIIsOffsetValid(pIns, offEnable),
1493 ("offEnable=%#x area %#x LB %#x\n",
1494 offEnable, HGSMIGetAreaOffset(pIns), HGSMIGetAreaSize(pIns)),
1495 VERR_INVALID_PARAMETER);
1496 }
1497 RT_UNTRUSTED_VALIDATED_FENCE();
1498
1499 /*
1500 * Execute.
1501 */
1502 int rc = VINF_SUCCESS;
1503 if (fEnableFlags & VBVA_F_ENABLE)
1504 {
1505 VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *pVBVA
1506 = (VBVABUFFER RT_UNTRUSTED_VOLATILE_GUEST *)HGSMIOffsetToPointerHost(pIns, offEnable);
1507 ASSERT_GUEST_LOGREL_RETURN(pVBVA, VERR_INVALID_PARAMETER); /* already check above, but let's be careful. */
1508
1509 /* Process any pending orders and empty the VBVA ring buffer. */
1510 vbvaFlush(pThis, pThisCC, pCtx);
1511
1512 rc = vbvaEnable(pThis, pThisCC, pCtx, idScreen, pVBVA, offEnable, false /* fRestored */);
1513 if (RT_FAILURE(rc))
1514 LogRelMax(8, ("VBVA: can not enable: %Rrc\n", rc));
1515 }
1516 else
1517 rc = vbvaDisable(pThis, pThisCC, pCtx, idScreen);
1518 return rc;
1519}
1520
1521static int vbvaHandleQueryModeHints(PVGASTATECC pThisCC, VBVAQUERYMODEHINTS volatile *pQueryModeHints, HGSMISIZE cbBuffer)
1522{
1523 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1524 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pIns);
1525
1526 /*
1527 * Copy and validate the request.
1528 */
1529 uint16_t const cHintsQueried = pQueryModeHints->cHintsQueried;
1530 uint16_t const cbHintStructureGuest = pQueryModeHints->cbHintStructureGuest;
1531 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1532
1533 LogRelFlowFunc(("VBVA: HandleQueryModeHints: cHintsQueried=%RU16, cbHintStructureGuest=%RU16\n",
1534 cHintsQueried, cbHintStructureGuest));
1535 ASSERT_GUEST_RETURN(cbBuffer >= sizeof(VBVAQUERYMODEHINTS) + (uint32_t)cHintsQueried * cbHintStructureGuest,
1536 VERR_INVALID_PARAMETER);
1537 RT_UNTRUSTED_VALIDATED_FENCE();
1538
1539 /*
1540 * Produce the requested data.
1541 */
1542 uint8_t *pbHint = (uint8_t *)(pQueryModeHints + 1);
1543 memset(pbHint, ~0, cbBuffer - sizeof(VBVAQUERYMODEHINTS));
1544
1545 for (unsigned iHint = 0; iHint < cHintsQueried && iHint < VBOX_VIDEO_MAX_SCREENS; ++iHint)
1546 {
1547 memcpy(pbHint, &pCtx->aModeHints[iHint], RT_MIN(cbHintStructureGuest, sizeof(VBVAMODEHINT)));
1548 pbHint += cbHintStructureGuest;
1549 Assert((uintptr_t)(pbHint - (uint8_t *)pQueryModeHints) <= cbBuffer);
1550 }
1551
1552 return VINF_SUCCESS;
1553}
1554
1555/*
1556 *
1557 * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
1558 *
1559 * VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
1560 * Read Write
1561 * Host port 0x3b0 to process completed
1562 * Guest port 0x3d0 control value? to process
1563 *
1564 */
1565
1566static DECLCALLBACK(void) vbvaNotifyGuest(void *pvCallback)
1567{
1568#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
1569 PPDMDEVINS pDevIns = (PPDMDEVINS)pvCallback;
1570 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1571 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
1572 VBVARaiseIrq(pDevIns, pThis, pThisCC, 0);
1573#else
1574 NOREF(pvCallback);
1575 /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */
1576#endif
1577}
1578
1579/**
1580 * The guest submitted a command buffer (hit VGA_PORT_HGSMI_GUEST).
1581 *
1582 * Verify the buffer size and invoke corresponding handler.
1583 *
1584 * @return VBox status code.
1585 * @param pvHandler The VBVA channel context.
1586 * @param u16ChannelInfo Command code.
1587 * @param pvBuffer HGSMI buffer with command data. Considered volatile!
1588 * @param cbBuffer Size of command data.
1589 *
1590 * @thread EMT
1591 */
1592static DECLCALLBACK(int) vbvaChannelHandler(void *pvHandler, uint16_t u16ChannelInfo,
1593 void RT_UNTRUSTED_VOLATILE_GUEST *pvBuffer, HGSMISIZE cbBuffer)
1594{
1595 int rc = VINF_SUCCESS;
1596
1597 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n", pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
1598
1599 PPDMDEVINS pDevIns = (PPDMDEVINS)pvHandler;
1600 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1601 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
1602 PHGSMIINSTANCE pIns = pThisCC->pHGSMI;
1603 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pIns);
1604
1605 switch (u16ChannelInfo)
1606 {
1607#ifdef VBOX_WITH_VDMA
1608 case VBVA_VDMA_CMD:
1609 if (cbBuffer >= VBoxSHGSMIBufferHeaderSize() + sizeof(VBOXVDMACBUF_DR))
1610 {
1611 VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_GUEST *pCmd
1612 = (VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_GUEST *)VBoxSHGSMIBufferData((VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1613 vboxVDMACommand(pThisCC->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1614 rc = VINF_SUCCESS;
1615 }
1616 else
1617 rc = VERR_INVALID_PARAMETER;
1618 break;
1619
1620 case VBVA_VDMA_CTL:
1621 if (cbBuffer >= VBoxSHGSMIBufferHeaderSize() + sizeof(VBOXVDMA_CTL))
1622 {
1623 VBOXVDMA_CTL RT_UNTRUSTED_VOLATILE_GUEST *pCmd
1624 = (VBOXVDMA_CTL RT_UNTRUSTED_VOLATILE_GUEST *)VBoxSHGSMIBufferData((VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1625 vboxVDMAControl(pThisCC->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1626 }
1627 else
1628 rc = VERR_INVALID_PARAMETER;
1629 break;
1630#endif /* VBOX_WITH_VDMA */
1631
1632 case VBVA_QUERY_CONF32:
1633 if (cbBuffer >= sizeof(VBVACONF32))
1634 rc = vbvaHandleQueryConf32(pThisCC, (VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1635 else
1636 rc = VERR_INVALID_PARAMETER;
1637 break;
1638
1639 case VBVA_SET_CONF32:
1640 if (cbBuffer >= sizeof(VBVACONF32))
1641 rc = vbvaHandleSetConf32((VBVACONF32 RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1642 else
1643 rc = VERR_INVALID_PARAMETER;
1644 break;
1645
1646 case VBVA_INFO_VIEW:
1647 /* Expect at least one VBVAINFOVIEW structure. */
1648 rc = VERR_INVALID_PARAMETER;
1649 if (cbBuffer >= sizeof(VBVAINFOVIEW))
1650 {
1651 /* Guest submits an array of VBVAINFOVIEW structures. */
1652 const VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_GUEST *pView = (VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1653 for (;
1654 cbBuffer >= sizeof(VBVAINFOVIEW);
1655 ++pView, cbBuffer -= sizeof(VBVAINFOVIEW))
1656 {
1657 rc = vbvaInfoView(pThis, pThisCC, pView);
1658 if (RT_FAILURE(rc))
1659 break;
1660 }
1661 }
1662 break;
1663
1664 case VBVA_INFO_HEAP:
1665 if (cbBuffer >= sizeof(VBVAINFOHEAP))
1666 rc = vbvaHandleInfoHeap(pThisCC, (VBVAINFOHEAP RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1667 else
1668 rc = VERR_INVALID_PARAMETER;
1669 break;
1670
1671 case VBVA_FLUSH:
1672 if (cbBuffer >= sizeof(VBVAFLUSH))
1673 rc = vbvaFlush(pThis, pThisCC, pCtx);
1674 else
1675 rc = VERR_INVALID_PARAMETER;
1676 break;
1677
1678 case VBVA_INFO_SCREEN:
1679 rc = VERR_INVALID_PARAMETER;
1680 if (cbBuffer >= sizeof(VBVAINFOSCREEN))
1681 rc = vbvaInfoScreen(pThisCC, (VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer);
1682 break;
1683
1684 case VBVA_ENABLE:
1685 rc = VERR_INVALID_PARAMETER;
1686 if (cbBuffer >= sizeof(VBVAENABLE))
1687 {
1688 VBVAENABLE RT_UNTRUSTED_VOLATILE_GUEST *pVbvaEnable = (VBVAENABLE RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1689 uint32_t const fEnableFlags = pVbvaEnable->u32Flags;
1690 uint32_t const offEnable = pVbvaEnable->u32Offset;
1691 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1692
1693 uint32_t idScreen;
1694 if (fEnableFlags & VBVA_F_EXTENDED)
1695 {
1696 ASSERT_GUEST_STMT_BREAK(cbBuffer >= sizeof(VBVAENABLE_EX), rc = VERR_INVALID_PARAMETER);
1697 idScreen = ((VBVAENABLE_EX RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer)->u32ScreenId;
1698 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1699 }
1700 else
1701 idScreen = vbvaViewFromBufferPtr(pIns, pCtx, pvBuffer);
1702
1703 rc = vbvaHandleEnable(pThis, pThisCC, fEnableFlags, offEnable, idScreen);
1704 pVbvaEnable->i32Result = rc;
1705 }
1706 break;
1707
1708 case VBVA_MOUSE_POINTER_SHAPE:
1709 if (cbBuffer >= sizeof(VBVAMOUSEPOINTERSHAPE))
1710 {
1711 VBVAMOUSEPOINTERSHAPE RT_UNTRUSTED_VOLATILE_GUEST *pShape
1712 = (VBVAMOUSEPOINTERSHAPE RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1713 rc = vbvaMousePointerShape(pThisCC, pCtx, pShape, cbBuffer);
1714 pShape->i32Result = rc;
1715 }
1716 else
1717 rc = VERR_INVALID_PARAMETER;
1718 break;
1719
1720#ifdef VBOX_WITH_WDDM
1721 case VBVA_INFO_CAPS:
1722 if (cbBuffer >= sizeof(VBVACAPS))
1723 {
1724 VBVACAPS RT_UNTRUSTED_VOLATILE_GUEST *pCaps = (VBVACAPS RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1725 pThis->fGuestCaps = pCaps->fCaps;
1726 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1727
1728 pThisCC->pDrv->pfnVBVAGuestCapabilityUpdate(pThisCC->pDrv, pThis->fGuestCaps);
1729 pCaps->rc = rc = VINF_SUCCESS;
1730 }
1731 else
1732 rc = VERR_INVALID_PARAMETER;
1733 break;
1734#endif
1735
1736 case VBVA_SCANLINE_CFG:
1737 if (cbBuffer >= sizeof(VBVASCANLINECFG))
1738 {
1739 VBVASCANLINECFG RT_UNTRUSTED_VOLATILE_GUEST *pCfg = (VBVASCANLINECFG RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1740 pThis->fScanLineCfg = pCfg->fFlags;
1741 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1742
1743 pCfg->rc = rc = VINF_SUCCESS;
1744 }
1745 else
1746 rc = VERR_INVALID_PARAMETER;
1747 break;
1748
1749 case VBVA_QUERY_MODE_HINTS:
1750 if (cbBuffer >= sizeof(VBVAQUERYMODEHINTS))
1751 {
1752 VBVAQUERYMODEHINTS RT_UNTRUSTED_VOLATILE_GUEST *pQueryModeHints
1753 = (VBVAQUERYMODEHINTS RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1754 rc = vbvaHandleQueryModeHints(pThisCC, pQueryModeHints, cbBuffer);
1755 pQueryModeHints->rc = rc;
1756 }
1757 else
1758 rc = VERR_INVALID_PARAMETER;
1759 break;
1760
1761 case VBVA_REPORT_INPUT_MAPPING:
1762 if (cbBuffer >= sizeof(VBVAREPORTINPUTMAPPING))
1763 {
1764 VBVAREPORTINPUTMAPPING inputMapping;
1765 {
1766 VBVAREPORTINPUTMAPPING RT_UNTRUSTED_VOLATILE_GUEST *pInputMapping
1767 = (VBVAREPORTINPUTMAPPING RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1768 inputMapping.x = pInputMapping->x;
1769 inputMapping.y = pInputMapping->y;
1770 inputMapping.cx = pInputMapping->cx;
1771 inputMapping.cy = pInputMapping->cy;
1772 }
1773 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1774
1775 LogRelFlowFunc(("VBVA: ChannelHandler: VBVA_REPORT_INPUT_MAPPING: x=%RI32, y=%RI32, cx=%RU32, cy=%RU32\n",
1776 inputMapping.x, inputMapping.y, inputMapping.cx, inputMapping.cy));
1777 pThisCC->pDrv->pfnVBVAInputMappingUpdate(pThisCC->pDrv,
1778 inputMapping.x, inputMapping.y,
1779 inputMapping.cx, inputMapping.cy);
1780 rc = VINF_SUCCESS;
1781 }
1782 else
1783 rc = VERR_INVALID_PARAMETER;
1784 break;
1785
1786 case VBVA_CURSOR_POSITION:
1787 if (cbBuffer >= sizeof(VBVACURSORPOSITION))
1788 {
1789 VBVACURSORPOSITION RT_UNTRUSTED_VOLATILE_GUEST *pReport = (VBVACURSORPOSITION RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1790 VBVACURSORPOSITION Report;
1791 Report.fReportPosition = pReport->fReportPosition;
1792 Report.x = pReport->x;
1793 Report.y = pReport->y;
1794 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1795
1796 LogRelFlowFunc(("VBVA: ChannelHandler: VBVA_CURSOR_POSITION: fReportPosition=%RTbool, Id=%RU32, x=%RU32, y=%RU32\n",
1797 RT_BOOL(Report.fReportPosition), vbvaViewFromBufferPtr(pIns, pCtx, pvBuffer), Report.x, Report.y));
1798
1799 pThisCC->pDrv->pfnVBVAReportCursorPosition(pThisCC->pDrv, RT_BOOL(Report.fReportPosition), vbvaViewFromBufferPtr(pIns, pCtx, pvBuffer), Report.x, Report.y);
1800 /* This was only ever briefly used by the guest, and a value
1801 * of zero in both was taken to mean "ignore". */
1802 pReport->x = 0;
1803 pReport->y = 0;
1804 rc = VINF_SUCCESS;
1805 }
1806 else
1807 rc = VERR_INVALID_PARAMETER;
1808 break;
1809
1810 default:
1811 Log(("Unsupported VBVA guest command %d (%#x)!!!\n", u16ChannelInfo, u16ChannelInfo));
1812 break;
1813 }
1814
1815 return rc;
1816}
1817
1818/** When VBVA is paused, the VGA device is allowed to work but
1819 * no HGSMI etc state is changed.
1820 */
1821static void vbvaPause(PVGASTATECC pThisCC, bool fPause)
1822{
1823 if (!pThisCC || !pThisCC->pHGSMI)
1824 return;
1825
1826 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1827 if (pCtx)
1828 pCtx->fPaused = fPause;
1829}
1830
1831bool VBVAIsPaused(PVGASTATECC pThisCC)
1832{
1833 if (pThisCC && pThisCC->pHGSMI)
1834 {
1835 const VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1836 if (pCtx && pCtx->cViews)
1837 {
1838 /* If VBVA is enabled at all. */
1839 const VBVAVIEW *pView = &pCtx->aViews[0];
1840 if (pView->vbva.guest.pVBVA)
1841 return pCtx->fPaused;
1842 }
1843 }
1844 /* VBVA is disabled. */
1845 return true;
1846}
1847
1848void VBVAOnVBEChanged(PVGASTATE pThis, PVGASTATECC pThisCC)
1849{
1850 /* The guest does not depend on host handling the VBE registers. */
1851 if (pThis->fGuestCaps & VBVACAPS_USE_VBVA_ONLY)
1852 return;
1853
1854 vbvaPause(pThisCC, (pThis->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) == 0);
1855}
1856
1857void VBVAReset(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
1858{
1859 if (!pThis || !pThisCC->pHGSMI)
1860 return;
1861
1862 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1863
1864 HGSMIReset(pThisCC->pHGSMI);
1865 /* Make sure the IRQ is reset. */
1866 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_LOW);
1867 pThis->fu32PendingGuestFlags = 0;
1868
1869 if (pCtx)
1870 {
1871 vbvaFlush(pThis, pThisCC, pCtx);
1872
1873 for (unsigned idScreen = 0; idScreen < pCtx->cViews; idScreen++)
1874 vbvaDisable(pThis, pThisCC, pCtx, idScreen);
1875
1876 pCtx->mouseShapeInfo.fSet = false;
1877 RTMemFreeZ(pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbAllocated);
1878 pCtx->mouseShapeInfo.pu8Shape = NULL;
1879 pCtx->mouseShapeInfo.cbAllocated = 0;
1880 pCtx->mouseShapeInfo.cbShape = 0;
1881 }
1882
1883}
1884
1885int VBVAUpdateDisplay(PVGASTATE pThis, PVGASTATECC pThisCC)
1886{
1887 int rc = VERR_NOT_SUPPORTED; /* Assuming that the VGA device will have to do updates. */
1888
1889 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1890 if (pCtx)
1891 {
1892 if (!pCtx->fPaused)
1893 {
1894 rc = vbvaFlush(pThis, pThisCC, pCtx);
1895 if (RT_SUCCESS(rc))
1896 {
1897 if (!pCtx->aViews[0].vbva.guest.pVBVA)
1898 {
1899 /* VBVA is not enabled for the first view, so VGA device must do updates. */
1900 rc = VERR_NOT_SUPPORTED;
1901 }
1902 }
1903 }
1904 }
1905
1906 return rc;
1907}
1908
1909static int vbvaSendModeHintWorker(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
1910 uint32_t cx, uint32_t cy, uint32_t cBPP, uint32_t iDisplay, uint32_t dx,
1911 uint32_t dy, uint32_t fEnabled,
1912 uint32_t fNotifyGuest)
1913{
1914 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1915 /** @note See Display::setVideoModeHint: "It is up to the guest to decide
1916 * whether the hint is valid. Therefore don't do any VRAM sanity checks
1917 * here! */
1918 if (iDisplay >= RT_MIN(pThis->cMonitors, RT_ELEMENTS(pCtx->aModeHints)))
1919 return VERR_OUT_OF_RANGE;
1920 pCtx->aModeHints[iDisplay].magic = VBVAMODEHINT_MAGIC;
1921 pCtx->aModeHints[iDisplay].cx = cx;
1922 pCtx->aModeHints[iDisplay].cy = cy;
1923 pCtx->aModeHints[iDisplay].cBPP = cBPP;
1924 pCtx->aModeHints[iDisplay].dx = dx;
1925 pCtx->aModeHints[iDisplay].dy = dy;
1926 pCtx->aModeHints[iDisplay].fEnabled = fEnabled;
1927 if (fNotifyGuest && pThis->fGuestCaps & VBVACAPS_IRQ && pThis->fGuestCaps & VBVACAPS_VIDEO_MODE_HINTS)
1928 VBVARaiseIrq(pDevIns, pThis, pThisCC, HGSMIHOSTFLAGS_HOTPLUG);
1929 return VINF_SUCCESS;
1930}
1931
1932
1933/**
1934 * @interface_method_impl{PDMIDISPLAYPORT,pfnSendModeHint}
1935 */
1936DECLCALLBACK(int) vbvaR3PortSendModeHint(PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy, uint32_t cBPP,
1937 uint32_t iDisplay, uint32_t dx, uint32_t dy, uint32_t fEnabled, uint32_t fNotifyGuest)
1938{
1939 PVGASTATECC pThisCC = RT_FROM_MEMBER(pInterface, VGASTATECC, IPort);
1940 PPDMDEVINS pDevIns = pThisCC->pDevIns;
1941 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1942 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
1943 AssertRCReturn(rc, rc);
1944
1945 rc = vbvaSendModeHintWorker(pDevIns, pThis, pThisCC, cx, cy, cBPP, iDisplay, dx, dy, fEnabled, fNotifyGuest);
1946
1947 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
1948 return rc;
1949}
1950
1951int VBVAInit(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
1952{
1953 int rc = HGSMICreate(&pThisCC->pHGSMI,
1954 pDevIns,
1955 "VBVA",
1956 0,
1957 pThisCC->pbVRam,
1958 pThis->vram_size,
1959 vbvaNotifyGuest,
1960 pDevIns,
1961 sizeof(VBVACONTEXT));
1962 if (RT_SUCCESS(rc))
1963 {
1964 rc = HGSMIHostChannelRegister(pThisCC->pHGSMI,
1965 HGSMI_CH_VBVA,
1966 vbvaChannelHandler,
1967 pDevIns);
1968 if (RT_SUCCESS(rc))
1969 {
1970 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThisCC->pHGSMI);
1971 pCtx->cViews = pThis->cMonitors;
1972 pCtx->fPaused = true;
1973 memset(pCtx->aModeHints, ~0, sizeof(pCtx->aModeHints));
1974 }
1975 }
1976
1977 return rc;
1978
1979}
1980
1981void VBVADestroy(PVGASTATECC pThisCC)
1982{
1983 PHGSMIINSTANCE pHgsmi = pThisCC->pHGSMI;
1984 if (pHgsmi)
1985 {
1986 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pHgsmi);
1987 pCtx->mouseShapeInfo.fSet = false;
1988 RTMemFreeZ(pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbAllocated);
1989 pCtx->mouseShapeInfo.pu8Shape = NULL;
1990 pCtx->mouseShapeInfo.cbAllocated = 0;
1991 pCtx->mouseShapeInfo.cbShape = 0;
1992
1993 HGSMIDestroy(pHgsmi);
1994 pThisCC->pHGSMI = NULL;
1995 }
1996}
1997
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