VirtualBox

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

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

DevVGA: log VBVA enable failures.

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

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