VirtualBox

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

Last change on this file since 44000 was 42409, checked in by vboxsync, 12 years ago

Devices/VGA: added additional enable-able release loggingfor screen area updates by the Additions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.7 KB
Line 
1/** @file
2 * VirtualBox Video Acceleration (VBVA).
3 */
4
5/*
6 * Copyright (C) 2006-2009 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#define LOG_GROUP LOG_GROUP_DEV_VGA
18#include <VBox/vmm/pdmifs.h>
19#include <VBox/vmm/pdmdev.h>
20#include <VBox/vmm/pgm.h>
21#include <VBox/vmm/ssm.h>
22#include <VBox/VMMDev.h>
23#include <VBox/VBoxVideo.h>
24#include <iprt/alloc.h>
25#include <iprt/assert.h>
26#include <iprt/asm.h>
27#include <iprt/string.h>
28#include <iprt/param.h>
29#ifdef VBOX_WITH_VIDEOHWACCEL
30#include <iprt/semaphore.h>
31#endif
32
33#include "DevVGA.h"
34
35/* A very detailed logging. */
36#if 0 // def DEBUG_sunlover
37#define LOGVBVABUFFER(a) LogFlow(a)
38#else
39#define LOGVBVABUFFER(a) do {} while(0)
40#endif
41
42typedef struct VBVAPARTIALRECORD
43{
44 uint8_t *pu8;
45 uint32_t cb;
46} VBVAPARTIALRECORD;
47
48typedef struct VBVAVIEW
49{
50 VBVAINFOVIEW view;
51 VBVAINFOSCREEN screen;
52 VBVABUFFER *pVBVA;
53 uint32_t u32VBVAOffset;
54 VBVAPARTIALRECORD partialRecord;
55} VBVAVIEW;
56
57typedef struct VBVAMOUSESHAPEINFO
58{
59 bool fSet;
60 bool fVisible;
61 bool fAlpha;
62 uint32_t u32HotX;
63 uint32_t u32HotY;
64 uint32_t u32Width;
65 uint32_t u32Height;
66 uint32_t cbShape;
67 uint32_t cbAllocated;
68 uint8_t *pu8Shape;
69} VBVAMOUSESHAPEINFO;
70
71/* @todo saved state: save and restore VBVACONTEXT */
72typedef struct VBVACONTEXT
73{
74 uint32_t cViews;
75 VBVAVIEW aViews[64 /* @todo SchemaDefs::MaxGuestMonitors*/];
76 VBVAMOUSESHAPEINFO mouseShapeInfo;
77} VBVACONTEXT;
78
79/* Copies 'cb' bytes from the VBVA ring buffer to the 'pu8Dst'.
80 * Used for partial records or for records which cross the ring boundary.
81 */
82static void vbvaFetchBytes (VBVABUFFER *pVBVA, uint8_t *pu8Dst, uint32_t cb)
83{
84 /* @todo replace the 'if' with an assert. The caller must ensure this condition. */
85 if (cb >= pVBVA->cbData)
86 {
87 AssertMsgFailed (("cb = 0x%08X, ring buffer size 0x%08X", cb, pVBVA->cbData));
88 return;
89 }
90
91 const uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
92 const uint8_t *src = &pVBVA->au8Data[pVBVA->off32Data];
93 const int32_t i32Diff = cb - u32BytesTillBoundary;
94
95 if (i32Diff <= 0)
96 {
97 /* Chunk will not cross buffer boundary. */
98 memcpy (pu8Dst, src, cb);
99 }
100 else
101 {
102 /* Chunk crosses buffer boundary. */
103 memcpy (pu8Dst, src, u32BytesTillBoundary);
104 memcpy (pu8Dst + u32BytesTillBoundary, &pVBVA->au8Data[0], i32Diff);
105 }
106
107 /* Advance data offset. */
108 pVBVA->off32Data = (pVBVA->off32Data + cb) % pVBVA->cbData;
109
110 return;
111}
112
113
114static bool vbvaPartialRead (VBVAPARTIALRECORD *pPartialRecord, uint32_t cbRecord, VBVABUFFER *pVBVA)
115{
116 uint8_t *pu8New;
117
118 LOGVBVABUFFER(("vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
119 pPartialRecord->pu8, pPartialRecord->cb, cbRecord));
120
121 if (pPartialRecord->pu8)
122 {
123 Assert (pPartialRecord->cb);
124 pu8New = (uint8_t *)RTMemRealloc (pPartialRecord->pu8, cbRecord);
125 }
126 else
127 {
128 Assert (!pPartialRecord->cb);
129 pu8New = (uint8_t *)RTMemAlloc (cbRecord);
130 }
131
132 if (!pu8New)
133 {
134 /* Memory allocation failed, fail the function. */
135 Log(("vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
136 cbRecord));
137
138 if (pPartialRecord->pu8)
139 {
140 RTMemFree (pPartialRecord->pu8);
141 }
142
143 pPartialRecord->pu8 = NULL;
144 pPartialRecord->cb = 0;
145
146 return false;
147 }
148
149 /* Fetch data from the ring buffer. */
150 vbvaFetchBytes (pVBVA, pu8New + pPartialRecord->cb, cbRecord - pPartialRecord->cb);
151
152 pPartialRecord->pu8 = pu8New;
153 pPartialRecord->cb = cbRecord;
154
155 return true;
156}
157
158/* For contiguous chunks just return the address in the buffer.
159 * For crossing boundary - allocate a buffer from heap.
160 */
161static bool vbvaFetchCmd (VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA, VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
162{
163 uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
164 uint32_t indexRecordFree = pVBVA->indexRecordFree;
165
166 LOGVBVABUFFER(("first = %d, free = %d\n",
167 indexRecordFirst, indexRecordFree));
168
169 if (indexRecordFirst == indexRecordFree)
170 {
171 /* No records to process. Return without assigning output variables. */
172 return true;
173 }
174
175 uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVBVA->aRecords[indexRecordFirst].cbRecord);
176
177 LOGVBVABUFFER(("cbRecord = 0x%08X, pPartialRecord->cb = 0x%08X\n", cbRecordCurrent, pPartialRecord->cb));
178
179 uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
180
181 if (pPartialRecord->cb)
182 {
183 /* There is a partial read in process. Continue with it. */
184 Assert (pPartialRecord->pu8);
185
186 LOGVBVABUFFER(("continue partial record cb = %d cbRecord 0x%08X, first = %d, free = %d\n",
187 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
188
189 if (cbRecord > pPartialRecord->cb)
190 {
191 /* New data has been added to the record. */
192 if (!vbvaPartialRead (pPartialRecord, cbRecord, pVBVA))
193 {
194 return false;
195 }
196 }
197
198 if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL))
199 {
200 /* The record is completed by guest. Return it to the caller. */
201 *ppHdr = (VBVACMDHDR *)pPartialRecord->pu8;
202 *pcbCmd = pPartialRecord->cb;
203
204 pPartialRecord->pu8 = NULL;
205 pPartialRecord->cb = 0;
206
207 /* Advance the record index. */
208 pVBVA->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
209
210 LOGVBVABUFFER(("partial done ok, data = %d, free = %d\n",
211 pVBVA->off32Data, pVBVA->off32Free));
212 }
213
214 return true;
215 }
216
217 /* A new record need to be processed. */
218 if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
219 {
220 /* Current record is being written by guest. '=' is important here,
221 * because the guest will do a FLUSH at this condition.
222 * This partial record is too large for the ring buffer and must
223 * be accumulated in an allocated buffer.
224 */
225 if (cbRecord >= pVBVA->cbData - pVBVA->cbPartialWriteThreshold)
226 {
227 /* Partial read must be started. */
228 if (!vbvaPartialRead (pPartialRecord, cbRecord, pVBVA))
229 {
230 return false;
231 }
232
233 LOGVBVABUFFER(("started partial record cb = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
234 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
235 }
236
237 return true;
238 }
239
240 /* Current record is complete. If it is not empty, process it. */
241 if (cbRecord)
242 {
243 /* The size of largest contiguous chunk in the ring biffer. */
244 uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
245
246 /* The pointer to data in the ring buffer. */
247 uint8_t *src = &pVBVA->au8Data[pVBVA->off32Data];
248
249 /* Fetch or point the data. */
250 if (u32BytesTillBoundary >= cbRecord)
251 {
252 /* The command does not cross buffer boundary. Return address in the buffer. */
253 *ppHdr = (VBVACMDHDR *)src;
254
255 /* Advance data offset. */
256 pVBVA->off32Data = (pVBVA->off32Data + cbRecord) % pVBVA->cbData;
257 }
258 else
259 {
260 /* The command crosses buffer boundary. Rare case, so not optimized. */
261 uint8_t *dst = (uint8_t *)RTMemAlloc (cbRecord);
262
263 if (!dst)
264 {
265 LogFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord));
266 pVBVA->off32Data = (pVBVA->off32Data + cbRecord) % pVBVA->cbData;
267 return false;
268 }
269
270 vbvaFetchBytes (pVBVA, dst, cbRecord);
271
272 *ppHdr = (VBVACMDHDR *)dst;
273
274 LOGVBVABUFFER(("Allocated from heap %p\n", dst));
275 }
276 }
277
278 *pcbCmd = cbRecord;
279
280 /* Advance the record index. */
281 pVBVA->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
282
283 LOGVBVABUFFER(("done ok, data = %d, free = %d\n",
284 pVBVA->off32Data, pVBVA->off32Free));
285
286 return true;
287}
288
289static void vbvaReleaseCmd (VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA, VBVACMDHDR *pHdr, uint32_t cbCmd)
290{
291 uint8_t *au8RingBuffer = &pVBVA->au8Data[0];
292
293 if ( (uint8_t *)pHdr >= au8RingBuffer
294 && (uint8_t *)pHdr < &au8RingBuffer[pVBVA->cbData])
295 {
296 /* The pointer is inside ring buffer. Must be continuous chunk. */
297 Assert (pVBVA->cbData - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);
298
299 /* Do nothing. */
300
301 Assert (!pPartialRecord->pu8 && pPartialRecord->cb == 0);
302 }
303 else
304 {
305 /* The pointer is outside. It is then an allocated copy. */
306 LOGVBVABUFFER(("Free heap %p\n", pHdr));
307
308 if ((uint8_t *)pHdr == pPartialRecord->pu8)
309 {
310 pPartialRecord->pu8 = NULL;
311 pPartialRecord->cb = 0;
312 }
313 else
314 {
315 Assert (!pPartialRecord->pu8 && pPartialRecord->cb == 0);
316 }
317
318 RTMemFree (pHdr);
319 }
320
321 return;
322}
323
324static int vbvaFlushProcess (unsigned uScreenId, PVGASTATE pVGAState, VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA)
325{
326 LOGVBVABUFFER(("uScreenId %d, indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
327 uScreenId, pVBVA->indexRecordFirst, pVBVA->indexRecordFree, pVBVA->off32Data, pVBVA->off32Free));
328 struct {
329 /* The rectangle that includes all dirty rectangles. */
330 int32_t xLeft;
331 int32_t xRight;
332 int32_t yTop;
333 int32_t yBottom;
334 } dirtyRect;
335 RT_ZERO(dirtyRect);
336
337 bool fUpdate = false; /* Whether there were any updates. */
338 bool fDirtyEmpty = true;
339
340 for (;;)
341 {
342 VBVACMDHDR *phdr = NULL;
343 uint32_t cbCmd = ~0;
344
345 /* Fetch the command data. */
346 if (!vbvaFetchCmd (pPartialRecord, pVBVA, &phdr, &cbCmd))
347 {
348 LogFunc(("unable to fetch command. off32Data = %d, off32Free = %d!!!\n",
349 pVBVA->off32Data, pVBVA->off32Free));
350
351 /* @todo old code disabled VBVA processing here. */
352 return VERR_NOT_SUPPORTED;
353 }
354
355 if (cbCmd == uint32_t(~0))
356 {
357 /* No more commands yet in the queue. */
358 break;
359 }
360
361 if (cbCmd != 0)
362 {
363 if (!fUpdate)
364 {
365 pVGAState->pDrv->pfnVBVAUpdateBegin (pVGAState->pDrv, uScreenId);
366 fUpdate = true;
367 }
368
369 /* Updates the rectangle and sends the command to the VRDP server. */
370 pVGAState->pDrv->pfnVBVAUpdateProcess (pVGAState->pDrv, uScreenId, phdr, cbCmd);
371
372 int32_t xRight = phdr->x + phdr->w;
373 int32_t yBottom = phdr->y + phdr->h;
374
375 /* These are global coords, relative to the primary screen. */
376
377 LOGVBVABUFFER(("cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
378 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));
379 LogRel3(("%s: update command cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
380 __PRETTY_FUNCTION__, cbCmd, phdr->x, phdr->y, phdr->w,
381 phdr->h));
382
383 /* Collect all rects into one. */
384 if (fDirtyEmpty)
385 {
386 /* This is the first rectangle to be added. */
387 dirtyRect.xLeft = phdr->x;
388 dirtyRect.yTop = phdr->y;
389 dirtyRect.xRight = xRight;
390 dirtyRect.yBottom = yBottom;
391 fDirtyEmpty = false;
392 }
393 else
394 {
395 /* Adjust region coordinates. */
396 if (dirtyRect.xLeft > phdr->x)
397 {
398 dirtyRect.xLeft = phdr->x;
399 }
400
401 if (dirtyRect.yTop > phdr->y)
402 {
403 dirtyRect.yTop = phdr->y;
404 }
405
406 if (dirtyRect.xRight < xRight)
407 {
408 dirtyRect.xRight = xRight;
409 }
410
411 if (dirtyRect.yBottom < yBottom)
412 {
413 dirtyRect.yBottom = yBottom;
414 }
415 }
416 }
417
418 vbvaReleaseCmd (pPartialRecord, pVBVA, phdr, cbCmd);
419 }
420
421 if (fUpdate)
422 {
423 if (dirtyRect.xRight - dirtyRect.xLeft)
424 {
425 LogRel3(("%s: sending update screen=%d, x=%d, y=%d, w=%d, h=%d\n",
426 __PRETTY_FUNCTION__, uScreenId, dirtyRect.xLeft,
427 dirtyRect.yTop, dirtyRect.xRight - dirtyRect.xLeft,
428 dirtyRect.yBottom - dirtyRect.yTop));
429 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, dirtyRect.xLeft, dirtyRect.yTop,
430 dirtyRect.xRight - dirtyRect.xLeft, dirtyRect.yBottom - dirtyRect.yTop);
431 }
432 else
433 {
434 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, 0, 0, 0, 0);
435 }
436 }
437
438 return VINF_SUCCESS;
439}
440
441static int vbvaFlush (PVGASTATE pVGAState, VBVACONTEXT *pCtx)
442{
443 unsigned uScreenId;
444
445 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
446 {
447 VBVAPARTIALRECORD *pPartialRecord = &pCtx->aViews[uScreenId].partialRecord;
448 VBVABUFFER *pVBVA = pCtx->aViews[uScreenId].pVBVA;
449
450 if (pVBVA)
451 {
452 vbvaFlushProcess (uScreenId, pVGAState, pPartialRecord, pVBVA);
453 }
454 }
455
456 /* @todo rc */
457 return VINF_SUCCESS;
458}
459
460static int vbvaResize (PVGASTATE pVGAState, VBVAVIEW *pView, const VBVAINFOSCREEN *pNewScreen)
461{
462 /* Verify pNewScreen. */
463 /* @todo */
464
465 /* Apply these changes. */
466 pView->screen = *pNewScreen;
467
468 uint8_t *pu8VRAM = pVGAState->vram_ptrR3 + pView->view.u32ViewOffset;
469
470 int rc = pVGAState->pDrv->pfnVBVAResize (pVGAState->pDrv, &pView->view, &pView->screen, pu8VRAM);
471
472 /* @todo process VINF_VGA_RESIZE_IN_PROGRESS? */
473
474 return rc;
475}
476
477static int vbvaEnable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCtx, VBVABUFFER *pVBVA, uint32_t u32Offset, bool fRestored)
478{
479 /* @todo old code did a UpdateDisplayAll at this place. */
480
481 int rc;
482
483 if (pVGAState->pDrv->pfnVBVAEnable)
484 {
485 pVBVA->hostFlags.u32HostEvents = 0;
486 pVBVA->hostFlags.u32SupportedOrders = 0;
487
488 rc = pVGAState->pDrv->pfnVBVAEnable (pVGAState->pDrv, uScreenId, &pVBVA->hostFlags);
489 }
490 else
491 {
492 rc = VERR_NOT_SUPPORTED;
493 }
494
495 if (RT_SUCCESS (rc))
496 {
497 /* pVBVA->hostFlags has been set up by pfnVBVAEnable. */
498 LogFlowFunc(("u32HostEvents 0x%08X, u32SupportedOrders 0x%08X\n",
499 pVBVA->hostFlags.u32HostEvents, pVBVA->hostFlags.u32SupportedOrders));
500
501 if (!fRestored)
502 {
503 /* @todo Actually this function must not touch the partialRecord structure at all,
504 * because initially it is a zero and when VBVA is disabled this should be set to zero.
505 * But I'm not sure that no code depends on zeroing partialRecord here.
506 * So for now (a quick fix for 4.1) just do not do this if the VM was restored,
507 * when partialRecord might be loaded already from the saved state.
508 */
509 pCtx->aViews[uScreenId].partialRecord.pu8 = NULL;
510 pCtx->aViews[uScreenId].partialRecord.cb = 0;
511 }
512
513 pCtx->aViews[uScreenId].pVBVA = pVBVA;
514 pCtx->aViews[uScreenId].u32VBVAOffset = u32Offset;
515 }
516
517 return rc;
518}
519
520static int vbvaDisable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCtx)
521{
522 /* Process any pending orders and empty the VBVA ring buffer. */
523 vbvaFlush (pVGAState, pCtx);
524
525 VBVAVIEW *pView = &pCtx->aViews[uScreenId];
526
527 if (pView->pVBVA)
528 {
529 pView->pVBVA->hostFlags.u32HostEvents = 0;
530 pView->pVBVA->hostFlags.u32SupportedOrders = 0;
531
532 pView->partialRecord.pu8 = NULL;
533 pView->partialRecord.cb = 0;
534
535 pView->pVBVA = NULL;
536 pView->u32VBVAOffset = HGSMIOFFSET_VOID;
537 }
538
539 pVGAState->pDrv->pfnVBVADisable (pVGAState->pDrv, uScreenId);
540 return VINF_SUCCESS;
541}
542
543bool VBVAIsEnabled(PVGASTATE pVGAState)
544{
545 PHGSMIINSTANCE pHGSMI = pVGAState->pHGSMI;
546 if (pHGSMI)
547 {
548 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pHGSMI);
549 if (pCtx)
550 {
551 if (pCtx->cViews)
552 {
553 VBVAVIEW * pView = &pCtx->aViews[0];
554 if (pView->pVBVA)
555 return true;
556 }
557 }
558 }
559 return false;
560}
561
562#ifdef DEBUG_sunlover
563void dumpMouseShapeInfo(const VBVAMOUSESHAPEINFO *pMouseShapeInfo)
564{
565 LogFlow(("fSet = %d, fVisible %d, fAlpha %d, @%d,%d %dx%d (%p, %d/%d)\n",
566 pMouseShapeInfo->fSet,
567 pMouseShapeInfo->fVisible,
568 pMouseShapeInfo->fAlpha,
569 pMouseShapeInfo->u32HotX,
570 pMouseShapeInfo->u32HotY,
571 pMouseShapeInfo->u32Width,
572 pMouseShapeInfo->u32Height,
573 pMouseShapeInfo->pu8Shape,
574 pMouseShapeInfo->cbShape,
575 pMouseShapeInfo->cbAllocated
576 ));
577}
578#endif
579
580static int vbvaUpdateMousePointerShape(PVGASTATE pVGAState, VBVAMOUSESHAPEINFO *pMouseShapeInfo, bool fShape, const uint8_t *pu8Shape)
581{
582 int rc;
583 LogFlowFunc(("pVGAState %p, pMouseShapeInfo %p, fShape %d, pu8Shape %p\n",
584 pVGAState, pMouseShapeInfo, fShape, pu8Shape));
585#ifdef DEBUG_sunlover
586 dumpMouseShapeInfo(pMouseShapeInfo);
587#endif
588
589 if (fShape && pu8Shape != NULL)
590 {
591 rc = pVGAState->pDrv->pfnVBVAMousePointerShape (pVGAState->pDrv,
592 pMouseShapeInfo->fVisible,
593 pMouseShapeInfo->fAlpha,
594 pMouseShapeInfo->u32HotX,
595 pMouseShapeInfo->u32HotY,
596 pMouseShapeInfo->u32Width,
597 pMouseShapeInfo->u32Height,
598 pu8Shape);
599 }
600 else
601 {
602 rc = pVGAState->pDrv->pfnVBVAMousePointerShape (pVGAState->pDrv,
603 pMouseShapeInfo->fVisible,
604 false,
605 0, 0,
606 0, 0,
607 NULL);
608 }
609
610 return rc;
611}
612
613static int vbvaMousePointerShape (PVGASTATE pVGAState, VBVACONTEXT *pCtx, const VBVAMOUSEPOINTERSHAPE *pShape, HGSMISIZE cbShape)
614{
615 bool fVisible = (pShape->fu32Flags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
616 bool fAlpha = (pShape->fu32Flags & VBOX_MOUSE_POINTER_ALPHA) != 0;
617 bool fShape = (pShape->fu32Flags & VBOX_MOUSE_POINTER_SHAPE) != 0;
618
619 HGSMISIZE cbPointerData = 0;
620
621 if (fShape)
622 {
623 cbPointerData = ((((pShape->u32Width + 7) / 8) * pShape->u32Height + 3) & ~3)
624 + pShape->u32Width * 4 * pShape->u32Height;
625 }
626
627 if (cbPointerData > cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data))
628 {
629 Log(("vbvaMousePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
630 cbPointerData, cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data)));
631 return VERR_INVALID_PARAMETER;
632 }
633
634 /* Save mouse info it will be used to restore mouse pointer after restoring saved state. */
635 pCtx->mouseShapeInfo.fSet = true;
636 pCtx->mouseShapeInfo.fVisible = fVisible;
637 pCtx->mouseShapeInfo.fAlpha = fAlpha;
638 if (fShape)
639 {
640 /* Data related to shape. */
641 pCtx->mouseShapeInfo.u32HotX = pShape->u32HotX;
642 pCtx->mouseShapeInfo.u32HotY = pShape->u32HotY;
643 pCtx->mouseShapeInfo.u32Width = pShape->u32Width;
644 pCtx->mouseShapeInfo.u32Height = pShape->u32Height;
645
646 /* Reallocate memory buffer if necessary. */
647 if (cbPointerData > pCtx->mouseShapeInfo.cbAllocated)
648 {
649 RTMemFree (pCtx->mouseShapeInfo.pu8Shape);
650 pCtx->mouseShapeInfo.pu8Shape = NULL;
651 pCtx->mouseShapeInfo.cbShape = 0;
652
653 uint8_t *pu8Shape = (uint8_t *)RTMemAlloc (cbPointerData);
654 if (pu8Shape)
655 {
656 pCtx->mouseShapeInfo.pu8Shape = pu8Shape;
657 pCtx->mouseShapeInfo.cbAllocated = cbPointerData;
658 }
659 }
660
661 /* Copy shape bitmaps. */
662 if (pCtx->mouseShapeInfo.pu8Shape)
663 {
664 memcpy (pCtx->mouseShapeInfo.pu8Shape, &pShape->au8Data[0], cbPointerData);
665 pCtx->mouseShapeInfo.cbShape = cbPointerData;
666 }
667 }
668
669 if (pVGAState->pDrv->pfnVBVAMousePointerShape == NULL)
670 {
671 return VERR_NOT_SUPPORTED;
672 }
673
674 int rc = vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, fShape, &pShape->au8Data[0]);
675
676 return rc;
677}
678
679static unsigned vbvaViewFromOffset (PHGSMIINSTANCE pIns, VBVACONTEXT *pCtx, const void *pvBuffer)
680{
681 /* Check which view contains the buffer. */
682 HGSMIOFFSET offBuffer = HGSMIPointerToOffsetHost (pIns, pvBuffer);
683
684 if (offBuffer != HGSMIOFFSET_VOID)
685 {
686 unsigned uScreenId;
687
688 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
689 {
690 VBVAINFOVIEW *pView = &pCtx->aViews[uScreenId].view;
691
692 if ( pView->u32ViewSize > 0
693 && pView->u32ViewOffset <= offBuffer
694 && offBuffer <= pView->u32ViewOffset + pView->u32ViewSize - 1)
695 {
696 return pView->u32ViewIndex;
697 }
698 }
699 }
700
701 return ~0U;
702}
703
704#ifdef DEBUG_sunlover
705static void dumpctx(const VBVACONTEXT *pCtx)
706{
707 Log(("VBVACONTEXT dump: cViews %d\n", pCtx->cViews));
708
709 uint32_t iView;
710 for (iView = 0; iView < pCtx->cViews; iView++)
711 {
712 const VBVAVIEW *pView = &pCtx->aViews[iView];
713
714 Log((" view %d o 0x%x s 0x%x m 0x%x\n",
715 pView->view.u32ViewIndex,
716 pView->view.u32ViewOffset,
717 pView->view.u32ViewSize,
718 pView->view.u32MaxScreenSize));
719
720 Log((" screen %d @%d,%d s 0x%x l 0x%x %dx%d bpp %d f 0x%x\n",
721 pView->screen.u32ViewIndex,
722 pView->screen.i32OriginX,
723 pView->screen.i32OriginY,
724 pView->screen.u32StartOffset,
725 pView->screen.u32LineSize,
726 pView->screen.u32Width,
727 pView->screen.u32Height,
728 pView->screen.u16BitsPerPixel,
729 pView->screen.u16Flags));
730
731 Log((" VBVA o 0x%x p %p\n",
732 pView->u32VBVAOffset,
733 pView->pVBVA));
734
735 Log((" PR cb 0x%x p %p\n",
736 pView->partialRecord.cb,
737 pView->partialRecord.pu8));
738 }
739
740 dumpMouseShapeInfo(&pCtx->mouseShapeInfo);
741}
742#endif /* DEBUG_sunlover */
743
744#define VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC 0x12345678
745#define VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC 0x9abcdef0
746
747#ifdef VBOX_WITH_VIDEOHWACCEL
748static void vbvaVHWAHHCommandReinit(VBOXVHWACMD* pHdr, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay)
749{
750 memset(pHdr, 0, VBOXVHWACMD_HEADSIZE());
751 pHdr->cRefs = 1;
752 pHdr->iDisplay = iDisplay;
753 pHdr->rc = VERR_NOT_IMPLEMENTED;
754 pHdr->enmCmd = enmCmd;
755 pHdr->Flags = VBOXVHWACMD_FLAG_HH_CMD;
756}
757
758static VBOXVHWACMD* vbvaVHWAHHCommandCreate (PVGASTATE pVGAState, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay, VBOXVHWACMD_LENGTH cbCmd)
759{
760 VBOXVHWACMD* pHdr = (VBOXVHWACMD*)RTMemAlloc(cbCmd + VBOXVHWACMD_HEADSIZE());
761 Assert(pHdr);
762 if (pHdr)
763 vbvaVHWAHHCommandReinit(pHdr, enmCmd, iDisplay);
764
765 return pHdr;
766}
767
768DECLINLINE(void) vbvaVHWAHHCommandRelease (VBOXVHWACMD* pCmd)
769{
770 uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs);
771 if(!cRefs)
772 {
773 RTMemFree(pCmd);
774 }
775}
776
777DECLINLINE(void) vbvaVHWAHHCommandRetain (VBOXVHWACMD* pCmd)
778{
779 ASMAtomicIncU32(&pCmd->cRefs);
780}
781
782static unsigned vbvaVHWAHandleCommand (PVGASTATE pVGAState, VBVACONTEXT *pCtx, PVBOXVHWACMD pCmd)
783{
784 if (pVGAState->pDrv->pfnVHWACommandProcess)
785 pVGAState->pDrv->pfnVHWACommandProcess(pVGAState->pDrv, pCmd);
786#ifdef DEBUG_misha
787 else
788 AssertFailed();
789#endif
790 return 0;
791}
792
793static DECLCALLBACK(void) vbvaVHWAHHCommandSetEventCallback(void * pContext)
794{
795 RTSemEventSignal((RTSEMEVENT)pContext);
796}
797
798static int vbvaVHWAHHCommandPost(PVGASTATE pVGAState, VBOXVHWACMD* pCmd)
799{
800 RTSEMEVENT hComplEvent;
801 int rc = RTSemEventCreate(&hComplEvent);
802 AssertRC(rc);
803 if(RT_SUCCESS(rc))
804 {
805 /* ensure the cmd is not deleted until we process it */
806 vbvaVHWAHHCommandRetain (pCmd);
807 VBOXVHWA_HH_CALLBACK_SET(pCmd, vbvaVHWAHHCommandSetEventCallback, (void*)hComplEvent);
808 vbvaVHWAHandleCommand(pVGAState, NULL, pCmd);
809 if((ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_ASYNCH) != 0)
810 {
811 rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT);
812 }
813 else
814 {
815 /* the command is completed */
816 }
817
818 AssertRC(rc);
819 if(RT_SUCCESS(rc))
820 {
821 RTSemEventDestroy(hComplEvent);
822 }
823 vbvaVHWAHHCommandRelease(pCmd);
824 }
825 return rc;
826}
827
828int vbvaVHWAConstruct (PVGASTATE pVGAState)
829{
830 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_CONSTRUCT, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
831 Assert(pCmd);
832 if(pCmd)
833 {
834 uint32_t iDisplay = 0;
835 int rc = VINF_SUCCESS;
836 VBOXVHWACMD_HH_CONSTRUCT * pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_CONSTRUCT);
837
838 do
839 {
840 memset(pBody, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
841
842 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
843 PVM pVM = PDMDevHlpGetVM(pDevIns);
844
845 pBody->pVM = pVM;
846 pBody->pvVRAM = pVGAState->vram_ptrR3;
847 pBody->cbVRAM = pVGAState->vram_size;
848
849 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
850 AssertRC(rc);
851 if(RT_SUCCESS(rc))
852 {
853 rc = pCmd->rc;
854 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
855 if(rc == VERR_NOT_IMPLEMENTED)
856 {
857 /* @todo: set some flag in pVGAState indicating VHWA is not supported */
858 /* VERR_NOT_IMPLEMENTED is not a failure, we just do not support it */
859 rc = VINF_SUCCESS;
860 }
861
862 if (!RT_SUCCESS(rc))
863 break;
864 }
865 else
866 break;
867
868 ++iDisplay;
869 if (iDisplay >= pVGAState->cMonitors)
870 break;
871 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_CONSTRUCT, (int32_t)iDisplay);
872 } while (true);
873
874 vbvaVHWAHHCommandRelease(pCmd);
875
876 return rc;
877 }
878 return VERR_OUT_OF_RESOURCES;
879}
880
881int vbvaVHWAReset (PVGASTATE pVGAState)
882{
883 /* ensure we have all pending cmds processed and h->g cmds disabled */
884 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_RESET, 0, 0);
885 Assert(pCmd);
886 if(pCmd)
887 {
888 int rc = VINF_SUCCESS;
889 uint32_t iDisplay = 0;
890
891 do
892 {
893 rc =vbvaVHWAHHCommandPost(pVGAState, pCmd);
894 AssertRC(rc);
895 if(RT_SUCCESS(rc))
896 {
897 rc = pCmd->rc;
898 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
899 if (rc == VERR_NOT_IMPLEMENTED)
900 rc = VINF_SUCCESS;
901 }
902
903 if (!RT_SUCCESS(rc))
904 break;
905
906 ++iDisplay;
907 if (iDisplay >= pVGAState->cMonitors)
908 break;
909 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_RESET, (int32_t)iDisplay);
910
911 } while (true);
912
913 vbvaVHWAHHCommandRelease(pCmd);
914
915 return rc;
916 }
917 return VERR_OUT_OF_RESOURCES;
918}
919
920typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPRECB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext);
921typedef FNVBOXVHWAHHCMDPRECB *PFNVBOXVHWAHHCMDPRECB;
922
923typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPOSTCB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext);
924typedef FNVBOXVHWAHHCMDPOSTCB *PFNVBOXVHWAHHCMDPOSTCB;
925
926int vbvaVHWAHHPost(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, PFNVBOXVHWAHHCMDPRECB pfnPre, PFNVBOXVHWAHHCMDPOSTCB pfnPost, void *pvContext)
927{
928 const VBOXVHWACMD_TYPE enmType = pCmd->enmCmd;
929 int rc = VINF_SUCCESS;
930 uint32_t iDisplay = 0;
931
932 do
933 {
934 if (!pfnPre || pfnPre(pVGAState, pCmd, iDisplay, pvContext))
935 {
936 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
937 AssertRC(rc);
938 if (pfnPost)
939 {
940 if (!pfnPost(pVGAState, pCmd, iDisplay, rc, pvContext))
941 {
942 rc = VINF_SUCCESS;
943 break;
944 }
945 rc = VINF_SUCCESS;
946 }
947 else if(RT_SUCCESS(rc))
948 {
949 rc = pCmd->rc;
950 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
951 if(rc == VERR_NOT_IMPLEMENTED)
952 {
953 rc = VINF_SUCCESS;
954 }
955 }
956
957 if (!RT_SUCCESS(rc))
958 break;
959 }
960
961 ++iDisplay;
962 if (iDisplay >= pVGAState->cMonitors)
963 break;
964 vbvaVHWAHHCommandReinit(pCmd, enmType, (int32_t)iDisplay);
965 } while (true);
966
967 return rc;
968}
969
970/* @todo call this also on reset? */
971int vbvaVHWAEnable (PVGASTATE pVGAState, bool bEnable)
972{
973 const VBOXVHWACMD_TYPE enmType = bEnable ? VBOXVHWACMD_TYPE_HH_ENABLE : VBOXVHWACMD_TYPE_HH_DISABLE;
974 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState,
975 enmType,
976 0, 0);
977 Assert(pCmd);
978 if(pCmd)
979 {
980 int rc = vbvaVHWAHHPost (pVGAState, pCmd, NULL, NULL, NULL);
981 vbvaVHWAHHCommandRelease(pCmd);
982 return rc;
983 }
984 return VERR_OUT_OF_RESOURCES;
985}
986
987int vboxVBVASaveStatePrep (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
988{
989 /* ensure we have no pending commands */
990 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), false);
991}
992
993int vboxVBVASaveStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
994{
995 /* ensure we have no pending commands */
996 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), true);
997}
998
999int vbvaVHWACommandCompleteAsynch(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVHWACMD pCmd)
1000{
1001 int rc;
1002 if((pCmd->Flags & VBOXVHWACMD_FLAG_HH_CMD) == 0)
1003 {
1004 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
1005 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1006
1007 Assert(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
1008#ifdef VBOX_WITH_WDDM
1009 if (pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD)
1010 {
1011 rc = HGSMICompleteGuestCommand(pIns, pCmd, !!(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ));
1012 AssertRC(rc);
1013 }
1014 else
1015#endif
1016 {
1017 VBVAHOSTCMD *pHostCmd;
1018 int32_t iDisplay = pCmd->iDisplay;
1019
1020 if(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT)
1021 {
1022 rc = HGSMIHostCommandAlloc (pIns,
1023 (void**)&pHostCmd,
1024 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)),
1025 HGSMI_CH_VBVA,
1026 VBVAHG_EVENT);
1027 AssertRC(rc);
1028 if(RT_SUCCESS(rc))
1029 {
1030 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)));
1031 pHostCmd->iDstID = pCmd->iDisplay;
1032 pHostCmd->customOpCode = 0;
1033 VBVAHOSTCMDEVENT *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDEVENT);
1034 pBody->pEvent = pCmd->GuestVBVAReserved1;
1035 }
1036 }
1037 else
1038 {
1039 HGSMIOFFSET offCmd = HGSMIPointerToOffsetHost (pIns, pCmd);
1040 Assert(offCmd != HGSMIOFFSET_VOID);
1041 if(offCmd != HGSMIOFFSET_VOID)
1042 {
1043 rc = HGSMIHostCommandAlloc (pIns,
1044 (void**)&pHostCmd,
1045 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)),
1046 HGSMI_CH_VBVA,
1047 VBVAHG_DISPLAY_CUSTOM);
1048 AssertRC(rc);
1049 if(RT_SUCCESS(rc))
1050 {
1051 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)));
1052 pHostCmd->iDstID = pCmd->iDisplay;
1053 pHostCmd->customOpCode = VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE;
1054 VBVAHOSTCMDVHWACMDCOMPLETE *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDVHWACMDCOMPLETE);
1055 pBody->offCmd = offCmd;
1056 }
1057 }
1058 else
1059 {
1060 rc = VERR_INVALID_PARAMETER;
1061 }
1062 }
1063
1064 if(RT_SUCCESS(rc))
1065 {
1066 rc = HGSMIHostCommandProcessAndFreeAsynch(pIns, pHostCmd, (pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ) != 0);
1067 AssertRC(rc);
1068 if(RT_SUCCESS(rc))
1069 {
1070 return rc;
1071 }
1072 HGSMIHostCommandFree (pIns, pHostCmd);
1073 }
1074 }
1075 }
1076 else
1077 {
1078 PFNVBOXVHWA_HH_CALLBACK pfn = VBOXVHWA_HH_CALLBACK_GET(pCmd);
1079 if(pfn)
1080 {
1081 pfn(VBOXVHWA_HH_CALLBACK_GET_ARG(pCmd));
1082 }
1083 rc = VINF_SUCCESS;
1084 }
1085 return rc;
1086}
1087
1088typedef struct VBOXVBVASAVEDSTATECBDATA
1089{
1090 PSSMHANDLE pSSM;
1091 int rc;
1092 bool ab2DOn[VBOX_VIDEO_MAX_SCREENS];
1093} VBOXVBVASAVEDSTATECBDATA, *PVBOXVBVASAVEDSTATECBDATA;
1094
1095static DECLCALLBACK(bool) vboxVBVASaveStateBeginPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1096{
1097 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1098 if (RT_FAILURE(pData->rc))
1099 return false;
1100 if (RT_FAILURE(rc))
1101 {
1102 pData->rc = rc;
1103 return false;
1104 }
1105
1106 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1107 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1108 {
1109 pData->rc = VERR_INVALID_PARAMETER;
1110 return false;
1111 }
1112
1113 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1114 if (RT_SUCCESS(pCmd->rc))
1115 {
1116 pData->ab2DOn[iDisplay] = true;
1117 }
1118 else if (pCmd->rc != VERR_NOT_IMPLEMENTED)
1119 {
1120 pData->rc = pCmd->rc;
1121 return false;
1122 }
1123
1124 return true;
1125}
1126
1127static DECLCALLBACK(bool) vboxVBVASaveStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1128{
1129 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1130 if (RT_FAILURE(pData->rc))
1131 return false;
1132
1133 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1134 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1135 {
1136 pData->rc = VERR_INVALID_PARAMETER;
1137 return false;
1138 }
1139
1140 int rc;
1141
1142 if (pData->ab2DOn[iDisplay])
1143 {
1144 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC); AssertRC(rc);
1145 if (RT_FAILURE(rc))
1146 {
1147 pData->rc = rc;
1148 return false;
1149 }
1150 return true;
1151 }
1152
1153 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC); AssertRC(rc);
1154 if (RT_FAILURE(rc))
1155 {
1156 pData->rc = rc;
1157 return false;
1158 }
1159
1160 return false;
1161}
1162
1163static DECLCALLBACK(bool) vboxVBVASaveStateEndPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1164{
1165 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1166 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1167 if (pData->ab2DOn[iDisplay])
1168 {
1169 return true;
1170 }
1171
1172 return false;
1173}
1174
1175static DECLCALLBACK(bool) vboxVBVALoadStatePerformPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1176{
1177 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1178 if (RT_FAILURE(pData->rc))
1179 return false;
1180 if (RT_FAILURE(rc))
1181 {
1182 pData->rc = rc;
1183 return false;
1184 }
1185
1186 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1187 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1188 {
1189 pData->rc = VERR_INVALID_PARAMETER;
1190 return false;
1191 }
1192
1193 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1194 if (pCmd->rc == VERR_NOT_IMPLEMENTED)
1195 {
1196 pData->rc = SSMR3SkipToEndOfUnit(pData->pSSM);
1197 AssertRC(pData->rc);
1198 return false;
1199 }
1200 if (RT_FAILURE(pCmd->rc))
1201 {
1202 pData->rc = pCmd->rc;
1203 return false;
1204 }
1205
1206 return true;
1207}
1208
1209static DECLCALLBACK(bool) vboxVBVALoadStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1210{
1211 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1212 if (RT_FAILURE(pData->rc))
1213 return false;
1214
1215 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1216 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1217 {
1218 pData->rc = VERR_INVALID_PARAMETER;
1219 return false;
1220 }
1221
1222 int rc;
1223 uint32_t u32;
1224 rc = SSMR3GetU32(pData->pSSM, &u32); AssertRC(rc);
1225 if (RT_FAILURE(rc))
1226 {
1227 pData->rc = rc;
1228 return false;
1229 }
1230
1231 switch (u32)
1232 {
1233 case VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC:
1234 return true;
1235 case VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC:
1236 return false;
1237 default:
1238 pData->rc = VERR_INVALID_STATE;
1239 return false;
1240 }
1241}
1242#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
1243
1244int vboxVBVASaveDevStateExec (PVGASTATE pVGAState, PSSMHANDLE pSSM)
1245{
1246 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1247 int rc = HGSMIHostSaveStateExec (pIns, pSSM);
1248 if (RT_SUCCESS(rc))
1249 {
1250 /* Save VBVACONTEXT. */
1251 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1252
1253 if (!pCtx)
1254 {
1255 AssertFailed();
1256
1257 /* Still write a valid value to the SSM. */
1258 rc = SSMR3PutU32 (pSSM, 0);
1259 AssertRCReturn(rc, rc);
1260 }
1261 else
1262 {
1263#ifdef DEBUG_sunlover
1264 dumpctx(pCtx);
1265#endif
1266
1267 rc = SSMR3PutU32 (pSSM, pCtx->cViews);
1268 AssertRCReturn(rc, rc);
1269
1270 uint32_t iView;
1271 for (iView = 0; iView < pCtx->cViews; iView++)
1272 {
1273 VBVAVIEW *pView = &pCtx->aViews[iView];
1274
1275 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewIndex);
1276 AssertRCReturn(rc, rc);
1277 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewOffset);
1278 AssertRCReturn(rc, rc);
1279 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewSize);
1280 AssertRCReturn(rc, rc);
1281 rc = SSMR3PutU32 (pSSM, pView->view.u32MaxScreenSize);
1282 AssertRCReturn(rc, rc);
1283
1284 rc = SSMR3PutU32 (pSSM, pView->screen.u32ViewIndex);
1285 AssertRCReturn(rc, rc);
1286 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginX);
1287 AssertRCReturn(rc, rc);
1288 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginY);
1289 AssertRCReturn(rc, rc);
1290 rc = SSMR3PutU32 (pSSM, pView->screen.u32StartOffset);
1291 AssertRCReturn(rc, rc);
1292 rc = SSMR3PutU32 (pSSM, pView->screen.u32LineSize);
1293 AssertRCReturn(rc, rc);
1294 rc = SSMR3PutU32 (pSSM, pView->screen.u32Width);
1295 AssertRCReturn(rc, rc);
1296 rc = SSMR3PutU32 (pSSM, pView->screen.u32Height);
1297 AssertRCReturn(rc, rc);
1298 rc = SSMR3PutU16 (pSSM, pView->screen.u16BitsPerPixel);
1299 AssertRCReturn(rc, rc);
1300 rc = SSMR3PutU16 (pSSM, pView->screen.u16Flags);
1301 AssertRCReturn(rc, rc);
1302
1303 rc = SSMR3PutU32 (pSSM, pView->pVBVA? pView->u32VBVAOffset: HGSMIOFFSET_VOID);
1304 AssertRCReturn(rc, rc);
1305
1306 rc = SSMR3PutU32 (pSSM, pView->partialRecord.cb);
1307 AssertRCReturn(rc, rc);
1308
1309 if (pView->partialRecord.cb > 0)
1310 {
1311 rc = SSMR3PutMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1312 AssertRCReturn(rc, rc);
1313 }
1314 }
1315
1316 /* Save mouse pointer shape information. */
1317 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fSet);
1318 AssertRCReturn(rc, rc);
1319 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fVisible);
1320 AssertRCReturn(rc, rc);
1321 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fAlpha);
1322 AssertRCReturn(rc, rc);
1323 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotX);
1324 AssertRCReturn(rc, rc);
1325 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotY);
1326 AssertRCReturn(rc, rc);
1327 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Width);
1328 AssertRCReturn(rc, rc);
1329 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Height);
1330 AssertRCReturn(rc, rc);
1331 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.cbShape);
1332 AssertRCReturn(rc, rc);
1333 if (pCtx->mouseShapeInfo.cbShape)
1334 {
1335 rc = SSMR3PutMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1336 AssertRCReturn(rc, rc);
1337 }
1338
1339#ifdef VBOX_WITH_WDDM
1340 /* Size of some additional data. For future extensions. */
1341 rc = SSMR3PutU32 (pSSM, 4);
1342 AssertRCReturn(rc, rc);
1343 rc = SSMR3PutU32 (pSSM, pVGAState->fGuestCaps);
1344 AssertRCReturn(rc, rc);
1345#else
1346 /* Size of some additional data. For future extensions. */
1347 rc = SSMR3PutU32 (pSSM, 0);
1348 AssertRCReturn(rc, rc);
1349#endif
1350 }
1351 }
1352
1353 return rc;
1354}
1355
1356int vboxVBVASaveStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1357{
1358 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1359 int rc;
1360#ifdef VBOX_WITH_VIDEOHWACCEL
1361 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1362 VhwaData.pSSM = pSSM;
1363 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM); /* maximum cmd size */
1364 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN, 0, cbCmd);
1365 Assert(pCmd);
1366 if(pCmd)
1367 {
1368 vbvaVHWAHHPost (pVGAState, pCmd, NULL, vboxVBVASaveStateBeginPostCb, &VhwaData);
1369 rc = VhwaData.rc;
1370 AssertRC(rc);
1371 if (RT_SUCCESS(rc))
1372 {
1373#endif
1374 rc = vboxVBVASaveDevStateExec (pVGAState, pSSM);
1375 AssertRC(rc);
1376#ifdef VBOX_WITH_VIDEOHWACCEL
1377 if (RT_SUCCESS(rc))
1378 {
1379 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM, 0);
1380 VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM *pSave = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM);
1381 pSave->pSSM = pSSM;
1382 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStatePerformPreCb, NULL, &VhwaData);
1383 rc = VhwaData.rc;
1384 AssertRC(rc);
1385 if (RT_SUCCESS(rc))
1386 {
1387 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND, 0);
1388 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStateEndPreCb, NULL, &VhwaData);
1389 rc = VhwaData.rc;
1390 AssertRC(rc);
1391 }
1392 }
1393 }
1394
1395 vbvaVHWAHHCommandRelease(pCmd);
1396 }
1397 else
1398 rc = VERR_OUT_OF_RESOURCES;
1399#else
1400 if (RT_SUCCESS(rc))
1401 {
1402 for (uint32_t i = 0; i < pVGAState->cMonitors; ++i)
1403 {
1404 rc = SSMR3PutU32 (pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC);
1405 AssertRCReturn(rc, rc);
1406 }
1407 }
1408#endif
1409 return rc;
1410}
1411
1412int vboxVBVALoadStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t u32Version)
1413{
1414 if (u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1415 {
1416 /* Nothing was saved. */
1417 return VINF_SUCCESS;
1418 }
1419
1420 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1421 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1422 int rc = HGSMIHostLoadStateExec (pIns, pSSM, u32Version);
1423 if (RT_SUCCESS(rc))
1424 {
1425 /* Load VBVACONTEXT. */
1426 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1427
1428 if (!pCtx)
1429 {
1430 /* This should not happen. */
1431 AssertFailed();
1432 rc = VERR_INVALID_PARAMETER;
1433 }
1434 else
1435 {
1436 uint32_t cViews = 0;
1437 rc = SSMR3GetU32 (pSSM, &cViews);
1438 AssertRCReturn(rc, rc);
1439
1440 uint32_t iView;
1441 for (iView = 0; iView < cViews; iView++)
1442 {
1443 VBVAVIEW *pView = &pCtx->aViews[iView];
1444
1445 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewIndex);
1446 AssertRCReturn(rc, rc);
1447 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewOffset);
1448 AssertRCReturn(rc, rc);
1449 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewSize);
1450 AssertRCReturn(rc, rc);
1451 rc = SSMR3GetU32 (pSSM, &pView->view.u32MaxScreenSize);
1452 AssertRCReturn(rc, rc);
1453
1454 rc = SSMR3GetU32 (pSSM, &pView->screen.u32ViewIndex);
1455 AssertRCReturn(rc, rc);
1456 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginX);
1457 AssertRCReturn(rc, rc);
1458 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginY);
1459 AssertRCReturn(rc, rc);
1460 rc = SSMR3GetU32 (pSSM, &pView->screen.u32StartOffset);
1461 AssertRCReturn(rc, rc);
1462 rc = SSMR3GetU32 (pSSM, &pView->screen.u32LineSize);
1463 AssertRCReturn(rc, rc);
1464 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Width);
1465 AssertRCReturn(rc, rc);
1466 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Height);
1467 AssertRCReturn(rc, rc);
1468 rc = SSMR3GetU16 (pSSM, &pView->screen.u16BitsPerPixel);
1469 AssertRCReturn(rc, rc);
1470 rc = SSMR3GetU16 (pSSM, &pView->screen.u16Flags);
1471 AssertRCReturn(rc, rc);
1472
1473 rc = SSMR3GetU32 (pSSM, &pView->u32VBVAOffset);
1474 AssertRCReturn(rc, rc);
1475
1476 rc = SSMR3GetU32 (pSSM, &pView->partialRecord.cb);
1477 AssertRCReturn(rc, rc);
1478
1479 if (pView->partialRecord.cb == 0)
1480 {
1481 pView->partialRecord.pu8 = NULL;
1482 }
1483 else
1484 {
1485 Assert(pView->partialRecord.pu8 == NULL); /* Should be it. */
1486
1487 uint8_t *pu8 = (uint8_t *)RTMemAlloc (pView->partialRecord.cb);
1488
1489 if (!pu8)
1490 {
1491 return VERR_NO_MEMORY;
1492 }
1493
1494 pView->partialRecord.pu8 = pu8;
1495
1496 rc = SSMR3GetMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1497 AssertRCReturn(rc, rc);
1498 }
1499
1500 if ( pView->u32VBVAOffset == HGSMIOFFSET_VOID
1501 || pView->screen.u32LineSize == 0) /* Earlier broken saved states. */
1502 {
1503 pView->pVBVA = NULL;
1504 }
1505 else
1506 {
1507 pView->pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, pView->u32VBVAOffset);
1508 }
1509 }
1510
1511 if (u32Version > VGA_SAVEDSTATE_VERSION_WITH_CONFIG)
1512 {
1513 /* Read mouse pointer shape information. */
1514 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fSet);
1515 AssertRCReturn(rc, rc);
1516 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fVisible);
1517 AssertRCReturn(rc, rc);
1518 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fAlpha);
1519 AssertRCReturn(rc, rc);
1520 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotX);
1521 AssertRCReturn(rc, rc);
1522 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotY);
1523 AssertRCReturn(rc, rc);
1524 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Width);
1525 AssertRCReturn(rc, rc);
1526 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Height);
1527 AssertRCReturn(rc, rc);
1528 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.cbShape);
1529 AssertRCReturn(rc, rc);
1530 if (pCtx->mouseShapeInfo.cbShape)
1531 {
1532 pCtx->mouseShapeInfo.pu8Shape = (uint8_t *)RTMemAlloc(pCtx->mouseShapeInfo.cbShape);
1533 if (pCtx->mouseShapeInfo.pu8Shape == NULL)
1534 {
1535 return VERR_NO_MEMORY;
1536 }
1537 pCtx->mouseShapeInfo.cbAllocated = pCtx->mouseShapeInfo.cbShape;
1538 rc = SSMR3GetMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1539 AssertRCReturn(rc, rc);
1540 }
1541 else
1542 {
1543 pCtx->mouseShapeInfo.pu8Shape = NULL;
1544 }
1545
1546 /* Size of some additional data. For future extensions. */
1547 uint32_t cbExtra = 0;
1548 rc = SSMR3GetU32 (pSSM, &cbExtra);
1549 AssertRCReturn(rc, rc);
1550#ifdef VBOX_WITH_WDDM
1551 if (cbExtra >= 4)
1552 {
1553 rc = SSMR3GetU32 (pSSM, &pVGAState->fGuestCaps);
1554 AssertRCReturn(rc, rc);
1555 cbExtra -= 4;
1556 }
1557#endif
1558 if (cbExtra > 0)
1559 {
1560 rc = SSMR3Skip(pSSM, cbExtra);
1561 AssertRCReturn(rc, rc);
1562 }
1563 }
1564
1565 pCtx->cViews = iView;
1566 LogFlowFunc(("%d views loaded\n", pCtx->cViews));
1567
1568 if (u32Version > VGA_SAVEDSTATE_VERSION_WDDM)
1569 {
1570#ifdef VBOX_WITH_VIDEOHWACCEL
1571 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM); /* maximum cmd size */
1572 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM, 0, cbCmd);
1573 Assert(pCmd);
1574 if(pCmd)
1575 {
1576 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1577 VhwaData.pSSM = pSSM;
1578 VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM *pLoad = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM);
1579 pLoad->pSSM = pSSM;
1580 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVALoadStatePerformPreCb, vboxVBVALoadStatePerformPostCb, &VhwaData);
1581 rc = VhwaData.rc;
1582 AssertRC(rc);
1583 vbvaVHWAHHCommandRelease(pCmd);
1584 }
1585 else
1586 {
1587 rc = VERR_OUT_OF_RESOURCES;
1588 }
1589#else
1590 rc = SSMR3SkipToEndOfUnit(pSSM);
1591 AssertRCReturn(rc, rc);
1592#endif
1593 }
1594
1595#ifdef DEBUG_sunlover
1596 dumpctx(pCtx);
1597#endif
1598 }
1599 }
1600
1601 return rc;
1602}
1603
1604int vboxVBVALoadStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1605{
1606 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1607 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
1608
1609 if (pCtx)
1610 {
1611 uint32_t iView;
1612 for (iView = 0; iView < pCtx->cViews; iView++)
1613 {
1614 VBVAVIEW *pView = &pCtx->aViews[iView];
1615
1616 if (pView->pVBVA)
1617 {
1618 vbvaEnable (iView, pVGAState, pCtx, pView->pVBVA, pView->u32VBVAOffset, true /* fRestored */);
1619 vbvaResize (pVGAState, pView, &pView->screen);
1620 }
1621 }
1622
1623 if (pCtx->mouseShapeInfo.fSet)
1624 {
1625 vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, true, pCtx->mouseShapeInfo.pu8Shape);
1626 }
1627 }
1628
1629 return VINF_SUCCESS;
1630}
1631
1632void VBVARaiseIrq (PVGASTATE pVGAState, uint32_t fFlags)
1633{
1634 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1635 PDMCritSectEnter(&pVGAState->lock, VERR_SEM_BUSY);
1636 HGSMISetHostGuestFlags(pVGAState->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
1637 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1638 PDMCritSectLeave(&pVGAState->lock);
1639}
1640
1641/*
1642 *
1643 * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
1644 *
1645 * VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
1646 * Read Write
1647 * Host port 0x3b0 to process completed
1648 * Guest port 0x3d0 control value? to process
1649 *
1650 */
1651
1652static DECLCALLBACK(void) vbvaNotifyGuest (void *pvCallback)
1653{
1654#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
1655 PVGASTATE pVGAState = (PVGASTATE)pvCallback;
1656 VBVARaiseIrq (pVGAState, 0);
1657#else
1658 NOREF(pvCallback);
1659 /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */
1660#endif
1661}
1662
1663/* The guest submitted a buffer. @todo Verify all guest data. */
1664static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1665{
1666 int rc = VINF_SUCCESS;
1667
1668 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
1669 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
1670
1671 PVGASTATE pVGAState = (PVGASTATE)pvHandler;
1672 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1673 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1674
1675 switch (u16ChannelInfo)
1676 {
1677#ifdef VBOX_WITH_VDMA
1678 case VBVA_VDMA_CMD:
1679 {
1680 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMACBUF_DR))
1681 {
1682 rc = VERR_INVALID_PARAMETER;
1683 break;
1684 }
1685 PVBOXVDMACBUF_DR pCmd = (PVBOXVDMACBUF_DR)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
1686 vboxVDMACommand(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1687 rc = VINF_SUCCESS;
1688 break;
1689 }
1690 case VBVA_VDMA_CTL:
1691 {
1692 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMA_CTL))
1693 {
1694 rc = VERR_INVALID_PARAMETER;
1695 break;
1696 }
1697 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
1698 vboxVDMAControl(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1699 rc = VINF_SUCCESS;
1700 break;
1701 }
1702#endif
1703 case VBVA_QUERY_CONF32:
1704 {
1705 if (cbBuffer < sizeof (VBVACONF32))
1706 {
1707 rc = VERR_INVALID_PARAMETER;
1708 break;
1709 }
1710
1711 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
1712 LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n",
1713 pConf32->u32Index, pConf32->u32Value));
1714
1715 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
1716 {
1717 pConf32->u32Value = pCtx->cViews;
1718 }
1719 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
1720 {
1721 /* @todo a value calculated from the vram size */
1722 pConf32->u32Value = 64*_1K;
1723 }
1724 else
1725 {
1726 Log(("Unsupported VBVA_QUERY_CONF32 index %d!!!\n",
1727 pConf32->u32Index));
1728 rc = VERR_INVALID_PARAMETER;
1729 }
1730 } break;
1731
1732 case VBVA_SET_CONF32:
1733 {
1734 if (cbBuffer < sizeof (VBVACONF32))
1735 {
1736 rc = VERR_INVALID_PARAMETER;
1737 break;
1738 }
1739
1740 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
1741 LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n",
1742 pConf32->u32Index, pConf32->u32Value));
1743
1744 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
1745 {
1746 /* do nothing. this is a const. */
1747 }
1748 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
1749 {
1750 /* do nothing. this is a const. */
1751 }
1752 else
1753 {
1754 Log(("Unsupported VBVA_SET_CONF32 index %d!!!\n",
1755 pConf32->u32Index));
1756 rc = VERR_INVALID_PARAMETER;
1757 }
1758 } break;
1759
1760 case VBVA_INFO_VIEW:
1761 {
1762 if (cbBuffer < sizeof (VBVAINFOVIEW))
1763 {
1764 rc = VERR_INVALID_PARAMETER;
1765 break;
1766 }
1767
1768 /* Guest submits an array of VBVAINFOVIEW structures. */
1769 VBVAINFOVIEW *pView = (VBVAINFOVIEW *)pvBuffer;
1770
1771 for (;
1772 cbBuffer >= sizeof (VBVAINFOVIEW);
1773 pView++, cbBuffer -= sizeof (VBVAINFOVIEW))
1774 {
1775 LogFlowFunc(("VBVA_INFO_VIEW: index %d, offset 0x%x, size 0x%x, max screen size 0x%x\n",
1776 pView->u32ViewIndex, pView->u32ViewOffset, pView->u32ViewSize, pView->u32MaxScreenSize));
1777
1778 /* @todo verify view data. */
1779 if (pView->u32ViewIndex >= pCtx->cViews)
1780 {
1781 Log(("View index too large %d!!!\n",
1782 pView->u32ViewIndex));
1783 rc = VERR_INVALID_PARAMETER;
1784 break;
1785 }
1786
1787 pCtx->aViews[pView->u32ViewIndex].view = *pView;
1788 }
1789 } break;
1790
1791 case VBVA_INFO_HEAP:
1792 {
1793 if (cbBuffer < sizeof (VBVAINFOHEAP))
1794 {
1795 rc = VERR_INVALID_PARAMETER;
1796 break;
1797 }
1798
1799 VBVAINFOHEAP *pHeap = (VBVAINFOHEAP *)pvBuffer;
1800 LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n",
1801 pHeap->u32HeapOffset, pHeap->u32HeapSize));
1802
1803 rc = HGSMISetupHostHeap (pIns, pHeap->u32HeapOffset, pHeap->u32HeapSize);
1804 } break;
1805
1806 case VBVA_FLUSH:
1807 {
1808 if (cbBuffer < sizeof (VBVAFLUSH))
1809 {
1810 rc = VERR_INVALID_PARAMETER;
1811 break;
1812 }
1813
1814 VBVAFLUSH *pFlush = (VBVAFLUSH *)pvBuffer;
1815 LogFlowFunc(("VBVA_FLUSH: u32Reserved 0x%x\n",
1816 pFlush->u32Reserved));
1817
1818 rc = vbvaFlush (pVGAState, pCtx);
1819 } break;
1820
1821 case VBVA_INFO_SCREEN:
1822 {
1823 if (cbBuffer < sizeof (VBVAINFOSCREEN))
1824 {
1825 rc = VERR_INVALID_PARAMETER;
1826 break;
1827 }
1828
1829 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)pvBuffer;
1830 VBVAINFOVIEW *pView = &pCtx->aViews[pScreen->u32ViewIndex].view;
1831 /* Calculate the offset of the end of the screen so we can make
1832 * sure it is inside the view. I assume that screen rollover is not
1833 * implemented. */
1834 int64_t offEnd = (int64_t)pScreen->u32Height * pScreen->u32LineSize
1835 + pScreen->u32Width + pScreen->u32StartOffset;
1836 LogRelFlowFunc(("VBVA_INFO_SCREEN: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
1837 pScreen->u32ViewIndex, pScreen->i32OriginX, pScreen->i32OriginY,
1838 pScreen->u32Width, pScreen->u32Height,
1839 pScreen->u32LineSize, pScreen->u16BitsPerPixel, pScreen->u16Flags));
1840
1841 if ( pScreen->u32ViewIndex < RT_ELEMENTS (pCtx->aViews)
1842 && pScreen->u16BitsPerPixel <= 32
1843 && pScreen->u32Width <= UINT16_MAX
1844 && pScreen->u32Height <= UINT16_MAX
1845 && pScreen->u32LineSize <= UINT16_MAX * 4
1846 && offEnd < pView->u32MaxScreenSize)
1847 {
1848 vbvaResize (pVGAState, &pCtx->aViews[pScreen->u32ViewIndex], pScreen);
1849 }
1850 else
1851 {
1852 LogRelFlow(("VBVA_INFO_SCREEN [%lu]: bad data: %lux%lu, line 0x%lx, BPP %u, start offset %lu, max screen size %lu\n",
1853 (unsigned long)pScreen->u32ViewIndex,
1854 (unsigned long)pScreen->u32Width,
1855 (unsigned long)pScreen->u32Height,
1856 (unsigned long)pScreen->u32LineSize,
1857 (unsigned long)pScreen->u16BitsPerPixel,
1858 (unsigned long)pScreen->u32StartOffset,
1859 (unsigned long)pView->u32MaxScreenSize));
1860 rc = VERR_INVALID_PARAMETER;
1861 }
1862 } break;
1863
1864 case VBVA_ENABLE:
1865 {
1866 if (cbBuffer < sizeof (VBVAENABLE))
1867 {
1868 rc = VERR_INVALID_PARAMETER;
1869 break;
1870 }
1871
1872 VBVAENABLE *pEnable = (VBVAENABLE *)pvBuffer;
1873 unsigned uScreenId;
1874 if (pEnable->u32Flags & VBVA_F_EXTENDED)
1875 {
1876 if (cbBuffer < sizeof (VBVAENABLE_EX))
1877 {
1878 rc = VERR_INVALID_PARAMETER;
1879 break;
1880 }
1881
1882 VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)pvBuffer;
1883 uScreenId = pEnableEx->u32ScreenId;
1884 }
1885 else
1886 {
1887 uScreenId = vbvaViewFromOffset (pIns, pCtx, pvBuffer);
1888 }
1889
1890 if (uScreenId == ~0U)
1891 {
1892 rc = VERR_INVALID_PARAMETER;
1893 break;
1894 }
1895
1896 LogFlowFunc(("VBVA_ENABLE[%d]: u32Flags 0x%x u32Offset 0x%x\n",
1897 uScreenId, pEnable->u32Flags, pEnable->u32Offset));
1898
1899 if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE)
1900 {
1901 /* Guest reported offset relative to view. */
1902 uint32_t u32Offset = pEnable->u32Offset;
1903 if (!(pEnable->u32Flags & VBVA_F_ABSOFFSET))
1904 {
1905 u32Offset += pCtx->aViews[uScreenId].view.u32ViewOffset;
1906 }
1907
1908 VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, u32Offset);
1909
1910 if (pVBVA)
1911 {
1912 /* Process any pending orders and empty the VBVA ring buffer. */
1913 vbvaFlush (pVGAState, pCtx);
1914
1915 rc = vbvaEnable (uScreenId, pVGAState, pCtx, pVBVA, u32Offset, false /* fRestored */);
1916 }
1917 else
1918 {
1919 Log(("Invalid VBVABUFFER offset 0x%x!!!\n",
1920 pEnable->u32Offset));
1921 rc = VERR_INVALID_PARAMETER;
1922 }
1923 }
1924 else if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE)
1925 {
1926 rc = vbvaDisable (uScreenId, pVGAState, pCtx);
1927 }
1928 else
1929 {
1930 Log(("Invalid VBVA_ENABLE flags 0x%x!!!\n",
1931 pEnable->u32Flags));
1932 rc = VERR_INVALID_PARAMETER;
1933 }
1934
1935 pEnable->i32Result = rc;
1936 } break;
1937
1938 case VBVA_MOUSE_POINTER_SHAPE:
1939 {
1940 if (cbBuffer < sizeof (VBVAMOUSEPOINTERSHAPE))
1941 {
1942 rc = VERR_INVALID_PARAMETER;
1943 break;
1944 }
1945
1946 VBVAMOUSEPOINTERSHAPE *pShape = (VBVAMOUSEPOINTERSHAPE *)pvBuffer;
1947
1948 LogFlowFunc(("VBVA_MOUSE_POINTER_SHAPE: i32Result 0x%x, fu32Flags 0x%x, hot spot %d,%d, size %dx%d\n",
1949 pShape->i32Result,
1950 pShape->fu32Flags,
1951 pShape->u32HotX,
1952 pShape->u32HotY,
1953 pShape->u32Width,
1954 pShape->u32Height));
1955
1956 rc = vbvaMousePointerShape (pVGAState, pCtx, pShape, cbBuffer);
1957
1958 pShape->i32Result = rc;
1959 } break;
1960
1961
1962#ifdef VBOX_WITH_VIDEOHWACCEL
1963 case VBVA_VHWA_CMD:
1964 {
1965 rc = vbvaVHWAHandleCommand (pVGAState, pCtx, (PVBOXVHWACMD)pvBuffer);
1966 } break;
1967#endif
1968
1969#ifdef VBOX_WITH_WDDM
1970 case VBVA_INFO_CAPS:
1971 {
1972 if (cbBuffer < sizeof (VBVACAPS))
1973 {
1974 rc = VERR_INVALID_PARAMETER;
1975 break;
1976 }
1977
1978 VBVACAPS *pCaps = (VBVACAPS*)pvBuffer;
1979 pVGAState->fGuestCaps = pCaps->fCaps;
1980 pCaps->rc = VINF_SUCCESS;
1981 } break;
1982#endif
1983 case VBVA_SCANLINE_CFG:
1984 {
1985 if (cbBuffer < sizeof (VBVASCANLINECFG))
1986 {
1987 rc = VERR_INVALID_PARAMETER;
1988 break;
1989 }
1990
1991 VBVASCANLINECFG *pCfg = (VBVASCANLINECFG*)pvBuffer;
1992 pVGAState->fScanLineCfg = pCfg->fFlags;
1993 pCfg->rc = VINF_SUCCESS;
1994 } break;
1995 default:
1996 Log(("Unsupported VBVA guest command %d!!!\n",
1997 u16ChannelInfo));
1998 break;
1999 }
2000
2001 return rc;
2002}
2003
2004void VBVAReset (PVGASTATE pVGAState)
2005{
2006 if (!pVGAState || !pVGAState->pHGSMI)
2007 {
2008 return;
2009 }
2010
2011 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2012
2013#ifdef VBOX_WITH_VIDEOHWACCEL
2014 vbvaVHWAReset (pVGAState);
2015#endif
2016
2017 uint32_t HgFlags = HGSMIReset (pVGAState->pHGSMI);
2018 if(HgFlags & HGSMIHOSTFLAGS_IRQ)
2019 {
2020 /* this means the IRQ is LEVEL_HIGH, need to reset it */
2021 PDMDevHlpPCISetIrq(pVGAState->pDevInsR3, 0, PDM_IRQ_LEVEL_LOW);
2022 }
2023
2024 if (pCtx)
2025 {
2026 vbvaFlush (pVGAState, pCtx);
2027
2028 unsigned uScreenId;
2029
2030 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
2031 {
2032 vbvaDisable (uScreenId, pVGAState, pCtx);
2033 }
2034
2035 pCtx->mouseShapeInfo.fSet = false;
2036 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2037 pCtx->mouseShapeInfo.pu8Shape = NULL;
2038 pCtx->mouseShapeInfo.cbAllocated = 0;
2039 pCtx->mouseShapeInfo.cbShape = 0;
2040 }
2041
2042}
2043
2044int VBVAUpdateDisplay (PVGASTATE pVGAState)
2045{
2046 int rc = VERR_NOT_SUPPORTED; /* Assuming that the VGA device will have to do updates. */
2047
2048 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2049
2050 if (pCtx)
2051 {
2052 rc = vbvaFlush (pVGAState, pCtx);
2053
2054 if (RT_SUCCESS (rc))
2055 {
2056 if (!pCtx->aViews[0].pVBVA)
2057 {
2058 /* VBVA is not enabled for the first view, so VGA device must do updates. */
2059 rc = VERR_NOT_SUPPORTED;
2060 }
2061 }
2062 }
2063
2064 return rc;
2065}
2066
2067static HGSMICHANNELHANDLER sOldChannelHandler;
2068
2069int VBVAInit (PVGASTATE pVGAState)
2070{
2071 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
2072
2073 PVM pVM = PDMDevHlpGetVM(pDevIns);
2074
2075 int rc = HGSMICreate (&pVGAState->pHGSMI,
2076 pVM,
2077 "VBVA",
2078 0,
2079 pVGAState->vram_ptrR3,
2080 pVGAState->vram_size,
2081 vbvaNotifyGuest,
2082 pVGAState,
2083 sizeof (VBVACONTEXT));
2084
2085 if (RT_SUCCESS (rc))
2086 {
2087 rc = HGSMIHostChannelRegister (pVGAState->pHGSMI,
2088 HGSMI_CH_VBVA,
2089 vbvaChannelHandler,
2090 pVGAState,
2091 &sOldChannelHandler);
2092 if (RT_SUCCESS (rc))
2093 {
2094 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2095 pCtx->cViews = pVGAState->cMonitors;
2096 }
2097 }
2098
2099 return rc;
2100
2101}
2102
2103void VBVADestroy (PVGASTATE pVGAState)
2104{
2105 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2106
2107 if (pCtx)
2108 {
2109 pCtx->mouseShapeInfo.fSet = false;
2110 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2111 pCtx->mouseShapeInfo.pu8Shape = NULL;
2112 pCtx->mouseShapeInfo.cbAllocated = 0;
2113 pCtx->mouseShapeInfo.cbShape = 0;
2114 }
2115
2116 HGSMIDestroy (pVGAState->pHGSMI);
2117 pVGAState->pHGSMI = NULL;
2118}
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