VirtualBox

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

Last change on this file since 56969 was 56969, checked in by vboxsync, 9 years ago

DevVGA: Added markers to the saved state that separates various parts so we can more easily pin down load troubles when reading the log file.

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

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