VirtualBox

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

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

bugref:8183: Mouse Integration sometimes not working after restore from saved state: fix a mishandling of the guest cursor shape protocol in the graphics device. When the guest sends a cursor shape event with the visible flag set but no shape data, the value of the alpha flag should be ignored. We were indeed ignoring it, but still saving its (usually incorrect) value to the device context, overwriting the old value, and from there to the saved state.

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