VirtualBox

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

Last change on this file since 56785 was 56785, checked in by vboxsync, 10 years ago

DevVGA: correctly restore VBVA state.

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