VirtualBox

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

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

Windows guest additions, VBVA: reverted part of r100972: host mouse cursor capability, other fixes remain.

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