VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA-SVGA.cpp@ 86679

Last change on this file since 86679 was 86479, checked in by vboxsync, 4 years ago

AMD IOMMU: bugref:9654 DevVGA-SVGA: Use PCI interfaces while reading/writing guest physical memory.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 271.4 KB
Line 
1/* $Id: DevVGA-SVGA.cpp 86479 2020-10-08 06:50:49Z vboxsync $ */
2/** @file
3 * VMware SVGA device.
4 *
5 * Logging levels guidelines for this and related files:
6 * - Log() for normal bits.
7 * - LogFlow() for more info.
8 * - Log2 for hex dump of cursor data.
9 * - Log3 for hex dump of shader code.
10 * - Log4 for hex dumps of 3D data.
11 * - Log5 for info about GMR pages.
12 * - LogRel for the usual important stuff.
13 * - LogRel2 for cursor.
14 * - LogRel3 for 3D performance data.
15 * - LogRel4 for HW accelerated graphics output.
16 */
17
18/*
19 * Copyright (C) 2013-2020 Oracle Corporation
20 *
21 * This file is part of VirtualBox Open Source Edition (OSE), as
22 * available from http://www.virtualbox.org. This file is free software;
23 * you can redistribute it and/or modify it under the terms of the GNU
24 * General Public License (GPL) as published by the Free Software
25 * Foundation, in version 2 as it comes in the "COPYING" file of the
26 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
27 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
28 */
29
30
31/** @page pg_dev_vmsvga VMSVGA - VMware SVGA II Device Emulation
32 *
33 * This device emulation was contributed by trivirt AG. It offers an
34 * alternative to our Bochs based VGA graphics and 3d emulations. This is
35 * valuable for Xorg based guests, as there is driver support shipping with Xorg
36 * since it forked from XFree86.
37 *
38 *
39 * @section sec_dev_vmsvga_sdk The VMware SDK
40 *
41 * This is officially deprecated now, however it's still quite useful,
42 * especially for getting the old features working:
43 * http://vmware-svga.sourceforge.net/
44 *
45 * They currently point developers at the following resources.
46 * - http://cgit.freedesktop.org/xorg/driver/xf86-video-vmware/
47 * - http://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/svga/
48 * - http://cgit.freedesktop.org/mesa/vmwgfx/
49 *
50 * @subsection subsec_dev_vmsvga_sdk_results Test results
51 *
52 * Test results:
53 * - 2dmark.img:
54 * + todo
55 * - backdoor-tclo.img:
56 * + todo
57 * - blit-cube.img:
58 * + todo
59 * - bunnies.img:
60 * + todo
61 * - cube.img:
62 * + todo
63 * - cubemark.img:
64 * + todo
65 * - dynamic-vertex-stress.img:
66 * + todo
67 * - dynamic-vertex.img:
68 * + todo
69 * - fence-stress.img:
70 * + todo
71 * - gmr-test.img:
72 * + todo
73 * - half-float-test.img:
74 * + todo
75 * - noscreen-cursor.img:
76 * - The CURSOR I/O and FIFO registers are not implemented, so the mouse
77 * cursor doesn't show. (Hacking the GUI a little, would make the cursor
78 * visible though.)
79 * - Cursor animation via the palette doesn't work.
80 * - During debugging, it turns out that the framebuffer content seems to
81 * be halfways ignore or something (memset(fb, 0xcc, lots)).
82 * - Trouble with way to small FIFO and the 256x256 cursor fails. Need to
83 * grow it 0x10 fold (128KB -> 2MB like in WS10).
84 * - null.img:
85 * + todo
86 * - pong.img:
87 * + todo
88 * - presentReadback.img:
89 * + todo
90 * - resolution-set.img:
91 * + todo
92 * - rt-gamma-test.img:
93 * + todo
94 * - screen-annotation.img:
95 * + todo
96 * - screen-cursor.img:
97 * + todo
98 * - screen-dma-coalesce.img:
99 * + todo
100 * - screen-gmr-discontig.img:
101 * + todo
102 * - screen-gmr-remap.img:
103 * + todo
104 * - screen-multimon.img:
105 * + todo
106 * - screen-present-clip.img:
107 * + todo
108 * - screen-render-test.img:
109 * + todo
110 * - screen-simple.img:
111 * + todo
112 * - screen-text.img:
113 * + todo
114 * - simple-shaders.img:
115 * + todo
116 * - simple_blit.img:
117 * + todo
118 * - tiny-2d-updates.img:
119 * + todo
120 * - video-formats.img:
121 * + todo
122 * - video-sync.img:
123 * + todo
124 *
125 */
126
127
128/*********************************************************************************************************************************
129* Header Files *
130*********************************************************************************************************************************/
131#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
132#include <VBox/vmm/pdmdev.h>
133#include <VBox/version.h>
134#include <VBox/err.h>
135#include <VBox/log.h>
136#include <VBox/vmm/pgm.h>
137#include <VBox/sup.h>
138
139#include <iprt/assert.h>
140#include <iprt/semaphore.h>
141#include <iprt/uuid.h>
142#ifdef IN_RING3
143# include <iprt/ctype.h>
144# include <iprt/mem.h>
145# ifdef VBOX_STRICT
146# include <iprt/time.h>
147# endif
148#endif
149
150#include <VBox/AssertGuest.h>
151#include <VBox/VMMDev.h>
152#include <VBoxVideo.h>
153#include <VBox/bioslogo.h>
154
155/* should go BEFORE any other DevVGA include to make all DevVGA.h config defines be visible */
156#include "DevVGA.h"
157
158#ifdef IN_RING3
159/* Should be included after DevVGA.h/DevVGA-SVGA.h to pick all defines. */
160#include "DevVGA-SVGA-internal.h"
161#endif
162#ifdef VBOX_WITH_VMSVGA3D
163# include "DevVGA-SVGA3d.h"
164# ifdef RT_OS_DARWIN
165# include "DevVGA-SVGA3d-cocoa.h"
166# endif
167# ifdef RT_OS_LINUX
168# ifdef IN_RING3
169# include "DevVGA-SVGA3d-glLdr.h"
170# endif
171# endif
172#endif
173
174
175/*********************************************************************************************************************************
176* Defined Constants And Macros *
177*********************************************************************************************************************************/
178/**
179 * Macro for checking if a fixed FIFO register is valid according to the
180 * current FIFO configuration.
181 *
182 * @returns true / false.
183 * @param a_iIndex The fifo register index (like SVGA_FIFO_CAPABILITIES).
184 * @param a_offFifoMin A valid SVGA_FIFO_MIN value.
185 */
186#define VMSVGA_IS_VALID_FIFO_REG(a_iIndex, a_offFifoMin) ( ((a_iIndex) + 1) * sizeof(uint32_t) <= (a_offFifoMin) )
187
188
189/*********************************************************************************************************************************
190* Structures and Typedefs *
191*********************************************************************************************************************************/
192
193
194/*********************************************************************************************************************************
195* Internal Functions *
196*********************************************************************************************************************************/
197#ifdef IN_RING3
198# if defined(VMSVGA_USE_FIFO_ACCESS_HANDLER) || defined(DEBUG_FIFO_ACCESS)
199static FNPGMPHYSHANDLER vmsvgaR3FifoAccessHandler;
200# endif
201# ifdef DEBUG_GMR_ACCESS
202static FNPGMPHYSHANDLER vmsvgaR3GmrAccessHandler;
203# endif
204#endif
205
206
207/*********************************************************************************************************************************
208* Global Variables *
209*********************************************************************************************************************************/
210#ifdef IN_RING3
211
212/**
213 * SSM descriptor table for the VMSVGAGMRDESCRIPTOR structure.
214 */
215static SSMFIELD const g_aVMSVGAGMRDESCRIPTORFields[] =
216{
217 SSMFIELD_ENTRY_GCPHYS( VMSVGAGMRDESCRIPTOR, GCPhys),
218 SSMFIELD_ENTRY( VMSVGAGMRDESCRIPTOR, numPages),
219 SSMFIELD_ENTRY_TERM()
220};
221
222/**
223 * SSM descriptor table for the GMR structure.
224 */
225static SSMFIELD const g_aGMRFields[] =
226{
227 SSMFIELD_ENTRY( GMR, cMaxPages),
228 SSMFIELD_ENTRY( GMR, cbTotal),
229 SSMFIELD_ENTRY( GMR, numDescriptors),
230 SSMFIELD_ENTRY_IGN_HCPTR( GMR, paDesc),
231 SSMFIELD_ENTRY_TERM()
232};
233
234/**
235 * SSM descriptor table for the VMSVGASCREENOBJECT structure.
236 */
237static SSMFIELD const g_aVMSVGASCREENOBJECTFields[] =
238{
239 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, fuScreen),
240 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, idScreen),
241 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, xOrigin),
242 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, yOrigin),
243 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, cWidth),
244 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, cHeight),
245 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, offVRAM),
246 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, cbPitch),
247 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, cBpp),
248 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, fDefined),
249 SSMFIELD_ENTRY( VMSVGASCREENOBJECT, fModified),
250 SSMFIELD_ENTRY_TERM()
251};
252
253/**
254 * SSM descriptor table for the VMSVGAR3STATE structure.
255 */
256static SSMFIELD const g_aVMSVGAR3STATEFields[] =
257{
258 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, paGMR),
259 SSMFIELD_ENTRY( VMSVGAR3STATE, GMRFB),
260 SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.fActive),
261 SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.xHotspot),
262 SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.yHotspot),
263 SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.width),
264 SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.height),
265 SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.cbData),
266 SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAR3STATE, Cursor.pData),
267 SSMFIELD_ENTRY( VMSVGAR3STATE, colorAnnotation),
268 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, cBusyDelayedEmts),
269#ifdef VMSVGA_USE_EMT_HALT_CODE
270 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, BusyDelayedEmts),
271#else
272 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, hBusyDelayedEmts),
273#endif
274 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatBusyDelayEmts),
275 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dPresentProf),
276 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dDrawPrimitivesProf),
277 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSurfaceDmaProf),
278 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dBlitSurfaceToScreenProf),
279 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDefineGmr2),
280 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDefineGmr2Free),
281 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDefineGmr2Modify),
282 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdRemapGmr2),
283 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdRemapGmr2Modify),
284 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdInvalidCmd),
285 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdFence),
286 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdUpdate),
287 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdUpdateVerbose),
288 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDefineCursor),
289 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDefineAlphaCursor),
290 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdMoveCursor),
291 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDisplayCursor),
292 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdRectFill),
293 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdRectCopy),
294 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdRectRopCopy),
295 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdEscape),
296 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDefineScreen),
297 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDestroyScreen),
298 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDefineGmrFb),
299 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdBlitGmrFbToScreen),
300 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdBlitScreentoGmrFb),
301 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdAnnotationFill),
302 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdAnnotationCopy),
303 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSurfaceDefine),
304 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSurfaceDefineV2),
305 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSurfaceDestroy),
306 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSurfaceCopy),
307 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSurfaceStretchBlt),
308 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSurfaceDma),
309 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSurfaceScreen),
310 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dContextDefine),
311 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dContextDestroy),
312 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetTransform),
313 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetZRange),
314 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetRenderState),
315 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetRenderTarget),
316 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetTextureState),
317 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetMaterial),
318 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetLightData),
319 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetLightEnable),
320 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetViewPort),
321 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetClipPlane),
322 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dClear),
323 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dPresent),
324 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dPresentReadBack),
325 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dShaderDefine),
326 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dShaderDestroy),
327 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetShader),
328 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetShaderConst),
329 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dDrawPrimitives),
330 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dSetScissorRect),
331 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dBeginQuery),
332 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dEndQuery),
333 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dWaitForQuery),
334 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dGenerateMipmaps),
335 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dActivateSurface),
336 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3Cmd3dDeactivateSurface),
337
338 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3RegConfigDoneWr),
339 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3RegGmrDescriptorWr),
340 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3RegGmrDescriptorWrErrors),
341 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3RegGmrDescriptorWrFree),
342
343 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoCommands),
344 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoErrors),
345 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoUnkCmds),
346 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoTodoTimeout),
347 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoTodoWoken),
348 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoStalls),
349 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoExtendedSleep),
350# if defined(VMSVGA_USE_FIFO_ACCESS_HANDLER) || defined(DEBUG_FIFO_ACCESS)
351 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoAccessHandler),
352# endif
353 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoCursorFetchAgain),
354 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoCursorNoChange),
355 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoCursorPosition),
356 SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoCursorVisiblity),
357
358 SSMFIELD_ENTRY_TERM()
359};
360
361/**
362 * SSM descriptor table for the VGAState.svga structure.
363 */
364static SSMFIELD const g_aVGAStateSVGAFields[] =
365{
366 SSMFIELD_ENTRY_IGN_GCPHYS( VMSVGAState, GCPhysFIFO),
367 SSMFIELD_ENTRY_IGNORE( VMSVGAState, cbFIFO),
368 SSMFIELD_ENTRY_IGNORE( VMSVGAState, cbFIFOConfig),
369 SSMFIELD_ENTRY( VMSVGAState, u32SVGAId),
370 SSMFIELD_ENTRY( VMSVGAState, fEnabled),
371 SSMFIELD_ENTRY( VMSVGAState, fConfigured),
372 SSMFIELD_ENTRY( VMSVGAState, fBusy),
373 SSMFIELD_ENTRY( VMSVGAState, fTraces),
374 SSMFIELD_ENTRY( VMSVGAState, u32GuestId),
375 SSMFIELD_ENTRY( VMSVGAState, cScratchRegion),
376 SSMFIELD_ENTRY( VMSVGAState, au32ScratchRegion),
377 SSMFIELD_ENTRY( VMSVGAState, u32IrqStatus),
378 SSMFIELD_ENTRY( VMSVGAState, u32IrqMask),
379 SSMFIELD_ENTRY( VMSVGAState, u32PitchLock),
380 SSMFIELD_ENTRY( VMSVGAState, u32CurrentGMRId),
381 SSMFIELD_ENTRY( VMSVGAState, u32DeviceCaps),
382 SSMFIELD_ENTRY( VMSVGAState, u32IndexReg),
383 SSMFIELD_ENTRY_IGNORE( VMSVGAState, hFIFORequestSem),
384 SSMFIELD_ENTRY_IGNORE( VMSVGAState, uLastCursorUpdateCount),
385 SSMFIELD_ENTRY_IGNORE( VMSVGAState, fFIFOThreadSleeping),
386 SSMFIELD_ENTRY_VER( VMSVGAState, fGFBRegisters, VGA_SAVEDSTATE_VERSION_VMSVGA_SCREENS),
387 SSMFIELD_ENTRY( VMSVGAState, uWidth),
388 SSMFIELD_ENTRY( VMSVGAState, uHeight),
389 SSMFIELD_ENTRY( VMSVGAState, uBpp),
390 SSMFIELD_ENTRY( VMSVGAState, cbScanline),
391 SSMFIELD_ENTRY_VER( VMSVGAState, uScreenOffset, VGA_SAVEDSTATE_VERSION_VMSVGA),
392 SSMFIELD_ENTRY_VER( VMSVGAState, uCursorX, VGA_SAVEDSTATE_VERSION_VMSVGA_CURSOR),
393 SSMFIELD_ENTRY_VER( VMSVGAState, uCursorY, VGA_SAVEDSTATE_VERSION_VMSVGA_CURSOR),
394 SSMFIELD_ENTRY_VER( VMSVGAState, uCursorID, VGA_SAVEDSTATE_VERSION_VMSVGA_CURSOR),
395 SSMFIELD_ENTRY_VER( VMSVGAState, uCursorOn, VGA_SAVEDSTATE_VERSION_VMSVGA_CURSOR),
396 SSMFIELD_ENTRY( VMSVGAState, u32MaxWidth),
397 SSMFIELD_ENTRY( VMSVGAState, u32MaxHeight),
398 SSMFIELD_ENTRY( VMSVGAState, u32ActionFlags),
399 SSMFIELD_ENTRY( VMSVGAState, f3DEnabled),
400 SSMFIELD_ENTRY( VMSVGAState, fVRAMTracking),
401 SSMFIELD_ENTRY_IGNORE( VMSVGAState, u8FIFOExtCommand),
402 SSMFIELD_ENTRY_IGNORE( VMSVGAState, fFifoExtCommandWakeup),
403 SSMFIELD_ENTRY_IGNORE( VMSVGAState, cGMR),
404 SSMFIELD_ENTRY_TERM()
405};
406#endif /* IN_RING3 */
407
408
409/*********************************************************************************************************************************
410* Internal Functions *
411*********************************************************************************************************************************/
412#ifdef IN_RING3
413static void vmsvgaR3SetTraces(PPDMDEVINS pDevIns, PVGASTATE pThis, bool fTraces);
414static int vmsvgaR3LoadExecFifo(PCPDMDEVHLPR3 pHlp, PVGASTATE pThis, PVGASTATECC pThisCC, PSSMHANDLE pSSM,
415 uint32_t uVersion, uint32_t uPass);
416static int vmsvgaR3SaveExecFifo(PCPDMDEVHLPR3 pHlp, PVGASTATECC pThisCC, PSSMHANDLE pSSM);
417static void vmsvgaR3CmdBufSubmit(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, RTGCPHYS GCPhysCB, SVGACBContext CBCtx);
418#endif /* IN_RING3 */
419
420
421#if defined(LOG_ENABLED)
422# define SVGA_CASE_ID2STR(idx) case idx: return #idx
423/**
424 * Index register string name lookup
425 *
426 * @returns Index register string or "UNKNOWN"
427 * @param pThis The shared VGA/VMSVGA state.
428 * @param idxReg The index register.
429 */
430static const char *vmsvgaIndexToString(PVGASTATE pThis, uint32_t idxReg)
431{
432 switch (idxReg)
433 {
434 SVGA_CASE_ID2STR(SVGA_REG_ID);
435 SVGA_CASE_ID2STR(SVGA_REG_ENABLE);
436 SVGA_CASE_ID2STR(SVGA_REG_WIDTH);
437 SVGA_CASE_ID2STR(SVGA_REG_HEIGHT);
438 SVGA_CASE_ID2STR(SVGA_REG_MAX_WIDTH);
439 SVGA_CASE_ID2STR(SVGA_REG_MAX_HEIGHT);
440 SVGA_CASE_ID2STR(SVGA_REG_DEPTH);
441 SVGA_CASE_ID2STR(SVGA_REG_BITS_PER_PIXEL); /* Current bpp in the guest */
442 SVGA_CASE_ID2STR(SVGA_REG_PSEUDOCOLOR);
443 SVGA_CASE_ID2STR(SVGA_REG_RED_MASK);
444 SVGA_CASE_ID2STR(SVGA_REG_GREEN_MASK);
445 SVGA_CASE_ID2STR(SVGA_REG_BLUE_MASK);
446 SVGA_CASE_ID2STR(SVGA_REG_BYTES_PER_LINE);
447 SVGA_CASE_ID2STR(SVGA_REG_FB_START); /* (Deprecated) */
448 SVGA_CASE_ID2STR(SVGA_REG_FB_OFFSET);
449 SVGA_CASE_ID2STR(SVGA_REG_VRAM_SIZE);
450 SVGA_CASE_ID2STR(SVGA_REG_FB_SIZE);
451
452 /* ID 0 implementation only had the above registers, then the palette */
453 SVGA_CASE_ID2STR(SVGA_REG_CAPABILITIES);
454 SVGA_CASE_ID2STR(SVGA_REG_MEM_START); /* (Deprecated) */
455 SVGA_CASE_ID2STR(SVGA_REG_MEM_SIZE);
456 SVGA_CASE_ID2STR(SVGA_REG_CONFIG_DONE); /* Set when memory area configured */
457 SVGA_CASE_ID2STR(SVGA_REG_SYNC); /* See "FIFO Synchronization Registers" */
458 SVGA_CASE_ID2STR(SVGA_REG_BUSY); /* See "FIFO Synchronization Registers" */
459 SVGA_CASE_ID2STR(SVGA_REG_GUEST_ID); /* Set guest OS identifier */
460 SVGA_CASE_ID2STR(SVGA_REG_CURSOR_ID); /* (Deprecated) */
461 SVGA_CASE_ID2STR(SVGA_REG_CURSOR_X); /* (Deprecated) */
462 SVGA_CASE_ID2STR(SVGA_REG_CURSOR_Y); /* (Deprecated) */
463 SVGA_CASE_ID2STR(SVGA_REG_CURSOR_ON); /* (Deprecated) */
464 SVGA_CASE_ID2STR(SVGA_REG_HOST_BITS_PER_PIXEL); /* (Deprecated) */
465 SVGA_CASE_ID2STR(SVGA_REG_SCRATCH_SIZE); /* Number of scratch registers */
466 SVGA_CASE_ID2STR(SVGA_REG_MEM_REGS); /* Number of FIFO registers */
467 SVGA_CASE_ID2STR(SVGA_REG_NUM_DISPLAYS); /* (Deprecated) */
468 SVGA_CASE_ID2STR(SVGA_REG_PITCHLOCK); /* Fixed pitch for all modes */
469 SVGA_CASE_ID2STR(SVGA_REG_IRQMASK); /* Interrupt mask */
470
471 /* Legacy multi-monitor support */
472 SVGA_CASE_ID2STR(SVGA_REG_NUM_GUEST_DISPLAYS); /* Number of guest displays in X/Y direction */
473 SVGA_CASE_ID2STR(SVGA_REG_DISPLAY_ID); /* Display ID for the following display attributes */
474 SVGA_CASE_ID2STR(SVGA_REG_DISPLAY_IS_PRIMARY); /* Whether this is a primary display */
475 SVGA_CASE_ID2STR(SVGA_REG_DISPLAY_POSITION_X); /* The display position x */
476 SVGA_CASE_ID2STR(SVGA_REG_DISPLAY_POSITION_Y); /* The display position y */
477 SVGA_CASE_ID2STR(SVGA_REG_DISPLAY_WIDTH); /* The display's width */
478 SVGA_CASE_ID2STR(SVGA_REG_DISPLAY_HEIGHT); /* The display's height */
479
480 SVGA_CASE_ID2STR(SVGA_REG_GMR_ID);
481 SVGA_CASE_ID2STR(SVGA_REG_GMR_DESCRIPTOR);
482 SVGA_CASE_ID2STR(SVGA_REG_GMR_MAX_IDS);
483 SVGA_CASE_ID2STR(SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH);
484
485 SVGA_CASE_ID2STR(SVGA_REG_TRACES); /* Enable trace-based updates even when FIFO is on */
486 SVGA_CASE_ID2STR(SVGA_REG_GMRS_MAX_PAGES); /* Maximum number of 4KB pages for all GMRs */
487 SVGA_CASE_ID2STR(SVGA_REG_MEMORY_SIZE); /* Total dedicated device memory excluding FIFO */
488 SVGA_CASE_ID2STR(SVGA_REG_COMMAND_LOW); /* Lower 32 bits and submits commands */
489 SVGA_CASE_ID2STR(SVGA_REG_COMMAND_HIGH); /* Upper 32 bits of command buffer PA */
490 SVGA_CASE_ID2STR(SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM); /* Max primary memory */
491 SVGA_CASE_ID2STR(SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB); /* Suggested limit on mob mem */
492 SVGA_CASE_ID2STR(SVGA_REG_DEV_CAP); /* Write dev cap index, read value */
493 SVGA_CASE_ID2STR(SVGA_REG_CMD_PREPEND_LOW);
494 SVGA_CASE_ID2STR(SVGA_REG_iCMD_PREPEND_HIGH);
495 SVGA_CASE_ID2STR(SVGA_REG_SCREENTARGET_MAX_WIDTH);
496 SVGA_CASE_ID2STR(SVGA_REG_SCREENTARGET_MAX_HEIGHT);
497 SVGA_CASE_ID2STR(SVGA_REG_MOB_MAX_SIZE);
498 SVGA_CASE_ID2STR(SVGA_REG_TOP); /* Must be 1 more than the last register */
499
500 default:
501 if (idxReg - (uint32_t)SVGA_SCRATCH_BASE < pThis->svga.cScratchRegion)
502 return "SVGA_SCRATCH_BASE reg";
503 if (idxReg - (uint32_t)SVGA_PALETTE_BASE < (uint32_t)SVGA_NUM_PALETTE_REGS)
504 return "SVGA_PALETTE_BASE reg";
505 return "UNKNOWN";
506 }
507}
508# undef SVGA_CASE_ID2STR
509#endif /* LOG_ENABLED */
510
511
512#ifdef IN_RING3
513
514/**
515 * @interface_method_impl{PDMIDISPLAYPORT,pfnSetViewport}
516 */
517DECLCALLBACK(void) vmsvgaR3PortSetViewport(PPDMIDISPLAYPORT pInterface, uint32_t idScreen, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
518{
519 PVGASTATECC pThisCC = RT_FROM_MEMBER(pInterface, VGASTATECC, IPort);
520 PVGASTATE pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVGASTATE);
521
522 Log(("vmsvgaPortSetViewPort: screen %d (%d,%d)(%d,%d)\n", idScreen, x, y, cx, cy));
523 VMSVGAVIEWPORT const OldViewport = pThis->svga.viewport;
524
525 /** @todo Test how it interacts with multiple screen objects. */
526 VMSVGASCREENOBJECT *pScreen = vmsvgaR3GetScreenObject(pThisCC, idScreen);
527 uint32_t const uWidth = pScreen ? pScreen->cWidth : 0;
528 uint32_t const uHeight = pScreen ? pScreen->cHeight : 0;
529
530 if (x < uWidth)
531 {
532 pThis->svga.viewport.x = x;
533 pThis->svga.viewport.cx = RT_MIN(cx, uWidth - x);
534 pThis->svga.viewport.xRight = x + pThis->svga.viewport.cx;
535 }
536 else
537 {
538 pThis->svga.viewport.x = uWidth;
539 pThis->svga.viewport.cx = 0;
540 pThis->svga.viewport.xRight = uWidth;
541 }
542 if (y < uHeight)
543 {
544 pThis->svga.viewport.y = y;
545 pThis->svga.viewport.cy = RT_MIN(cy, uHeight - y);
546 pThis->svga.viewport.yLowWC = uHeight - y - pThis->svga.viewport.cy;
547 pThis->svga.viewport.yHighWC = uHeight - y;
548 }
549 else
550 {
551 pThis->svga.viewport.y = uHeight;
552 pThis->svga.viewport.cy = 0;
553 pThis->svga.viewport.yLowWC = 0;
554 pThis->svga.viewport.yHighWC = 0;
555 }
556
557# ifdef VBOX_WITH_VMSVGA3D
558 /*
559 * Now inform the 3D backend.
560 */
561 if (pThis->svga.f3DEnabled)
562 vmsvga3dUpdateHostScreenViewport(pThisCC, idScreen, &OldViewport);
563# else
564 RT_NOREF(OldViewport);
565# endif
566}
567
568
569/**
570 * Updating screen information in API
571 *
572 * @param pThis The The shared VGA/VMSVGA instance data.
573 * @param pThisCC The VGA/VMSVGA state for ring-3.
574 */
575void vmsvgaR3VBVAResize(PVGASTATE pThis, PVGASTATECC pThisCC)
576{
577 int rc;
578
579 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
580
581 for (unsigned iScreen = 0; iScreen < RT_ELEMENTS(pSVGAState->aScreens); ++iScreen)
582 {
583 VMSVGASCREENOBJECT *pScreen = &pSVGAState->aScreens[iScreen];
584 if (!pScreen->fModified)
585 continue;
586
587 pScreen->fModified = false;
588
589 VBVAINFOVIEW view;
590 RT_ZERO(view);
591 view.u32ViewIndex = pScreen->idScreen;
592 // view.u32ViewOffset = 0;
593 view.u32ViewSize = pThis->vram_size;
594 view.u32MaxScreenSize = pThis->vram_size;
595
596 VBVAINFOSCREEN screen;
597 RT_ZERO(screen);
598 screen.u32ViewIndex = pScreen->idScreen;
599
600 if (pScreen->fDefined)
601 {
602 if ( pScreen->cWidth == VMSVGA_VAL_UNINITIALIZED
603 || pScreen->cHeight == VMSVGA_VAL_UNINITIALIZED
604 || pScreen->cBpp == VMSVGA_VAL_UNINITIALIZED)
605 {
606 Assert(pThis->svga.fGFBRegisters);
607 continue;
608 }
609
610 screen.i32OriginX = pScreen->xOrigin;
611 screen.i32OriginY = pScreen->yOrigin;
612 screen.u32StartOffset = pScreen->offVRAM;
613 screen.u32LineSize = pScreen->cbPitch;
614 screen.u32Width = pScreen->cWidth;
615 screen.u32Height = pScreen->cHeight;
616 screen.u16BitsPerPixel = pScreen->cBpp;
617 if (!(pScreen->fuScreen & SVGA_SCREEN_DEACTIVATE))
618 screen.u16Flags = VBVA_SCREEN_F_ACTIVE;
619 if (pScreen->fuScreen & SVGA_SCREEN_BLANKING)
620 screen.u16Flags |= VBVA_SCREEN_F_BLANK2;
621 }
622 else
623 {
624 /* Screen is destroyed. */
625 screen.u16Flags = VBVA_SCREEN_F_DISABLED;
626 }
627
628 rc = pThisCC->pDrv->pfnVBVAResize(pThisCC->pDrv, &view, &screen, pThisCC->pbVRam, /*fResetInputMapping=*/ true);
629 AssertRC(rc);
630 }
631}
632
633
634/**
635 * @interface_method_impl{PDMIDISPLAYPORT,pfnReportMonitorPositions}
636 *
637 * Used to update screen offsets (positions) since appearently vmwgfx fails to
638 * pass correct offsets thru FIFO.
639 */
640DECLCALLBACK(void) vmsvgaR3PortReportMonitorPositions(PPDMIDISPLAYPORT pInterface, uint32_t cPositions, PCRTPOINT paPositions)
641{
642 PVGASTATECC pThisCC = RT_FROM_MEMBER(pInterface, VGASTATECC, IPort);
643 PVGASTATE pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVGASTATE);
644 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
645
646 AssertReturnVoid(pSVGAState);
647
648 /* We assume cPositions is the # of outputs Xserver reports and paPositions is (-1, -1) for disabled monitors. */
649 cPositions = RT_MIN(cPositions, RT_ELEMENTS(pSVGAState->aScreens));
650 for (uint32_t i = 0; i < cPositions; ++i)
651 {
652 if ( pSVGAState->aScreens[i].xOrigin == paPositions[i].x
653 && pSVGAState->aScreens[i].yOrigin == paPositions[i].y)
654 continue;
655
656 if (pSVGAState->aScreens[i].xOrigin == -1)
657 continue;
658 if (pSVGAState->aScreens[i].yOrigin == -1)
659 continue;
660
661 pSVGAState->aScreens[i].xOrigin = paPositions[i].x;
662 pSVGAState->aScreens[i].yOrigin = paPositions[i].y;
663 pSVGAState->aScreens[i].fModified = true;
664 }
665
666 vmsvgaR3VBVAResize(pThis, pThisCC);
667}
668
669#endif /* IN_RING3 */
670
671/**
672 * Read port register
673 *
674 * @returns VBox status code.
675 * @param pDevIns The device instance.
676 * @param pThis The shared VGA/VMSVGA state.
677 * @param pu32 Where to store the read value
678 */
679static int vmsvgaReadPort(PPDMDEVINS pDevIns, PVGASTATE pThis, uint32_t *pu32)
680{
681#ifdef IN_RING3
682 PVGASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
683#endif
684 int rc = VINF_SUCCESS;
685 *pu32 = 0;
686
687 /* Rough index register validation. */
688 uint32_t idxReg = pThis->svga.u32IndexReg;
689#if !defined(IN_RING3) && defined(VBOX_STRICT)
690 ASSERT_GUEST_MSG_RETURN(idxReg < SVGA_SCRATCH_BASE + pThis->svga.cScratchRegion, ("idxReg=%#x\n", idxReg),
691 VINF_IOM_R3_IOPORT_READ);
692#else
693 ASSERT_GUEST_MSG_STMT_RETURN(idxReg < SVGA_SCRATCH_BASE + pThis->svga.cScratchRegion, ("idxReg=%#x\n", idxReg),
694 STAM_REL_COUNTER_INC(&pThis->svga.StatRegUnknownRd),
695 VINF_SUCCESS);
696#endif
697 RT_UNTRUSTED_VALIDATED_FENCE();
698
699 /* We must adjust the register number if we're in SVGA_ID_0 mode because the PALETTE range moved. */
700 if ( idxReg >= SVGA_REG_ID_0_TOP
701 && pThis->svga.u32SVGAId == SVGA_ID_0)
702 {
703 idxReg += SVGA_PALETTE_BASE - SVGA_REG_ID_0_TOP;
704 Log(("vmsvgaWritePort: SVGA_ID_0 reg adj %#x -> %#x\n", pThis->svga.u32IndexReg, idxReg));
705 }
706
707 switch (idxReg)
708 {
709 case SVGA_REG_ID:
710 STAM_REL_COUNTER_INC(&pThis->svga.StatRegIdRd);
711 *pu32 = pThis->svga.u32SVGAId;
712 break;
713
714 case SVGA_REG_ENABLE:
715 STAM_REL_COUNTER_INC(&pThis->svga.StatRegEnableRd);
716 *pu32 = pThis->svga.fEnabled;
717 break;
718
719 case SVGA_REG_WIDTH:
720 {
721 STAM_REL_COUNTER_INC(&pThis->svga.StatRegWidthRd);
722 if ( pThis->svga.fEnabled
723 && pThis->svga.uWidth != VMSVGA_VAL_UNINITIALIZED)
724 *pu32 = pThis->svga.uWidth;
725 else
726 {
727#ifndef IN_RING3
728 rc = VINF_IOM_R3_IOPORT_READ;
729#else
730 *pu32 = pThisCC->pDrv->cx;
731#endif
732 }
733 break;
734 }
735
736 case SVGA_REG_HEIGHT:
737 {
738 STAM_REL_COUNTER_INC(&pThis->svga.StatRegHeightRd);
739 if ( pThis->svga.fEnabled
740 && pThis->svga.uHeight != VMSVGA_VAL_UNINITIALIZED)
741 *pu32 = pThis->svga.uHeight;
742 else
743 {
744#ifndef IN_RING3
745 rc = VINF_IOM_R3_IOPORT_READ;
746#else
747 *pu32 = pThisCC->pDrv->cy;
748#endif
749 }
750 break;
751 }
752
753 case SVGA_REG_MAX_WIDTH:
754 STAM_REL_COUNTER_INC(&pThis->svga.StatRegMaxWidthRd);
755 *pu32 = pThis->svga.u32MaxWidth;
756 break;
757
758 case SVGA_REG_MAX_HEIGHT:
759 STAM_REL_COUNTER_INC(&pThis->svga.StatRegMaxHeightRd);
760 *pu32 = pThis->svga.u32MaxHeight;
761 break;
762
763 case SVGA_REG_DEPTH:
764 /* This returns the color depth of the current mode. */
765 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDepthRd);
766 switch (pThis->svga.uBpp)
767 {
768 case 15:
769 case 16:
770 case 24:
771 *pu32 = pThis->svga.uBpp;
772 break;
773
774 default:
775 case 32:
776 *pu32 = 24; /* The upper 8 bits are either alpha bits or not used. */
777 break;
778 }
779 break;
780
781 case SVGA_REG_HOST_BITS_PER_PIXEL: /* (Deprecated) */
782 STAM_REL_COUNTER_INC(&pThis->svga.StatRegHostBitsPerPixelRd);
783 *pu32 = pThis->svga.uHostBpp;
784 break;
785
786 case SVGA_REG_BITS_PER_PIXEL: /* Current bpp in the guest */
787 STAM_REL_COUNTER_INC(&pThis->svga.StatRegBitsPerPixelRd);
788 *pu32 = pThis->svga.uBpp;
789 break;
790
791 case SVGA_REG_PSEUDOCOLOR:
792 STAM_REL_COUNTER_INC(&pThis->svga.StatRegPsuedoColorRd);
793 *pu32 = pThis->svga.uBpp == 8; /* See section 6 "Pseudocolor" in svga_interface.txt. */
794 break;
795
796 case SVGA_REG_RED_MASK:
797 case SVGA_REG_GREEN_MASK:
798 case SVGA_REG_BLUE_MASK:
799 {
800 uint32_t uBpp;
801
802 if (pThis->svga.fEnabled)
803 uBpp = pThis->svga.uBpp;
804 else
805 uBpp = pThis->svga.uHostBpp;
806
807 uint32_t u32RedMask, u32GreenMask, u32BlueMask;
808 switch (uBpp)
809 {
810 case 8:
811 u32RedMask = 0x07;
812 u32GreenMask = 0x38;
813 u32BlueMask = 0xc0;
814 break;
815
816 case 15:
817 u32RedMask = 0x0000001f;
818 u32GreenMask = 0x000003e0;
819 u32BlueMask = 0x00007c00;
820 break;
821
822 case 16:
823 u32RedMask = 0x0000001f;
824 u32GreenMask = 0x000007e0;
825 u32BlueMask = 0x0000f800;
826 break;
827
828 case 24:
829 case 32:
830 default:
831 u32RedMask = 0x00ff0000;
832 u32GreenMask = 0x0000ff00;
833 u32BlueMask = 0x000000ff;
834 break;
835 }
836 switch (idxReg)
837 {
838 case SVGA_REG_RED_MASK:
839 STAM_REL_COUNTER_INC(&pThis->svga.StatRegRedMaskRd);
840 *pu32 = u32RedMask;
841 break;
842
843 case SVGA_REG_GREEN_MASK:
844 STAM_REL_COUNTER_INC(&pThis->svga.StatRegGreenMaskRd);
845 *pu32 = u32GreenMask;
846 break;
847
848 case SVGA_REG_BLUE_MASK:
849 STAM_REL_COUNTER_INC(&pThis->svga.StatRegBlueMaskRd);
850 *pu32 = u32BlueMask;
851 break;
852 }
853 break;
854 }
855
856 case SVGA_REG_BYTES_PER_LINE:
857 {
858 STAM_REL_COUNTER_INC(&pThis->svga.StatRegBytesPerLineRd);
859 if ( pThis->svga.fEnabled
860 && pThis->svga.cbScanline)
861 *pu32 = pThis->svga.cbScanline;
862 else
863 {
864#ifndef IN_RING3
865 rc = VINF_IOM_R3_IOPORT_READ;
866#else
867 *pu32 = pThisCC->pDrv->cbScanline;
868#endif
869 }
870 break;
871 }
872
873 case SVGA_REG_VRAM_SIZE: /* VRAM size */
874 STAM_REL_COUNTER_INC(&pThis->svga.StatRegVramSizeRd);
875 *pu32 = pThis->vram_size;
876 break;
877
878 case SVGA_REG_FB_START: /* Frame buffer physical address. */
879 STAM_REL_COUNTER_INC(&pThis->svga.StatRegFbStartRd);
880 Assert(pThis->GCPhysVRAM <= 0xffffffff);
881 *pu32 = pThis->GCPhysVRAM;
882 break;
883
884 case SVGA_REG_FB_OFFSET: /* Offset of the frame buffer in VRAM */
885 STAM_REL_COUNTER_INC(&pThis->svga.StatRegFbOffsetRd);
886 /* Always zero in our case. */
887 *pu32 = 0;
888 break;
889
890 case SVGA_REG_FB_SIZE: /* Frame buffer size */
891 {
892#ifndef IN_RING3
893 rc = VINF_IOM_R3_IOPORT_READ;
894#else
895 STAM_REL_COUNTER_INC(&pThis->svga.StatRegFbSizeRd);
896
897 /* VMWare testcases want at least 4 MB in case the hardware is disabled. */
898 if ( pThis->svga.fEnabled
899 && pThis->svga.uHeight != VMSVGA_VAL_UNINITIALIZED)
900 {
901 /* Hardware enabled; return real framebuffer size .*/
902 *pu32 = (uint32_t)pThis->svga.uHeight * pThis->svga.cbScanline;
903 }
904 else
905 *pu32 = RT_MAX(0x100000, (uint32_t)pThisCC->pDrv->cy * pThisCC->pDrv->cbScanline);
906
907 *pu32 = RT_MIN(pThis->vram_size, *pu32);
908 Log(("h=%d w=%d bpp=%d\n", pThisCC->pDrv->cy, pThisCC->pDrv->cx, pThisCC->pDrv->cBits));
909#endif
910 break;
911 }
912
913 case SVGA_REG_CAPABILITIES:
914 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCapabilitesRd);
915 *pu32 = pThis->svga.u32DeviceCaps;
916 break;
917
918 case SVGA_REG_MEM_START: /* FIFO start */
919 STAM_REL_COUNTER_INC(&pThis->svga.StatRegMemStartRd);
920 Assert(pThis->svga.GCPhysFIFO <= 0xffffffff);
921 *pu32 = pThis->svga.GCPhysFIFO;
922 break;
923
924 case SVGA_REG_MEM_SIZE: /* FIFO size */
925 STAM_REL_COUNTER_INC(&pThis->svga.StatRegMemSizeRd);
926 *pu32 = pThis->svga.cbFIFO;
927 break;
928
929 case SVGA_REG_CONFIG_DONE: /* Set when memory area configured */
930 STAM_REL_COUNTER_INC(&pThis->svga.StatRegConfigDoneRd);
931 *pu32 = pThis->svga.fConfigured;
932 break;
933
934 case SVGA_REG_SYNC: /* See "FIFO Synchronization Registers" */
935 STAM_REL_COUNTER_INC(&pThis->svga.StatRegSyncRd);
936 *pu32 = 0;
937 break;
938
939 case SVGA_REG_BUSY: /* See "FIFO Synchronization Registers" */
940 STAM_REL_COUNTER_INC(&pThis->svga.StatRegBusyRd);
941 if (pThis->svga.fBusy)
942 {
943#ifndef IN_RING3
944 /* Go to ring-3 and halt the CPU. */
945 rc = VINF_IOM_R3_IOPORT_READ;
946 RT_NOREF(pDevIns);
947 break;
948#else
949# if defined(VMSVGA_USE_EMT_HALT_CODE)
950 /* The guest is basically doing a HLT via the device here, but with
951 a special wake up condition on FIFO completion. */
952 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
953 STAM_REL_PROFILE_START(&pSVGAState->StatBusyDelayEmts, EmtDelay);
954 PVM pVM = PDMDevHlpGetVM(pDevIns);
955 VMCPUID idCpu = PDMDevHlpGetCurrentCpuId(pDevIns);
956 VMCPUSET_ATOMIC_ADD(&pSVGAState->BusyDelayedEmts, idCpu);
957 ASMAtomicIncU32(&pSVGAState->cBusyDelayedEmts);
958 if (pThis->svga.fBusy)
959 {
960 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect); /* hack around lock order issue. */
961 rc = VMR3WaitForDeviceReady(pVM, idCpu);
962 PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
963 }
964 ASMAtomicDecU32(&pSVGAState->cBusyDelayedEmts);
965 VMCPUSET_ATOMIC_DEL(&pSVGAState->BusyDelayedEmts, idCpu);
966# else
967
968 /* Delay the EMT a bit so the FIFO and others can get some work done.
969 This used to be a crude 50 ms sleep. The current code tries to be
970 more efficient, but the consept is still very crude. */
971 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
972 STAM_REL_PROFILE_START(&pSVGAState->StatBusyDelayEmts, EmtDelay);
973 RTThreadYield();
974 if (pThis->svga.fBusy)
975 {
976 uint32_t cRefs = ASMAtomicIncU32(&pSVGAState->cBusyDelayedEmts);
977
978 if (pThis->svga.fBusy && cRefs == 1)
979 RTSemEventMultiReset(pSVGAState->hBusyDelayedEmts);
980 if (pThis->svga.fBusy)
981 {
982 /** @todo If this code is going to stay, we need to call into the halt/wait
983 * code in VMEmt.cpp here, otherwise all kind of EMT interaction will
984 * suffer when the guest is polling on a busy FIFO. */
985 uint64_t cNsMaxWait = TMVirtualSyncGetNsToDeadline(PDMDevHlpGetVM(pDevIns));
986 if (cNsMaxWait >= RT_NS_100US)
987 RTSemEventMultiWaitEx(pSVGAState->hBusyDelayedEmts,
988 RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_NORESUME,
989 RT_MIN(cNsMaxWait, RT_NS_10MS));
990 }
991
992 ASMAtomicDecU32(&pSVGAState->cBusyDelayedEmts);
993 }
994 STAM_REL_PROFILE_STOP(&pSVGAState->StatBusyDelayEmts, EmtDelay);
995# endif
996 *pu32 = pThis->svga.fBusy != 0;
997#endif
998 }
999 else
1000 *pu32 = false;
1001 break;
1002
1003 case SVGA_REG_GUEST_ID: /* Set guest OS identifier */
1004 STAM_REL_COUNTER_INC(&pThis->svga.StatRegGuestIdRd);
1005 *pu32 = pThis->svga.u32GuestId;
1006 break;
1007
1008 case SVGA_REG_SCRATCH_SIZE: /* Number of scratch registers */
1009 STAM_REL_COUNTER_INC(&pThis->svga.StatRegScratchSizeRd);
1010 *pu32 = pThis->svga.cScratchRegion;
1011 break;
1012
1013 case SVGA_REG_MEM_REGS: /* Number of FIFO registers */
1014 STAM_REL_COUNTER_INC(&pThis->svga.StatRegMemRegsRd);
1015 *pu32 = SVGA_FIFO_NUM_REGS;
1016 break;
1017
1018 case SVGA_REG_PITCHLOCK: /* Fixed pitch for all modes */
1019 STAM_REL_COUNTER_INC(&pThis->svga.StatRegPitchLockRd);
1020 *pu32 = pThis->svga.u32PitchLock;
1021 break;
1022
1023 case SVGA_REG_IRQMASK: /* Interrupt mask */
1024 STAM_REL_COUNTER_INC(&pThis->svga.StatRegIrqMaskRd);
1025 *pu32 = pThis->svga.u32IrqMask;
1026 break;
1027
1028 /* See "Guest memory regions" below. */
1029 case SVGA_REG_GMR_ID:
1030 STAM_REL_COUNTER_INC(&pThis->svga.StatRegGmrIdRd);
1031 *pu32 = pThis->svga.u32CurrentGMRId;
1032 break;
1033
1034 case SVGA_REG_GMR_DESCRIPTOR:
1035 STAM_REL_COUNTER_INC(&pThis->svga.StatRegWriteOnlyRd);
1036 /* Write only */
1037 *pu32 = 0;
1038 break;
1039
1040 case SVGA_REG_GMR_MAX_IDS:
1041 STAM_REL_COUNTER_INC(&pThis->svga.StatRegGmrMaxIdsRd);
1042 *pu32 = pThis->svga.cGMR;
1043 break;
1044
1045 case SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH:
1046 STAM_REL_COUNTER_INC(&pThis->svga.StatRegGmrMaxDescriptorLengthRd);
1047 *pu32 = VMSVGA_MAX_GMR_PAGES;
1048 break;
1049
1050 case SVGA_REG_TRACES: /* Enable trace-based updates even when FIFO is on */
1051 STAM_REL_COUNTER_INC(&pThis->svga.StatRegTracesRd);
1052 *pu32 = pThis->svga.fTraces;
1053 break;
1054
1055 case SVGA_REG_GMRS_MAX_PAGES: /* Maximum number of 4KB pages for all GMRs */
1056 STAM_REL_COUNTER_INC(&pThis->svga.StatRegGmrsMaxPagesRd);
1057 *pu32 = VMSVGA_MAX_GMR_PAGES;
1058 break;
1059
1060 case SVGA_REG_MEMORY_SIZE: /* Total dedicated device memory excluding FIFO */
1061 STAM_REL_COUNTER_INC(&pThis->svga.StatRegMemorySizeRd);
1062 *pu32 = VMSVGA_SURFACE_SIZE;
1063 break;
1064
1065 case SVGA_REG_TOP: /* Must be 1 more than the last register */
1066 STAM_REL_COUNTER_INC(&pThis->svga.StatRegTopRd);
1067 break;
1068
1069 /* Mouse cursor support. */
1070 case SVGA_REG_CURSOR_ID:
1071 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCursorIdRd);
1072 *pu32 = pThis->svga.uCursorID;
1073 break;
1074
1075 case SVGA_REG_CURSOR_X:
1076 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCursorXRd);
1077 *pu32 = pThis->svga.uCursorX;
1078 break;
1079
1080 case SVGA_REG_CURSOR_Y:
1081 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCursorYRd);
1082 *pu32 = pThis->svga.uCursorY;
1083 break;
1084
1085 case SVGA_REG_CURSOR_ON:
1086 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCursorOnRd);
1087 *pu32 = pThis->svga.uCursorOn;
1088 break;
1089
1090 /* Legacy multi-monitor support */
1091 case SVGA_REG_NUM_GUEST_DISPLAYS:/* Number of guest displays in X/Y direction */
1092 STAM_REL_COUNTER_INC(&pThis->svga.StatRegNumGuestDisplaysRd);
1093 *pu32 = 1;
1094 break;
1095
1096 case SVGA_REG_DISPLAY_ID: /* Display ID for the following display attributes */
1097 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayIdRd);
1098 *pu32 = 0;
1099 break;
1100
1101 case SVGA_REG_DISPLAY_IS_PRIMARY:/* Whether this is a primary display */
1102 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayIsPrimaryRd);
1103 *pu32 = 0;
1104 break;
1105
1106 case SVGA_REG_DISPLAY_POSITION_X:/* The display position x */
1107 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayPositionXRd);
1108 *pu32 = 0;
1109 break;
1110
1111 case SVGA_REG_DISPLAY_POSITION_Y:/* The display position y */
1112 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayPositionYRd);
1113 *pu32 = 0;
1114 break;
1115
1116 case SVGA_REG_DISPLAY_WIDTH: /* The display's width */
1117 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayWidthRd);
1118 *pu32 = pThis->svga.uWidth;
1119 break;
1120
1121 case SVGA_REG_DISPLAY_HEIGHT: /* The display's height */
1122 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayHeightRd);
1123 *pu32 = pThis->svga.uHeight;
1124 break;
1125
1126 case SVGA_REG_NUM_DISPLAYS: /* (Deprecated) */
1127 STAM_REL_COUNTER_INC(&pThis->svga.StatRegNumDisplaysRd);
1128 /* We must return something sensible here otherwise the Linux driver
1129 will take a legacy code path without 3d support. This number also
1130 limits how many screens Linux guests will allow. */
1131 *pu32 = pThis->cMonitors;
1132 break;
1133
1134 /*
1135 * SVGA_CAP_GBOBJECTS+ registers.
1136 */
1137 case SVGA_REG_COMMAND_LOW:
1138 /* Lower 32 bits of command buffer physical address. */
1139 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCommandLowRd);
1140 *pu32 = pThis->svga.u32RegCommandLow;
1141 break;
1142
1143 case SVGA_REG_COMMAND_HIGH:
1144 /* Upper 32 bits of command buffer PA. */
1145 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCommandHighRd);
1146 *pu32 = pThis->svga.u32RegCommandHigh;
1147 break;
1148
1149 case SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM:
1150 /* Max primary (screen) memory. */
1151 STAM_REL_COUNTER_INC(&pThis->svga.StatRegMaxPrimBBMemRd);
1152 *pu32 = pThis->vram_size; /** @todo Maybe half VRAM? */
1153 break;
1154
1155 case SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB:
1156 /* Suggested limit on mob mem (i.e. size of the guest mapped VRAM in KB) */
1157 STAM_REL_COUNTER_INC(&pThis->svga.StatRegGBMemSizeRd);
1158 *pu32 = pThis->vram_size / 1024;
1159 break;
1160
1161 case SVGA_REG_DEV_CAP:
1162 /* Write dev cap index, read value */
1163 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDevCapRd);
1164 if (pThis->svga.u32DevCapIndex < RT_ELEMENTS(pThis->svga.au32DevCaps))
1165 {
1166 RT_UNTRUSTED_VALIDATED_FENCE();
1167 *pu32 = pThis->svga.au32DevCaps[pThis->svga.u32DevCapIndex];
1168 }
1169 else
1170 *pu32 = 0;
1171 break;
1172
1173 case SVGA_REG_CMD_PREPEND_LOW:
1174 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCmdPrependLowRd);
1175 *pu32 = 0; /* Not supported. */
1176 break;
1177
1178 case SVGA_REG_iCMD_PREPEND_HIGH:
1179 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCmdPrependHighRd);
1180 *pu32 = 0; /* Not supported. */
1181 break;
1182
1183 case SVGA_REG_SCREENTARGET_MAX_WIDTH:
1184 STAM_REL_COUNTER_INC(&pThis->svga.StatRegScrnTgtMaxWidthRd);
1185 *pu32 = pThis->svga.u32MaxWidth;
1186 break;
1187
1188 case SVGA_REG_SCREENTARGET_MAX_HEIGHT:
1189 STAM_REL_COUNTER_INC(&pThis->svga.StatRegScrnTgtMaxHeightRd);
1190 *pu32 = pThis->svga.u32MaxHeight;
1191 break;
1192
1193 case SVGA_REG_MOB_MAX_SIZE:
1194 /* Essentially the max texture size */
1195 STAM_REL_COUNTER_INC(&pThis->svga.StatRegMobMaxSizeRd);
1196 *pu32 = _128M; /** @todo Some actual value. Probably the mapped VRAM size. */
1197 break;
1198
1199 default:
1200 {
1201 uint32_t offReg;
1202 if ((offReg = idxReg - SVGA_SCRATCH_BASE) < pThis->svga.cScratchRegion)
1203 {
1204 STAM_REL_COUNTER_INC(&pThis->svga.StatRegScratchRd);
1205 RT_UNTRUSTED_VALIDATED_FENCE();
1206 *pu32 = pThis->svga.au32ScratchRegion[offReg];
1207 }
1208 else if ((offReg = idxReg - SVGA_PALETTE_BASE) < (uint32_t)SVGA_NUM_PALETTE_REGS)
1209 {
1210 /* Note! Using last_palette rather than palette here to preserve the VGA one. */
1211 STAM_REL_COUNTER_INC(&pThis->svga.StatRegPaletteRd);
1212 RT_UNTRUSTED_VALIDATED_FENCE();
1213 uint32_t u32 = pThis->last_palette[offReg / 3];
1214 switch (offReg % 3)
1215 {
1216 case 0: *pu32 = (u32 >> 16) & 0xff; break; /* red */
1217 case 1: *pu32 = (u32 >> 8) & 0xff; break; /* green */
1218 case 2: *pu32 = u32 & 0xff; break; /* blue */
1219 }
1220 }
1221 else
1222 {
1223#if !defined(IN_RING3) && defined(VBOX_STRICT)
1224 rc = VINF_IOM_R3_IOPORT_READ;
1225#else
1226 STAM_REL_COUNTER_INC(&pThis->svga.StatRegUnknownRd);
1227
1228 /* Do not assert. The guest might be reading all registers. */
1229 LogFunc(("Unknown reg=%#x\n", idxReg));
1230#endif
1231 }
1232 break;
1233 }
1234 }
1235 Log(("vmsvgaReadPort index=%s (%d) val=%#x rc=%x\n", vmsvgaIndexToString(pThis, idxReg), idxReg, *pu32, rc));
1236 return rc;
1237}
1238
1239#ifdef IN_RING3
1240/**
1241 * Apply the current resolution settings to change the video mode.
1242 *
1243 * @returns VBox status code.
1244 * @param pThis The shared VGA state.
1245 * @param pThisCC The ring-3 VGA state.
1246 */
1247int vmsvgaR3ChangeMode(PVGASTATE pThis, PVGASTATECC pThisCC)
1248{
1249 /* Always do changemode on FIFO thread. */
1250 Assert(RTThreadSelf() == pThisCC->svga.pFIFOIOThread->Thread);
1251
1252 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
1253
1254 pThisCC->pDrv->pfnLFBModeChange(pThisCC->pDrv, true);
1255
1256 if (pThis->svga.fGFBRegisters)
1257 {
1258 /* "For backwards compatibility, when the GFB mode registers (WIDTH,
1259 * HEIGHT, PITCHLOCK, BITS_PER_PIXEL) are modified, the SVGA device
1260 * deletes all screens other than screen #0, and redefines screen
1261 * #0 according to the specified mode. Drivers that use
1262 * SVGA_CMD_DEFINE_SCREEN should destroy or redefine screen #0."
1263 */
1264
1265 VMSVGASCREENOBJECT *pScreen = &pSVGAState->aScreens[0];
1266 pScreen->fDefined = true;
1267 pScreen->fModified = true;
1268 pScreen->fuScreen = SVGA_SCREEN_MUST_BE_SET | SVGA_SCREEN_IS_PRIMARY;
1269 pScreen->idScreen = 0;
1270 pScreen->xOrigin = 0;
1271 pScreen->yOrigin = 0;
1272 pScreen->offVRAM = 0;
1273 pScreen->cbPitch = pThis->svga.cbScanline;
1274 pScreen->cWidth = pThis->svga.uWidth;
1275 pScreen->cHeight = pThis->svga.uHeight;
1276 pScreen->cBpp = pThis->svga.uBpp;
1277
1278 for (unsigned iScreen = 1; iScreen < RT_ELEMENTS(pSVGAState->aScreens); ++iScreen)
1279 {
1280 /* Delete screen. */
1281 pScreen = &pSVGAState->aScreens[iScreen];
1282 if (pScreen->fDefined)
1283 {
1284 pScreen->fModified = true;
1285 pScreen->fDefined = false;
1286 }
1287 }
1288 }
1289 else
1290 {
1291 /* "If Screen Objects are supported, they can be used to fully
1292 * replace the functionality provided by the framebuffer registers
1293 * (SVGA_REG_WIDTH, HEIGHT, etc.) and by SVGA_CAP_DISPLAY_TOPOLOGY."
1294 */
1295 pThis->svga.uWidth = VMSVGA_VAL_UNINITIALIZED;
1296 pThis->svga.uHeight = VMSVGA_VAL_UNINITIALIZED;
1297 pThis->svga.uBpp = pThis->svga.uHostBpp;
1298 }
1299
1300 vmsvgaR3VBVAResize(pThis, pThisCC);
1301
1302 /* Last stuff. For the VGA device screenshot. */
1303 pThis->last_bpp = pSVGAState->aScreens[0].cBpp;
1304 pThis->last_scr_width = pSVGAState->aScreens[0].cWidth;
1305 pThis->last_scr_height = pSVGAState->aScreens[0].cHeight;
1306 pThis->last_width = pSVGAState->aScreens[0].cWidth;
1307 pThis->last_height = pSVGAState->aScreens[0].cHeight;
1308
1309 /* vmsvgaPortSetViewPort not called after state load; set sensible defaults. */
1310 if ( pThis->svga.viewport.cx == 0
1311 && pThis->svga.viewport.cy == 0)
1312 {
1313 pThis->svga.viewport.cx = pSVGAState->aScreens[0].cWidth;
1314 pThis->svga.viewport.xRight = pSVGAState->aScreens[0].cWidth;
1315 pThis->svga.viewport.cy = pSVGAState->aScreens[0].cHeight;
1316 pThis->svga.viewport.yHighWC = pSVGAState->aScreens[0].cHeight;
1317 pThis->svga.viewport.yLowWC = 0;
1318 }
1319
1320 return VINF_SUCCESS;
1321}
1322
1323int vmsvgaR3UpdateScreen(PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen, int x, int y, int w, int h)
1324{
1325 VBVACMDHDR cmd;
1326 cmd.x = (int16_t)(pScreen->xOrigin + x);
1327 cmd.y = (int16_t)(pScreen->yOrigin + y);
1328 cmd.w = (uint16_t)w;
1329 cmd.h = (uint16_t)h;
1330
1331 pThisCC->pDrv->pfnVBVAUpdateBegin(pThisCC->pDrv, pScreen->idScreen);
1332 pThisCC->pDrv->pfnVBVAUpdateProcess(pThisCC->pDrv, pScreen->idScreen, &cmd, sizeof(cmd));
1333 pThisCC->pDrv->pfnVBVAUpdateEnd(pThisCC->pDrv, pScreen->idScreen,
1334 pScreen->xOrigin + x, pScreen->yOrigin + y, w, h);
1335
1336 return VINF_SUCCESS;
1337}
1338
1339#endif /* IN_RING3 */
1340#if defined(IN_RING0) || defined(IN_RING3)
1341
1342/**
1343 * Safely updates the SVGA_FIFO_BUSY register (in shared memory).
1344 *
1345 * @param pThis The shared VGA/VMSVGA instance data.
1346 * @param pThisCC The VGA/VMSVGA state for the current context.
1347 * @param fState The busy state.
1348 */
1349DECLINLINE(void) vmsvgaHCSafeFifoBusyRegUpdate(PVGASTATE pThis, PVGASTATECC pThisCC, bool fState)
1350{
1351 ASMAtomicWriteU32(&pThisCC->svga.pau32FIFO[SVGA_FIFO_BUSY], fState);
1352
1353 if (RT_UNLIKELY(fState != (pThis->svga.fBusy != 0)))
1354 {
1355 /* Race / unfortunately scheduling. Highly unlikly. */
1356 uint32_t cLoops = 64;
1357 do
1358 {
1359 ASMNopPause();
1360 fState = (pThis->svga.fBusy != 0);
1361 ASMAtomicWriteU32(&pThisCC->svga.pau32FIFO[SVGA_FIFO_BUSY], fState != 0);
1362 } while (cLoops-- > 0 && fState != (pThis->svga.fBusy != 0));
1363 }
1364}
1365
1366
1367/**
1368 * Update the scanline pitch in response to the guest changing mode
1369 * width/bpp.
1370 *
1371 * @param pThis The shared VGA/VMSVGA state.
1372 * @param pThisCC The VGA/VMSVGA state for the current context.
1373 */
1374DECLINLINE(void) vmsvgaHCUpdatePitch(PVGASTATE pThis, PVGASTATECC pThisCC)
1375{
1376 uint32_t RT_UNTRUSTED_VOLATILE_GUEST *pFIFO = pThisCC->svga.pau32FIFO;
1377 uint32_t uFifoPitchLock = pFIFO[SVGA_FIFO_PITCHLOCK];
1378 uint32_t uRegPitchLock = pThis->svga.u32PitchLock;
1379 uint32_t uFifoMin = pFIFO[SVGA_FIFO_MIN];
1380
1381 /* The SVGA_FIFO_PITCHLOCK register is only valid if SVGA_FIFO_MIN points past
1382 * it. If SVGA_FIFO_MIN is small, there may well be data at the SVGA_FIFO_PITCHLOCK
1383 * location but it has a different meaning.
1384 */
1385 if ((uFifoMin / sizeof(uint32_t)) <= SVGA_FIFO_PITCHLOCK)
1386 uFifoPitchLock = 0;
1387
1388 /* Sanitize values. */
1389 if ((uFifoPitchLock < 200) || (uFifoPitchLock > 32768))
1390 uFifoPitchLock = 0;
1391 if ((uRegPitchLock < 200) || (uRegPitchLock > 32768))
1392 uRegPitchLock = 0;
1393
1394 /* Prefer the register value to the FIFO value.*/
1395 if (uRegPitchLock)
1396 pThis->svga.cbScanline = uRegPitchLock;
1397 else if (uFifoPitchLock)
1398 pThis->svga.cbScanline = uFifoPitchLock;
1399 else
1400 pThis->svga.cbScanline = pThis->svga.uWidth * (RT_ALIGN(pThis->svga.uBpp, 8) / 8);
1401
1402 if ((uFifoMin / sizeof(uint32_t)) <= SVGA_FIFO_PITCHLOCK)
1403 pThis->svga.u32PitchLock = pThis->svga.cbScanline;
1404}
1405
1406#endif /* IN_RING0 || IN_RING3 */
1407
1408#ifdef IN_RING3
1409
1410/**
1411 * Sends cursor position and visibility information from legacy
1412 * SVGA registers to the front-end.
1413 */
1414static void vmsvgaR3RegUpdateCursor(PVGASTATECC pThisCC, PVGASTATE pThis, uint32_t uCursorOn)
1415{
1416 /*
1417 * Writing the X/Y/ID registers does not trigger changes; only writing the
1418 * SVGA_REG_CURSOR_ON register does. That minimizes the overhead.
1419 * We boldly assume that guests aren't stupid and aren't writing the CURSOR_ON
1420 * register if they don't have to.
1421 */
1422 uint32_t x, y, idScreen;
1423 uint32_t fFlags = VBVA_CURSOR_VALID_DATA;
1424
1425 x = pThis->svga.uCursorX;
1426 y = pThis->svga.uCursorY;
1427 idScreen = SVGA_ID_INVALID; /* The old register interface is single screen only. */
1428
1429 /* The original values for SVGA_REG_CURSOR_ON were off (0) and on (1); later, the values
1430 * were extended as follows:
1431 *
1432 * SVGA_CURSOR_ON_HIDE 0
1433 * SVGA_CURSOR_ON_SHOW 1
1434 * SVGA_CURSOR_ON_REMOVE_FROM_FB 2 - cursor on but not in the framebuffer
1435 * SVGA_CURSOR_ON_RESTORE_TO_FB 3 - cursor on, possibly in the framebuffer
1436 *
1437 * Since we never draw the cursor into the guest's framebuffer, we do not need to
1438 * distinguish between the non-zero values but still remember them.
1439 */
1440 if (RT_BOOL(pThis->svga.uCursorOn) != RT_BOOL(uCursorOn))
1441 {
1442 LogRel2(("vmsvgaR3RegUpdateCursor: uCursorOn %d prev CursorOn %d (%d,%d)\n", uCursorOn, pThis->svga.uCursorOn, x, y));
1443 pThisCC->pDrv->pfnVBVAMousePointerShape(pThisCC->pDrv, RT_BOOL(uCursorOn), false, 0, 0, 0, 0, NULL);
1444 }
1445 pThis->svga.uCursorOn = uCursorOn;
1446 pThisCC->pDrv->pfnVBVAReportCursorPosition(pThisCC->pDrv, fFlags, idScreen, x, y);
1447}
1448
1449#endif /* IN_RING3 */
1450
1451
1452/**
1453 * Write port register
1454 *
1455 * @returns Strict VBox status code.
1456 * @param pDevIns The device instance.
1457 * @param pThis The shared VGA/VMSVGA state.
1458 * @param pThisCC The VGA/VMSVGA state for the current context.
1459 * @param u32 Value to write
1460 */
1461static VBOXSTRICTRC vmsvgaWritePort(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, uint32_t u32)
1462{
1463#ifdef IN_RING3
1464 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
1465#endif
1466 VBOXSTRICTRC rc = VINF_SUCCESS;
1467 RT_NOREF(pThisCC);
1468
1469 /* Rough index register validation. */
1470 uint32_t idxReg = pThis->svga.u32IndexReg;
1471#if !defined(IN_RING3) && defined(VBOX_STRICT)
1472 ASSERT_GUEST_MSG_RETURN(idxReg < SVGA_SCRATCH_BASE + pThis->svga.cScratchRegion, ("idxReg=%#x\n", idxReg),
1473 VINF_IOM_R3_IOPORT_WRITE);
1474#else
1475 ASSERT_GUEST_MSG_STMT_RETURN(idxReg < SVGA_SCRATCH_BASE + pThis->svga.cScratchRegion, ("idxReg=%#x\n", idxReg),
1476 STAM_REL_COUNTER_INC(&pThis->svga.StatRegUnknownWr),
1477 VINF_SUCCESS);
1478#endif
1479 RT_UNTRUSTED_VALIDATED_FENCE();
1480
1481 /* We must adjust the register number if we're in SVGA_ID_0 mode because the PALETTE range moved. */
1482 if ( idxReg >= SVGA_REG_ID_0_TOP
1483 && pThis->svga.u32SVGAId == SVGA_ID_0)
1484 {
1485 idxReg += SVGA_PALETTE_BASE - SVGA_REG_ID_0_TOP;
1486 Log(("vmsvgaWritePort: SVGA_ID_0 reg adj %#x -> %#x\n", pThis->svga.u32IndexReg, idxReg));
1487 }
1488 Log(("vmsvgaWritePort index=%s (%d) val=%#x\n", vmsvgaIndexToString(pThis, idxReg), idxReg, u32));
1489 /* Check if the guest uses legacy registers. See vmsvgaR3ChangeMode */
1490 switch (idxReg)
1491 {
1492 case SVGA_REG_WIDTH:
1493 case SVGA_REG_HEIGHT:
1494 case SVGA_REG_PITCHLOCK:
1495 case SVGA_REG_BITS_PER_PIXEL:
1496 pThis->svga.fGFBRegisters = true;
1497 break;
1498 default:
1499 break;
1500 }
1501
1502 switch (idxReg)
1503 {
1504 case SVGA_REG_ID:
1505 STAM_REL_COUNTER_INC(&pThis->svga.StatRegIdWr);
1506 if ( u32 == SVGA_ID_0
1507 || u32 == SVGA_ID_1
1508 || u32 == SVGA_ID_2)
1509 pThis->svga.u32SVGAId = u32;
1510 else
1511 PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Trying to set SVGA_REG_ID to %#x (%d)\n", u32, u32);
1512 break;
1513
1514 case SVGA_REG_ENABLE:
1515 STAM_REL_COUNTER_INC(&pThis->svga.StatRegEnableWr);
1516#ifdef IN_RING3
1517 if ( (u32 & SVGA_REG_ENABLE_ENABLE)
1518 && pThis->svga.fEnabled == false)
1519 {
1520 /* Make a backup copy of the first 512kb in order to save font data etc. */
1521 /** @todo should probably swap here, rather than copy + zero */
1522 memcpy(pThisCC->svga.pbVgaFrameBufferR3, pThisCC->pbVRam, VMSVGA_VGA_FB_BACKUP_SIZE);
1523 memset(pThisCC->pbVRam, 0, VMSVGA_VGA_FB_BACKUP_SIZE);
1524 }
1525
1526 pThis->svga.fEnabled = u32;
1527 if (pThis->svga.fEnabled)
1528 {
1529 if ( pThis->svga.uWidth == VMSVGA_VAL_UNINITIALIZED
1530 && pThis->svga.uHeight == VMSVGA_VAL_UNINITIALIZED)
1531 {
1532 /* Keep the current mode. */
1533 pThis->svga.uWidth = pThisCC->pDrv->cx;
1534 pThis->svga.uHeight = pThisCC->pDrv->cy;
1535 pThis->svga.uBpp = (pThisCC->pDrv->cBits + 7) & ~7;
1536 }
1537
1538 if ( pThis->svga.uWidth != VMSVGA_VAL_UNINITIALIZED
1539 && pThis->svga.uHeight != VMSVGA_VAL_UNINITIALIZED)
1540 ASMAtomicOrU32(&pThis->svga.u32ActionFlags, VMSVGA_ACTION_CHANGEMODE);
1541# ifdef LOG_ENABLED
1542 uint32_t *pFIFO = pThisCC->svga.pau32FIFO;
1543 Log(("configured=%d busy=%d\n", pThis->svga.fConfigured, pFIFO[SVGA_FIFO_BUSY]));
1544 Log(("next %x stop %x\n", pFIFO[SVGA_FIFO_NEXT_CMD], pFIFO[SVGA_FIFO_STOP]));
1545# endif
1546
1547 /* Disable or enable dirty page tracking according to the current fTraces value. */
1548 vmsvgaR3SetTraces(pDevIns, pThis, !!pThis->svga.fTraces);
1549
1550 /* bird: Whatever this is was added to make screenshot work, ask sunlover should explain... */
1551 for (uint32_t idScreen = 0; idScreen < pThis->cMonitors; ++idScreen)
1552 pThisCC->pDrv->pfnVBVAEnable(pThisCC->pDrv, idScreen, NULL /*pHostFlags*/);
1553
1554 /* Make the cursor visible again as needed. */
1555 if (pSVGAState->Cursor.fActive)
1556 pThisCC->pDrv->pfnVBVAMousePointerShape(pThisCC->pDrv, true /*fVisible*/, false, 0, 0, 0, 0, NULL);
1557 }
1558 else
1559 {
1560 /* Make sure the cursor is off. */
1561 if (pSVGAState->Cursor.fActive)
1562 pThisCC->pDrv->pfnVBVAMousePointerShape(pThisCC->pDrv, false /*fVisible*/, false, 0, 0, 0, 0, NULL);
1563
1564 /* Restore the text mode backup. */
1565 memcpy(pThisCC->pbVRam, pThisCC->svga.pbVgaFrameBufferR3, VMSVGA_VGA_FB_BACKUP_SIZE);
1566
1567 pThisCC->pDrv->pfnLFBModeChange(pThisCC->pDrv, false);
1568
1569 /* Enable dirty page tracking again when going into legacy mode. */
1570 vmsvgaR3SetTraces(pDevIns, pThis, true);
1571
1572 /* bird: Whatever this is was added to make screenshot work, ask sunlover should explain... */
1573 for (uint32_t idScreen = 0; idScreen < pThis->cMonitors; ++idScreen)
1574 pThisCC->pDrv->pfnVBVADisable(pThisCC->pDrv, idScreen);
1575
1576 /* Clear the pitch lock. */
1577 pThis->svga.u32PitchLock = 0;
1578 }
1579#else /* !IN_RING3 */
1580 rc = VINF_IOM_R3_IOPORT_WRITE;
1581#endif /* !IN_RING3 */
1582 break;
1583
1584 case SVGA_REG_WIDTH:
1585 STAM_REL_COUNTER_INC(&pThis->svga.StatRegWidthWr);
1586 if (pThis->svga.uWidth != u32)
1587 {
1588#if defined(IN_RING3) || defined(IN_RING0)
1589 pThis->svga.uWidth = u32;
1590 vmsvgaHCUpdatePitch(pThis, pThisCC);
1591 if (pThis->svga.fEnabled)
1592 ASMAtomicOrU32(&pThis->svga.u32ActionFlags, VMSVGA_ACTION_CHANGEMODE);
1593#else
1594 rc = VINF_IOM_R3_IOPORT_WRITE;
1595#endif
1596 }
1597 /* else: nop */
1598 break;
1599
1600 case SVGA_REG_HEIGHT:
1601 STAM_REL_COUNTER_INC(&pThis->svga.StatRegHeightWr);
1602 if (pThis->svga.uHeight != u32)
1603 {
1604 pThis->svga.uHeight = u32;
1605 if (pThis->svga.fEnabled)
1606 ASMAtomicOrU32(&pThis->svga.u32ActionFlags, VMSVGA_ACTION_CHANGEMODE);
1607 }
1608 /* else: nop */
1609 break;
1610
1611 case SVGA_REG_DEPTH:
1612 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDepthWr);
1613 /** @todo read-only?? */
1614 break;
1615
1616 case SVGA_REG_BITS_PER_PIXEL: /* Current bpp in the guest */
1617 STAM_REL_COUNTER_INC(&pThis->svga.StatRegBitsPerPixelWr);
1618 if (pThis->svga.uBpp != u32)
1619 {
1620#if defined(IN_RING3) || defined(IN_RING0)
1621 pThis->svga.uBpp = u32;
1622 vmsvgaHCUpdatePitch(pThis, pThisCC);
1623 if (pThis->svga.fEnabled)
1624 ASMAtomicOrU32(&pThis->svga.u32ActionFlags, VMSVGA_ACTION_CHANGEMODE);
1625#else
1626 rc = VINF_IOM_R3_IOPORT_WRITE;
1627#endif
1628 }
1629 /* else: nop */
1630 break;
1631
1632 case SVGA_REG_PSEUDOCOLOR:
1633 STAM_REL_COUNTER_INC(&pThis->svga.StatRegPseudoColorWr);
1634 break;
1635
1636 case SVGA_REG_CONFIG_DONE: /* Set when memory area configured */
1637#ifdef IN_RING3
1638 STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegConfigDoneWr);
1639 pThis->svga.fConfigured = u32;
1640 /* Disabling the FIFO enables tracing (dirty page detection) by default. */
1641 if (!pThis->svga.fConfigured)
1642 pThis->svga.fTraces = true;
1643 vmsvgaR3SetTraces(pDevIns, pThis, !!pThis->svga.fTraces);
1644#else
1645 rc = VINF_IOM_R3_IOPORT_WRITE;
1646#endif
1647 break;
1648
1649 case SVGA_REG_SYNC: /* See "FIFO Synchronization Registers" */
1650 STAM_REL_COUNTER_INC(&pThis->svga.StatRegSyncWr);
1651 if ( pThis->svga.fEnabled
1652 && pThis->svga.fConfigured)
1653 {
1654#if defined(IN_RING3) || defined(IN_RING0)
1655 Log(("SVGA_REG_SYNC: SVGA_FIFO_BUSY=%d\n", pThisCC->svga.pau32FIFO[SVGA_FIFO_BUSY]));
1656 /*
1657 * The VMSVGA_BUSY_F_EMT_FORCE flag makes sure we will check if the FIFO is empty
1658 * at least once; VMSVGA_BUSY_F_FIFO alone does not ensure that.
1659 */
1660 ASMAtomicWriteU32(&pThis->svga.fBusy, VMSVGA_BUSY_F_EMT_FORCE | VMSVGA_BUSY_F_FIFO);
1661 if (VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_BUSY, pThisCC->svga.pau32FIFO[SVGA_FIFO_MIN]))
1662 vmsvgaHCSafeFifoBusyRegUpdate(pThis, pThisCC, true);
1663
1664 /* Kick the FIFO thread to start processing commands again. */
1665 PDMDevHlpSUPSemEventSignal(pDevIns, pThis->svga.hFIFORequestSem);
1666#else
1667 rc = VINF_IOM_R3_IOPORT_WRITE;
1668#endif
1669 }
1670 /* else nothing to do. */
1671 else
1672 Log(("Sync ignored enabled=%d configured=%d\n", pThis->svga.fEnabled, pThis->svga.fConfigured));
1673
1674 break;
1675
1676 case SVGA_REG_BUSY: /* See "FIFO Synchronization Registers" (read-only) */
1677 STAM_REL_COUNTER_INC(&pThis->svga.StatRegBusyWr);
1678 break;
1679
1680 case SVGA_REG_GUEST_ID: /* Set guest OS identifier */
1681 STAM_REL_COUNTER_INC(&pThis->svga.StatRegGuestIdWr);
1682 pThis->svga.u32GuestId = u32;
1683 break;
1684
1685 case SVGA_REG_PITCHLOCK: /* Fixed pitch for all modes */
1686 STAM_REL_COUNTER_INC(&pThis->svga.StatRegPitchLockWr);
1687 pThis->svga.u32PitchLock = u32;
1688 /* Should this also update the FIFO pitch lock? Unclear. */
1689 break;
1690
1691 case SVGA_REG_IRQMASK: /* Interrupt mask */
1692 STAM_REL_COUNTER_INC(&pThis->svga.StatRegIrqMaskWr);
1693 pThis->svga.u32IrqMask = u32;
1694
1695 /* Irq pending after the above change? */
1696 if (pThis->svga.u32IrqStatus & u32)
1697 {
1698 Log(("SVGA_REG_IRQMASK: Trigger interrupt with status %x\n", pThis->svga.u32IrqStatus));
1699 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, 1);
1700 }
1701 else
1702 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, 0);
1703 break;
1704
1705 /* Mouse cursor support */
1706 case SVGA_REG_CURSOR_ID:
1707 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCursorIdWr);
1708 pThis->svga.uCursorID = u32;
1709 break;
1710
1711 case SVGA_REG_CURSOR_X:
1712 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCursorXWr);
1713 pThis->svga.uCursorX = u32;
1714 break;
1715
1716 case SVGA_REG_CURSOR_Y:
1717 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCursorYWr);
1718 pThis->svga.uCursorY = u32;
1719 break;
1720
1721 case SVGA_REG_CURSOR_ON:
1722#ifdef IN_RING3
1723 /* The cursor is only updated when SVGA_REG_CURSOR_ON is written. */
1724 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCursorOnWr);
1725 vmsvgaR3RegUpdateCursor(pThisCC, pThis, u32);
1726#else
1727 rc = VINF_IOM_R3_IOPORT_WRITE;
1728#endif
1729 break;
1730
1731 /* Legacy multi-monitor support */
1732 case SVGA_REG_NUM_GUEST_DISPLAYS:/* Number of guest displays in X/Y direction */
1733 STAM_REL_COUNTER_INC(&pThis->svga.StatRegNumGuestDisplaysWr);
1734 break;
1735 case SVGA_REG_DISPLAY_ID: /* Display ID for the following display attributes */
1736 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayIdWr);
1737 break;
1738 case SVGA_REG_DISPLAY_IS_PRIMARY:/* Whether this is a primary display */
1739 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayIsPrimaryWr);
1740 break;
1741 case SVGA_REG_DISPLAY_POSITION_X:/* The display position x */
1742 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayPositionXWr);
1743 break;
1744 case SVGA_REG_DISPLAY_POSITION_Y:/* The display position y */
1745 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayPositionYWr);
1746 break;
1747 case SVGA_REG_DISPLAY_WIDTH: /* The display's width */
1748 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayWidthWr);
1749 break;
1750 case SVGA_REG_DISPLAY_HEIGHT: /* The display's height */
1751 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDisplayHeightWr);
1752 break;
1753#ifdef VBOX_WITH_VMSVGA3D
1754 /* See "Guest memory regions" below. */
1755 case SVGA_REG_GMR_ID:
1756 STAM_REL_COUNTER_INC(&pThis->svga.StatRegGmrIdWr);
1757 pThis->svga.u32CurrentGMRId = u32;
1758 break;
1759
1760 case SVGA_REG_GMR_DESCRIPTOR:
1761# ifndef IN_RING3
1762 rc = VINF_IOM_R3_IOPORT_WRITE;
1763 break;
1764# else /* IN_RING3 */
1765 {
1766 STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegGmrDescriptorWr);
1767
1768 /* Validate current GMR id. */
1769 uint32_t idGMR = pThis->svga.u32CurrentGMRId;
1770 AssertBreak(idGMR < pThis->svga.cGMR);
1771 RT_UNTRUSTED_VALIDATED_FENCE();
1772
1773 /* Free the old GMR if present. */
1774 vmsvgaR3GmrFree(pThisCC, idGMR);
1775
1776 /* Just undefine the GMR? */
1777 RTGCPHYS GCPhys = (RTGCPHYS)u32 << PAGE_SHIFT;
1778 if (GCPhys == 0)
1779 {
1780 STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegGmrDescriptorWrFree);
1781 break;
1782 }
1783
1784
1785 /* Never cross a page boundary automatically. */
1786 const uint32_t cMaxPages = RT_MIN(VMSVGA_MAX_GMR_PAGES, UINT32_MAX / X86_PAGE_SIZE);
1787 uint32_t cPagesTotal = 0;
1788 uint32_t iDesc = 0;
1789 PVMSVGAGMRDESCRIPTOR paDescs = NULL;
1790 uint32_t cLoops = 0;
1791 RTGCPHYS GCPhysBase = GCPhys;
1792 while (PHYS_PAGE_ADDRESS(GCPhys) == PHYS_PAGE_ADDRESS(GCPhysBase))
1793 {
1794 /* Read descriptor. */
1795 SVGAGuestMemDescriptor desc;
1796 rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, &desc, sizeof(desc));
1797 AssertRCBreak(VBOXSTRICTRC_VAL(rc));
1798
1799 if (desc.numPages != 0)
1800 {
1801 AssertBreakStmt(desc.numPages <= cMaxPages, rc = VERR_OUT_OF_RANGE);
1802 cPagesTotal += desc.numPages;
1803 AssertBreakStmt(cPagesTotal <= cMaxPages, rc = VERR_OUT_OF_RANGE);
1804
1805 if ((iDesc & 15) == 0)
1806 {
1807 void *pvNew = RTMemRealloc(paDescs, (iDesc + 16) * sizeof(VMSVGAGMRDESCRIPTOR));
1808 AssertBreakStmt(pvNew, rc = VERR_NO_MEMORY);
1809 paDescs = (PVMSVGAGMRDESCRIPTOR)pvNew;
1810 }
1811
1812 paDescs[iDesc].GCPhys = (RTGCPHYS)desc.ppn << PAGE_SHIFT;
1813 paDescs[iDesc++].numPages = desc.numPages;
1814
1815 /* Continue with the next descriptor. */
1816 GCPhys += sizeof(desc);
1817 }
1818 else if (desc.ppn == 0)
1819 break; /* terminator */
1820 else /* Pointer to the next physical page of descriptors. */
1821 GCPhys = GCPhysBase = (RTGCPHYS)desc.ppn << PAGE_SHIFT;
1822
1823 cLoops++;
1824 AssertBreakStmt(cLoops < VMSVGA_MAX_GMR_DESC_LOOP_COUNT, rc = VERR_OUT_OF_RANGE);
1825 }
1826
1827 AssertStmt(iDesc > 0 || RT_FAILURE_NP(rc), rc = VERR_OUT_OF_RANGE);
1828 if (RT_SUCCESS(rc))
1829 {
1830 /* Commit the GMR. */
1831 pSVGAState->paGMR[idGMR].paDesc = paDescs;
1832 pSVGAState->paGMR[idGMR].numDescriptors = iDesc;
1833 pSVGAState->paGMR[idGMR].cMaxPages = cPagesTotal;
1834 pSVGAState->paGMR[idGMR].cbTotal = cPagesTotal * PAGE_SIZE;
1835 Assert((pSVGAState->paGMR[idGMR].cbTotal >> PAGE_SHIFT) == cPagesTotal);
1836 Log(("Defined new gmr %x numDescriptors=%d cbTotal=%x (%#x pages)\n",
1837 idGMR, iDesc, pSVGAState->paGMR[idGMR].cbTotal, cPagesTotal));
1838 }
1839 else
1840 {
1841 RTMemFree(paDescs);
1842 STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegGmrDescriptorWrErrors);
1843 }
1844 break;
1845 }
1846# endif /* IN_RING3 */
1847#endif // VBOX_WITH_VMSVGA3D
1848
1849 case SVGA_REG_TRACES: /* Enable trace-based updates even when FIFO is on */
1850 STAM_REL_COUNTER_INC(&pThis->svga.StatRegTracesWr);
1851 if (pThis->svga.fTraces == u32)
1852 break; /* nothing to do */
1853
1854#ifdef IN_RING3
1855 vmsvgaR3SetTraces(pDevIns, pThis, !!u32);
1856#else
1857 rc = VINF_IOM_R3_IOPORT_WRITE;
1858#endif
1859 break;
1860
1861 case SVGA_REG_TOP: /* Must be 1 more than the last register */
1862 STAM_REL_COUNTER_INC(&pThis->svga.StatRegTopWr);
1863 break;
1864
1865 case SVGA_REG_NUM_DISPLAYS: /* (Deprecated) */
1866 STAM_REL_COUNTER_INC(&pThis->svga.StatRegNumDisplaysWr);
1867 Log(("Write to deprecated register %x - val %x ignored\n", idxReg, u32));
1868 break;
1869
1870 /*
1871 * SVGA_CAP_GBOBJECTS+ registers.
1872 */
1873 case SVGA_REG_COMMAND_LOW:
1874 {
1875 /* Lower 32 bits of command buffer physical address and submit the command buffer. */
1876#ifdef IN_RING3
1877 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCommandLowWr);
1878 pThis->svga.u32RegCommandLow = u32;
1879
1880 /* "lower 6 bits are used for the SVGACBContext" */
1881 RTGCPHYS GCPhysCB = pThis->svga.u32RegCommandHigh;
1882 GCPhysCB <<= 32;
1883 GCPhysCB |= pThis->svga.u32RegCommandLow & ~SVGA_CB_CONTEXT_MASK;
1884 SVGACBContext const CBCtx = (SVGACBContext)(pThis->svga.u32RegCommandLow & SVGA_CB_CONTEXT_MASK);
1885 vmsvgaR3CmdBufSubmit(pDevIns, pThis, pThisCC, GCPhysCB, CBCtx);
1886#else
1887 rc = VINF_IOM_R3_IOPORT_WRITE;
1888#endif
1889 break;
1890 }
1891
1892 case SVGA_REG_COMMAND_HIGH:
1893 /* Upper 32 bits of command buffer PA. */
1894 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCommandHighWr);
1895 pThis->svga.u32RegCommandHigh = u32;
1896 break;
1897
1898 case SVGA_REG_DEV_CAP:
1899 /* Write dev cap index, read value */
1900 STAM_REL_COUNTER_INC(&pThis->svga.StatRegDevCapWr);
1901 pThis->svga.u32DevCapIndex = u32;
1902 break;
1903
1904 case SVGA_REG_CMD_PREPEND_LOW:
1905 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCmdPrependLowWr);
1906 /* Not supported. */
1907 break;
1908
1909 case SVGA_REG_iCMD_PREPEND_HIGH:
1910 STAM_REL_COUNTER_INC(&pThis->svga.StatRegCmdPrependHighWr);
1911 /* Not supported. */
1912 break;
1913
1914 case SVGA_REG_FB_START:
1915 case SVGA_REG_MEM_START:
1916 case SVGA_REG_HOST_BITS_PER_PIXEL:
1917 case SVGA_REG_MAX_WIDTH:
1918 case SVGA_REG_MAX_HEIGHT:
1919 case SVGA_REG_VRAM_SIZE:
1920 case SVGA_REG_FB_SIZE:
1921 case SVGA_REG_CAPABILITIES:
1922 case SVGA_REG_MEM_SIZE:
1923 case SVGA_REG_SCRATCH_SIZE: /* Number of scratch registers */
1924 case SVGA_REG_MEM_REGS: /* Number of FIFO registers */
1925 case SVGA_REG_BYTES_PER_LINE:
1926 case SVGA_REG_FB_OFFSET:
1927 case SVGA_REG_RED_MASK:
1928 case SVGA_REG_GREEN_MASK:
1929 case SVGA_REG_BLUE_MASK:
1930 case SVGA_REG_GMRS_MAX_PAGES: /* Maximum number of 4KB pages for all GMRs */
1931 case SVGA_REG_MEMORY_SIZE: /* Total dedicated device memory excluding FIFO */
1932 case SVGA_REG_GMR_MAX_IDS:
1933 case SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH:
1934 case SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM:
1935 case SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB:
1936 case SVGA_REG_SCREENTARGET_MAX_WIDTH:
1937 case SVGA_REG_SCREENTARGET_MAX_HEIGHT:
1938 case SVGA_REG_MOB_MAX_SIZE:
1939 /* Read only - ignore. */
1940 Log(("Write to R/O register %x - val %x ignored\n", idxReg, u32));
1941 STAM_REL_COUNTER_INC(&pThis->svga.StatRegReadOnlyWr);
1942 break;
1943
1944 default:
1945 {
1946 uint32_t offReg;
1947 if ((offReg = idxReg - SVGA_SCRATCH_BASE) < pThis->svga.cScratchRegion)
1948 {
1949 RT_UNTRUSTED_VALIDATED_FENCE();
1950 pThis->svga.au32ScratchRegion[offReg] = u32;
1951 STAM_REL_COUNTER_INC(&pThis->svga.StatRegScratchWr);
1952 }
1953 else if ((offReg = idxReg - SVGA_PALETTE_BASE) < (uint32_t)SVGA_NUM_PALETTE_REGS)
1954 {
1955 /* Note! Using last_palette rather than palette here to preserve the VGA one.
1956 Btw, see rgb_to_pixel32. */
1957 STAM_REL_COUNTER_INC(&pThis->svga.StatRegPaletteWr);
1958 u32 &= 0xff;
1959 RT_UNTRUSTED_VALIDATED_FENCE();
1960 uint32_t uRgb = pThis->last_palette[offReg / 3];
1961 switch (offReg % 3)
1962 {
1963 case 0: uRgb = (uRgb & UINT32_C(0x0000ffff)) | (u32 << 16); break; /* red */
1964 case 1: uRgb = (uRgb & UINT32_C(0x00ff00ff)) | (u32 << 8); break; /* green */
1965 case 2: uRgb = (uRgb & UINT32_C(0x00ffff00)) | u32 ; break; /* blue */
1966 }
1967 pThis->last_palette[offReg / 3] = uRgb;
1968 }
1969 else
1970 {
1971#if !defined(IN_RING3) && defined(VBOX_STRICT)
1972 rc = VINF_IOM_R3_IOPORT_WRITE;
1973#else
1974 STAM_REL_COUNTER_INC(&pThis->svga.StatRegUnknownWr);
1975 AssertMsgFailed(("reg=%#x u32=%#x\n", idxReg, u32));
1976#endif
1977 }
1978 break;
1979 }
1980 }
1981 return rc;
1982}
1983
1984/**
1985 * @callback_method_impl{FNIOMIOPORTNEWIN}
1986 */
1987DECLCALLBACK(VBOXSTRICTRC) vmsvgaIORead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
1988{
1989 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
1990 RT_NOREF_PV(pvUser);
1991
1992 /* Only dword accesses. */
1993 if (cb == 4)
1994 {
1995 switch (offPort)
1996 {
1997 case SVGA_INDEX_PORT:
1998 *pu32 = pThis->svga.u32IndexReg;
1999 break;
2000
2001 case SVGA_VALUE_PORT:
2002 return vmsvgaReadPort(pDevIns, pThis, pu32);
2003
2004 case SVGA_BIOS_PORT:
2005 Log(("Ignoring BIOS port read\n"));
2006 *pu32 = 0;
2007 break;
2008
2009 case SVGA_IRQSTATUS_PORT:
2010 LogFlow(("vmsvgaIORead: SVGA_IRQSTATUS_PORT %x\n", pThis->svga.u32IrqStatus));
2011 *pu32 = pThis->svga.u32IrqStatus;
2012 break;
2013
2014 default:
2015 ASSERT_GUEST_MSG_FAILED(("vmsvgaIORead: Unknown register %u was read from.\n", offPort));
2016 *pu32 = UINT32_MAX;
2017 break;
2018 }
2019 }
2020 else
2021 {
2022 Log(("Ignoring non-dword I/O port read at %x cb=%d\n", offPort, cb));
2023 *pu32 = UINT32_MAX;
2024 }
2025 return VINF_SUCCESS;
2026}
2027
2028/**
2029 * @callback_method_impl{FNIOMIOPORTNEWOUT}
2030 */
2031DECLCALLBACK(VBOXSTRICTRC) vmsvgaIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
2032{
2033 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
2034 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
2035 RT_NOREF_PV(pvUser);
2036
2037 /* Only dword accesses. */
2038 if (cb == 4)
2039 switch (offPort)
2040 {
2041 case SVGA_INDEX_PORT:
2042 pThis->svga.u32IndexReg = u32;
2043 break;
2044
2045 case SVGA_VALUE_PORT:
2046 return vmsvgaWritePort(pDevIns, pThis, pThisCC, u32);
2047
2048 case SVGA_BIOS_PORT:
2049 Log(("Ignoring BIOS port write (val=%x)\n", u32));
2050 break;
2051
2052 case SVGA_IRQSTATUS_PORT:
2053 Log(("vmsvgaIOWrite SVGA_IRQSTATUS_PORT %x: status %x -> %x\n", u32, pThis->svga.u32IrqStatus, pThis->svga.u32IrqStatus & ~u32));
2054 ASMAtomicAndU32(&pThis->svga.u32IrqStatus, ~u32);
2055 /* Clear the irq in case all events have been cleared. */
2056 if (!(pThis->svga.u32IrqStatus & pThis->svga.u32IrqMask))
2057 {
2058 Log(("vmsvgaIOWrite SVGA_IRQSTATUS_PORT: clearing IRQ\n"));
2059 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, 0);
2060 }
2061 break;
2062
2063 default:
2064 ASSERT_GUEST_MSG_FAILED(("vmsvgaIOWrite: Unknown register %u was written to, value %#x LB %u.\n", offPort, u32, cb));
2065 break;
2066 }
2067 else
2068 Log(("Ignoring non-dword write at %x val=%x cb=%d\n", offPort, u32, cb));
2069
2070 return VINF_SUCCESS;
2071}
2072
2073#ifdef IN_RING3
2074
2075# ifdef DEBUG_FIFO_ACCESS
2076/**
2077 * Handle FIFO memory access.
2078 * @returns VBox status code.
2079 * @param pVM VM handle.
2080 * @param pThis The shared VGA/VMSVGA instance data.
2081 * @param GCPhys The access physical address.
2082 * @param fWriteAccess Read or write access
2083 */
2084static int vmsvgaR3DebugFifoAccess(PVM pVM, PVGASTATE pThis, RTGCPHYS GCPhys, bool fWriteAccess)
2085{
2086 RT_NOREF(pVM);
2087 RTGCPHYS GCPhysOffset = GCPhys - pThis->svga.GCPhysFIFO;
2088 uint32_t *pFIFO = pThisCC->svga.pau32FIFO;
2089
2090 switch (GCPhysOffset >> 2)
2091 {
2092 case SVGA_FIFO_MIN:
2093 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_MIN = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2094 break;
2095 case SVGA_FIFO_MAX:
2096 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_MAX = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2097 break;
2098 case SVGA_FIFO_NEXT_CMD:
2099 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_NEXT_CMD = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2100 break;
2101 case SVGA_FIFO_STOP:
2102 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_STOP = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2103 break;
2104 case SVGA_FIFO_CAPABILITIES:
2105 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_CAPABILITIES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2106 break;
2107 case SVGA_FIFO_FLAGS:
2108 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_FLAGS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2109 break;
2110 case SVGA_FIFO_FENCE:
2111 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_FENCE = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2112 break;
2113 case SVGA_FIFO_3D_HWVERSION:
2114 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_HWVERSION = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2115 break;
2116 case SVGA_FIFO_PITCHLOCK:
2117 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_PITCHLOCK = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2118 break;
2119 case SVGA_FIFO_CURSOR_ON:
2120 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_CURSOR_ON = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2121 break;
2122 case SVGA_FIFO_CURSOR_X:
2123 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_CURSOR_X = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2124 break;
2125 case SVGA_FIFO_CURSOR_Y:
2126 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_CURSOR_Y = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2127 break;
2128 case SVGA_FIFO_CURSOR_COUNT:
2129 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_CURSOR_COUNT = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2130 break;
2131 case SVGA_FIFO_CURSOR_LAST_UPDATED:
2132 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_CURSOR_LAST_UPDATED = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2133 break;
2134 case SVGA_FIFO_RESERVED:
2135 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_RESERVED = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2136 break;
2137 case SVGA_FIFO_CURSOR_SCREEN_ID:
2138 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_CURSOR_SCREEN_ID = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2139 break;
2140 case SVGA_FIFO_DEAD:
2141 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_DEAD = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2142 break;
2143 case SVGA_FIFO_3D_HWVERSION_REVISED:
2144 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_HWVERSION_REVISED = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2145 break;
2146 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_3D:
2147 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_3D = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2148 break;
2149 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_LIGHTS:
2150 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_LIGHTS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2151 break;
2152 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_TEXTURES:
2153 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_TEXTURES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2154 break;
2155 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_CLIP_PLANES:
2156 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_CLIP_PLANES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2157 break;
2158 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_VERTEX_SHADER_VERSION:
2159 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_VERTEX_SHADER_VERSION = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2160 break;
2161 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_VERTEX_SHADER:
2162 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_VERTEX_SHADER = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2163 break;
2164 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION:
2165 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2166 break;
2167 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_FRAGMENT_SHADER:
2168 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_FRAGMENT_SHADER = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2169 break;
2170 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_RENDER_TARGETS:
2171 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_RENDER_TARGETS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2172 break;
2173 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_S23E8_TEXTURES:
2174 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_S23E8_TEXTURES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2175 break;
2176 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_S10E5_TEXTURES:
2177 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_S10E5_TEXTURES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2178 break;
2179 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_FIXED_VERTEXBLEND:
2180 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_FIXED_VERTEXBLEND = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2181 break;
2182 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_D16_BUFFER_FORMAT:
2183 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_D16_BUFFER_FORMAT = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2184 break;
2185 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_D24S8_BUFFER_FORMAT:
2186 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_D24S8_BUFFER_FORMAT = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2187 break;
2188 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_D24X8_BUFFER_FORMAT:
2189 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_D24X8_BUFFER_FORMAT = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2190 break;
2191 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_QUERY_TYPES:
2192 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_QUERY_TYPES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2193 break;
2194 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_TEXTURE_GRADIENT_SAMPLING:
2195 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_TEXTURE_GRADIENT_SAMPLING = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2196 break;
2197 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_POINT_SIZE:
2198 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_POINT_SIZE = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2199 break;
2200 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_SHADER_TEXTURES:
2201 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_SHADER_TEXTURES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2202 break;
2203 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH:
2204 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2205 break;
2206 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT:
2207 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2208 break;
2209 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_VOLUME_EXTENT:
2210 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_VOLUME_EXTENT = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2211 break;
2212 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_TEXTURE_REPEAT:
2213 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_TEXTURE_REPEAT = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2214 break;
2215 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_TEXTURE_ASPECT_RATIO:
2216 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_TEXTURE_ASPECT_RATIO = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2217 break;
2218 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_TEXTURE_ANISOTROPY:
2219 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_TEXTURE_ANISOTROPY = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2220 break;
2221 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_PRIMITIVE_COUNT:
2222 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_PRIMITIVE_COUNT = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2223 break;
2224 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_VERTEX_INDEX:
2225 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_VERTEX_INDEX = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2226 break;
2227 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_VERTEX_SHADER_INSTRUCTIONS:
2228 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_VERTEX_SHADER_INSTRUCTIONS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2229 break;
2230 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_INSTRUCTIONS:
2231 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_INSTRUCTIONS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2232 break;
2233 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEMPS:
2234 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEMPS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2235 break;
2236 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_TEMPS:
2237 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_TEMPS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2238 break;
2239 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_TEXTURE_OPS:
2240 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_TEXTURE_OPS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2241 break;
2242 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8:
2243 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2244 break;
2245 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8:
2246 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2247 break;
2248 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_A2R10G10B10:
2249 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_A2R10G10B10 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2250 break;
2251 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_X1R5G5B5:
2252 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_X1R5G5B5 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2253 break;
2254 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5:
2255 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2256 break;
2257 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4:
2258 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2259 break;
2260 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_R5G6B5:
2261 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_R5G6B5 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2262 break;
2263 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE16:
2264 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE16 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2265 break;
2266 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8:
2267 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2268 break;
2269 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_ALPHA8:
2270 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_ALPHA8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2271 break;
2272 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8:
2273 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2274 break;
2275 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_Z_D16:
2276 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_Z_D16 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2277 break;
2278 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8:
2279 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2280 break;
2281 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8:
2282 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2283 break;
2284 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_DXT1:
2285 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_DXT1 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2286 break;
2287 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_DXT2:
2288 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_DXT2 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2289 break;
2290 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_DXT3:
2291 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_DXT3 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2292 break;
2293 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_DXT4:
2294 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_DXT4 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2295 break;
2296 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_DXT5:
2297 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_DXT5 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2298 break;
2299 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_BUMPX8L8V8U8:
2300 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_BUMPX8L8V8U8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2301 break;
2302 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_A2W10V10U10:
2303 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_A2W10V10U10 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2304 break;
2305 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_BUMPU8V8:
2306 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_BUMPU8V8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2307 break;
2308 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_Q8W8V8U8:
2309 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_Q8W8V8U8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2310 break;
2311 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_CxV8U8:
2312 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_CxV8U8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2313 break;
2314 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_R_S10E5:
2315 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_R_S10E5 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2316 break;
2317 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_R_S23E8:
2318 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_R_S23E8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2319 break;
2320 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_RG_S10E5:
2321 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_RG_S10E5 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2322 break;
2323 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_RG_S23E8:
2324 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_RG_S23E8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2325 break;
2326 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_ARGB_S10E5:
2327 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_ARGB_S10E5 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2328 break;
2329 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_ARGB_S23E8:
2330 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_ARGB_S23E8 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2331 break;
2332 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEXTURES:
2333 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEXTURES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2334 break;
2335 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_SIMULTANEOUS_RENDER_TARGETS:
2336 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_SIMULTANEOUS_RENDER_TARGETS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2337 break;
2338 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_V16U16:
2339 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_V16U16 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2340 break;
2341 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_G16R16:
2342 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_G16R16 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2343 break;
2344 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_A16B16G16R16:
2345 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_A16B16G16R16 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2346 break;
2347 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_UYVY:
2348 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_UYVY = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2349 break;
2350 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_YUY2:
2351 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_YUY2 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2352 break;
2353 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MULTISAMPLE_NONMASKABLESAMPLES:
2354 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MULTISAMPLE_NONMASKABLESAMPLES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2355 break;
2356 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MULTISAMPLE_MASKABLESAMPLES:
2357 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MULTISAMPLE_MASKABLESAMPLES = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2358 break;
2359 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_ALPHATOCOVERAGE:
2360 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_ALPHATOCOVERAGE = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2361 break;
2362 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SUPERSAMPLE:
2363 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SUPERSAMPLE = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2364 break;
2365 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_AUTOGENMIPMAPS:
2366 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_AUTOGENMIPMAPS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2367 break;
2368 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_NV12:
2369 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_NV12 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2370 break;
2371 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_AYUV:
2372 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_AYUV = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2373 break;
2374 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_CONTEXT_IDS:
2375 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_CONTEXT_IDS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2376 break;
2377 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_MAX_SURFACE_IDS:
2378 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_MAX_SURFACE_IDS = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2379 break;
2380 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_Z_DF16:
2381 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_Z_DF16 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2382 break;
2383 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_Z_DF24:
2384 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_Z_DF24 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2385 break;
2386 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8_INT:
2387 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8_INT = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2388 break;
2389 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_ATI1:
2390 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_ATI1 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2391 break;
2392 case SVGA_FIFO_3D_CAPS + SVGA3D_DEVCAP_SURFACEFMT_ATI2:
2393 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS SVGA3D_DEVCAP_SURFACEFMT_ATI2 = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2394 break;
2395 case SVGA_FIFO_3D_CAPS_LAST:
2396 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_3D_CAPS_LAST = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2397 break;
2398 case SVGA_FIFO_GUEST_3D_HWVERSION:
2399 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_GUEST_3D_HWVERSION = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2400 break;
2401 case SVGA_FIFO_FENCE_GOAL:
2402 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_FENCE_GOAL = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2403 break;
2404 case SVGA_FIFO_BUSY:
2405 Log(("vmsvgaFIFOAccess [0x%x]: %s SVGA_FIFO_BUSY = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", pFIFO[GCPhysOffset >> 2]));
2406 break;
2407 default:
2408 Log(("vmsvgaFIFOAccess [0x%x]: %s access at offset %x = %x\n", GCPhysOffset >> 2, (fWriteAccess) ? "WRITE" : "READ", GCPhysOffset, pFIFO[GCPhysOffset >> 2]));
2409 break;
2410 }
2411
2412 return VINF_EM_RAW_EMULATE_INSTR;
2413}
2414# endif /* DEBUG_FIFO_ACCESS */
2415
2416# if defined(VMSVGA_USE_FIFO_ACCESS_HANDLER) || defined(DEBUG_FIFO_ACCESS)
2417/**
2418 * HC access handler for the FIFO.
2419 *
2420 * @returns VINF_SUCCESS if the handler have carried out the operation.
2421 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
2422 * @param pVM VM Handle.
2423 * @param pVCpu The cross context CPU structure for the calling EMT.
2424 * @param GCPhys The physical address the guest is writing to.
2425 * @param pvPhys The HC mapping of that address.
2426 * @param pvBuf What the guest is reading/writing.
2427 * @param cbBuf How much it's reading/writing.
2428 * @param enmAccessType The access type.
2429 * @param enmOrigin Who is making the access.
2430 * @param pvUser User argument.
2431 */
2432static DECLCALLBACK(VBOXSTRICTRC)
2433vmsvgaR3FifoAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
2434 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
2435{
2436 NOREF(pVCpu); NOREF(pvPhys); NOREF(pvBuf); NOREF(cbBuf); NOREF(enmOrigin); NOREF(enmAccessType); NOREF(GCPhys);
2437 PVGASTATE pThis = (PVGASTATE)pvUser;
2438 AssertPtr(pThis);
2439
2440# ifdef VMSVGA_USE_FIFO_ACCESS_HANDLER
2441 /*
2442 * Wake up the FIFO thread as it might have work to do now.
2443 */
2444 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->svga.hFIFORequestSem);
2445 AssertLogRelRC(rc);
2446# endif
2447
2448# ifdef DEBUG_FIFO_ACCESS
2449 /*
2450 * When in debug-fifo-access mode, we do not disable the access handler,
2451 * but leave it on as we wish to catch all access.
2452 */
2453 Assert(GCPhys >= pThis->svga.GCPhysFIFO);
2454 rc = vmsvgaR3DebugFifoAccess(pVM, pThis, GCPhys, enmAccessType == PGMACCESSTYPE_WRITE);
2455# elif defined(VMSVGA_USE_FIFO_ACCESS_HANDLER)
2456 /*
2457 * Temporarily disable the access handler now that we've kicked the FIFO thread.
2458 */
2459 STAM_REL_COUNTER_INC(&pThisCC->svga.pSvgaR3State->StatFifoAccessHandler);
2460 rc = PGMHandlerPhysicalPageTempOff(pVM, pThis->svga.GCPhysFIFO, pThis->svga.GCPhysFIFO);
2461# endif
2462 if (RT_SUCCESS(rc))
2463 return VINF_PGM_HANDLER_DO_DEFAULT;
2464 AssertMsg(rc <= VINF_SUCCESS, ("rc=%Rrc\n", rc));
2465 return rc;
2466}
2467# endif /* VMSVGA_USE_FIFO_ACCESS_HANDLER || DEBUG_FIFO_ACCESS */
2468
2469#endif /* IN_RING3 */
2470
2471#ifdef DEBUG_GMR_ACCESS
2472# ifdef IN_RING3
2473
2474/**
2475 * HC access handler for the FIFO.
2476 *
2477 * @returns VINF_SUCCESS if the handler have carried out the operation.
2478 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
2479 * @param pVM VM Handle.
2480 * @param pVCpu The cross context CPU structure for the calling EMT.
2481 * @param GCPhys The physical address the guest is writing to.
2482 * @param pvPhys The HC mapping of that address.
2483 * @param pvBuf What the guest is reading/writing.
2484 * @param cbBuf How much it's reading/writing.
2485 * @param enmAccessType The access type.
2486 * @param enmOrigin Who is making the access.
2487 * @param pvUser User argument.
2488 */
2489static DECLCALLBACK(VBOXSTRICTRC)
2490vmsvgaR3GmrAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
2491 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
2492{
2493 PVGASTATE pThis = (PVGASTATE)pvUser;
2494 Assert(pThis);
2495 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
2496 NOREF(pVCpu); NOREF(pvPhys); NOREF(pvBuf); NOREF(cbBuf); NOREF(enmAccessType); NOREF(enmOrigin);
2497
2498 Log(("vmsvgaR3GmrAccessHandler: GMR access to page %RGp\n", GCPhys));
2499
2500 for (uint32_t i = 0; i < pThis->svga.cGMR; ++i)
2501 {
2502 PGMR pGMR = &pSVGAState->paGMR[i];
2503
2504 if (pGMR->numDescriptors)
2505 {
2506 for (uint32_t j = 0; j < pGMR->numDescriptors; j++)
2507 {
2508 if ( GCPhys >= pGMR->paDesc[j].GCPhys
2509 && GCPhys < pGMR->paDesc[j].GCPhys + pGMR->paDesc[j].numPages * PAGE_SIZE)
2510 {
2511 /*
2512 * Turn off the write handler for this particular page and make it R/W.
2513 * Then return telling the caller to restart the guest instruction.
2514 */
2515 int rc = PGMHandlerPhysicalPageTempOff(pVM, pGMR->paDesc[j].GCPhys, GCPhys);
2516 AssertRC(rc);
2517 return VINF_PGM_HANDLER_DO_DEFAULT;
2518 }
2519 }
2520 }
2521 }
2522
2523 return VINF_PGM_HANDLER_DO_DEFAULT;
2524}
2525
2526/** Callback handler for VMR3ReqCallWaitU */
2527static DECLCALLBACK(int) vmsvgaR3RegisterGmr(PPDMDEVINS pDevIns, uint32_t gmrId)
2528{
2529 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
2530 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
2531 PGMR pGMR = &pSVGAState->paGMR[gmrId];
2532 int rc;
2533
2534 for (uint32_t i = 0; i < pGMR->numDescriptors; i++)
2535 {
2536 rc = PGMHandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
2537 pGMR->paDesc[i].GCPhys, pGMR->paDesc[i].GCPhys + pGMR->paDesc[i].numPages * PAGE_SIZE - 1,
2538 pThis->svga.hGmrAccessHandlerType, pThis, NIL_RTR0PTR, NIL_RTRCPTR, "VMSVGA GMR");
2539 AssertRC(rc);
2540 }
2541 return VINF_SUCCESS;
2542}
2543
2544/** Callback handler for VMR3ReqCallWaitU */
2545static DECLCALLBACK(int) vmsvgaR3DeregisterGmr(PPDMDEVINS pDevIns, uint32_t gmrId)
2546{
2547 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
2548 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
2549 PGMR pGMR = &pSVGAState->paGMR[gmrId];
2550
2551 for (uint32_t i = 0; i < pGMR->numDescriptors; i++)
2552 {
2553 int rc = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns), pGMR->paDesc[i].GCPhys);
2554 AssertRC(rc);
2555 }
2556 return VINF_SUCCESS;
2557}
2558
2559/** Callback handler for VMR3ReqCallWaitU */
2560static DECLCALLBACK(int) vmsvgaR3ResetGmrHandlers(PVGASTATE pThis)
2561{
2562 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
2563
2564 for (uint32_t i = 0; i < pThis->svga.cGMR; ++i)
2565 {
2566 PGMR pGMR = &pSVGAState->paGMR[i];
2567
2568 if (pGMR->numDescriptors)
2569 {
2570 for (uint32_t j = 0; j < pGMR->numDescriptors; j++)
2571 {
2572 int rc = PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pGMR->paDesc[j].GCPhys);
2573 AssertRC(rc);
2574 }
2575 }
2576 }
2577 return VINF_SUCCESS;
2578}
2579
2580# endif /* IN_RING3 */
2581#endif /* DEBUG_GMR_ACCESS */
2582
2583/* -=-=-=-=-=- Ring 3 -=-=-=-=-=- */
2584
2585#ifdef IN_RING3
2586
2587
2588/*
2589 *
2590 * Command buffer submission.
2591 *
2592 * Guest submits a buffer by writing to SVGA_REG_COMMAND_LOW register.
2593 *
2594 * EMT thread appends a command buffer to the context queue (VMSVGACMDBUFCTX::listSubmitted)
2595 * and wakes up the FIFO thread.
2596 *
2597 * FIFO thread fetches the command buffer from the queue, processes the commands and writes
2598 * the buffer header back to the guest memory.
2599 *
2600 * If buffers are preempted, then the EMT thread removes all buffers from the context queue.
2601 *
2602 */
2603
2604
2605/** Update a command buffer header 'status' and 'errorOffset' fields in the guest memory.
2606 *
2607 * @param pDevIns The device instance.
2608 * @param GCPhysCB Guest physical address of the command buffer header.
2609 * @param status Command buffer status (SVGA_CB_STATUS_*).
2610 * @param errorOffset Offset to the first byte of the failing command for SVGA_CB_STATUS_COMMAND_ERROR.
2611 * errorOffset is ignored if the status is not SVGA_CB_STATUS_COMMAND_ERROR.
2612 * @thread FIFO or EMT.
2613 */
2614static void vmsvgaR3CmdBufWriteStatus(PPDMDEVINS pDevIns, RTGCPHYS GCPhysCB, SVGACBStatus status, uint32_t errorOffset)
2615{
2616 SVGACBHeader hdr;
2617 hdr.status = status;
2618 hdr.errorOffset = errorOffset;
2619 AssertCompile( RT_OFFSETOF(SVGACBHeader, status) == 0
2620 && RT_OFFSETOF(SVGACBHeader, errorOffset) == 4
2621 && RT_OFFSETOF(SVGACBHeader, id) == 8);
2622 size_t const cbWrite = status == SVGA_CB_STATUS_COMMAND_ERROR
2623 ? RT_UOFFSET_AFTER(SVGACBHeader, errorOffset) /* Both 'status' and 'errorOffset' fields. */
2624 : RT_UOFFSET_AFTER(SVGACBHeader, status); /* Only 'status' field. */
2625 PDMDevHlpPCIPhysWrite(pDevIns, GCPhysCB, &hdr, cbWrite);
2626}
2627
2628
2629/** Raise an IRQ.
2630 *
2631 * @param pDevIns The device instance.
2632 * @param pThis The shared VGA/VMSVGA state.
2633 * @param fIRQ SVGA_IRQFLAG_* bits.
2634 * @thread FIFO or EMT.
2635 */
2636static void vmsvgaR3CmdBufRaiseIRQ(PPDMDEVINS pDevIns, PVGASTATE pThis, uint32_t fIRQ)
2637{
2638 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
2639 AssertRC(rc);
2640
2641 if (pThis->svga.u32IrqMask & fIRQ)
2642 {
2643 LogFunc(("Trigger interrupt with status %#x\n", fIRQ));
2644 ASMAtomicOrU32(&pThis->svga.u32IrqStatus, fIRQ);
2645 PDMDevHlpPCISetIrq(pDevIns, 0, 1);
2646 }
2647
2648 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
2649}
2650
2651
2652/** Allocate a command buffer structure.
2653 *
2654 * @param pCmdBufCtx The command buffer context which must allocate the buffer.
2655 * @return Pointer to the allocated command buffer structure.
2656 */
2657static PVMSVGACMDBUF vmsvgaR3CmdBufAlloc(PVMSVGACMDBUFCTX pCmdBufCtx)
2658{
2659 if (!pCmdBufCtx)
2660 return NULL;
2661
2662 PVMSVGACMDBUF pCmdBuf = (PVMSVGACMDBUF)RTMemAllocZ(sizeof(*pCmdBuf));
2663 if (pCmdBuf)
2664 {
2665 // RT_ZERO(pCmdBuf->nodeBuffer);
2666 pCmdBuf->pCmdBufCtx = pCmdBufCtx;
2667 // pCmdBuf->GCPhysCB = 0;
2668 // RT_ZERO(pCmdBuf->hdr);
2669 // pCmdBuf->pvCommands = NULL;
2670 }
2671
2672 return pCmdBuf;
2673}
2674
2675
2676/** Free a command buffer structure.
2677 *
2678 * @param pCmdBuf The command buffer pointer.
2679 */
2680static void vmsvgaR3CmdBufFree(PVMSVGACMDBUF pCmdBuf)
2681{
2682 if (pCmdBuf)
2683 RTMemFree(pCmdBuf->pvCommands);
2684 RTMemFree(pCmdBuf);
2685}
2686
2687
2688/** Initialize a command buffer context.
2689 *
2690 * @param pCmdBufCtx The command buffer context.
2691 */
2692static void vmsvgaR3CmdBufCtxInit(PVMSVGACMDBUFCTX pCmdBufCtx)
2693{
2694 RTListInit(&pCmdBufCtx->listSubmitted);
2695 pCmdBufCtx->cSubmitted = 0;
2696}
2697
2698
2699/** Destroy a command buffer context.
2700 *
2701 * @param pCmdBufCtx The command buffer context pointer.
2702 */
2703static void vmsvgaR3CmdBufCtxTerm(PVMSVGACMDBUFCTX pCmdBufCtx)
2704{
2705 if (!pCmdBufCtx)
2706 return;
2707
2708 if (pCmdBufCtx->listSubmitted.pNext)
2709 {
2710 /* If the list has been initialized. */
2711 PVMSVGACMDBUF pIter, pNext;
2712 RTListForEachSafe(&pCmdBufCtx->listSubmitted, pIter, pNext, VMSVGACMDBUF, nodeBuffer)
2713 {
2714 RTListNodeRemove(&pIter->nodeBuffer);
2715 --pCmdBufCtx->cSubmitted;
2716 vmsvgaR3CmdBufFree(pIter);
2717 }
2718 }
2719 Assert(pCmdBufCtx->cSubmitted == 0);
2720 pCmdBufCtx->cSubmitted = 0;
2721}
2722
2723
2724/** Handles SVGA_DC_CMD_START_STOP_CONTEXT command.
2725 *
2726 * @param pSvgaR3State VMSVGA R3 state.
2727 * @param pCmd The command data.
2728 * @return SVGACBStatus code.
2729 * @thread EMT
2730 */
2731static SVGACBStatus vmsvgaR3CmdBufDCStartStop(PVMSVGAR3STATE pSvgaR3State, SVGADCCmdStartStop const *pCmd)
2732{
2733 /* Create or destroy a regular command buffer context. */
2734 if (pCmd->context >= RT_ELEMENTS(pSvgaR3State->apCmdBufCtxs))
2735 return SVGA_CB_STATUS_COMMAND_ERROR;
2736 RT_UNTRUSTED_VALIDATED_FENCE();
2737
2738 SVGACBStatus CBStatus = SVGA_CB_STATUS_COMPLETED;
2739
2740 int rc = RTCritSectEnter(&pSvgaR3State->CritSectCmdBuf);
2741 AssertRC(rc);
2742 if (pCmd->enable)
2743 {
2744 pSvgaR3State->apCmdBufCtxs[pCmd->context] = (PVMSVGACMDBUFCTX)RTMemAlloc(sizeof(VMSVGACMDBUFCTX));
2745 if (pSvgaR3State->apCmdBufCtxs[pCmd->context])
2746 vmsvgaR3CmdBufCtxInit(pSvgaR3State->apCmdBufCtxs[pCmd->context]);
2747 else
2748 CBStatus = SVGA_CB_STATUS_QUEUE_FULL;
2749 }
2750 else
2751 {
2752 vmsvgaR3CmdBufCtxTerm(pSvgaR3State->apCmdBufCtxs[pCmd->context]);
2753 pSvgaR3State->apCmdBufCtxs[pCmd->context] = NULL;
2754 }
2755 RTCritSectLeave(&pSvgaR3State->CritSectCmdBuf);
2756
2757 return CBStatus;
2758}
2759
2760
2761/** Handles SVGA_DC_CMD_PREEMPT command.
2762 *
2763 * @param pDevIns The device instance.
2764 * @param pSvgaR3State VMSVGA R3 state.
2765 * @param pCmd The command data.
2766 * @return SVGACBStatus code.
2767 * @thread EMT
2768 */
2769static SVGACBStatus vmsvgaR3CmdBufDCPreempt(PPDMDEVINS pDevIns, PVMSVGAR3STATE pSvgaR3State, SVGADCCmdPreempt const *pCmd)
2770{
2771 /* Remove buffers from the processing queue of the specified context. */
2772 if (pCmd->context >= RT_ELEMENTS(pSvgaR3State->apCmdBufCtxs))
2773 return SVGA_CB_STATUS_COMMAND_ERROR;
2774 RT_UNTRUSTED_VALIDATED_FENCE();
2775
2776 PVMSVGACMDBUFCTX const pCmdBufCtx = pSvgaR3State->apCmdBufCtxs[pCmd->context];
2777 RTLISTANCHOR listPreempted;
2778
2779 int rc = RTCritSectEnter(&pSvgaR3State->CritSectCmdBuf);
2780 AssertRC(rc);
2781 if (pCmd->ignoreIDZero)
2782 {
2783 RTListInit(&listPreempted);
2784
2785 PVMSVGACMDBUF pIter, pNext;
2786 RTListForEachSafe(&pCmdBufCtx->listSubmitted, pIter, pNext, VMSVGACMDBUF, nodeBuffer)
2787 {
2788 if (pIter->hdr.id == 0)
2789 continue;
2790
2791 RTListNodeRemove(&pIter->nodeBuffer);
2792 --pCmdBufCtx->cSubmitted;
2793 RTListAppend(&listPreempted, &pIter->nodeBuffer);
2794 }
2795 }
2796 else
2797 {
2798 RTListMove(&listPreempted, &pCmdBufCtx->listSubmitted);
2799 }
2800 RTCritSectLeave(&pSvgaR3State->CritSectCmdBuf);
2801
2802 PVMSVGACMDBUF pIter, pNext;
2803 RTListForEachSafe(&listPreempted, pIter, pNext, VMSVGACMDBUF, nodeBuffer)
2804 {
2805 RTListNodeRemove(&pIter->nodeBuffer);
2806 vmsvgaR3CmdBufWriteStatus(pDevIns, pIter->GCPhysCB, SVGA_CB_STATUS_PREEMPTED, 0);
2807 vmsvgaR3CmdBufFree(pIter);
2808 }
2809
2810 return SVGA_CB_STATUS_COMPLETED;
2811}
2812
2813
2814/** @def VMSVGA_INC_CMD_SIZE_BREAK
2815 * Increments the size of the command cbCmd by a_cbMore.
2816 * Checks that the command buffer has at least cbCmd bytes. Will break out of the switch if it doesn't.
2817 * Used by vmsvgaR3CmdBufProcessDC and vmsvgaR3CmdBufProcessCommands.
2818 */
2819#define VMSVGA_INC_CMD_SIZE_BREAK(a_cbMore) \
2820 if (1) { \
2821 cbCmd += (a_cbMore); \
2822 ASSERT_GUEST_MSG_STMT_BREAK(cbRemain >= cbCmd, ("size=%#x remain=%#zx\n", cbCmd, (size_t)cbRemain), CBstatus = SVGA_CB_STATUS_COMMAND_ERROR); \
2823 RT_UNTRUSTED_VALIDATED_FENCE(); \
2824 } else do {} while (0)
2825
2826
2827/** Processes Device Context command buffer.
2828 *
2829 * @param pDevIns The device instance.
2830 * @param pSvgaR3State VMSVGA R3 state.
2831 * @param pvCommands Pointer to the command buffer.
2832 * @param cbCommands Size of the command buffer.
2833 * @param poffNextCmd Where to store the offset of the first unprocessed command.
2834 * @return SVGACBStatus code.
2835 * @thread EMT
2836 */
2837static SVGACBStatus vmsvgaR3CmdBufProcessDC(PPDMDEVINS pDevIns, PVMSVGAR3STATE pSvgaR3State, void const *pvCommands, uint32_t cbCommands, uint32_t *poffNextCmd)
2838{
2839 SVGACBStatus CBstatus = SVGA_CB_STATUS_COMPLETED;
2840
2841 uint8_t const *pu8Cmd = (uint8_t *)pvCommands;
2842 uint32_t cbRemain = cbCommands;
2843 while (cbRemain)
2844 {
2845 /* Command identifier is a 32 bit value. */
2846 if (cbRemain < sizeof(uint32_t))
2847 {
2848 CBstatus = SVGA_CB_STATUS_COMMAND_ERROR;
2849 break;
2850 }
2851
2852 /* Fetch the command id. */
2853 uint32_t const cmdId = *(uint32_t *)pu8Cmd;
2854 uint32_t cbCmd = sizeof(uint32_t);
2855 switch (cmdId)
2856 {
2857 case SVGA_DC_CMD_NOP:
2858 {
2859 /* NOP */
2860 break;
2861 }
2862
2863 case SVGA_DC_CMD_START_STOP_CONTEXT:
2864 {
2865 SVGADCCmdStartStop *pCmd = (SVGADCCmdStartStop *)&pu8Cmd[cbCmd];
2866 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
2867 CBstatus = vmsvgaR3CmdBufDCStartStop(pSvgaR3State, pCmd);
2868 break;
2869 }
2870
2871 case SVGA_DC_CMD_PREEMPT:
2872 {
2873 SVGADCCmdPreempt *pCmd = (SVGADCCmdPreempt *)&pu8Cmd[cbCmd];
2874 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
2875 CBstatus = vmsvgaR3CmdBufDCPreempt(pDevIns, pSvgaR3State, pCmd);
2876 break;
2877 }
2878
2879 default:
2880 {
2881 /* Unsupported command. */
2882 CBstatus = SVGA_CB_STATUS_COMMAND_ERROR;
2883 break;
2884 }
2885 }
2886
2887 if (CBstatus != SVGA_CB_STATUS_COMPLETED)
2888 break;
2889
2890 pu8Cmd += cbCmd;
2891 cbRemain -= cbCmd;
2892 }
2893
2894 Assert(cbRemain <= cbCommands);
2895 *poffNextCmd = cbCommands - cbRemain;
2896 return CBstatus;
2897}
2898
2899
2900/** Submits a device context command buffer for synchronous processing.
2901 *
2902 * @param pDevIns The device instance.
2903 * @param pThisCC The VGA/VMSVGA state for the current context.
2904 * @param ppCmdBuf Pointer to the command buffer pointer.
2905 * The function can set the command buffer pointer to NULL to prevent deallocation by the caller.
2906 * @param poffNextCmd Where to store the offset of the first unprocessed command.
2907 * @return SVGACBStatus code.
2908 * @thread EMT
2909 */
2910static SVGACBStatus vmsvgaR3CmdBufSubmitDC(PPDMDEVINS pDevIns, PVGASTATECC pThisCC, PVMSVGACMDBUF *ppCmdBuf, uint32_t *poffNextCmd)
2911{
2912 /* Synchronously process the device context commands. */
2913 PVMSVGAR3STATE const pSvgaR3State = pThisCC->svga.pSvgaR3State;
2914 return vmsvgaR3CmdBufProcessDC(pDevIns, pSvgaR3State, (*ppCmdBuf)->pvCommands, (*ppCmdBuf)->hdr.length, poffNextCmd);
2915}
2916
2917/** Submits a command buffer for asynchronous processing by the FIFO thread.
2918 *
2919 * @param pDevIns The device instance.
2920 * @param pThis The shared VGA/VMSVGA state.
2921 * @param pThisCC The VGA/VMSVGA state for the current context.
2922 * @param ppCmdBuf Pointer to the command buffer pointer.
2923 * The function can set the command buffer pointer to NULL to prevent deallocation by the caller.
2924 * @return SVGACBStatus code.
2925 * @thread EMT
2926 */
2927static SVGACBStatus vmsvgaR3CmdBufSubmit(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, PVMSVGACMDBUF *ppCmdBuf)
2928{
2929 /* Command buffer submission. */
2930 PVMSVGAR3STATE const pSvgaR3State = pThisCC->svga.pSvgaR3State;
2931
2932 SVGACBStatus CBstatus = SVGA_CB_STATUS_NONE;
2933
2934 PVMSVGACMDBUF const pCmdBuf = *ppCmdBuf;
2935 PVMSVGACMDBUFCTX const pCmdBufCtx = pCmdBuf->pCmdBufCtx;
2936
2937 int rc = RTCritSectEnter(&pSvgaR3State->CritSectCmdBuf);
2938 AssertRC(rc);
2939
2940 if (RT_LIKELY(pCmdBufCtx->cSubmitted < SVGA_CB_MAX_QUEUED_PER_CONTEXT))
2941 {
2942 RTListAppend(&pCmdBufCtx->listSubmitted, &pCmdBuf->nodeBuffer);
2943 ++pCmdBufCtx->cSubmitted;
2944 *ppCmdBuf = NULL; /* Consume the buffer. */
2945 ASMAtomicWriteU32(&pThisCC->svga.pSvgaR3State->fCmdBuf, 1);
2946 }
2947 else
2948 CBstatus = SVGA_CB_STATUS_QUEUE_FULL;
2949
2950 RTCritSectLeave(&pSvgaR3State->CritSectCmdBuf);
2951
2952 /* Inform the FIFO thread. */
2953 if (*ppCmdBuf == NULL)
2954 PDMDevHlpSUPSemEventSignal(pDevIns, pThis->svga.hFIFORequestSem);
2955
2956 return CBstatus;
2957}
2958
2959
2960/** SVGA_REG_COMMAND_LOW write handler.
2961 * Submits a command buffer to the FIFO thread or processes a device context command.
2962 *
2963 * @param pDevIns The device instance.
2964 * @param pThis The shared VGA/VMSVGA state.
2965 * @param pThisCC The VGA/VMSVGA state for the current context.
2966 * @param GCPhysCB Guest physical address of the command buffer header.
2967 * @param CBCtx Context the command buffer is submitted to.
2968 * @thread EMT
2969 */
2970static void vmsvgaR3CmdBufSubmit(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, RTGCPHYS GCPhysCB, SVGACBContext CBCtx)
2971{
2972 PVMSVGAR3STATE const pSvgaR3State = pThisCC->svga.pSvgaR3State;
2973
2974 SVGACBStatus CBstatus = SVGA_CB_STATUS_NONE;
2975 uint32_t offNextCmd = 0;
2976 uint32_t fIRQ = 0;
2977
2978 /* Get the context if the device has the capability. */
2979 PVMSVGACMDBUFCTX pCmdBufCtx = NULL;
2980 if (pThis->svga.u32DeviceCaps & SVGA_CAP_COMMAND_BUFFERS)
2981 {
2982 if (RT_LIKELY(CBCtx < RT_ELEMENTS(pSvgaR3State->apCmdBufCtxs)))
2983 pCmdBufCtx = pSvgaR3State->apCmdBufCtxs[CBCtx];
2984 else if (CBCtx == SVGA_CB_CONTEXT_DEVICE)
2985 pCmdBufCtx = &pSvgaR3State->CmdBufCtxDC;
2986 RT_UNTRUSTED_VALIDATED_FENCE();
2987 }
2988
2989 /* Allocate a new command buffer. */
2990 PVMSVGACMDBUF pCmdBuf = vmsvgaR3CmdBufAlloc(pCmdBufCtx);
2991 if (RT_LIKELY(pCmdBuf))
2992 {
2993 pCmdBuf->GCPhysCB = GCPhysCB;
2994
2995 int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhysCB, &pCmdBuf->hdr, sizeof(pCmdBuf->hdr));
2996 if (RT_SUCCESS(rc))
2997 {
2998 /* Verify the command buffer header. */
2999 if (RT_LIKELY( pCmdBuf->hdr.status == SVGA_CB_STATUS_NONE
3000 && (pCmdBuf->hdr.flags & ~(SVGA_CB_FLAG_NO_IRQ)) == 0 /* No unexpected flags. */
3001 && pCmdBuf->hdr.length <= SVGA_CB_MAX_SIZE))
3002 {
3003 RT_UNTRUSTED_VALIDATED_FENCE();
3004
3005 /* Read the command buffer content. */
3006 pCmdBuf->pvCommands = RTMemAlloc(pCmdBuf->hdr.length);
3007 if (pCmdBuf->pvCommands)
3008 {
3009 RTGCPHYS const GCPhysCmd = (RTGCPHYS)pCmdBuf->hdr.ptr.pa;
3010 rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhysCmd, pCmdBuf->pvCommands, pCmdBuf->hdr.length);
3011 if (RT_SUCCESS(rc))
3012 {
3013 /* Submit the buffer. Device context buffers will be processed synchronously. */
3014 if (RT_LIKELY(CBCtx < RT_ELEMENTS(pSvgaR3State->apCmdBufCtxs)))
3015 /* This usually processes the CB async and sets pCmbBuf to NULL. */
3016 CBstatus = vmsvgaR3CmdBufSubmit(pDevIns, pThis, pThisCC, &pCmdBuf);
3017 else
3018 CBstatus = vmsvgaR3CmdBufSubmitDC(pDevIns, pThisCC, &pCmdBuf, &offNextCmd);
3019 }
3020 else
3021 {
3022 ASSERT_GUEST_MSG_FAILED(("Failed to read commands at %RGp\n", GCPhysCmd));
3023 CBstatus = SVGA_CB_STATUS_CB_HEADER_ERROR;
3024 fIRQ = SVGA_IRQFLAG_ERROR | SVGA_IRQFLAG_COMMAND_BUFFER;
3025 }
3026 }
3027 else
3028 {
3029 /* No memory for commands. */
3030 CBstatus = SVGA_CB_STATUS_QUEUE_FULL;
3031 }
3032 }
3033 else
3034 {
3035 ASSERT_GUEST_MSG_FAILED(("Invalid buffer header\n"));
3036 CBstatus = SVGA_CB_STATUS_CB_HEADER_ERROR;
3037 fIRQ = SVGA_IRQFLAG_ERROR | SVGA_IRQFLAG_COMMAND_BUFFER;
3038 }
3039 }
3040 else
3041 {
3042 LogFunc(("Failed to read buffer header at %RGp\n", GCPhysCB));
3043 ASSERT_GUEST_FAILED();
3044 /* Do not attempt to write the status. */
3045 }
3046
3047 /* Free the buffer if pfnCmdBufSubmit did not consume it. */
3048 vmsvgaR3CmdBufFree(pCmdBuf);
3049 }
3050 else
3051 {
3052 LogFunc(("Can't allocate buffer for context id %#x\n", CBCtx));
3053 ASSERT_GUEST_FAILED();
3054 CBstatus = SVGA_CB_STATUS_QUEUE_FULL;
3055 }
3056
3057 if (CBstatus != SVGA_CB_STATUS_NONE)
3058 {
3059 LogFunc(("Write status %#x, offNextCmd %#x (of %#x), fIRQ %#x\n", CBstatus, offNextCmd, pCmdBuf->hdr.length, fIRQ));
3060 vmsvgaR3CmdBufWriteStatus(pDevIns, GCPhysCB, CBstatus, offNextCmd);
3061 if (fIRQ)
3062 vmsvgaR3CmdBufRaiseIRQ(pDevIns, pThis, fIRQ);
3063 }
3064}
3065
3066
3067/** Checks if there are some buffers to be processed.
3068 *
3069 * @param pThisCC The VGA/VMSVGA state for the current context.
3070 * @return true if buffers must be processed.
3071 * @thread FIFO
3072 */
3073static bool vmsvgaR3CmdBufHasWork(PVGASTATECC pThisCC)
3074{
3075 PVMSVGAR3STATE const pSvgaR3State = pThisCC->svga.pSvgaR3State;
3076 return RT_BOOL(ASMAtomicReadU32(&pSvgaR3State->fCmdBuf));
3077}
3078
3079
3080/** Processes a command buffer.
3081 *
3082 * @param pDevIns The device instance.
3083 * @param pThis The shared VGA/VMSVGA state.
3084 * @param pThisCC The VGA/VMSVGA state for the current context.
3085 * @param pvCommands Pointer to the command buffer.
3086 * @param cbCommands Size of the command buffer.
3087 * @param poffNextCmd Where to store the offset of the first unprocessed command.
3088 * @return SVGACBStatus code.
3089 * @thread FIFO
3090 */
3091static SVGACBStatus vmsvgaR3CmdBufProcessCommands(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, void const *pvCommands, uint32_t cbCommands, uint32_t *poffNextCmd)
3092{
3093 SVGACBStatus CBstatus = SVGA_CB_STATUS_COMPLETED;
3094 PVMSVGAR3STATE const pSvgaR3State = pThisCC->svga.pSvgaR3State;
3095
3096 uint32_t RT_UNTRUSTED_VOLATILE_GUEST * const pFIFO = pThisCC->svga.pau32FIFO;
3097
3098 uint8_t const *pu8Cmd = (uint8_t *)pvCommands;
3099 uint32_t cbRemain = cbCommands;
3100 while (cbRemain)
3101 {
3102 /* Command identifier is a 32 bit value. */
3103 if (cbRemain < sizeof(uint32_t))
3104 {
3105 CBstatus = SVGA_CB_STATUS_COMMAND_ERROR;
3106 break;
3107 }
3108
3109 /* Fetch the command id.
3110 * 'cmdId' is actually a SVGAFifoCmdId. It is treated as uint32_t in order to avoid a compiler
3111 * warning. Because we support some obsolete and deprecated commands, which are not included in
3112 * the SVGAFifoCmdId enum in the VMSVGA headers anymore.
3113 */
3114 uint32_t const cmdId = *(uint32_t *)pu8Cmd;
3115 uint32_t cbCmd = sizeof(uint32_t);
3116
3117 LogFlowFunc(("%s %d\n", vmsvgaR3FifoCmdToString(cmdId), cmdId));
3118
3119 /* At the end of the switch cbCmd is equal to the total length of the command including the cmdId.
3120 * I.e. pu8Cmd + cbCmd must point to the next command.
3121 * However if CBstatus is set to anything but SVGA_CB_STATUS_COMPLETED in the switch, then
3122 * the cbCmd value is ignored (and pu8Cmd still points to the failed command).
3123 */
3124 /** @todo This code is very similar to the FIFO loop command processing. Think about merging. */
3125 switch (cmdId)
3126 {
3127 case SVGA_CMD_INVALID_CMD:
3128 {
3129 /* Nothing to do. */
3130 STAM_REL_COUNTER_INC(&pSvgaR3State->StatR3CmdInvalidCmd);
3131 break;
3132 }
3133
3134 case SVGA_CMD_FENCE:
3135 {
3136 SVGAFifoCmdFence *pCmd = (SVGAFifoCmdFence *)&pu8Cmd[cbCmd];
3137 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3138 STAM_REL_COUNTER_INC(&pSvgaR3State->StatR3CmdFence);
3139 Log(("SVGA_CMD_FENCE %#x\n", pCmd->fence));
3140
3141 uint32_t const offFifoMin = pFIFO[SVGA_FIFO_MIN];
3142 if (VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_FENCE, offFifoMin))
3143 {
3144 pFIFO[SVGA_FIFO_FENCE] = pCmd->fence;
3145
3146 uint32_t u32IrqStatus = 0;
3147 if (pThis->svga.u32IrqMask & SVGA_IRQFLAG_ANY_FENCE)
3148 {
3149 Log(("any fence irq\n"));
3150 u32IrqStatus |= SVGA_IRQFLAG_ANY_FENCE;
3151 }
3152 else if ( VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_FENCE_GOAL, offFifoMin)
3153 && (pThis->svga.u32IrqMask & SVGA_IRQFLAG_FENCE_GOAL)
3154 && pFIFO[SVGA_FIFO_FENCE_GOAL] == pCmd->fence)
3155 {
3156 Log(("fence goal reached irq (fence=%#x)\n", pCmd->fence));
3157 u32IrqStatus |= SVGA_IRQFLAG_FENCE_GOAL;
3158 }
3159
3160 if (u32IrqStatus)
3161 vmsvgaR3CmdBufRaiseIRQ(pDevIns, pThis, u32IrqStatus);
3162 }
3163 else
3164 Log(("SVGA_CMD_FENCE is bogus when offFifoMin is %#x!\n", offFifoMin));
3165 break;
3166 }
3167
3168 case SVGA_CMD_UPDATE:
3169 {
3170 SVGAFifoCmdUpdate *pCmd = (SVGAFifoCmdUpdate *)&pu8Cmd[cbCmd];
3171 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3172 vmsvgaR3CmdUpdate(pThis, pThisCC, pCmd);
3173 break;
3174 }
3175
3176 case SVGA_CMD_UPDATE_VERBOSE:
3177 {
3178 SVGAFifoCmdUpdateVerbose *pCmd = (SVGAFifoCmdUpdateVerbose *)&pu8Cmd[cbCmd];
3179 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3180 vmsvgaR3CmdUpdateVerbose(pThis, pThisCC, pCmd);
3181 break;
3182 }
3183
3184 case SVGA_CMD_DEFINE_CURSOR:
3185 {
3186 /* Followed by bitmap data. */
3187 SVGAFifoCmdDefineCursor *pCmd = (SVGAFifoCmdDefineCursor *)&pu8Cmd[cbCmd];
3188 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3189
3190 /* Figure out the size of the bitmap data. */
3191 ASSERT_GUEST_STMT_BREAK(pCmd->height < 2048 && pCmd->width < 2048, CBstatus = SVGA_CB_STATUS_COMMAND_ERROR);
3192 ASSERT_GUEST_STMT_BREAK(pCmd->andMaskDepth <= 32, CBstatus = SVGA_CB_STATUS_COMMAND_ERROR);
3193 ASSERT_GUEST_STMT_BREAK(pCmd->xorMaskDepth <= 32, CBstatus = SVGA_CB_STATUS_COMMAND_ERROR);
3194 RT_UNTRUSTED_VALIDATED_FENCE();
3195
3196 uint32_t const cbAndLine = RT_ALIGN_32(pCmd->width * (pCmd->andMaskDepth + (pCmd->andMaskDepth == 15)), 32) / 8;
3197 uint32_t const cbAndMask = cbAndLine * pCmd->height;
3198 uint32_t const cbXorLine = RT_ALIGN_32(pCmd->width * (pCmd->xorMaskDepth + (pCmd->xorMaskDepth == 15)), 32) / 8;
3199 uint32_t const cbXorMask = cbXorLine * pCmd->height;
3200
3201 VMSVGA_INC_CMD_SIZE_BREAK(cbAndMask + cbXorMask);
3202 vmsvgaR3CmdDefineCursor(pThis, pThisCC, pCmd);
3203 break;
3204 }
3205
3206 case SVGA_CMD_DEFINE_ALPHA_CURSOR:
3207 {
3208 /* Followed by bitmap data. */
3209 SVGAFifoCmdDefineAlphaCursor *pCmd = (SVGAFifoCmdDefineAlphaCursor *)&pu8Cmd[cbCmd];
3210 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3211
3212 /* Figure out the size of the bitmap data. */
3213 ASSERT_GUEST_STMT_BREAK(pCmd->height < 2048 && pCmd->width < 2048, CBstatus = SVGA_CB_STATUS_COMMAND_ERROR);
3214
3215 VMSVGA_INC_CMD_SIZE_BREAK(pCmd->width * pCmd->height * sizeof(uint32_t)); /* 32-bit BRGA format */
3216 vmsvgaR3CmdDefineAlphaCursor(pThis, pThisCC, pCmd);
3217 break;
3218 }
3219
3220 case SVGA_CMD_MOVE_CURSOR:
3221 {
3222 /* Deprecated; there should be no driver which *requires* this command. However, if
3223 * we do ecncounter this command, it might be useful to not get the FIFO completely out of
3224 * alignment.
3225 * May be issued by guest if SVGA_CAP_CURSOR_BYPASS is missing.
3226 */
3227 SVGAFifoCmdMoveCursor *pCmd = (SVGAFifoCmdMoveCursor *)&pu8Cmd[cbCmd];
3228 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3229 vmsvgaR3CmdMoveCursor(pThis, pThisCC, pCmd);
3230 break;
3231 }
3232
3233 case SVGA_CMD_DISPLAY_CURSOR:
3234 {
3235 /* Deprecated; there should be no driver which *requires* this command. However, if
3236 * we do ecncounter this command, it might be useful to not get the FIFO completely out of
3237 * alignment.
3238 * May be issued by guest if SVGA_CAP_CURSOR_BYPASS is missing.
3239 */
3240 SVGAFifoCmdDisplayCursor *pCmd = (SVGAFifoCmdDisplayCursor *)&pu8Cmd[cbCmd];
3241 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3242 vmsvgaR3CmdDisplayCursor(pThis, pThisCC, pCmd);
3243 break;
3244 }
3245
3246 case SVGA_CMD_RECT_FILL:
3247 {
3248 SVGAFifoCmdRectFill *pCmd = (SVGAFifoCmdRectFill *)&pu8Cmd[cbCmd];
3249 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3250 vmsvgaR3CmdRectFill(pThis, pThisCC, pCmd);
3251 break;
3252 }
3253
3254 case SVGA_CMD_RECT_COPY:
3255 {
3256 SVGAFifoCmdRectCopy *pCmd = (SVGAFifoCmdRectCopy *)&pu8Cmd[cbCmd];
3257 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3258 vmsvgaR3CmdRectCopy(pThis, pThisCC, pCmd);
3259 break;
3260 }
3261
3262 case SVGA_CMD_RECT_ROP_COPY:
3263 {
3264 SVGAFifoCmdRectRopCopy *pCmd = (SVGAFifoCmdRectRopCopy *)&pu8Cmd[cbCmd];
3265 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3266 vmsvgaR3CmdRectRopCopy(pThis, pThisCC, pCmd);
3267 break;
3268 }
3269
3270 case SVGA_CMD_ESCAPE:
3271 {
3272 /* Followed by 'size' bytes of data. */
3273 SVGAFifoCmdEscape *pCmd = (SVGAFifoCmdEscape *)&pu8Cmd[cbCmd];
3274 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3275
3276 ASSERT_GUEST_STMT_BREAK(pCmd->size < pThis->svga.cbFIFO - sizeof(SVGAFifoCmdEscape), CBstatus = SVGA_CB_STATUS_COMMAND_ERROR);
3277 RT_UNTRUSTED_VALIDATED_FENCE();
3278
3279 VMSVGA_INC_CMD_SIZE_BREAK(pCmd->size);
3280 vmsvgaR3CmdEscape(pThis, pThisCC, pCmd);
3281 break;
3282 }
3283# ifdef VBOX_WITH_VMSVGA3D
3284 case SVGA_CMD_DEFINE_GMR2:
3285 {
3286 SVGAFifoCmdDefineGMR2 *pCmd = (SVGAFifoCmdDefineGMR2 *)&pu8Cmd[cbCmd];
3287 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3288 vmsvgaR3CmdDefineGMR2(pThis, pThisCC, pCmd);
3289 break;
3290 }
3291
3292 case SVGA_CMD_REMAP_GMR2:
3293 {
3294 /* Followed by page descriptors or guest ptr. */
3295 SVGAFifoCmdRemapGMR2 *pCmd = (SVGAFifoCmdRemapGMR2 *)&pu8Cmd[cbCmd];
3296 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3297
3298 /* Calculate the size of what comes after next and fetch it. */
3299 uint32_t cbMore = 0;
3300 if (pCmd->flags & SVGA_REMAP_GMR2_VIA_GMR)
3301 cbMore = sizeof(SVGAGuestPtr);
3302 else
3303 {
3304 uint32_t const cbPageDesc = (pCmd->flags & SVGA_REMAP_GMR2_PPN64) ? sizeof(uint64_t) : sizeof(uint32_t);
3305 if (pCmd->flags & SVGA_REMAP_GMR2_SINGLE_PPN)
3306 {
3307 cbMore = cbPageDesc;
3308 pCmd->numPages = 1;
3309 }
3310 else
3311 {
3312 ASSERT_GUEST_STMT_BREAK(pCmd->numPages <= pThis->svga.cbFIFO / cbPageDesc, CBstatus = SVGA_CB_STATUS_COMMAND_ERROR);
3313 cbMore = cbPageDesc * pCmd->numPages;
3314 }
3315 }
3316 VMSVGA_INC_CMD_SIZE_BREAK(cbMore);
3317 vmsvgaR3CmdRemapGMR2(pThis, pThisCC, pCmd);
3318# ifdef DEBUG_GMR_ACCESS
3319 VMR3ReqCallWaitU(PDMDevHlpGetUVM(pDevIns), VMCPUID_ANY, (PFNRT)vmsvgaR3RegisterGmr, 2, pDevIns, pCmd->gmrId);
3320# endif
3321 break;
3322 }
3323# endif // VBOX_WITH_VMSVGA3D
3324 case SVGA_CMD_DEFINE_SCREEN:
3325 {
3326 /* The size of this command is specified by the guest and depends on capabilities. */
3327 SVGAFifoCmdDefineScreen *pCmd = (SVGAFifoCmdDefineScreen *)&pu8Cmd[cbCmd];
3328 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(pCmd->screen.structSize));
3329 ASSERT_GUEST_STMT_BREAK(pCmd->screen.structSize < pThis->svga.cbFIFO, CBstatus = SVGA_CB_STATUS_COMMAND_ERROR);
3330 RT_UNTRUSTED_VALIDATED_FENCE();
3331
3332 VMSVGA_INC_CMD_SIZE_BREAK(RT_MAX(sizeof(pCmd->screen.structSize), pCmd->screen.structSize) - sizeof(pCmd->screen.structSize));
3333 vmsvgaR3CmdDefineScreen(pThis, pThisCC, pCmd);
3334 break;
3335 }
3336
3337 case SVGA_CMD_DESTROY_SCREEN:
3338 {
3339 SVGAFifoCmdDestroyScreen *pCmd = (SVGAFifoCmdDestroyScreen *)&pu8Cmd[cbCmd];
3340 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3341 vmsvgaR3CmdDestroyScreen(pThis, pThisCC, pCmd);
3342 break;
3343 }
3344
3345 case SVGA_CMD_DEFINE_GMRFB:
3346 {
3347 SVGAFifoCmdDefineGMRFB *pCmd = (SVGAFifoCmdDefineGMRFB *)&pu8Cmd[cbCmd];
3348 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3349 vmsvgaR3CmdDefineGMRFB(pThis, pThisCC, pCmd);
3350 break;
3351 }
3352
3353 case SVGA_CMD_BLIT_GMRFB_TO_SCREEN:
3354 {
3355 SVGAFifoCmdBlitGMRFBToScreen *pCmd = (SVGAFifoCmdBlitGMRFBToScreen *)&pu8Cmd[cbCmd];
3356 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3357 vmsvgaR3CmdBlitGMRFBToScreen(pThis, pThisCC, pCmd);
3358 break;
3359 }
3360
3361 case SVGA_CMD_BLIT_SCREEN_TO_GMRFB:
3362 {
3363 SVGAFifoCmdBlitScreenToGMRFB *pCmd = (SVGAFifoCmdBlitScreenToGMRFB *)&pu8Cmd[cbCmd];
3364 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3365 vmsvgaR3CmdBlitScreenToGMRFB(pThis, pThisCC, pCmd);
3366 break;
3367 }
3368
3369 case SVGA_CMD_ANNOTATION_FILL:
3370 {
3371 SVGAFifoCmdAnnotationFill *pCmd = (SVGAFifoCmdAnnotationFill *)&pu8Cmd[cbCmd];
3372 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3373 vmsvgaR3CmdAnnotationFill(pThis, pThisCC, pCmd);
3374 break;
3375 }
3376
3377 case SVGA_CMD_ANNOTATION_COPY:
3378 {
3379 SVGAFifoCmdAnnotationCopy *pCmd = (SVGAFifoCmdAnnotationCopy *)&pu8Cmd[cbCmd];
3380 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pCmd));
3381 vmsvgaR3CmdAnnotationCopy(pThis, pThisCC, pCmd);
3382 break;
3383 }
3384
3385 default:
3386 {
3387# ifdef VBOX_WITH_VMSVGA3D
3388 if ( cmdId >= SVGA_3D_CMD_BASE
3389 && cmdId < SVGA_3D_CMD_MAX)
3390 {
3391 RT_UNTRUSTED_VALIDATED_FENCE();
3392
3393 /* All 3d commands start with a common header, which defines the identifier and the size
3394 * of the command. The identifier has been already read. Fetch the size.
3395 */
3396 uint32_t const *pcbMore = (uint32_t const *)&pu8Cmd[cbCmd];
3397 VMSVGA_INC_CMD_SIZE_BREAK(sizeof(*pcbMore));
3398 VMSVGA_INC_CMD_SIZE_BREAK(*pcbMore);
3399 if (RT_LIKELY(pThis->svga.f3DEnabled))
3400 { /* likely */ }
3401 else
3402 {
3403 LogRelMax(8, ("VMSVGA: 3D disabled, command %d skipped\n", cmdId));
3404 break;
3405 }
3406
3407 /* Command data begins after the 32 bit command length. */
3408 int rc = vmsvgaR3Process3dCmd(pThis, pThisCC, (SVGAFifo3dCmdId)cmdId, *pcbMore, pcbMore + 1);
3409 if (RT_SUCCESS(rc))
3410 { /* likely */ }
3411 else
3412 {
3413 CBstatus = SVGA_CB_STATUS_COMMAND_ERROR;
3414 break;
3415 }
3416 }
3417 else
3418# endif /* VBOX_WITH_VMSVGA3D */
3419 {
3420 /* Unsupported command. */
3421 STAM_REL_COUNTER_INC(&pSvgaR3State->StatFifoUnkCmds);
3422 ASSERT_GUEST_MSG_FAILED(("cmdId=%d\n", cmdId));
3423 CBstatus = SVGA_CB_STATUS_COMMAND_ERROR;
3424 break;
3425 }
3426 }
3427 }
3428
3429 if (CBstatus != SVGA_CB_STATUS_COMPLETED)
3430 break;
3431
3432 pu8Cmd += cbCmd;
3433 cbRemain -= cbCmd;
3434 }
3435
3436 Assert(cbRemain <= cbCommands);
3437 *poffNextCmd = cbCommands - cbRemain;
3438 return CBstatus;
3439}
3440
3441
3442/** Process command buffers.
3443 *
3444 * @param pDevIns The device instance.
3445 * @param pThis The shared VGA/VMSVGA state.
3446 * @param pThisCC The VGA/VMSVGA state for the current context.
3447 * @param pThread Handle of the FIFO thread.
3448 * @thread FIFO
3449 */
3450static void vmsvgaR3CmdBufProcessBuffers(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, PPDMTHREAD pThread)
3451{
3452 PVMSVGAR3STATE const pSvgaR3State = pThisCC->svga.pSvgaR3State;
3453
3454 for (;;)
3455 {
3456 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
3457 break;
3458
3459 /* See if there is a submitted buffer. */
3460 PVMSVGACMDBUF pCmdBuf = NULL;
3461
3462 int rc = RTCritSectEnter(&pSvgaR3State->CritSectCmdBuf);
3463 AssertRC(rc);
3464
3465 /* It seems that a higher queue index has a higher priority.
3466 * See SVGACBContext in svga_reg.h from latest vmwgfx Linux driver.
3467 */
3468 for (unsigned i = RT_ELEMENTS(pSvgaR3State->apCmdBufCtxs); i > 0; --i)
3469 {
3470 PVMSVGACMDBUFCTX pCmdBufCtx = pSvgaR3State->apCmdBufCtxs[i - 1];
3471 if (pCmdBufCtx)
3472 {
3473 pCmdBuf = RTListRemoveFirst(&pCmdBufCtx->listSubmitted, VMSVGACMDBUF, nodeBuffer);
3474 if (pCmdBuf)
3475 {
3476 Assert(pCmdBufCtx->cSubmitted > 0);
3477 --pCmdBufCtx->cSubmitted;
3478 break;
3479 }
3480 }
3481 }
3482
3483 if (!pCmdBuf)
3484 {
3485 ASMAtomicWriteU32(&pSvgaR3State->fCmdBuf, 0);
3486 RTCritSectLeave(&pSvgaR3State->CritSectCmdBuf);
3487 break;
3488 }
3489
3490 RTCritSectLeave(&pSvgaR3State->CritSectCmdBuf);
3491
3492 SVGACBStatus CBstatus = SVGA_CB_STATUS_NONE;
3493 uint32_t offNextCmd = 0;
3494
3495 /* Process one buffer. */
3496 CBstatus = vmsvgaR3CmdBufProcessCommands(pDevIns, pThis, pThisCC, pCmdBuf->pvCommands, pCmdBuf->hdr.length, &offNextCmd);
3497
3498 uint32_t fIRQ = 0;
3499 if (!RT_BOOL(pCmdBuf->hdr.flags & SVGA_CB_FLAG_NO_IRQ))
3500 fIRQ |= SVGA_IRQFLAG_COMMAND_BUFFER;
3501 if (CBstatus == SVGA_CB_STATUS_COMMAND_ERROR)
3502 fIRQ |= SVGA_IRQFLAG_ERROR;
3503
3504 vmsvgaR3CmdBufWriteStatus(pDevIns, pCmdBuf->GCPhysCB, CBstatus, offNextCmd);
3505 if (fIRQ)
3506 vmsvgaR3CmdBufRaiseIRQ(pDevIns, pThis, fIRQ);
3507
3508 vmsvgaR3CmdBufFree(pCmdBuf);
3509 }
3510}
3511
3512
3513/**
3514 * Worker for vmsvgaR3FifoThread that handles an external command.
3515 *
3516 * @param pDevIns The device instance.
3517 * @param pThis The shared VGA/VMSVGA instance data.
3518 * @param pThisCC The VGA/VMSVGA state for ring-3.
3519 */
3520static void vmsvgaR3FifoHandleExtCmd(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
3521{
3522 uint8_t uExtCmd = pThis->svga.u8FIFOExtCommand;
3523 switch (pThis->svga.u8FIFOExtCommand)
3524 {
3525 case VMSVGA_FIFO_EXTCMD_RESET:
3526 Log(("vmsvgaR3FifoLoop: reset the fifo thread.\n"));
3527 Assert(pThisCC->svga.pvFIFOExtCmdParam == NULL);
3528
3529 vmsvgaR3ResetScreens(pThis, pThisCC);
3530# ifdef VBOX_WITH_VMSVGA3D
3531 if (pThis->svga.f3DEnabled)
3532 {
3533 /* The 3d subsystem must be reset from the fifo thread. */
3534 vmsvga3dReset(pThisCC);
3535 }
3536# endif
3537 break;
3538
3539 case VMSVGA_FIFO_EXTCMD_POWEROFF:
3540 Log(("vmsvgaR3FifoLoop: power off.\n"));
3541 Assert(pThisCC->svga.pvFIFOExtCmdParam == NULL);
3542
3543 /* The screens must be reset on the FIFO thread, because they may use 3D resources. */
3544 vmsvgaR3ResetScreens(pThis, pThisCC);
3545 break;
3546
3547 case VMSVGA_FIFO_EXTCMD_TERMINATE:
3548 Log(("vmsvgaR3FifoLoop: terminate the fifo thread.\n"));
3549 Assert(pThisCC->svga.pvFIFOExtCmdParam == NULL);
3550# ifdef VBOX_WITH_VMSVGA3D
3551 if (pThis->svga.f3DEnabled)
3552 {
3553 /* The 3d subsystem must be shut down from the fifo thread. */
3554 vmsvga3dTerminate(pThisCC);
3555 }
3556# endif
3557 break;
3558
3559 case VMSVGA_FIFO_EXTCMD_SAVESTATE:
3560 {
3561 Log(("vmsvgaR3FifoLoop: VMSVGA_FIFO_EXTCMD_SAVESTATE.\n"));
3562 PSSMHANDLE pSSM = (PSSMHANDLE)pThisCC->svga.pvFIFOExtCmdParam;
3563 AssertLogRelMsgBreak(RT_VALID_PTR(pSSM), ("pSSM=%p\n", pSSM));
3564 vmsvgaR3SaveExecFifo(pDevIns->pHlpR3, pThisCC, pSSM);
3565# ifdef VBOX_WITH_VMSVGA3D
3566 if (pThis->svga.f3DEnabled)
3567 vmsvga3dSaveExec(pDevIns, pThisCC, pSSM);
3568# endif
3569 break;
3570 }
3571
3572 case VMSVGA_FIFO_EXTCMD_LOADSTATE:
3573 {
3574 Log(("vmsvgaR3FifoLoop: VMSVGA_FIFO_EXTCMD_LOADSTATE.\n"));
3575 PVMSVGA_STATE_LOAD pLoadState = (PVMSVGA_STATE_LOAD)pThisCC->svga.pvFIFOExtCmdParam;
3576 AssertLogRelMsgBreak(RT_VALID_PTR(pLoadState), ("pLoadState=%p\n", pLoadState));
3577 vmsvgaR3LoadExecFifo(pDevIns->pHlpR3, pThis, pThisCC, pLoadState->pSSM, pLoadState->uVersion, pLoadState->uPass);
3578# ifdef VBOX_WITH_VMSVGA3D
3579 if (pThis->svga.f3DEnabled)
3580 vmsvga3dLoadExec(pDevIns, pThis, pThisCC, pLoadState->pSSM, pLoadState->uVersion, pLoadState->uPass);
3581# endif
3582 break;
3583 }
3584
3585 case VMSVGA_FIFO_EXTCMD_UPDATE_SURFACE_HEAP_BUFFERS:
3586 {
3587# ifdef VBOX_WITH_VMSVGA3D
3588 uint32_t sid = (uint32_t)(uintptr_t)pThisCC->svga.pvFIFOExtCmdParam;
3589 Log(("vmsvgaR3FifoLoop: VMSVGA_FIFO_EXTCMD_UPDATE_SURFACE_HEAP_BUFFERS sid=%#x\n", sid));
3590 vmsvga3dUpdateHeapBuffersForSurfaces(pThisCC, sid);
3591# endif
3592 break;
3593 }
3594
3595
3596 default:
3597 AssertLogRelMsgFailed(("uExtCmd=%#x pvFIFOExtCmdParam=%p\n", uExtCmd, pThisCC->svga.pvFIFOExtCmdParam));
3598 break;
3599 }
3600
3601 /*
3602 * Signal the end of the external command.
3603 */
3604 pThisCC->svga.pvFIFOExtCmdParam = NULL;
3605 pThis->svga.u8FIFOExtCommand = VMSVGA_FIFO_EXTCMD_NONE;
3606 ASMMemoryFence(); /* paranoia^2 */
3607 int rc = RTSemEventSignal(pThisCC->svga.hFIFOExtCmdSem);
3608 AssertLogRelRC(rc);
3609}
3610
3611/**
3612 * Worker for vmsvgaR3Destruct, vmsvgaR3Reset, vmsvgaR3Save and vmsvgaR3Load for
3613 * doing a job on the FIFO thread (even when it's officially suspended).
3614 *
3615 * @returns VBox status code (fully asserted).
3616 * @param pDevIns The device instance.
3617 * @param pThis The shared VGA/VMSVGA instance data.
3618 * @param pThisCC The VGA/VMSVGA state for ring-3.
3619 * @param uExtCmd The command to execute on the FIFO thread.
3620 * @param pvParam Pointer to command parameters.
3621 * @param cMsWait The time to wait for the command, given in
3622 * milliseconds.
3623 */
3624static int vmsvgaR3RunExtCmdOnFifoThread(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC,
3625 uint8_t uExtCmd, void *pvParam, RTMSINTERVAL cMsWait)
3626{
3627 Assert(cMsWait >= RT_MS_1SEC * 5);
3628 AssertLogRelMsg(pThis->svga.u8FIFOExtCommand == VMSVGA_FIFO_EXTCMD_NONE,
3629 ("old=%d new=%d\n", pThis->svga.u8FIFOExtCommand, uExtCmd));
3630
3631 int rc;
3632 PPDMTHREAD pThread = pThisCC->svga.pFIFOIOThread;
3633 PDMTHREADSTATE enmState = pThread->enmState;
3634 if (enmState == PDMTHREADSTATE_SUSPENDED)
3635 {
3636 /*
3637 * The thread is suspended, we have to temporarily wake it up so it can
3638 * perform the task.
3639 * (We ASSUME not racing code here, both wrt thread state and ext commands.)
3640 */
3641 Log(("vmsvgaR3RunExtCmdOnFifoThread: uExtCmd=%d enmState=SUSPENDED\n", uExtCmd));
3642 /* Post the request. */
3643 pThis->svga.fFifoExtCommandWakeup = true;
3644 pThisCC->svga.pvFIFOExtCmdParam = pvParam;
3645 pThis->svga.u8FIFOExtCommand = uExtCmd;
3646 ASMMemoryFence(); /* paranoia^3 */
3647
3648 /* Resume the thread. */
3649 rc = PDMDevHlpThreadResume(pDevIns, pThread);
3650 AssertLogRelRC(rc);
3651 if (RT_SUCCESS(rc))
3652 {
3653 /* Wait. Take care in case the semaphore was already posted (same as below). */
3654 rc = RTSemEventWait(pThisCC->svga.hFIFOExtCmdSem, cMsWait);
3655 if ( rc == VINF_SUCCESS
3656 && pThis->svga.u8FIFOExtCommand == uExtCmd)
3657 rc = RTSemEventWait(pThisCC->svga.hFIFOExtCmdSem, cMsWait);
3658 AssertLogRelMsg(pThis->svga.u8FIFOExtCommand != uExtCmd || RT_FAILURE_NP(rc),
3659 ("%#x %Rrc\n", pThis->svga.u8FIFOExtCommand, rc));
3660
3661 /* suspend the thread */
3662 pThis->svga.fFifoExtCommandWakeup = false;
3663 int rc2 = PDMDevHlpThreadSuspend(pDevIns, pThread);
3664 AssertLogRelRC(rc2);
3665 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
3666 rc = rc2;
3667 }
3668 pThis->svga.fFifoExtCommandWakeup = false;
3669 pThisCC->svga.pvFIFOExtCmdParam = NULL;
3670 }
3671 else if (enmState == PDMTHREADSTATE_RUNNING)
3672 {
3673 /*
3674 * The thread is running, should only happen during reset and vmsvga3dsfc.
3675 * We ASSUME not racing code here, both wrt thread state and ext commands.
3676 */
3677 Log(("vmsvgaR3RunExtCmdOnFifoThread: uExtCmd=%d enmState=RUNNING\n", uExtCmd));
3678 Assert(uExtCmd == VMSVGA_FIFO_EXTCMD_RESET || uExtCmd == VMSVGA_FIFO_EXTCMD_UPDATE_SURFACE_HEAP_BUFFERS || uExtCmd == VMSVGA_FIFO_EXTCMD_POWEROFF);
3679
3680 /* Post the request. */
3681 pThisCC->svga.pvFIFOExtCmdParam = pvParam;
3682 pThis->svga.u8FIFOExtCommand = uExtCmd;
3683 ASMMemoryFence(); /* paranoia^2 */
3684 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->svga.hFIFORequestSem);
3685 AssertLogRelRC(rc);
3686
3687 /* Wait. Take care in case the semaphore was already posted (same as above). */
3688 rc = RTSemEventWait(pThisCC->svga.hFIFOExtCmdSem, cMsWait);
3689 if ( rc == VINF_SUCCESS
3690 && pThis->svga.u8FIFOExtCommand == uExtCmd)
3691 rc = RTSemEventWait(pThisCC->svga.hFIFOExtCmdSem, cMsWait); /* it was already posted, retry the wait. */
3692 AssertLogRelMsg(pThis->svga.u8FIFOExtCommand != uExtCmd || RT_FAILURE_NP(rc),
3693 ("%#x %Rrc\n", pThis->svga.u8FIFOExtCommand, rc));
3694
3695 pThisCC->svga.pvFIFOExtCmdParam = NULL;
3696 }
3697 else
3698 {
3699 /*
3700 * Something is wrong with the thread!
3701 */
3702 AssertLogRelMsgFailed(("uExtCmd=%d enmState=%d\n", uExtCmd, enmState));
3703 rc = VERR_INVALID_STATE;
3704 }
3705 return rc;
3706}
3707
3708
3709/**
3710 * Marks the FIFO non-busy, notifying any waiting EMTs.
3711 *
3712 * @param pDevIns The device instance.
3713 * @param pThis The shared VGA/VMSVGA instance data.
3714 * @param pThisCC The VGA/VMSVGA state for ring-3.
3715 * @param pSVGAState Pointer to the ring-3 only SVGA state data.
3716 * @param offFifoMin The start byte offset of the command FIFO.
3717 */
3718static void vmsvgaR3FifoSetNotBusy(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, PVMSVGAR3STATE pSVGAState, uint32_t offFifoMin)
3719{
3720 ASMAtomicAndU32(&pThis->svga.fBusy, ~(VMSVGA_BUSY_F_FIFO | VMSVGA_BUSY_F_EMT_FORCE));
3721 if (VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_BUSY, offFifoMin))
3722 vmsvgaHCSafeFifoBusyRegUpdate(pThis, pThisCC, pThis->svga.fBusy != 0);
3723
3724 /* Wake up any waiting EMTs. */
3725 if (pSVGAState->cBusyDelayedEmts > 0)
3726 {
3727# ifdef VMSVGA_USE_EMT_HALT_CODE
3728 PVM pVM = PDMDevHlpGetVM(pDevIns);
3729 VMCPUID idCpu = VMCpuSetFindLastPresentInternal(&pSVGAState->BusyDelayedEmts);
3730 if (idCpu != NIL_VMCPUID)
3731 {
3732 VMR3NotifyCpuDeviceReady(pVM, idCpu);
3733 while (idCpu-- > 0)
3734 if (VMCPUSET_IS_PRESENT(&pSVGAState->BusyDelayedEmts, idCpu))
3735 VMR3NotifyCpuDeviceReady(pVM, idCpu);
3736 }
3737# else
3738 int rc2 = RTSemEventMultiSignal(pSVGAState->hBusyDelayedEmts);
3739 AssertRC(rc2);
3740# endif
3741 }
3742}
3743
3744/**
3745 * Reads (more) payload into the command buffer.
3746 *
3747 * @returns pbBounceBuf on success
3748 * @retval (void *)1 if the thread was requested to stop.
3749 * @retval NULL on FIFO error.
3750 *
3751 * @param cbPayloadReq The number of bytes of payload requested.
3752 * @param pFIFO The FIFO.
3753 * @param offCurrentCmd The FIFO byte offset of the current command.
3754 * @param offFifoMin The start byte offset of the command FIFO.
3755 * @param offFifoMax The end byte offset of the command FIFO.
3756 * @param pbBounceBuf The bounch buffer. Same size as the entire FIFO, so
3757 * always sufficient size.
3758 * @param pcbAlreadyRead How much payload we've already read into the bounce
3759 * buffer. (We will NEVER re-read anything.)
3760 * @param pThread The calling PDM thread handle.
3761 * @param pThis The shared VGA/VMSVGA instance data.
3762 * @param pSVGAState Pointer to the ring-3 only SVGA state data. For
3763 * statistics collection.
3764 * @param pDevIns The device instance.
3765 */
3766static void *vmsvgaR3FifoGetCmdPayload(uint32_t cbPayloadReq, uint32_t RT_UNTRUSTED_VOLATILE_GUEST *pFIFO,
3767 uint32_t offCurrentCmd, uint32_t offFifoMin, uint32_t offFifoMax,
3768 uint8_t *pbBounceBuf, uint32_t *pcbAlreadyRead,
3769 PPDMTHREAD pThread, PVGASTATE pThis, PVMSVGAR3STATE pSVGAState, PPDMDEVINS pDevIns)
3770{
3771 Assert(pbBounceBuf);
3772 Assert(pcbAlreadyRead);
3773 Assert(offFifoMin < offFifoMax);
3774 Assert(offCurrentCmd >= offFifoMin && offCurrentCmd < offFifoMax);
3775 Assert(offFifoMax <= pThis->svga.cbFIFO);
3776
3777 /*
3778 * Check if the requested payload size has already been satisfied .
3779 * .
3780 * When called to read more, the caller is responsible for making sure the .
3781 * new command size (cbRequsted) never is smaller than what has already .
3782 * been read.
3783 */
3784 uint32_t cbAlreadyRead = *pcbAlreadyRead;
3785 if (cbPayloadReq <= cbAlreadyRead)
3786 {
3787 AssertLogRelReturn(cbPayloadReq == cbAlreadyRead, NULL);
3788 return pbBounceBuf;
3789 }
3790
3791 /*
3792 * Commands bigger than the fifo buffer are invalid.
3793 */
3794 uint32_t const cbFifoCmd = offFifoMax - offFifoMin;
3795 AssertMsgReturnStmt(cbPayloadReq <= cbFifoCmd, ("cbPayloadReq=%#x cbFifoCmd=%#x\n", cbPayloadReq, cbFifoCmd),
3796 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoErrors),
3797 NULL);
3798
3799 /*
3800 * Move offCurrentCmd past the command dword.
3801 */
3802 offCurrentCmd += sizeof(uint32_t);
3803 if (offCurrentCmd >= offFifoMax)
3804 offCurrentCmd = offFifoMin;
3805
3806 /*
3807 * Do we have sufficient payload data available already?
3808 * The host should not read beyond [SVGA_FIFO_NEXT_CMD], therefore '>=' in the condition below.
3809 */
3810 uint32_t cbAfter, cbBefore;
3811 uint32_t offNextCmd = pFIFO[SVGA_FIFO_NEXT_CMD];
3812 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
3813 if (offNextCmd >= offCurrentCmd)
3814 {
3815 if (RT_LIKELY(offNextCmd < offFifoMax))
3816 cbAfter = offNextCmd - offCurrentCmd;
3817 else
3818 {
3819 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoErrors);
3820 LogRelMax(16, ("vmsvgaR3FifoGetCmdPayload: Invalid offNextCmd=%#x (offFifoMin=%#x offFifoMax=%#x)\n",
3821 offNextCmd, offFifoMin, offFifoMax));
3822 cbAfter = offFifoMax - offCurrentCmd;
3823 }
3824 cbBefore = 0;
3825 }
3826 else
3827 {
3828 cbAfter = offFifoMax - offCurrentCmd;
3829 if (offNextCmd >= offFifoMin)
3830 cbBefore = offNextCmd - offFifoMin;
3831 else
3832 {
3833 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoErrors);
3834 LogRelMax(16, ("vmsvgaR3FifoGetCmdPayload: Invalid offNextCmd=%#x (offFifoMin=%#x offFifoMax=%#x)\n",
3835 offNextCmd, offFifoMin, offFifoMax));
3836 cbBefore = 0;
3837 }
3838 }
3839 if (cbAfter + cbBefore < cbPayloadReq)
3840 {
3841 /*
3842 * Insufficient, must wait for it to arrive.
3843 */
3844/** @todo Should clear the busy flag here to maybe encourage the guest to wake us up. */
3845 STAM_REL_PROFILE_START(&pSVGAState->StatFifoStalls, Stall);
3846 for (uint32_t i = 0;; i++)
3847 {
3848 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
3849 {
3850 STAM_REL_PROFILE_STOP(&pSVGAState->StatFifoStalls, Stall);
3851 return (void *)(uintptr_t)1;
3852 }
3853 Log(("Guest still copying (%x vs %x) current %x next %x stop %x loop %u; sleep a bit\n",
3854 cbPayloadReq, cbAfter + cbBefore, offCurrentCmd, offNextCmd, pFIFO[SVGA_FIFO_STOP], i));
3855
3856 PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->svga.hFIFORequestSem, i < 16 ? 1 : 2);
3857
3858 offNextCmd = pFIFO[SVGA_FIFO_NEXT_CMD];
3859 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
3860 if (offNextCmd >= offCurrentCmd)
3861 {
3862 cbAfter = RT_MIN(offNextCmd, offFifoMax) - offCurrentCmd;
3863 cbBefore = 0;
3864 }
3865 else
3866 {
3867 cbAfter = offFifoMax - offCurrentCmd;
3868 cbBefore = RT_MAX(offNextCmd, offFifoMin) - offFifoMin;
3869 }
3870
3871 if (cbAfter + cbBefore >= cbPayloadReq)
3872 break;
3873 }
3874 STAM_REL_PROFILE_STOP(&pSVGAState->StatFifoStalls, Stall);
3875 }
3876
3877 /*
3878 * Copy out the memory and update what pcbAlreadyRead points to.
3879 */
3880 if (cbAfter >= cbPayloadReq)
3881 memcpy(pbBounceBuf + cbAlreadyRead,
3882 (uint8_t *)pFIFO + offCurrentCmd + cbAlreadyRead,
3883 cbPayloadReq - cbAlreadyRead);
3884 else
3885 {
3886 LogFlow(("Split data buffer at %x (%u-%u)\n", offCurrentCmd, cbAfter, cbBefore));
3887 if (cbAlreadyRead < cbAfter)
3888 {
3889 memcpy(pbBounceBuf + cbAlreadyRead,
3890 (uint8_t *)pFIFO + offCurrentCmd + cbAlreadyRead,
3891 cbAfter - cbAlreadyRead);
3892 cbAlreadyRead = cbAfter;
3893 }
3894 memcpy(pbBounceBuf + cbAlreadyRead,
3895 (uint8_t *)pFIFO + offFifoMin + cbAlreadyRead - cbAfter,
3896 cbPayloadReq - cbAlreadyRead);
3897 }
3898 *pcbAlreadyRead = cbPayloadReq;
3899 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
3900 return pbBounceBuf;
3901}
3902
3903
3904/**
3905 * Sends cursor position and visibility information from the FIFO to the front-end.
3906 * @returns SVGA_FIFO_CURSOR_COUNT value used.
3907 */
3908static uint32_t
3909vmsvgaR3FifoUpdateCursor(PVGASTATECC pThisCC, PVMSVGAR3STATE pSVGAState, uint32_t RT_UNTRUSTED_VOLATILE_GUEST *pFIFO,
3910 uint32_t offFifoMin, uint32_t uCursorUpdateCount,
3911 uint32_t *pxLast, uint32_t *pyLast, uint32_t *pfLastVisible)
3912{
3913 /*
3914 * Check if the cursor update counter has changed and try get a stable
3915 * set of values if it has. This is race-prone, especially consindering
3916 * the screen ID, but little we can do about that.
3917 */
3918 uint32_t x, y, fVisible, idScreen;
3919 for (uint32_t i = 0; ; i++)
3920 {
3921 x = pFIFO[SVGA_FIFO_CURSOR_X];
3922 y = pFIFO[SVGA_FIFO_CURSOR_Y];
3923 fVisible = pFIFO[SVGA_FIFO_CURSOR_ON];
3924 idScreen = VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_CURSOR_SCREEN_ID, offFifoMin)
3925 ? pFIFO[SVGA_FIFO_CURSOR_SCREEN_ID] : SVGA_ID_INVALID;
3926 if ( uCursorUpdateCount == pFIFO[SVGA_FIFO_CURSOR_COUNT]
3927 || i > 3)
3928 break;
3929 if (i == 0)
3930 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoCursorFetchAgain);
3931 ASMNopPause();
3932 uCursorUpdateCount = pFIFO[SVGA_FIFO_CURSOR_COUNT];
3933 }
3934
3935 /*
3936 * Check if anything has changed, as calling into pDrv is not light-weight.
3937 */
3938 if ( *pxLast == x
3939 && *pyLast == y
3940 && (idScreen != SVGA_ID_INVALID || *pfLastVisible == fVisible))
3941 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoCursorNoChange);
3942 else
3943 {
3944 /*
3945 * Detected changes.
3946 *
3947 * We handle global, not per-screen visibility information by sending
3948 * pfnVBVAMousePointerShape without shape data.
3949 */
3950 *pxLast = x;
3951 *pyLast = y;
3952 uint32_t fFlags = VBVA_CURSOR_VALID_DATA;
3953 if (idScreen != SVGA_ID_INVALID)
3954 fFlags |= VBVA_CURSOR_SCREEN_RELATIVE;
3955 else if (*pfLastVisible != fVisible)
3956 {
3957 LogRel2(("vmsvgaR3FifoUpdateCursor: fVisible %d fLastVisible %d (%d,%d)\n", fVisible, *pfLastVisible, x, y));
3958 *pfLastVisible = fVisible;
3959 pThisCC->pDrv->pfnVBVAMousePointerShape(pThisCC->pDrv, RT_BOOL(fVisible), false, 0, 0, 0, 0, NULL);
3960 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoCursorVisiblity);
3961 }
3962 pThisCC->pDrv->pfnVBVAReportCursorPosition(pThisCC->pDrv, fFlags, idScreen, x, y);
3963 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoCursorPosition);
3964 }
3965
3966 /*
3967 * Update done. Signal this to the guest.
3968 */
3969 pFIFO[SVGA_FIFO_CURSOR_LAST_UPDATED] = uCursorUpdateCount;
3970
3971 return uCursorUpdateCount;
3972}
3973
3974
3975/**
3976 * Checks if there is work to be done, either cursor updating or FIFO commands.
3977 *
3978 * @returns true if pending work, false if not.
3979 * @param pThisCC The VGA/VMSVGA state for ring-3.
3980 * @param uLastCursorCount The last cursor update counter value.
3981 */
3982DECLINLINE(bool) vmsvgaR3FifoHasWork(PVGASTATECC pThisCC, uint32_t uLastCursorCount)
3983{
3984 /* If FIFO does not exist than there is nothing to do. Command buffers also require the enabled FIFO. */
3985 uint32_t RT_UNTRUSTED_VOLATILE_GUEST * const pFIFO = pThisCC->svga.pau32FIFO;
3986 AssertReturn(pFIFO, false);
3987
3988 if (vmsvgaR3CmdBufHasWork(pThisCC))
3989 return true;
3990
3991 if (pFIFO[SVGA_FIFO_NEXT_CMD] != pFIFO[SVGA_FIFO_STOP])
3992 return true;
3993
3994 if ( uLastCursorCount != pFIFO[SVGA_FIFO_CURSOR_COUNT]
3995 && VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_CURSOR_LAST_UPDATED, pFIFO[SVGA_FIFO_MIN]))
3996 return true;
3997
3998 return false;
3999}
4000
4001
4002/**
4003 * Called by the VGA refresh timer to wake up the FIFO thread when needed.
4004 *
4005 * @param pDevIns The device instance.
4006 * @param pThis The shared VGA/VMSVGA instance data.
4007 * @param pThisCC The VGA/VMSVGA state for ring-3.
4008 */
4009void vmsvgaR3FifoWatchdogTimer(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
4010{
4011 /* Caller already checked pThis->svga.fFIFOThreadSleeping, so we only have
4012 to recheck it before doing the signalling. */
4013 if ( vmsvgaR3FifoHasWork(pThisCC, ASMAtomicReadU32(&pThis->svga.uLastCursorUpdateCount))
4014 && pThis->svga.fFIFOThreadSleeping)
4015 {
4016 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->svga.hFIFORequestSem);
4017 AssertRC(rc);
4018 STAM_REL_COUNTER_INC(&pThisCC->svga.pSvgaR3State->StatFifoWatchdogWakeUps);
4019 }
4020}
4021
4022
4023/**
4024 * Called by the FIFO thread to process pending actions.
4025 *
4026 * @param pDevIns The device instance.
4027 * @param pThis The shared VGA/VMSVGA instance data.
4028 * @param pThisCC The VGA/VMSVGA state for ring-3.
4029 */
4030void vmsvgaR3FifoPendingActions(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC)
4031{
4032 RT_NOREF(pDevIns);
4033
4034 /* Currently just mode changes. */
4035 if (ASMBitTestAndClear(&pThis->svga.u32ActionFlags, VMSVGA_ACTION_CHANGEMODE_BIT))
4036 {
4037 vmsvgaR3ChangeMode(pThis, pThisCC);
4038# ifdef VBOX_WITH_VMSVGA3D
4039 if (pThisCC->svga.p3dState != NULL)
4040 vmsvga3dChangeMode(pThisCC);
4041# endif
4042 }
4043}
4044
4045
4046/*
4047 * These two macros are put outside vmsvgaR3FifoLoop because doxygen gets confused,
4048 * even the latest version, and thinks we're documenting vmsvgaR3FifoLoop. Sigh.
4049 */
4050/** @def VMSVGAFIFO_GET_CMD_BUFFER_BREAK
4051 * Macro for shortening calls to vmsvgaR3FifoGetCmdPayload.
4052 *
4053 * Will break out of the switch on failure.
4054 * Will restart and quit the loop if the thread was requested to stop.
4055 *
4056 * @param a_PtrVar Request variable pointer.
4057 * @param a_Type Request typedef (not pointer) for casting.
4058 * @param a_cbPayloadReq How much payload to fetch.
4059 * @remarks Accesses a bunch of variables in the current scope!
4060 */
4061# define VMSVGAFIFO_GET_CMD_BUFFER_BREAK(a_PtrVar, a_Type, a_cbPayloadReq) \
4062 if (1) { \
4063 (a_PtrVar) = (a_Type *)vmsvgaR3FifoGetCmdPayload((a_cbPayloadReq), pFIFO, offCurrentCmd, offFifoMin, offFifoMax, \
4064 pbBounceBuf, &cbPayload, pThread, pThis, pSVGAState, pDevIns); \
4065 if (RT_UNLIKELY((uintptr_t)(a_PtrVar) < 2)) { if ((uintptr_t)(a_PtrVar) == 1) continue; break; } \
4066 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); \
4067 } else do {} while (0)
4068/* @def VMSVGAFIFO_GET_MORE_CMD_BUFFER_BREAK
4069 * Macro for shortening calls to vmsvgaR3FifoGetCmdPayload for refetching the
4070 * buffer after figuring out the actual command size.
4071 *
4072 * Will break out of the switch on failure.
4073 *
4074 * @param a_PtrVar Request variable pointer.
4075 * @param a_Type Request typedef (not pointer) for casting.
4076 * @param a_cbPayloadReq How much payload to fetch.
4077 * @remarks Accesses a bunch of variables in the current scope!
4078 */
4079# define VMSVGAFIFO_GET_MORE_CMD_BUFFER_BREAK(a_PtrVar, a_Type, a_cbPayloadReq) \
4080 if (1) { \
4081 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(a_PtrVar, a_Type, a_cbPayloadReq); \
4082 } else do {} while (0)
4083
4084/**
4085 * @callback_method_impl{PFNPDMTHREADDEV, The async FIFO handling thread.}
4086 */
4087static DECLCALLBACK(int) vmsvgaR3FifoLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4088{
4089 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
4090 PVGASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
4091 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
4092 int rc;
4093
4094# if defined(VBOX_WITH_VMSVGA3D) && defined(RT_OS_LINUX)
4095 if (pThis->svga.f3DEnabled)
4096 {
4097 /* The FIFO thread may use X API for accelerated screen output. */
4098 XInitThreads();
4099 }
4100# endif
4101
4102 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
4103 return VINF_SUCCESS;
4104
4105 /*
4106 * Special mode where we only execute an external command and the go back
4107 * to being suspended. Currently, all ext cmds ends up here, with the reset
4108 * one also being eligble for runtime execution further down as well.
4109 */
4110 if (pThis->svga.fFifoExtCommandWakeup)
4111 {
4112 vmsvgaR3FifoHandleExtCmd(pDevIns, pThis, pThisCC);
4113 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
4114 if (pThis->svga.u8FIFOExtCommand == VMSVGA_FIFO_EXTCMD_NONE)
4115 PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->svga.hFIFORequestSem, RT_MS_1MIN);
4116 else
4117 vmsvgaR3FifoHandleExtCmd(pDevIns, pThis, pThisCC);
4118 return VINF_SUCCESS;
4119 }
4120
4121
4122 /*
4123 * Signal the semaphore to make sure we don't wait for 250ms after a
4124 * suspend & resume scenario (see vmsvgaR3FifoGetCmdPayload).
4125 */
4126 PDMDevHlpSUPSemEventSignal(pDevIns, pThis->svga.hFIFORequestSem);
4127
4128 /*
4129 * Allocate a bounce buffer for command we get from the FIFO.
4130 * (All code must return via the end of the function to free this buffer.)
4131 */
4132 uint8_t *pbBounceBuf = (uint8_t *)RTMemAllocZ(pThis->svga.cbFIFO);
4133 AssertReturn(pbBounceBuf, VERR_NO_MEMORY);
4134
4135 /*
4136 * Polling/sleep interval config.
4137 *
4138 * We wait for an a short interval if the guest has recently given us work
4139 * to do, but the interval increases the longer we're kept idle. Once we've
4140 * reached the refresh timer interval, we'll switch to extended waits,
4141 * depending on it or the guest to kick us into action when needed.
4142 *
4143 * Should the refresh time go fishing, we'll just continue increasing the
4144 * sleep length till we reaches the 250 ms max after about 16 seconds.
4145 */
4146 RTMSINTERVAL const cMsMinSleep = 16;
4147 RTMSINTERVAL const cMsIncSleep = 2;
4148 RTMSINTERVAL const cMsMaxSleep = 250;
4149 RTMSINTERVAL const cMsExtendedSleep = 15 * RT_MS_1SEC; /* Regular paranoia dictates that this cannot be indefinite. */
4150 RTMSINTERVAL cMsSleep = cMsMaxSleep;
4151
4152 /*
4153 * Cursor update state (SVGA_FIFO_CAP_CURSOR_BYPASS_3).
4154 *
4155 * Initialize with values that will detect an update from the guest.
4156 * Make sure that if the guest never updates the cursor position, then the device does not report it.
4157 * The guest has to change the value of uLastCursorUpdateCount, when the cursor position is actually updated.
4158 * xLastCursor, yLastCursor and fLastCursorVisible are set to report the first update.
4159 */
4160 uint32_t RT_UNTRUSTED_VOLATILE_GUEST * const pFIFO = pThisCC->svga.pau32FIFO;
4161 pThis->svga.uLastCursorUpdateCount = pFIFO[SVGA_FIFO_CURSOR_COUNT];
4162 uint32_t xLastCursor = ~pFIFO[SVGA_FIFO_CURSOR_X];
4163 uint32_t yLastCursor = ~pFIFO[SVGA_FIFO_CURSOR_Y];
4164 uint32_t fLastCursorVisible = ~pFIFO[SVGA_FIFO_CURSOR_ON];
4165
4166 /*
4167 * The FIFO loop.
4168 */
4169 LogFlow(("vmsvgaR3FifoLoop: started loop\n"));
4170 bool fBadOrDisabledFifo = false;
4171 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
4172 {
4173# if defined(RT_OS_DARWIN) && defined(VBOX_WITH_VMSVGA3D)
4174 /*
4175 * Should service the run loop every so often.
4176 */
4177 if (pThis->svga.f3DEnabled)
4178 vmsvga3dCocoaServiceRunLoop();
4179# endif
4180
4181 /* First check any pending actions. */
4182 vmsvgaR3FifoPendingActions(pDevIns, pThis, pThisCC);
4183
4184 /*
4185 * Unless there's already work pending, go to sleep for a short while.
4186 * (See polling/sleep interval config above.)
4187 */
4188 if ( fBadOrDisabledFifo
4189 || !vmsvgaR3FifoHasWork(pThisCC, pThis->svga.uLastCursorUpdateCount))
4190 {
4191 ASMAtomicWriteBool(&pThis->svga.fFIFOThreadSleeping, true);
4192 Assert(pThis->cMilliesRefreshInterval > 0);
4193 if (cMsSleep < pThis->cMilliesRefreshInterval)
4194 rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->svga.hFIFORequestSem, cMsSleep);
4195 else
4196 {
4197# ifdef VMSVGA_USE_FIFO_ACCESS_HANDLER
4198 int rc2 = PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->svga.GCPhysFIFO);
4199 AssertRC(rc2); /* No break. Racing EMTs unmapping and remapping the region. */
4200# endif
4201 if ( !fBadOrDisabledFifo
4202 && vmsvgaR3FifoHasWork(pThisCC, pThis->svga.uLastCursorUpdateCount))
4203 rc = VINF_SUCCESS;
4204 else
4205 {
4206 STAM_REL_PROFILE_START(&pSVGAState->StatFifoExtendedSleep, Acc);
4207 rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->svga.hFIFORequestSem, cMsExtendedSleep);
4208 STAM_REL_PROFILE_STOP(&pSVGAState->StatFifoExtendedSleep, Acc);
4209 }
4210 }
4211 ASMAtomicWriteBool(&pThis->svga.fFIFOThreadSleeping, false);
4212 AssertBreak(RT_SUCCESS(rc) || rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED);
4213 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
4214 {
4215 LogFlow(("vmsvgaR3FifoLoop: thread state %x\n", pThread->enmState));
4216 break;
4217 }
4218 }
4219 else
4220 rc = VINF_SUCCESS;
4221 fBadOrDisabledFifo = false;
4222 if (rc == VERR_TIMEOUT)
4223 {
4224 if (!vmsvgaR3FifoHasWork(pThisCC, pThis->svga.uLastCursorUpdateCount))
4225 {
4226 cMsSleep = RT_MIN(cMsSleep + cMsIncSleep, cMsMaxSleep);
4227 continue;
4228 }
4229 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoTodoTimeout);
4230
4231 Log(("vmsvgaR3FifoLoop: timeout\n"));
4232 }
4233 else if (vmsvgaR3FifoHasWork(pThisCC, pThis->svga.uLastCursorUpdateCount))
4234 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoTodoWoken);
4235 cMsSleep = cMsMinSleep;
4236
4237 Log(("vmsvgaR3FifoLoop: enabled=%d configured=%d busy=%d\n", pThis->svga.fEnabled, pThis->svga.fConfigured, pFIFO[SVGA_FIFO_BUSY]));
4238 Log(("vmsvgaR3FifoLoop: min %x max %x\n", pFIFO[SVGA_FIFO_MIN], pFIFO[SVGA_FIFO_MAX]));
4239 Log(("vmsvgaR3FifoLoop: next %x stop %x\n", pFIFO[SVGA_FIFO_NEXT_CMD], pFIFO[SVGA_FIFO_STOP]));
4240
4241 /*
4242 * Handle external commands (currently only reset).
4243 */
4244 if (pThis->svga.u8FIFOExtCommand != VMSVGA_FIFO_EXTCMD_NONE)
4245 {
4246 vmsvgaR3FifoHandleExtCmd(pDevIns, pThis, pThisCC);
4247 continue;
4248 }
4249
4250 /*
4251 * The device must be enabled and configured.
4252 */
4253 if ( !pThis->svga.fEnabled
4254 || !pThis->svga.fConfigured)
4255 {
4256 vmsvgaR3FifoSetNotBusy(pDevIns, pThis, pThisCC, pSVGAState, pFIFO[SVGA_FIFO_MIN]);
4257 fBadOrDisabledFifo = true;
4258 cMsSleep = cMsMaxSleep; /* cheat */
4259 continue;
4260 }
4261
4262 /*
4263 * Get and check the min/max values. We ASSUME that they will remain
4264 * unchanged while we process requests. A further ASSUMPTION is that
4265 * the guest won't mess with SVGA_FIFO_NEXT_CMD while we're busy, so
4266 * we don't read it back while in the loop.
4267 */
4268 uint32_t const offFifoMin = pFIFO[SVGA_FIFO_MIN];
4269 uint32_t const offFifoMax = pFIFO[SVGA_FIFO_MAX];
4270 uint32_t offCurrentCmd = pFIFO[SVGA_FIFO_STOP];
4271 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
4272 if (RT_UNLIKELY( !VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_STOP, offFifoMin)
4273 || offFifoMax <= offFifoMin
4274 || offFifoMax > pThis->svga.cbFIFO
4275 || (offFifoMax & 3) != 0
4276 || (offFifoMin & 3) != 0
4277 || offCurrentCmd < offFifoMin
4278 || offCurrentCmd > offFifoMax))
4279 {
4280 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoErrors);
4281 LogRelMax(8, ("vmsvgaR3FifoLoop: Bad fifo: min=%#x stop=%#x max=%#x\n", offFifoMin, offCurrentCmd, offFifoMax));
4282 vmsvgaR3FifoSetNotBusy(pDevIns, pThis, pThisCC, pSVGAState, offFifoMin);
4283 fBadOrDisabledFifo = true;
4284 continue;
4285 }
4286 RT_UNTRUSTED_VALIDATED_FENCE();
4287 if (RT_UNLIKELY(offCurrentCmd & 3))
4288 {
4289 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoErrors);
4290 LogRelMax(8, ("vmsvgaR3FifoLoop: Misaligned offCurrentCmd=%#x?\n", offCurrentCmd));
4291 offCurrentCmd &= ~UINT32_C(3);
4292 }
4293
4294 /*
4295 * Update the cursor position before we start on the FIFO commands.
4296 */
4297 /** @todo do we need to check whether the guest disabled the SVGA_FIFO_CAP_CURSOR_BYPASS_3 capability here? */
4298 if (VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_CURSOR_LAST_UPDATED, offFifoMin))
4299 {
4300 uint32_t const uCursorUpdateCount = pFIFO[SVGA_FIFO_CURSOR_COUNT];
4301 if (uCursorUpdateCount == pThis->svga.uLastCursorUpdateCount)
4302 { /* halfways likely */ }
4303 else
4304 {
4305 uint32_t const uNewCount = vmsvgaR3FifoUpdateCursor(pThisCC, pSVGAState, pFIFO, offFifoMin, uCursorUpdateCount,
4306 &xLastCursor, &yLastCursor, &fLastCursorVisible);
4307 ASMAtomicWriteU32(&pThis->svga.uLastCursorUpdateCount, uNewCount);
4308 }
4309 }
4310
4311 /*
4312 * Mark the FIFO as busy.
4313 */
4314 ASMAtomicWriteU32(&pThis->svga.fBusy, VMSVGA_BUSY_F_FIFO); // Clears VMSVGA_BUSY_F_EMT_FORCE!
4315 if (VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_BUSY, offFifoMin))
4316 ASMAtomicWriteU32(&pFIFO[SVGA_FIFO_BUSY], true);
4317
4318 /*
4319 * Process all submitted command buffers.
4320 */
4321 vmsvgaR3CmdBufProcessBuffers(pDevIns, pThis, pThisCC, pThread);
4322
4323 /*
4324 * Execute all queued FIFO commands.
4325 * Quit if pending external command or changes in the thread state.
4326 */
4327 bool fDone = false;
4328 while ( !(fDone = (pFIFO[SVGA_FIFO_NEXT_CMD] == offCurrentCmd))
4329 && pThread->enmState == PDMTHREADSTATE_RUNNING)
4330 {
4331 uint32_t cbPayload = 0;
4332 uint32_t u32IrqStatus = 0;
4333
4334 Assert(offCurrentCmd < offFifoMax && offCurrentCmd >= offFifoMin);
4335
4336 /* First check any pending actions. */
4337 vmsvgaR3FifoPendingActions(pDevIns, pThis, pThisCC);
4338
4339 /* Check for pending external commands (reset). */
4340 if (pThis->svga.u8FIFOExtCommand != VMSVGA_FIFO_EXTCMD_NONE)
4341 break;
4342
4343 /*
4344 * Process the command.
4345 */
4346 /* 'enmCmdId' is actually a SVGAFifoCmdId. It is treated as uint32_t in order to avoid a compiler
4347 * warning. Because we implement some obsolete and deprecated commands, which are not included in
4348 * the SVGAFifoCmdId enum in the VMSVGA headers anymore.
4349 */
4350 uint32_t const enmCmdId = pFIFO[offCurrentCmd / sizeof(uint32_t)];
4351 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
4352 LogFlow(("vmsvgaR3FifoLoop: FIFO command (iCmd=0x%x) %s %d\n",
4353 offCurrentCmd / sizeof(uint32_t), vmsvgaR3FifoCmdToString(enmCmdId), enmCmdId));
4354 switch (enmCmdId)
4355 {
4356 case SVGA_CMD_INVALID_CMD:
4357 /* Nothing to do. */
4358 STAM_REL_COUNTER_INC(&pSVGAState->StatR3CmdInvalidCmd);
4359 break;
4360
4361 case SVGA_CMD_FENCE:
4362 {
4363 SVGAFifoCmdFence *pCmdFence;
4364 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmdFence, SVGAFifoCmdFence, sizeof(*pCmdFence));
4365 STAM_REL_COUNTER_INC(&pSVGAState->StatR3CmdFence);
4366 if (VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_FENCE, offFifoMin))
4367 {
4368 Log(("vmsvgaR3FifoLoop: SVGA_CMD_FENCE %#x\n", pCmdFence->fence));
4369 pFIFO[SVGA_FIFO_FENCE] = pCmdFence->fence;
4370
4371 if (pThis->svga.u32IrqMask & SVGA_IRQFLAG_ANY_FENCE)
4372 {
4373 Log(("vmsvgaR3FifoLoop: any fence irq\n"));
4374 u32IrqStatus |= SVGA_IRQFLAG_ANY_FENCE;
4375 }
4376 else
4377 if ( VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_FENCE_GOAL, offFifoMin)
4378 && (pThis->svga.u32IrqMask & SVGA_IRQFLAG_FENCE_GOAL)
4379 && pFIFO[SVGA_FIFO_FENCE_GOAL] == pCmdFence->fence)
4380 {
4381 Log(("vmsvgaR3FifoLoop: fence goal reached irq (fence=%#x)\n", pCmdFence->fence));
4382 u32IrqStatus |= SVGA_IRQFLAG_FENCE_GOAL;
4383 }
4384 }
4385 else
4386 Log(("SVGA_CMD_FENCE is bogus when offFifoMin is %#x!\n", offFifoMin));
4387 break;
4388 }
4389
4390 case SVGA_CMD_UPDATE:
4391 {
4392 SVGAFifoCmdUpdate *pCmd;
4393 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdUpdate, sizeof(*pCmd));
4394 vmsvgaR3CmdUpdate(pThis, pThisCC, pCmd);
4395 break;
4396 }
4397
4398 case SVGA_CMD_UPDATE_VERBOSE:
4399 {
4400 SVGAFifoCmdUpdateVerbose *pCmd;
4401 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdUpdateVerbose, sizeof(*pCmd));
4402 vmsvgaR3CmdUpdateVerbose(pThis, pThisCC, pCmd);
4403 break;
4404 }
4405
4406 case SVGA_CMD_DEFINE_CURSOR:
4407 {
4408 /* Followed by bitmap data. */
4409 SVGAFifoCmdDefineCursor *pCmd;
4410 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDefineCursor, sizeof(*pCmd));
4411
4412 /* Figure out the size of the bitmap data. */
4413 ASSERT_GUEST_BREAK(pCmd->height < 2048 && pCmd->width < 2048);
4414 ASSERT_GUEST_BREAK(pCmd->andMaskDepth <= 32);
4415 ASSERT_GUEST_BREAK(pCmd->xorMaskDepth <= 32);
4416 RT_UNTRUSTED_VALIDATED_FENCE();
4417
4418 uint32_t const cbAndLine = RT_ALIGN_32(pCmd->width * (pCmd->andMaskDepth + (pCmd->andMaskDepth == 15)), 32) / 8;
4419 uint32_t const cbAndMask = cbAndLine * pCmd->height;
4420 uint32_t const cbXorLine = RT_ALIGN_32(pCmd->width * (pCmd->xorMaskDepth + (pCmd->xorMaskDepth == 15)), 32) / 8;
4421 uint32_t const cbXorMask = cbXorLine * pCmd->height;
4422
4423 uint32_t const cbCmd = sizeof(SVGAFifoCmdDefineCursor) + cbAndMask + cbXorMask;
4424 VMSVGAFIFO_GET_MORE_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDefineCursor, cbCmd);
4425 vmsvgaR3CmdDefineCursor(pThis, pThisCC, pCmd);
4426 break;
4427 }
4428
4429 case SVGA_CMD_DEFINE_ALPHA_CURSOR:
4430 {
4431 /* Followed by bitmap data. */
4432 SVGAFifoCmdDefineAlphaCursor *pCmd;
4433 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDefineAlphaCursor, sizeof(*pCmd));
4434
4435 /* Figure out the size of the bitmap data. */
4436 ASSERT_GUEST_BREAK(pCmd->height < 2048 && pCmd->width < 2048);
4437
4438 uint32_t const cbCmd = sizeof(SVGAFifoCmdDefineAlphaCursor) + pCmd->width * pCmd->height * sizeof(uint32_t) /* 32-bit BRGA format */;
4439 VMSVGAFIFO_GET_MORE_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDefineAlphaCursor, cbCmd);
4440 vmsvgaR3CmdDefineAlphaCursor(pThis, pThisCC, pCmd);
4441 break;
4442 }
4443
4444 case SVGA_CMD_MOVE_CURSOR:
4445 {
4446 /* Deprecated; there should be no driver which *requires* this command. However, if
4447 * we do ecncounter this command, it might be useful to not get the FIFO completely out of
4448 * alignment.
4449 * May be issued by guest if SVGA_CAP_CURSOR_BYPASS is missing.
4450 */
4451 SVGAFifoCmdMoveCursor *pCmd;
4452 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdMoveCursor, sizeof(*pCmd));
4453 vmsvgaR3CmdMoveCursor(pThis, pThisCC, pCmd);
4454 break;
4455 }
4456
4457 case SVGA_CMD_DISPLAY_CURSOR:
4458 {
4459 /* Deprecated; there should be no driver which *requires* this command. However, if
4460 * we do ecncounter this command, it might be useful to not get the FIFO completely out of
4461 * alignment.
4462 * May be issued by guest if SVGA_CAP_CURSOR_BYPASS is missing.
4463 */
4464 SVGAFifoCmdDisplayCursor *pCmd;
4465 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDisplayCursor, sizeof(*pCmd));
4466 vmsvgaR3CmdDisplayCursor(pThis, pThisCC, pCmd);
4467 break;
4468 }
4469
4470 case SVGA_CMD_RECT_FILL:
4471 {
4472 SVGAFifoCmdRectFill *pCmd;
4473 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdRectFill, sizeof(*pCmd));
4474 vmsvgaR3CmdRectFill(pThis, pThisCC, pCmd);
4475 break;
4476 }
4477
4478 case SVGA_CMD_RECT_COPY:
4479 {
4480 SVGAFifoCmdRectCopy *pCmd;
4481 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdRectCopy, sizeof(*pCmd));
4482 vmsvgaR3CmdRectCopy(pThis, pThisCC, pCmd);
4483 break;
4484 }
4485
4486 case SVGA_CMD_RECT_ROP_COPY:
4487 {
4488 SVGAFifoCmdRectRopCopy *pCmd;
4489 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdRectRopCopy, sizeof(*pCmd));
4490 vmsvgaR3CmdRectRopCopy(pThis, pThisCC, pCmd);
4491 break;
4492 }
4493
4494 case SVGA_CMD_ESCAPE:
4495 {
4496 /* Followed by 'size' bytes of data. */
4497 SVGAFifoCmdEscape *pCmd;
4498 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdEscape, sizeof(*pCmd));
4499
4500 ASSERT_GUEST_BREAK(pCmd->size < pThis->svga.cbFIFO - sizeof(SVGAFifoCmdEscape));
4501 RT_UNTRUSTED_VALIDATED_FENCE();
4502
4503 uint32_t const cbCmd = sizeof(SVGAFifoCmdEscape) + pCmd->size;
4504 VMSVGAFIFO_GET_MORE_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdEscape, cbCmd);
4505 vmsvgaR3CmdEscape(pThis, pThisCC, pCmd);
4506 break;
4507 }
4508# ifdef VBOX_WITH_VMSVGA3D
4509 case SVGA_CMD_DEFINE_GMR2:
4510 {
4511 SVGAFifoCmdDefineGMR2 *pCmd;
4512 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDefineGMR2, sizeof(*pCmd));
4513 vmsvgaR3CmdDefineGMR2(pThis, pThisCC, pCmd);
4514 break;
4515 }
4516
4517 case SVGA_CMD_REMAP_GMR2:
4518 {
4519 /* Followed by page descriptors or guest ptr. */
4520 SVGAFifoCmdRemapGMR2 *pCmd;
4521 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdRemapGMR2, sizeof(*pCmd));
4522
4523 /* Calculate the size of what comes after next and fetch it. */
4524 uint32_t cbCmd = sizeof(SVGAFifoCmdRemapGMR2);
4525 if (pCmd->flags & SVGA_REMAP_GMR2_VIA_GMR)
4526 cbCmd += sizeof(SVGAGuestPtr);
4527 else
4528 {
4529 uint32_t const cbPageDesc = (pCmd->flags & SVGA_REMAP_GMR2_PPN64) ? sizeof(uint64_t) : sizeof(uint32_t);
4530 if (pCmd->flags & SVGA_REMAP_GMR2_SINGLE_PPN)
4531 {
4532 cbCmd += cbPageDesc;
4533 pCmd->numPages = 1;
4534 }
4535 else
4536 {
4537 ASSERT_GUEST_BREAK(pCmd->numPages <= pThis->svga.cbFIFO / cbPageDesc);
4538 cbCmd += cbPageDesc * pCmd->numPages;
4539 }
4540 }
4541 VMSVGAFIFO_GET_MORE_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdRemapGMR2, cbCmd);
4542 vmsvgaR3CmdRemapGMR2(pThis, pThisCC, pCmd);
4543# ifdef DEBUG_GMR_ACCESS
4544 VMR3ReqCallWaitU(PDMDevHlpGetUVM(pDevIns), VMCPUID_ANY, (PFNRT)vmsvgaR3RegisterGmr, 2, pDevIns, pCmd->gmrId);
4545# endif
4546 break;
4547 }
4548# endif // VBOX_WITH_VMSVGA3D
4549 case SVGA_CMD_DEFINE_SCREEN:
4550 {
4551 /* The size of this command is specified by the guest and depends on capabilities. */
4552 Assert(pFIFO[SVGA_FIFO_CAPABILITIES] & SVGA_FIFO_CAP_SCREEN_OBJECT_2);
4553
4554 SVGAFifoCmdDefineScreen *pCmd;
4555 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDefineScreen, sizeof(pCmd->screen.structSize));
4556 AssertBreak(pCmd->screen.structSize < pThis->svga.cbFIFO);
4557 RT_UNTRUSTED_VALIDATED_FENCE();
4558
4559 RT_BZERO(&pCmd->screen.id, sizeof(*pCmd) - RT_OFFSETOF(SVGAFifoCmdDefineScreen, screen.id));
4560 VMSVGAFIFO_GET_MORE_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDefineScreen, RT_MAX(sizeof(pCmd->screen.structSize), pCmd->screen.structSize));
4561 vmsvgaR3CmdDefineScreen(pThis, pThisCC, pCmd);
4562 break;
4563 }
4564
4565 case SVGA_CMD_DESTROY_SCREEN:
4566 {
4567 SVGAFifoCmdDestroyScreen *pCmd;
4568 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDestroyScreen, sizeof(*pCmd));
4569 vmsvgaR3CmdDestroyScreen(pThis, pThisCC, pCmd);
4570 break;
4571 }
4572
4573 case SVGA_CMD_DEFINE_GMRFB:
4574 {
4575 SVGAFifoCmdDefineGMRFB *pCmd;
4576 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdDefineGMRFB, sizeof(*pCmd));
4577 vmsvgaR3CmdDefineGMRFB(pThis, pThisCC, pCmd);
4578 break;
4579 }
4580
4581 case SVGA_CMD_BLIT_GMRFB_TO_SCREEN:
4582 {
4583 SVGAFifoCmdBlitGMRFBToScreen *pCmd;
4584 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdBlitGMRFBToScreen, sizeof(*pCmd));
4585 vmsvgaR3CmdBlitGMRFBToScreen(pThis, pThisCC, pCmd);
4586 break;
4587 }
4588
4589 case SVGA_CMD_BLIT_SCREEN_TO_GMRFB:
4590 {
4591 SVGAFifoCmdBlitScreenToGMRFB *pCmd;
4592 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdBlitScreenToGMRFB, sizeof(*pCmd));
4593 vmsvgaR3CmdBlitScreenToGMRFB(pThis, pThisCC, pCmd);
4594 break;
4595 }
4596
4597 case SVGA_CMD_ANNOTATION_FILL:
4598 {
4599 SVGAFifoCmdAnnotationFill *pCmd;
4600 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdAnnotationFill, sizeof(*pCmd));
4601 vmsvgaR3CmdAnnotationFill(pThis, pThisCC, pCmd);
4602 break;
4603 }
4604
4605 case SVGA_CMD_ANNOTATION_COPY:
4606 {
4607 SVGAFifoCmdAnnotationCopy *pCmd;
4608 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdAnnotationCopy, sizeof(*pCmd));
4609 vmsvgaR3CmdAnnotationCopy(pThis, pThisCC, pCmd);
4610 break;
4611 }
4612
4613 default:
4614# ifdef VBOX_WITH_VMSVGA3D
4615 if ( (int)enmCmdId >= SVGA_3D_CMD_BASE
4616 && (int)enmCmdId < SVGA_3D_CMD_MAX)
4617 {
4618 RT_UNTRUSTED_VALIDATED_FENCE();
4619
4620 /* All 3d commands start with a common header, which defines the identifier and the size
4621 * of the command. The identifier has been already read from FIFO. Fetch the size.
4622 */
4623 uint32_t *pcbCmd;
4624 VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pcbCmd, uint32_t, sizeof(*pcbCmd));
4625 uint32_t const cbCmd = *pcbCmd;
4626 AssertBreak(cbCmd < pThis->svga.cbFIFO);
4627 uint32_t *pu32Cmd;
4628 VMSVGAFIFO_GET_MORE_CMD_BUFFER_BREAK(pu32Cmd, uint32_t, sizeof(*pcbCmd) + cbCmd);
4629 pu32Cmd++; /* Skip the command size. */
4630
4631 if (RT_LIKELY(pThis->svga.f3DEnabled))
4632 { /* likely */ }
4633 else
4634 {
4635 LogRelMax(8, ("VMSVGA: 3D disabled, command %d skipped\n", enmCmdId));
4636 break;
4637 }
4638
4639 vmsvgaR3Process3dCmd(pThis, pThisCC, (SVGAFifo3dCmdId)enmCmdId, cbCmd, pu32Cmd);
4640 }
4641 else
4642# endif // VBOX_WITH_VMSVGA3D
4643 {
4644 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoUnkCmds);
4645 AssertMsgFailed(("enmCmdId=%d\n", enmCmdId));
4646 }
4647 }
4648
4649 /* Go to the next slot */
4650 Assert(cbPayload + sizeof(uint32_t) <= offFifoMax - offFifoMin);
4651 offCurrentCmd += RT_ALIGN_32(cbPayload + sizeof(uint32_t), sizeof(uint32_t));
4652 if (offCurrentCmd >= offFifoMax)
4653 {
4654 offCurrentCmd -= offFifoMax - offFifoMin;
4655 Assert(offCurrentCmd >= offFifoMin);
4656 Assert(offCurrentCmd < offFifoMax);
4657 }
4658 ASMAtomicWriteU32(&pFIFO[SVGA_FIFO_STOP], offCurrentCmd);
4659 STAM_REL_COUNTER_INC(&pSVGAState->StatFifoCommands);
4660
4661 /*
4662 * Raise IRQ if required. Must enter the critical section here
4663 * before making final decisions here, otherwise cubebench and
4664 * others may end up waiting forever.
4665 */
4666 if ( u32IrqStatus
4667 || (pThis->svga.u32IrqMask & SVGA_IRQFLAG_FIFO_PROGRESS))
4668 {
4669 int rc2 = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4670 AssertRC(rc2);
4671
4672 /* FIFO progress might trigger an interrupt. */
4673 if (pThis->svga.u32IrqMask & SVGA_IRQFLAG_FIFO_PROGRESS)
4674 {
4675 Log(("vmsvgaR3FifoLoop: fifo progress irq\n"));
4676 u32IrqStatus |= SVGA_IRQFLAG_FIFO_PROGRESS;
4677 }
4678
4679 /* Unmasked IRQ pending? */
4680 if (pThis->svga.u32IrqMask & u32IrqStatus)
4681 {
4682 Log(("vmsvgaR3FifoLoop: Trigger interrupt with status %x\n", u32IrqStatus));
4683 ASMAtomicOrU32(&pThis->svga.u32IrqStatus, u32IrqStatus);
4684 PDMDevHlpPCISetIrq(pDevIns, 0, 1);
4685 }
4686
4687 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4688 }
4689 }
4690
4691 /* If really done, clear the busy flag. */
4692 if (fDone)
4693 {
4694 Log(("vmsvgaR3FifoLoop: emptied the FIFO next=%x stop=%x\n", pFIFO[SVGA_FIFO_NEXT_CMD], offCurrentCmd));
4695 vmsvgaR3FifoSetNotBusy(pDevIns, pThis, pThisCC, pSVGAState, offFifoMin);
4696 }
4697 }
4698
4699 /*
4700 * Free the bounce buffer. (There are no returns above!)
4701 */
4702 RTMemFree(pbBounceBuf);
4703
4704 return VINF_SUCCESS;
4705}
4706
4707#undef VMSVGAFIFO_GET_MORE_CMD_BUFFER_BREAK
4708#undef VMSVGAFIFO_GET_CMD_BUFFER_BREAK
4709
4710/**
4711 * @callback_method_impl{PFNPDMTHREADWAKEUPDEV,
4712 * Unblock the FIFO I/O thread so it can respond to a state change.}
4713 */
4714static DECLCALLBACK(int) vmsvgaR3FifoLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4715{
4716 RT_NOREF(pDevIns);
4717 PVGASTATE pThis = (PVGASTATE)pThread->pvUser;
4718 Log(("vmsvgaR3FifoLoopWakeUp\n"));
4719 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->svga.hFIFORequestSem);
4720}
4721
4722/**
4723 * Enables or disables dirty page tracking for the framebuffer
4724 *
4725 * @param pDevIns The device instance.
4726 * @param pThis The shared VGA/VMSVGA instance data.
4727 * @param fTraces Enable/disable traces
4728 */
4729static void vmsvgaR3SetTraces(PPDMDEVINS pDevIns, PVGASTATE pThis, bool fTraces)
4730{
4731 if ( (!pThis->svga.fConfigured || !pThis->svga.fEnabled)
4732 && !fTraces)
4733 {
4734 //Assert(pThis->svga.fTraces);
4735 Log(("vmsvgaR3SetTraces: *not* allowed to disable dirty page tracking when the device is in legacy mode.\n"));
4736 return;
4737 }
4738
4739 pThis->svga.fTraces = fTraces;
4740 if (pThis->svga.fTraces)
4741 {
4742 unsigned cbFrameBuffer = pThis->vram_size;
4743
4744 Log(("vmsvgaR3SetTraces: enable dirty page handling for the frame buffer only (%x bytes)\n", 0));
4745 /** @todo How does this work with screens? */
4746 if (pThis->svga.uHeight != VMSVGA_VAL_UNINITIALIZED)
4747 {
4748# ifndef DEBUG_bird /* BB-10.3.1 triggers this as it initializes everything to zero. Better just ignore it. */
4749 Assert(pThis->svga.cbScanline);
4750# endif
4751 /* Hardware enabled; return real framebuffer size .*/
4752 cbFrameBuffer = (uint32_t)pThis->svga.uHeight * pThis->svga.cbScanline;
4753 cbFrameBuffer = RT_ALIGN(cbFrameBuffer, PAGE_SIZE);
4754 }
4755
4756 if (!pThis->svga.fVRAMTracking)
4757 {
4758 Log(("vmsvgaR3SetTraces: enable frame buffer dirty page tracking. (%x bytes; vram %x)\n", cbFrameBuffer, pThis->vram_size));
4759 vgaR3RegisterVRAMHandler(pDevIns, pThis, cbFrameBuffer);
4760 pThis->svga.fVRAMTracking = true;
4761 }
4762 }
4763 else
4764 {
4765 if (pThis->svga.fVRAMTracking)
4766 {
4767 Log(("vmsvgaR3SetTraces: disable frame buffer dirty page tracking\n"));
4768 vgaR3UnregisterVRAMHandler(pDevIns, pThis);
4769 pThis->svga.fVRAMTracking = false;
4770 }
4771 }
4772}
4773
4774/**
4775 * @callback_method_impl{FNPCIIOREGIONMAP}
4776 */
4777DECLCALLBACK(int) vmsvgaR3PciIORegionFifoMapUnmap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
4778 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
4779{
4780 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
4781 int rc;
4782 RT_NOREF(pPciDev);
4783 Assert(pPciDev == pDevIns->apPciDevs[0]);
4784
4785 Log(("vmsvgaR3PciIORegionFifoMapUnmap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
4786 AssertReturn( iRegion == pThis->pciRegions.iFIFO
4787 && ( enmType == PCI_ADDRESS_SPACE_MEM
4788 || (enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH /* got wrong in 6.1.0RC1 */ && pThis->fStateLoaded))
4789 , VERR_INTERNAL_ERROR);
4790 if (GCPhysAddress != NIL_RTGCPHYS)
4791 {
4792 /*
4793 * Mapping the FIFO RAM.
4794 */
4795 AssertLogRelMsg(cb == pThis->svga.cbFIFO, ("cb=%#RGp cbFIFO=%#x\n", cb, pThis->svga.cbFIFO));
4796 rc = PDMDevHlpMmio2Map(pDevIns, pThis->hMmio2VmSvgaFifo, GCPhysAddress);
4797 AssertRC(rc);
4798
4799# if defined(VMSVGA_USE_FIFO_ACCESS_HANDLER) || defined(DEBUG_FIFO_ACCESS)
4800 if (RT_SUCCESS(rc))
4801 {
4802 rc = PGMHandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns), GCPhysAddress,
4803# ifdef DEBUG_FIFO_ACCESS
4804 GCPhysAddress + (pThis->svga.cbFIFO - 1),
4805# else
4806 GCPhysAddress + PAGE_SIZE - 1,
4807# endif
4808 pThis->svga.hFifoAccessHandlerType, pThis, NIL_RTR0PTR, NIL_RTRCPTR,
4809 "VMSVGA FIFO");
4810 AssertRC(rc);
4811 }
4812# endif
4813 if (RT_SUCCESS(rc))
4814 {
4815 pThis->svga.GCPhysFIFO = GCPhysAddress;
4816 Log(("vmsvgaR3IORegionMap: GCPhysFIFO=%RGp cbFIFO=%#x\n", GCPhysAddress, pThis->svga.cbFIFO));
4817 }
4818 rc = VINF_PCI_MAPPING_DONE; /* caller only cares about this status, so it is okay that we overwrite errors here. */
4819 }
4820 else
4821 {
4822 Assert(pThis->svga.GCPhysFIFO);
4823# if defined(VMSVGA_USE_FIFO_ACCESS_HANDLER) || defined(DEBUG_FIFO_ACCESS)
4824 rc = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns), pThis->svga.GCPhysFIFO);
4825 AssertRC(rc);
4826# else
4827 rc = VINF_SUCCESS;
4828# endif
4829 pThis->svga.GCPhysFIFO = 0;
4830 }
4831 return rc;
4832}
4833
4834# ifdef VBOX_WITH_VMSVGA3D
4835
4836/**
4837 * Used by vmsvga3dInfoSurfaceWorker to make the FIFO thread to save one or all
4838 * surfaces to VMSVGA3DMIPMAPLEVEL::pSurfaceData heap buffers.
4839 *
4840 * @param pDevIns The device instance.
4841 * @param pThis The The shared VGA/VMSVGA instance data.
4842 * @param pThisCC The VGA/VMSVGA state for ring-3.
4843 * @param sid Either UINT32_MAX or the ID of a specific surface. If
4844 * UINT32_MAX is used, all surfaces are processed.
4845 */
4846void vmsvgaR33dSurfaceUpdateHeapBuffersOnFifoThread(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC, uint32_t sid)
4847{
4848 vmsvgaR3RunExtCmdOnFifoThread(pDevIns, pThis, pThisCC, VMSVGA_FIFO_EXTCMD_UPDATE_SURFACE_HEAP_BUFFERS, (void *)(uintptr_t)sid,
4849 sid == UINT32_MAX ? 10 * RT_MS_1SEC : RT_MS_1MIN);
4850}
4851
4852
4853/**
4854 * @callback_method_impl{FNDBGFHANDLERDEV, "vmsvga3dsfc"}
4855 */
4856DECLCALLBACK(void) vmsvgaR3Info3dSurface(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4857{
4858 /* There might be a specific surface ID at the start of the
4859 arguments, if not show all surfaces. */
4860 uint32_t sid = UINT32_MAX;
4861 if (pszArgs)
4862 pszArgs = RTStrStripL(pszArgs);
4863 if (pszArgs && RT_C_IS_DIGIT(*pszArgs))
4864 sid = RTStrToUInt32(pszArgs);
4865
4866 /* Verbose or terse display, we default to verbose. */
4867 bool fVerbose = true;
4868 if (RTStrIStr(pszArgs, "terse"))
4869 fVerbose = false;
4870
4871 /* The size of the ascii art (x direction, y is 3/4 of x). */
4872 uint32_t cxAscii = 80;
4873 if (RTStrIStr(pszArgs, "gigantic"))
4874 cxAscii = 300;
4875 else if (RTStrIStr(pszArgs, "huge"))
4876 cxAscii = 180;
4877 else if (RTStrIStr(pszArgs, "big"))
4878 cxAscii = 132;
4879 else if (RTStrIStr(pszArgs, "normal"))
4880 cxAscii = 80;
4881 else if (RTStrIStr(pszArgs, "medium"))
4882 cxAscii = 64;
4883 else if (RTStrIStr(pszArgs, "small"))
4884 cxAscii = 48;
4885 else if (RTStrIStr(pszArgs, "tiny"))
4886 cxAscii = 24;
4887
4888 /* Y invert the image when producing the ASCII art. */
4889 bool fInvY = false;
4890 if (RTStrIStr(pszArgs, "invy"))
4891 fInvY = true;
4892
4893 vmsvga3dInfoSurfaceWorker(pDevIns, PDMDEVINS_2_DATA(pDevIns, PVGASTATE), PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC),
4894 pHlp, sid, fVerbose, cxAscii, fInvY, NULL);
4895}
4896
4897
4898/**
4899 * @callback_method_impl{FNDBGFHANDLERDEV, "vmsvga3dsurf"}
4900 */
4901DECLCALLBACK(void) vmsvgaR3Info3dSurfaceBmp(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4902{
4903 /* pszArg = "sid[>dir]"
4904 * Writes %dir%/info-S-sidI.bmp, where S - sequential bitmap number, I - decimal surface id.
4905 */
4906 char *pszBitmapPath = NULL;
4907 uint32_t sid = UINT32_MAX;
4908 if (pszArgs)
4909 pszArgs = RTStrStripL(pszArgs);
4910 if (pszArgs && RT_C_IS_DIGIT(*pszArgs))
4911 RTStrToUInt32Ex(pszArgs, &pszBitmapPath, 0, &sid);
4912 if ( pszBitmapPath
4913 && *pszBitmapPath == '>')
4914 ++pszBitmapPath;
4915
4916 const bool fVerbose = true;
4917 const uint32_t cxAscii = 0; /* No ASCII */
4918 const bool fInvY = false; /* Do not invert. */
4919 vmsvga3dInfoSurfaceWorker(pDevIns, PDMDEVINS_2_DATA(pDevIns, PVGASTATE), PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC),
4920 pHlp, sid, fVerbose, cxAscii, fInvY, pszBitmapPath);
4921}
4922
4923/**
4924 * @callback_method_impl{FNDBGFHANDLERDEV, "vmsvga3dctx"}
4925 */
4926DECLCALLBACK(void) vmsvgaR3Info3dContext(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4927{
4928 /* There might be a specific surface ID at the start of the
4929 arguments, if not show all contexts. */
4930 uint32_t sid = UINT32_MAX;
4931 if (pszArgs)
4932 pszArgs = RTStrStripL(pszArgs);
4933 if (pszArgs && RT_C_IS_DIGIT(*pszArgs))
4934 sid = RTStrToUInt32(pszArgs);
4935
4936 /* Verbose or terse display, we default to verbose. */
4937 bool fVerbose = true;
4938 if (RTStrIStr(pszArgs, "terse"))
4939 fVerbose = false;
4940
4941 vmsvga3dInfoContextWorker(PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC), pHlp, sid, fVerbose);
4942}
4943# endif /* VBOX_WITH_VMSVGA3D */
4944
4945/**
4946 * @callback_method_impl{FNDBGFHANDLERDEV, "vmsvga"}
4947 */
4948static DECLCALLBACK(void) vmsvgaR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4949{
4950 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
4951 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
4952 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
4953 uint32_t RT_UNTRUSTED_VOLATILE_GUEST *pFIFO = pThisCC->svga.pau32FIFO;
4954 RT_NOREF(pszArgs);
4955
4956 pHlp->pfnPrintf(pHlp, "Extension enabled: %RTbool\n", pThis->svga.fEnabled);
4957 pHlp->pfnPrintf(pHlp, "Configured: %RTbool\n", pThis->svga.fConfigured);
4958 pHlp->pfnPrintf(pHlp, "Base I/O port: %#x\n",
4959 pThis->hIoPortVmSvga != NIL_IOMIOPORTHANDLE
4960 ? PDMDevHlpIoPortGetMappingAddress(pDevIns, pThis->hIoPortVmSvga) : UINT32_MAX);
4961 pHlp->pfnPrintf(pHlp, "FIFO address: %RGp\n", pThis->svga.GCPhysFIFO);
4962 pHlp->pfnPrintf(pHlp, "FIFO size: %u (%#x)\n", pThis->svga.cbFIFO, pThis->svga.cbFIFO);
4963 pHlp->pfnPrintf(pHlp, "FIFO external cmd: %#x\n", pThis->svga.u8FIFOExtCommand);
4964 pHlp->pfnPrintf(pHlp, "FIFO extcmd wakeup: %u\n", pThis->svga.fFifoExtCommandWakeup);
4965 pHlp->pfnPrintf(pHlp, "FIFO min/max: %u/%u\n", pFIFO[SVGA_FIFO_MIN], pFIFO[SVGA_FIFO_MAX]);
4966 pHlp->pfnPrintf(pHlp, "Busy: %#x\n", pThis->svga.fBusy);
4967 pHlp->pfnPrintf(pHlp, "Traces: %RTbool (effective: %RTbool)\n", pThis->svga.fTraces, pThis->svga.fVRAMTracking);
4968 pHlp->pfnPrintf(pHlp, "Guest ID: %#x (%d)\n", pThis->svga.u32GuestId, pThis->svga.u32GuestId);
4969 pHlp->pfnPrintf(pHlp, "IRQ status: %#x\n", pThis->svga.u32IrqStatus);
4970 pHlp->pfnPrintf(pHlp, "IRQ mask: %#x\n", pThis->svga.u32IrqMask);
4971 pHlp->pfnPrintf(pHlp, "Pitch lock: %#x (FIFO:%#x)\n", pThis->svga.u32PitchLock, pFIFO[SVGA_FIFO_PITCHLOCK]);
4972 pHlp->pfnPrintf(pHlp, "Current GMR ID: %#x\n", pThis->svga.u32CurrentGMRId);
4973 pHlp->pfnPrintf(pHlp, "Device Capabilites: %#x\n", pThis->svga.u32DeviceCaps);
4974 pHlp->pfnPrintf(pHlp, "Index reg: %#x\n", pThis->svga.u32IndexReg);
4975 pHlp->pfnPrintf(pHlp, "Action flags: %#x\n", pThis->svga.u32ActionFlags);
4976 pHlp->pfnPrintf(pHlp, "Max display size: %ux%u\n", pThis->svga.u32MaxWidth, pThis->svga.u32MaxHeight);
4977 pHlp->pfnPrintf(pHlp, "Display size: %ux%u %ubpp\n", pThis->svga.uWidth, pThis->svga.uHeight, pThis->svga.uBpp);
4978 pHlp->pfnPrintf(pHlp, "Scanline: %u (%#x)\n", pThis->svga.cbScanline, pThis->svga.cbScanline);
4979 pHlp->pfnPrintf(pHlp, "Viewport position: %ux%u\n", pThis->svga.viewport.x, pThis->svga.viewport.y);
4980 pHlp->pfnPrintf(pHlp, "Viewport size: %ux%u\n", pThis->svga.viewport.cx, pThis->svga.viewport.cy);
4981
4982 pHlp->pfnPrintf(pHlp, "Cursor active: %RTbool\n", pSVGAState->Cursor.fActive);
4983 pHlp->pfnPrintf(pHlp, "Cursor hotspot: %ux%u\n", pSVGAState->Cursor.xHotspot, pSVGAState->Cursor.yHotspot);
4984 pHlp->pfnPrintf(pHlp, "Cursor size: %ux%u\n", pSVGAState->Cursor.width, pSVGAState->Cursor.height);
4985 pHlp->pfnPrintf(pHlp, "Cursor byte size: %u (%#x)\n", pSVGAState->Cursor.cbData, pSVGAState->Cursor.cbData);
4986
4987 pHlp->pfnPrintf(pHlp, "FIFO cursor: state %u, screen %d\n", pFIFO[SVGA_FIFO_CURSOR_ON], pFIFO[SVGA_FIFO_CURSOR_SCREEN_ID]);
4988 pHlp->pfnPrintf(pHlp, "FIFO cursor at: %u,%u\n", pFIFO[SVGA_FIFO_CURSOR_X], pFIFO[SVGA_FIFO_CURSOR_Y]);
4989
4990 pHlp->pfnPrintf(pHlp, "Legacy cursor: ID %u, state %u\n", pThis->svga.uCursorID, pThis->svga.uCursorOn);
4991 pHlp->pfnPrintf(pHlp, "Legacy cursor at: %u,%u\n", pThis->svga.uCursorX, pThis->svga.uCursorY);
4992
4993# ifdef VBOX_WITH_VMSVGA3D
4994 pHlp->pfnPrintf(pHlp, "3D enabled: %RTbool\n", pThis->svga.f3DEnabled);
4995# endif
4996 if (pThisCC->pDrv)
4997 {
4998 pHlp->pfnPrintf(pHlp, "Driver mode: %ux%u %ubpp\n", pThisCC->pDrv->cx, pThisCC->pDrv->cy, pThisCC->pDrv->cBits);
4999 pHlp->pfnPrintf(pHlp, "Driver pitch: %u (%#x)\n", pThisCC->pDrv->cbScanline, pThisCC->pDrv->cbScanline);
5000 }
5001
5002 /* Dump screen information. */
5003 for (unsigned iScreen = 0; iScreen < RT_ELEMENTS(pSVGAState->aScreens); ++iScreen)
5004 {
5005 VMSVGASCREENOBJECT *pScreen = vmsvgaR3GetScreenObject(pThisCC, iScreen);
5006 if (pScreen)
5007 {
5008 pHlp->pfnPrintf(pHlp, "Screen %u defined (ID %u):\n", iScreen, pScreen->idScreen);
5009 pHlp->pfnPrintf(pHlp, " %u x %u x %ubpp @ %u, %u\n", pScreen->cWidth, pScreen->cHeight,
5010 pScreen->cBpp, pScreen->xOrigin, pScreen->yOrigin);
5011 pHlp->pfnPrintf(pHlp, " Pitch %u bytes, VRAM offset %X\n", pScreen->cbPitch, pScreen->offVRAM);
5012 pHlp->pfnPrintf(pHlp, " Flags %X", pScreen->fuScreen);
5013 if (pScreen->fuScreen != SVGA_SCREEN_MUST_BE_SET)
5014 {
5015 pHlp->pfnPrintf(pHlp, " (");
5016 if (pScreen->fuScreen & SVGA_SCREEN_IS_PRIMARY)
5017 pHlp->pfnPrintf(pHlp, " IS_PRIMARY");
5018 if (pScreen->fuScreen & SVGA_SCREEN_FULLSCREEN_HINT)
5019 pHlp->pfnPrintf(pHlp, " FULLSCREEN_HINT");
5020 if (pScreen->fuScreen & SVGA_SCREEN_DEACTIVATE)
5021 pHlp->pfnPrintf(pHlp, " DEACTIVATE");
5022 if (pScreen->fuScreen & SVGA_SCREEN_BLANKING)
5023 pHlp->pfnPrintf(pHlp, " BLANKING");
5024 pHlp->pfnPrintf(pHlp, " )");
5025 }
5026 pHlp->pfnPrintf(pHlp, ", %smodified\n", pScreen->fModified ? "" : "not ");
5027 }
5028 }
5029
5030}
5031
5032/**
5033 * Portion of VMSVGA state which must be loaded oin the FIFO thread.
5034 */
5035static int vmsvgaR3LoadExecFifo(PCPDMDEVHLPR3 pHlp, PVGASTATE pThis, PVGASTATECC pThisCC,
5036 PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
5037{
5038 RT_NOREF(uPass);
5039
5040 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
5041 int rc;
5042
5043 if (uVersion >= VGA_SAVEDSTATE_VERSION_VMSVGA_SCREENS)
5044 {
5045 uint32_t cScreens = 0;
5046 rc = pHlp->pfnSSMGetU32(pSSM, &cScreens);
5047 AssertRCReturn(rc, rc);
5048 AssertLogRelMsgReturn(cScreens <= _64K, /* big enough */
5049 ("cScreens=%#x\n", cScreens),
5050 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
5051
5052 for (uint32_t i = 0; i < cScreens; ++i)
5053 {
5054 VMSVGASCREENOBJECT screen;
5055 RT_ZERO(screen);
5056
5057 rc = pHlp->pfnSSMGetStructEx(pSSM, &screen, sizeof(screen), 0, g_aVMSVGASCREENOBJECTFields, NULL);
5058 AssertLogRelRCReturn(rc, rc);
5059
5060 if (screen.idScreen < RT_ELEMENTS(pSVGAState->aScreens))
5061 {
5062 VMSVGASCREENOBJECT *pScreen = &pSVGAState->aScreens[screen.idScreen];
5063 *pScreen = screen;
5064 pScreen->fModified = true;
5065 }
5066 else
5067 {
5068 LogRel(("VGA: ignored screen object %d\n", screen.idScreen));
5069 }
5070 }
5071 }
5072 else
5073 {
5074 /* Try to setup at least the first screen. */
5075 VMSVGASCREENOBJECT *pScreen = &pSVGAState->aScreens[0];
5076 pScreen->fDefined = true;
5077 pScreen->fModified = true;
5078 pScreen->fuScreen = SVGA_SCREEN_MUST_BE_SET | SVGA_SCREEN_IS_PRIMARY;
5079 pScreen->idScreen = 0;
5080 pScreen->xOrigin = 0;
5081 pScreen->yOrigin = 0;
5082 pScreen->offVRAM = pThis->svga.uScreenOffset;
5083 pScreen->cbPitch = pThis->svga.cbScanline;
5084 pScreen->cWidth = pThis->svga.uWidth;
5085 pScreen->cHeight = pThis->svga.uHeight;
5086 pScreen->cBpp = pThis->svga.uBpp;
5087 }
5088
5089 return VINF_SUCCESS;
5090}
5091
5092/**
5093 * @copydoc FNSSMDEVLOADEXEC
5094 */
5095int vmsvgaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
5096{
5097 RT_NOREF(uPass);
5098 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
5099 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
5100 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
5101 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
5102 int rc;
5103
5104 /* Load our part of the VGAState */
5105 rc = pHlp->pfnSSMGetStructEx(pSSM, &pThis->svga, sizeof(pThis->svga), 0, g_aVGAStateSVGAFields, NULL);
5106 AssertRCReturn(rc, rc);
5107
5108 /* Load the VGA framebuffer. */
5109 AssertCompile(VMSVGA_VGA_FB_BACKUP_SIZE >= _32K);
5110 uint32_t cbVgaFramebuffer = _32K;
5111 if (uVersion >= VGA_SAVEDSTATE_VERSION_VMSVGA_VGA_FB_FIX)
5112 {
5113 rc = pHlp->pfnSSMGetU32(pSSM, &cbVgaFramebuffer);
5114 AssertRCReturn(rc, rc);
5115 AssertLogRelMsgReturn(cbVgaFramebuffer <= _4M && cbVgaFramebuffer >= _32K && RT_IS_POWER_OF_TWO(cbVgaFramebuffer),
5116 ("cbVgaFramebuffer=%#x - expected 32KB..4MB, power of two\n", cbVgaFramebuffer),
5117 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
5118 AssertCompile(VMSVGA_VGA_FB_BACKUP_SIZE <= _4M);
5119 AssertCompile(RT_IS_POWER_OF_TWO(VMSVGA_VGA_FB_BACKUP_SIZE));
5120 }
5121 rc = pHlp->pfnSSMGetMem(pSSM, pThisCC->svga.pbVgaFrameBufferR3, RT_MIN(cbVgaFramebuffer, VMSVGA_VGA_FB_BACKUP_SIZE));
5122 AssertRCReturn(rc, rc);
5123 if (cbVgaFramebuffer > VMSVGA_VGA_FB_BACKUP_SIZE)
5124 pHlp->pfnSSMSkip(pSSM, cbVgaFramebuffer - VMSVGA_VGA_FB_BACKUP_SIZE);
5125 else if (cbVgaFramebuffer < VMSVGA_VGA_FB_BACKUP_SIZE)
5126 RT_BZERO(&pThisCC->svga.pbVgaFrameBufferR3[cbVgaFramebuffer], VMSVGA_VGA_FB_BACKUP_SIZE - cbVgaFramebuffer);
5127
5128 /* Load the VMSVGA state. */
5129 rc = pHlp->pfnSSMGetStructEx(pSSM, pSVGAState, sizeof(*pSVGAState), 0, g_aVMSVGAR3STATEFields, NULL);
5130 AssertRCReturn(rc, rc);
5131
5132 /* Load the active cursor bitmaps. */
5133 if (pSVGAState->Cursor.fActive)
5134 {
5135 pSVGAState->Cursor.pData = RTMemAlloc(pSVGAState->Cursor.cbData);
5136 AssertReturn(pSVGAState->Cursor.pData, VERR_NO_MEMORY);
5137
5138 rc = pHlp->pfnSSMGetMem(pSSM, pSVGAState->Cursor.pData, pSVGAState->Cursor.cbData);
5139 AssertRCReturn(rc, rc);
5140 }
5141
5142 /* Load the GMR state. */
5143 uint32_t cGMR = 256; /* Hardcoded in previous saved state versions. */
5144 if (uVersion >= VGA_SAVEDSTATE_VERSION_VMSVGA_GMR_COUNT)
5145 {
5146 rc = pHlp->pfnSSMGetU32(pSSM, &cGMR);
5147 AssertRCReturn(rc, rc);
5148 /* Numbers of GMRs was never less than 256. 1MB is a large arbitrary limit. */
5149 AssertLogRelMsgReturn(cGMR <= _1M && cGMR >= 256,
5150 ("cGMR=%#x - expected 256B..1MB\n", cGMR),
5151 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
5152 }
5153
5154 if (pThis->svga.cGMR != cGMR)
5155 {
5156 /* Reallocate GMR array. */
5157 Assert(pSVGAState->paGMR != NULL);
5158 RTMemFree(pSVGAState->paGMR);
5159 pSVGAState->paGMR = (PGMR)RTMemAllocZ(cGMR * sizeof(GMR));
5160 AssertReturn(pSVGAState->paGMR, VERR_NO_MEMORY);
5161 pThis->svga.cGMR = cGMR;
5162 }
5163
5164 for (uint32_t i = 0; i < cGMR; ++i)
5165 {
5166 PGMR pGMR = &pSVGAState->paGMR[i];
5167
5168 rc = pHlp->pfnSSMGetStructEx(pSSM, pGMR, sizeof(*pGMR), 0, g_aGMRFields, NULL);
5169 AssertRCReturn(rc, rc);
5170
5171 if (pGMR->numDescriptors)
5172 {
5173 Assert(pGMR->cMaxPages || pGMR->cbTotal);
5174 pGMR->paDesc = (PVMSVGAGMRDESCRIPTOR)RTMemAllocZ(pGMR->numDescriptors * sizeof(VMSVGAGMRDESCRIPTOR));
5175 AssertReturn(pGMR->paDesc, VERR_NO_MEMORY);
5176
5177 for (uint32_t j = 0; j < pGMR->numDescriptors; ++j)
5178 {
5179 rc = pHlp->pfnSSMGetStructEx(pSSM, &pGMR->paDesc[j], sizeof(pGMR->paDesc[j]), 0, g_aVMSVGAGMRDESCRIPTORFields, NULL);
5180 AssertRCReturn(rc, rc);
5181 }
5182 }
5183 }
5184
5185# ifdef RT_OS_DARWIN /** @todo r=bird: this is normally done on the EMT, so for DARWIN we do that when loading saved state too now. See DevVGA-SVGA3d-shared.h. */
5186 vmsvga3dPowerOn(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC));
5187# endif
5188
5189 VMSVGA_STATE_LOAD LoadState;
5190 LoadState.pSSM = pSSM;
5191 LoadState.uVersion = uVersion;
5192 LoadState.uPass = uPass;
5193 rc = vmsvgaR3RunExtCmdOnFifoThread(pDevIns, pThis, pThisCC, VMSVGA_FIFO_EXTCMD_LOADSTATE, &LoadState, RT_INDEFINITE_WAIT);
5194 AssertLogRelRCReturn(rc, rc);
5195
5196 return VINF_SUCCESS;
5197}
5198
5199/**
5200 * Reinit the video mode after the state has been loaded.
5201 */
5202int vmsvgaR3LoadDone(PPDMDEVINS pDevIns)
5203{
5204 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
5205 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
5206 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
5207
5208 /* Set the active cursor. */
5209 if (pSVGAState->Cursor.fActive)
5210 {
5211 /* We don't store the alpha flag, but we can take a guess that if
5212 * the old register interface was used, the cursor was B&W.
5213 */
5214 bool fAlpha = pThis->svga.uCursorOn ? false : true;
5215
5216 int rc = pThisCC->pDrv->pfnVBVAMousePointerShape(pThisCC->pDrv,
5217 true /*fVisible*/,
5218 fAlpha,
5219 pSVGAState->Cursor.xHotspot,
5220 pSVGAState->Cursor.yHotspot,
5221 pSVGAState->Cursor.width,
5222 pSVGAState->Cursor.height,
5223 pSVGAState->Cursor.pData);
5224 AssertRC(rc);
5225
5226 if (pThis->svga.uCursorOn)
5227 pThisCC->pDrv->pfnVBVAReportCursorPosition(pThisCC->pDrv, VBVA_CURSOR_VALID_DATA, SVGA_ID_INVALID, pThis->svga.uCursorX, pThis->svga.uCursorY);
5228 }
5229
5230 /* If the VRAM handler should not be registered, we have to explicitly
5231 * unregister it here!
5232 */
5233 if (!pThis->svga.fVRAMTracking)
5234 {
5235 vgaR3UnregisterVRAMHandler(pDevIns, pThis);
5236 }
5237
5238 /* Let the FIFO thread deal with changing the mode. */
5239 ASMAtomicOrU32(&pThis->svga.u32ActionFlags, VMSVGA_ACTION_CHANGEMODE);
5240
5241 return VINF_SUCCESS;
5242}
5243
5244/**
5245 * Portion of SVGA state which must be saved in the FIFO thread.
5246 */
5247static int vmsvgaR3SaveExecFifo(PCPDMDEVHLPR3 pHlp, PVGASTATECC pThisCC, PSSMHANDLE pSSM)
5248{
5249 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
5250 int rc;
5251
5252 /* Save the screen objects. */
5253 /* Count defined screen object. */
5254 uint32_t cScreens = 0;
5255 for (uint32_t i = 0; i < RT_ELEMENTS(pSVGAState->aScreens); ++i)
5256 {
5257 if (pSVGAState->aScreens[i].fDefined)
5258 ++cScreens;
5259 }
5260
5261 rc = pHlp->pfnSSMPutU32(pSSM, cScreens);
5262 AssertLogRelRCReturn(rc, rc);
5263
5264 for (uint32_t i = 0; i < cScreens; ++i)
5265 {
5266 VMSVGASCREENOBJECT *pScreen = &pSVGAState->aScreens[i];
5267
5268 rc = pHlp->pfnSSMPutStructEx(pSSM, pScreen, sizeof(*pScreen), 0, g_aVMSVGASCREENOBJECTFields, NULL);
5269 AssertLogRelRCReturn(rc, rc);
5270 }
5271 return VINF_SUCCESS;
5272}
5273
5274/**
5275 * @copydoc FNSSMDEVSAVEEXEC
5276 */
5277int vmsvgaR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5278{
5279 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
5280 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
5281 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
5282 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
5283 int rc;
5284
5285 /* Save our part of the VGAState */
5286 rc = pHlp->pfnSSMPutStructEx(pSSM, &pThis->svga, sizeof(pThis->svga), 0, g_aVGAStateSVGAFields, NULL);
5287 AssertLogRelRCReturn(rc, rc);
5288
5289 /* Save the framebuffer backup. */
5290 rc = pHlp->pfnSSMPutU32(pSSM, VMSVGA_VGA_FB_BACKUP_SIZE);
5291 rc = pHlp->pfnSSMPutMem(pSSM, pThisCC->svga.pbVgaFrameBufferR3, VMSVGA_VGA_FB_BACKUP_SIZE);
5292 AssertLogRelRCReturn(rc, rc);
5293
5294 /* Save the VMSVGA state. */
5295 rc = pHlp->pfnSSMPutStructEx(pSSM, pSVGAState, sizeof(*pSVGAState), 0, g_aVMSVGAR3STATEFields, NULL);
5296 AssertLogRelRCReturn(rc, rc);
5297
5298 /* Save the active cursor bitmaps. */
5299 if (pSVGAState->Cursor.fActive)
5300 {
5301 rc = pHlp->pfnSSMPutMem(pSSM, pSVGAState->Cursor.pData, pSVGAState->Cursor.cbData);
5302 AssertLogRelRCReturn(rc, rc);
5303 }
5304
5305 /* Save the GMR state */
5306 rc = pHlp->pfnSSMPutU32(pSSM, pThis->svga.cGMR);
5307 AssertLogRelRCReturn(rc, rc);
5308 for (uint32_t i = 0; i < pThis->svga.cGMR; ++i)
5309 {
5310 PGMR pGMR = &pSVGAState->paGMR[i];
5311
5312 rc = pHlp->pfnSSMPutStructEx(pSSM, pGMR, sizeof(*pGMR), 0, g_aGMRFields, NULL);
5313 AssertLogRelRCReturn(rc, rc);
5314
5315 for (uint32_t j = 0; j < pGMR->numDescriptors; ++j)
5316 {
5317 rc = pHlp->pfnSSMPutStructEx(pSSM, &pGMR->paDesc[j], sizeof(pGMR->paDesc[j]), 0, g_aVMSVGAGMRDESCRIPTORFields, NULL);
5318 AssertLogRelRCReturn(rc, rc);
5319 }
5320 }
5321
5322 /*
5323 * Must save some state (3D in particular) in the FIFO thread.
5324 */
5325 rc = vmsvgaR3RunExtCmdOnFifoThread(pDevIns, pThis, pThisCC, VMSVGA_FIFO_EXTCMD_SAVESTATE, pSSM, RT_INDEFINITE_WAIT);
5326 AssertLogRelRCReturn(rc, rc);
5327
5328 return VINF_SUCCESS;
5329}
5330
5331/**
5332 * Destructor for PVMSVGAR3STATE structure.
5333 *
5334 * @param pThis The shared VGA/VMSVGA instance data.
5335 * @param pSVGAState Pointer to the structure. It is not deallocated.
5336 */
5337static void vmsvgaR3StateTerm(PVGASTATE pThis, PVMSVGAR3STATE pSVGAState)
5338{
5339# ifndef VMSVGA_USE_EMT_HALT_CODE
5340 if (pSVGAState->hBusyDelayedEmts != NIL_RTSEMEVENTMULTI)
5341 {
5342 RTSemEventMultiDestroy(pSVGAState->hBusyDelayedEmts);
5343 pSVGAState->hBusyDelayedEmts = NIL_RTSEMEVENT;
5344 }
5345# endif
5346
5347 if (pSVGAState->Cursor.fActive)
5348 {
5349 RTMemFreeZ(pSVGAState->Cursor.pData, pSVGAState->Cursor.cbData);
5350 pSVGAState->Cursor.pData = NULL;
5351 pSVGAState->Cursor.fActive = false;
5352 }
5353
5354 if (pSVGAState->paGMR)
5355 {
5356 for (unsigned i = 0; i < pThis->svga.cGMR; ++i)
5357 if (pSVGAState->paGMR[i].paDesc)
5358 RTMemFree(pSVGAState->paGMR[i].paDesc);
5359
5360 RTMemFree(pSVGAState->paGMR);
5361 pSVGAState->paGMR = NULL;
5362 }
5363
5364 if (RTCritSectIsInitialized(&pSVGAState->CritSectCmdBuf))
5365 {
5366 RTCritSectEnter(&pSVGAState->CritSectCmdBuf);
5367 for (unsigned i = 0; i < RT_ELEMENTS(pSVGAState->apCmdBufCtxs); ++i)
5368 {
5369 vmsvgaR3CmdBufCtxTerm(pSVGAState->apCmdBufCtxs[i]);
5370 pSVGAState->apCmdBufCtxs[i] = NULL;
5371 }
5372 vmsvgaR3CmdBufCtxTerm(&pSVGAState->CmdBufCtxDC);
5373 RTCritSectLeave(&pSVGAState->CritSectCmdBuf);
5374 RTCritSectDelete(&pSVGAState->CritSectCmdBuf);
5375 }
5376}
5377
5378/**
5379 * Constructor for PVMSVGAR3STATE structure.
5380 *
5381 * @returns VBox status code.
5382 * @param pThis The shared VGA/VMSVGA instance data.
5383 * @param pSVGAState Pointer to the structure. It is already allocated.
5384 */
5385static int vmsvgaR3StateInit(PVGASTATE pThis, PVMSVGAR3STATE pSVGAState)
5386{
5387 int rc = VINF_SUCCESS;
5388 RT_ZERO(*pSVGAState);
5389
5390 pSVGAState->paGMR = (PGMR)RTMemAllocZ(pThis->svga.cGMR * sizeof(GMR));
5391 AssertReturn(pSVGAState->paGMR, VERR_NO_MEMORY);
5392
5393# ifndef VMSVGA_USE_EMT_HALT_CODE
5394 /* Create semaphore for delaying EMTs wait for the FIFO to stop being busy. */
5395 rc = RTSemEventMultiCreate(&pSVGAState->hBusyDelayedEmts);
5396 AssertRCReturn(rc, rc);
5397# endif
5398
5399 rc = RTCritSectInit(&pSVGAState->CritSectCmdBuf);
5400 AssertRCReturn(rc, rc);
5401
5402 vmsvgaR3CmdBufCtxInit(&pSVGAState->CmdBufCtxDC);
5403 return rc;
5404}
5405
5406/**
5407 * Initializes the host capabilities: device and FIFO.
5408 *
5409 * @returns VBox status code.
5410 * @param pThis The shared VGA/VMSVGA instance data.
5411 * @param pThisCC The VGA/VMSVGA state for ring-3.
5412 */
5413static void vmsvgaR3InitCaps(PVGASTATE pThis, PVGASTATECC pThisCC)
5414{
5415 /* Device caps. */
5416 pThis->svga.u32DeviceCaps = SVGA_CAP_GMR
5417 | SVGA_CAP_GMR2
5418 | SVGA_CAP_CURSOR
5419 | SVGA_CAP_CURSOR_BYPASS
5420 | SVGA_CAP_CURSOR_BYPASS_2
5421 | SVGA_CAP_EXTENDED_FIFO
5422 | SVGA_CAP_IRQMASK
5423 | SVGA_CAP_PITCHLOCK
5424 | SVGA_CAP_RECT_COPY
5425 | SVGA_CAP_TRACES
5426 | SVGA_CAP_SCREEN_OBJECT_2
5427 | SVGA_CAP_ALPHA_CURSOR;
5428
5429 /* VGPU10 capabilities. */
5430 if (pThis->fVMSVGA10)
5431 {
5432 pThis->svga.u32DeviceCaps |= SVGA_CAP_COMMAND_BUFFERS /* Enable register based command buffer submission. */
5433// | SVGA_CAP_CMD_BUFFERS_2 /* Support for SVGA_REG_CMD_PREPEND_LOW/HIGH */
5434// | SVGA_CAP_GBOBJECTS /* Enable guest-backed objects and surfaces. */
5435// | SVGA_CAP_CMD_BUFFERS_3 /* AKA SVGA_CAP_DX. Enable support for DX commands, and command buffers in a mob. */
5436 ;
5437 }
5438
5439# ifdef VBOX_WITH_VMSVGA3D
5440 pThis->svga.u32DeviceCaps |= SVGA_CAP_3D;
5441# endif
5442
5443 /* Clear the FIFO. */
5444 RT_BZERO(pThisCC->svga.pau32FIFO, pThis->svga.cbFIFO);
5445
5446 /* Setup FIFO capabilities. */
5447 pThisCC->svga.pau32FIFO[SVGA_FIFO_CAPABILITIES] = SVGA_FIFO_CAP_FENCE
5448 | SVGA_FIFO_CAP_PITCHLOCK
5449 | SVGA_FIFO_CAP_CURSOR_BYPASS_3
5450 | SVGA_FIFO_CAP_RESERVE
5451 | SVGA_FIFO_CAP_GMR2
5452 | SVGA_FIFO_CAP_3D_HWVERSION_REVISED
5453 | SVGA_FIFO_CAP_SCREEN_OBJECT_2;
5454
5455 /* Valid with SVGA_FIFO_CAP_SCREEN_OBJECT_2 */
5456 pThisCC->svga.pau32FIFO[SVGA_FIFO_CURSOR_SCREEN_ID] = SVGA_ID_INVALID;
5457}
5458
5459# ifdef VBOX_WITH_VMSVGA3D
5460/** Names for the vmsvga 3d capabilities, prefixed with format type hint char. */
5461static const char * const g_apszVmSvgaDevCapNames[] =
5462{
5463 "x3D", /* = 0 */
5464 "xMAX_LIGHTS",
5465 "xMAX_TEXTURES",
5466 "xMAX_CLIP_PLANES",
5467 "xVERTEX_SHADER_VERSION",
5468 "xVERTEX_SHADER",
5469 "xFRAGMENT_SHADER_VERSION",
5470 "xFRAGMENT_SHADER",
5471 "xMAX_RENDER_TARGETS",
5472 "xS23E8_TEXTURES",
5473 "xS10E5_TEXTURES",
5474 "xMAX_FIXED_VERTEXBLEND",
5475 "xD16_BUFFER_FORMAT",
5476 "xD24S8_BUFFER_FORMAT",
5477 "xD24X8_BUFFER_FORMAT",
5478 "xQUERY_TYPES",
5479 "xTEXTURE_GRADIENT_SAMPLING",
5480 "rMAX_POINT_SIZE",
5481 "xMAX_SHADER_TEXTURES",
5482 "xMAX_TEXTURE_WIDTH",
5483 "xMAX_TEXTURE_HEIGHT",
5484 "xMAX_VOLUME_EXTENT",
5485 "xMAX_TEXTURE_REPEAT",
5486 "xMAX_TEXTURE_ASPECT_RATIO",
5487 "xMAX_TEXTURE_ANISOTROPY",
5488 "xMAX_PRIMITIVE_COUNT",
5489 "xMAX_VERTEX_INDEX",
5490 "xMAX_VERTEX_SHADER_INSTRUCTIONS",
5491 "xMAX_FRAGMENT_SHADER_INSTRUCTIONS",
5492 "xMAX_VERTEX_SHADER_TEMPS",
5493 "xMAX_FRAGMENT_SHADER_TEMPS",
5494 "xTEXTURE_OPS",
5495 "xSURFACEFMT_X8R8G8B8",
5496 "xSURFACEFMT_A8R8G8B8",
5497 "xSURFACEFMT_A2R10G10B10",
5498 "xSURFACEFMT_X1R5G5B5",
5499 "xSURFACEFMT_A1R5G5B5",
5500 "xSURFACEFMT_A4R4G4B4",
5501 "xSURFACEFMT_R5G6B5",
5502 "xSURFACEFMT_LUMINANCE16",
5503 "xSURFACEFMT_LUMINANCE8_ALPHA8",
5504 "xSURFACEFMT_ALPHA8",
5505 "xSURFACEFMT_LUMINANCE8",
5506 "xSURFACEFMT_Z_D16",
5507 "xSURFACEFMT_Z_D24S8",
5508 "xSURFACEFMT_Z_D24X8",
5509 "xSURFACEFMT_DXT1",
5510 "xSURFACEFMT_DXT2",
5511 "xSURFACEFMT_DXT3",
5512 "xSURFACEFMT_DXT4",
5513 "xSURFACEFMT_DXT5",
5514 "xSURFACEFMT_BUMPX8L8V8U8",
5515 "xSURFACEFMT_A2W10V10U10",
5516 "xSURFACEFMT_BUMPU8V8",
5517 "xSURFACEFMT_Q8W8V8U8",
5518 "xSURFACEFMT_CxV8U8",
5519 "xSURFACEFMT_R_S10E5",
5520 "xSURFACEFMT_R_S23E8",
5521 "xSURFACEFMT_RG_S10E5",
5522 "xSURFACEFMT_RG_S23E8",
5523 "xSURFACEFMT_ARGB_S10E5",
5524 "xSURFACEFMT_ARGB_S23E8",
5525 "xMISSING62",
5526 "xMAX_VERTEX_SHADER_TEXTURES",
5527 "xMAX_SIMULTANEOUS_RENDER_TARGETS",
5528 "xSURFACEFMT_V16U16",
5529 "xSURFACEFMT_G16R16",
5530 "xSURFACEFMT_A16B16G16R16",
5531 "xSURFACEFMT_UYVY",
5532 "xSURFACEFMT_YUY2",
5533 "xMULTISAMPLE_NONMASKABLESAMPLES",
5534 "xMULTISAMPLE_MASKABLESAMPLES",
5535 "xALPHATOCOVERAGE",
5536 "xSUPERSAMPLE",
5537 "xAUTOGENMIPMAPS",
5538 "xSURFACEFMT_NV12",
5539 "xSURFACEFMT_AYUV",
5540 "xMAX_CONTEXT_IDS",
5541 "xMAX_SURFACE_IDS",
5542 "xSURFACEFMT_Z_DF16",
5543 "xSURFACEFMT_Z_DF24",
5544 "xSURFACEFMT_Z_D24S8_INT",
5545 "xSURFACEFMT_ATI1",
5546 "xSURFACEFMT_ATI2", /* 83 */
5547 "xDEAD1",
5548 "xVIDEO_DECODE",
5549 "xVIDEO_PROCESS",
5550 "xLINE_AA",
5551 "xLINE_STIPPLE",
5552 "rMAX_LINE_WIDTH",
5553 "rMAX_AA_LINE_WIDTH",
5554 "xSURFACEFMT_YV12",
5555 "xLOGICOPS",
5556 "xTS_COLOR_KEY",
5557 "xDEAD2",
5558 "xDX",
5559 "xMAX_TEXTURE_ARRAY_SIZE",
5560 "xDX_MAX_VERTEXBUFFERS",
5561 "xDX_MAX_CONSTANT_BUFFERS",
5562 "xDX_PROVOKING_VERTEX",
5563 "xDXFMT_X8R8G8B8",
5564 "xDXFMT_A8R8G8B8",
5565 "xDXFMT_R5G6B5",
5566 "xDXFMT_X1R5G5B5",
5567 "xDXFMT_A1R5G5B5",
5568 "xDXFMT_A4R4G4B4",
5569 "xDXFMT_Z_D32",
5570 "xDXFMT_Z_D16",
5571 "xDXFMT_Z_D24S8",
5572 "xDXFMT_Z_D15S1",
5573 "xDXFMT_LUMINANCE8",
5574 "xDXFMT_LUMINANCE4_ALPHA4",
5575 "xDXFMT_LUMINANCE16",
5576 "xDXFMT_LUMINANCE8_ALPHA8",
5577 "xDXFMT_DXT1",
5578 "xDXFMT_DXT2",
5579 "xDXFMT_DXT3",
5580 "xDXFMT_DXT4",
5581 "xDXFMT_DXT5",
5582 "xDXFMT_BUMPU8V8",
5583 "xDXFMT_BUMPL6V5U5",
5584 "xDXFMT_BUMPX8L8V8U8",
5585 "xDXFMT_FORMAT_DEAD1",
5586 "xDXFMT_ARGB_S10E5",
5587 "xDXFMT_ARGB_S23E8",
5588 "xDXFMT_A2R10G10B10",
5589 "xDXFMT_V8U8",
5590 "xDXFMT_Q8W8V8U8",
5591 "xDXFMT_CxV8U8",
5592 "xDXFMT_X8L8V8U8",
5593 "xDXFMT_A2W10V10U10",
5594 "xDXFMT_ALPHA8",
5595 "xDXFMT_R_S10E5",
5596 "xDXFMT_R_S23E8",
5597 "xDXFMT_RG_S10E5",
5598 "xDXFMT_RG_S23E8",
5599 "xDXFMT_BUFFER",
5600 "xDXFMT_Z_D24X8",
5601 "xDXFMT_V16U16",
5602 "xDXFMT_G16R16",
5603 "xDXFMT_A16B16G16R16",
5604 "xDXFMT_UYVY",
5605 "xDXFMT_YUY2",
5606 "xDXFMT_NV12",
5607 "xDXFMT_AYUV",
5608 "xDXFMT_R32G32B32A32_TYPELESS",
5609 "xDXFMT_R32G32B32A32_UINT",
5610 "xDXFMT_R32G32B32A32_SINT",
5611 "xDXFMT_R32G32B32_TYPELESS",
5612 "xDXFMT_R32G32B32_FLOAT",
5613 "xDXFMT_R32G32B32_UINT",
5614 "xDXFMT_R32G32B32_SINT",
5615 "xDXFMT_R16G16B16A16_TYPELESS",
5616 "xDXFMT_R16G16B16A16_UINT",
5617 "xDXFMT_R16G16B16A16_SNORM",
5618 "xDXFMT_R16G16B16A16_SINT",
5619 "xDXFMT_R32G32_TYPELESS",
5620 "xDXFMT_R32G32_UINT",
5621 "xDXFMT_R32G32_SINT",
5622 "xDXFMT_R32G8X24_TYPELESS",
5623 "xDXFMT_D32_FLOAT_S8X24_UINT",
5624 "xDXFMT_R32_FLOAT_X8X24_TYPELESS",
5625 "xDXFMT_X32_TYPELESS_G8X24_UINT",
5626 "xDXFMT_R10G10B10A2_TYPELESS",
5627 "xDXFMT_R10G10B10A2_UINT",
5628 "xDXFMT_R11G11B10_FLOAT",
5629 "xDXFMT_R8G8B8A8_TYPELESS",
5630 "xDXFMT_R8G8B8A8_UNORM",
5631 "xDXFMT_R8G8B8A8_UNORM_SRGB",
5632 "xDXFMT_R8G8B8A8_UINT",
5633 "xDXFMT_R8G8B8A8_SINT",
5634 "xDXFMT_R16G16_TYPELESS",
5635 "xDXFMT_R16G16_UINT",
5636 "xDXFMT_R16G16_SINT",
5637 "xDXFMT_R32_TYPELESS",
5638 "xDXFMT_D32_FLOAT",
5639 "xDXFMT_R32_UINT",
5640 "xDXFMT_R32_SINT",
5641 "xDXFMT_R24G8_TYPELESS",
5642 "xDXFMT_D24_UNORM_S8_UINT",
5643 "xDXFMT_R24_UNORM_X8_TYPELESS",
5644 "xDXFMT_X24_TYPELESS_G8_UINT",
5645 "xDXFMT_R8G8_TYPELESS",
5646 "xDXFMT_R8G8_UNORM",
5647 "xDXFMT_R8G8_UINT",
5648 "xDXFMT_R8G8_SINT",
5649 "xDXFMT_R16_TYPELESS",
5650 "xDXFMT_R16_UNORM",
5651 "xDXFMT_R16_UINT",
5652 "xDXFMT_R16_SNORM",
5653 "xDXFMT_R16_SINT",
5654 "xDXFMT_R8_TYPELESS",
5655 "xDXFMT_R8_UNORM",
5656 "xDXFMT_R8_UINT",
5657 "xDXFMT_R8_SNORM",
5658 "xDXFMT_R8_SINT",
5659 "xDXFMT_P8",
5660 "xDXFMT_R9G9B9E5_SHAREDEXP",
5661 "xDXFMT_R8G8_B8G8_UNORM",
5662 "xDXFMT_G8R8_G8B8_UNORM",
5663 "xDXFMT_BC1_TYPELESS",
5664 "xDXFMT_BC1_UNORM_SRGB",
5665 "xDXFMT_BC2_TYPELESS",
5666 "xDXFMT_BC2_UNORM_SRGB",
5667 "xDXFMT_BC3_TYPELESS",
5668 "xDXFMT_BC3_UNORM_SRGB",
5669 "xDXFMT_BC4_TYPELESS",
5670 "xDXFMT_ATI1",
5671 "xDXFMT_BC4_SNORM",
5672 "xDXFMT_BC5_TYPELESS",
5673 "xDXFMT_ATI2",
5674 "xDXFMT_BC5_SNORM",
5675 "xDXFMT_R10G10B10_XR_BIAS_A2_UNORM",
5676 "xDXFMT_B8G8R8A8_TYPELESS",
5677 "xDXFMT_B8G8R8A8_UNORM_SRGB",
5678 "xDXFMT_B8G8R8X8_TYPELESS",
5679 "xDXFMT_B8G8R8X8_UNORM_SRGB",
5680 "xDXFMT_Z_DF16",
5681 "xDXFMT_Z_DF24",
5682 "xDXFMT_Z_D24S8_INT",
5683 "xDXFMT_YV12",
5684 "xDXFMT_R32G32B32A32_FLOAT",
5685 "xDXFMT_R16G16B16A16_FLOAT",
5686 "xDXFMT_R16G16B16A16_UNORM",
5687 "xDXFMT_R32G32_FLOAT",
5688 "xDXFMT_R10G10B10A2_UNORM",
5689 "xDXFMT_R8G8B8A8_SNORM",
5690 "xDXFMT_R16G16_FLOAT",
5691 "xDXFMT_R16G16_UNORM",
5692 "xDXFMT_R16G16_SNORM",
5693 "xDXFMT_R32_FLOAT",
5694 "xDXFMT_R8G8_SNORM",
5695 "xDXFMT_R16_FLOAT",
5696 "xDXFMT_D16_UNORM",
5697 "xDXFMT_A8_UNORM",
5698 "xDXFMT_BC1_UNORM",
5699 "xDXFMT_BC2_UNORM",
5700 "xDXFMT_BC3_UNORM",
5701 "xDXFMT_B5G6R5_UNORM",
5702 "xDXFMT_B5G5R5A1_UNORM",
5703 "xDXFMT_B8G8R8A8_UNORM",
5704 "xDXFMT_B8G8R8X8_UNORM",
5705 "xDXFMT_BC4_UNORM",
5706 "xDXFMT_BC5_UNORM",
5707};
5708
5709/**
5710 * Initializes the host 3D capabilities and writes them to FIFO memory.
5711 *
5712 * @returns VBox status code.
5713 * @param pThis The shared VGA/VMSVGA instance data.
5714 * @param pThisCC The VGA/VMSVGA state for ring-3.
5715 */
5716static void vmsvgaR3InitFifo3DCaps(PVGASTATE pThis, PVGASTATECC pThisCC)
5717{
5718 /* Query the capabilities and store them in the pThis->svga.au32DevCaps array. */
5719 bool const fSavedBuffering = RTLogRelSetBuffering(true);
5720
5721 for (unsigned i = 0; i < RT_ELEMENTS(pThis->svga.au32DevCaps); ++i)
5722 {
5723 uint32_t val = 0;
5724 int rc = vmsvga3dQueryCaps(pThisCC, i, &val);
5725 if (RT_SUCCESS(rc))
5726 pThis->svga.au32DevCaps[i] = val;
5727 else
5728 pThis->svga.au32DevCaps[i] = 0;
5729
5730 /* LogRel the capability value. */
5731 if (i < RT_ELEMENTS(g_apszVmSvgaDevCapNames))
5732 {
5733 if (RT_SUCCESS(rc))
5734 {
5735 if (g_apszVmSvgaDevCapNames[i][0] == 'x')
5736 LogRel(("VMSVGA3d: cap[%u]=%#010x {%s}\n", i, val, &g_apszVmSvgaDevCapNames[i][1]));
5737 else
5738 {
5739 float const fval = *(float *)&val;
5740 LogRel(("VMSVGA3d: cap[%u]=" FLOAT_FMT_STR " {%s}\n", i, FLOAT_FMT_ARGS(fval), &g_apszVmSvgaDevCapNames[i][1]));
5741 }
5742 }
5743 else
5744 LogRel(("VMSVGA3d: cap[%u]=failed rc=%Rrc {%s}\n", i, rc, &g_apszVmSvgaDevCapNames[i][1]));
5745 }
5746 else
5747 LogRel(("VMSVGA3d: new cap[%u]=%#010x rc=%Rrc\n", i, val, rc));
5748 }
5749
5750 RTLogRelSetBuffering(fSavedBuffering);
5751
5752 /* 3d hardware version; latest and greatest */
5753 pThisCC->svga.pau32FIFO[SVGA_FIFO_3D_HWVERSION_REVISED] = SVGA3D_HWVERSION_CURRENT;
5754 pThisCC->svga.pau32FIFO[SVGA_FIFO_3D_HWVERSION] = SVGA3D_HWVERSION_CURRENT;
5755
5756 /* Fill out 3d capabilities up to SVGA3D_DEVCAP_SURFACEFMT_ATI2 in the FIFO memory.
5757 * SVGA3D_DEVCAP_SURFACEFMT_ATI2 is the last capabiltiy for pre-SVGA_CAP_GBOBJECTS hardware.
5758 * If the VMSVGA device supports SVGA_CAP_GBOBJECTS capability, then the guest has to use SVGA_REG_DEV_CAP
5759 * register to query the devcaps. Older guests will still try to read the devcaps from FIFO.
5760 */
5761 SVGA3dCapsRecord *pCaps;
5762 SVGA3dCapPair *pData;
5763
5764 pCaps = (SVGA3dCapsRecord *)&pThisCC->svga.pau32FIFO[SVGA_FIFO_3D_CAPS];
5765 pCaps->header.type = SVGA3DCAPS_RECORD_DEVCAPS;
5766 pData = (SVGA3dCapPair *)&pCaps->data;
5767
5768 AssertCompile(SVGA3D_DEVCAP_DEAD1 == SVGA3D_DEVCAP_SURFACEFMT_ATI2 + 1);
5769 for (unsigned i = 0; i < SVGA3D_DEVCAP_DEAD1; ++i)
5770 {
5771 pData[i][0] = i;
5772 pData[i][1] = pThis->svga.au32DevCaps[i];
5773 }
5774 pCaps->header.length = (sizeof(pCaps->header) + SVGA3D_DEVCAP_DEAD1 * sizeof(SVGA3dCapPair)) / sizeof(uint32_t);
5775 pCaps = (SVGA3dCapsRecord *)((uint32_t *)pCaps + pCaps->header.length);
5776
5777 /* Mark end of record array (a zero word). */
5778 pCaps->header.length = 0;
5779}
5780
5781# endif
5782
5783/**
5784 * Resets the SVGA hardware state
5785 *
5786 * @returns VBox status code.
5787 * @param pDevIns The device instance.
5788 */
5789int vmsvgaR3Reset(PPDMDEVINS pDevIns)
5790{
5791 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
5792 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
5793 PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
5794
5795 /* Reset before init? */
5796 if (!pSVGAState)
5797 return VINF_SUCCESS;
5798
5799 Log(("vmsvgaR3Reset\n"));
5800
5801 /* Reset the FIFO processing as well as the 3d state (if we have one). */
5802 pThisCC->svga.pau32FIFO[SVGA_FIFO_NEXT_CMD] = pThisCC->svga.pau32FIFO[SVGA_FIFO_STOP] = 0; /** @todo should probably let the FIFO thread do this ... */
5803 int rc = vmsvgaR3RunExtCmdOnFifoThread(pDevIns, pThis, pThisCC, VMSVGA_FIFO_EXTCMD_RESET, NULL /*pvParam*/, 10000 /*ms*/);
5804
5805 /* Reset other stuff. */
5806 pThis->svga.cScratchRegion = VMSVGA_SCRATCH_SIZE;
5807 RT_ZERO(pThis->svga.au32ScratchRegion);
5808
5809 vmsvgaR3StateTerm(pThis, pThisCC->svga.pSvgaR3State);
5810 vmsvgaR3StateInit(pThis, pThisCC->svga.pSvgaR3State);
5811
5812 RT_BZERO(pThisCC->svga.pbVgaFrameBufferR3, VMSVGA_VGA_FB_BACKUP_SIZE);
5813
5814 /* Initialize FIFO and register capabilities. */
5815 vmsvgaR3InitCaps(pThis, pThisCC);
5816
5817# ifdef VBOX_WITH_VMSVGA3D
5818 if (pThis->svga.f3DEnabled)
5819 vmsvgaR3InitFifo3DCaps(pThis, pThisCC);
5820# endif
5821
5822 /* VRAM tracking is enabled by default during bootup. */
5823 pThis->svga.fVRAMTracking = true;
5824 pThis->svga.fEnabled = false;
5825
5826 /* Invalidate current settings. */
5827 pThis->svga.uWidth = VMSVGA_VAL_UNINITIALIZED;
5828 pThis->svga.uHeight = VMSVGA_VAL_UNINITIALIZED;
5829 pThis->svga.uBpp = pThis->svga.uHostBpp;
5830 pThis->svga.cbScanline = 0;
5831 pThis->svga.u32PitchLock = 0;
5832
5833 return rc;
5834}
5835
5836/**
5837 * Cleans up the SVGA hardware state
5838 *
5839 * @returns VBox status code.
5840 * @param pDevIns The device instance.
5841 */
5842int vmsvgaR3Destruct(PPDMDEVINS pDevIns)
5843{
5844 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
5845 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
5846
5847 /*
5848 * Ask the FIFO thread to terminate the 3d state and then terminate it.
5849 */
5850 if (pThisCC->svga.pFIFOIOThread)
5851 {
5852 int rc = vmsvgaR3RunExtCmdOnFifoThread(pDevIns, pThis, pThisCC, VMSVGA_FIFO_EXTCMD_TERMINATE,
5853 NULL /*pvParam*/, 30000 /*ms*/);
5854 AssertLogRelRC(rc);
5855
5856 rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->svga.pFIFOIOThread, NULL);
5857 AssertLogRelRC(rc);
5858 pThisCC->svga.pFIFOIOThread = NULL;
5859 }
5860
5861 /*
5862 * Destroy the special SVGA state.
5863 */
5864 if (pThisCC->svga.pSvgaR3State)
5865 {
5866 vmsvgaR3StateTerm(pThis, pThisCC->svga.pSvgaR3State);
5867
5868 RTMemFree(pThisCC->svga.pSvgaR3State);
5869 pThisCC->svga.pSvgaR3State = NULL;
5870 }
5871
5872 /*
5873 * Free our resources residing in the VGA state.
5874 */
5875 if (pThisCC->svga.pbVgaFrameBufferR3)
5876 {
5877 RTMemFree(pThisCC->svga.pbVgaFrameBufferR3);
5878 pThisCC->svga.pbVgaFrameBufferR3 = NULL;
5879 }
5880 if (pThisCC->svga.hFIFOExtCmdSem != NIL_RTSEMEVENT)
5881 {
5882 RTSemEventDestroy(pThisCC->svga.hFIFOExtCmdSem);
5883 pThisCC->svga.hFIFOExtCmdSem = NIL_RTSEMEVENT;
5884 }
5885 if (pThis->svga.hFIFORequestSem != NIL_SUPSEMEVENT)
5886 {
5887 PDMDevHlpSUPSemEventClose(pDevIns, pThis->svga.hFIFORequestSem);
5888 pThis->svga.hFIFORequestSem = NIL_SUPSEMEVENT;
5889 }
5890
5891 return VINF_SUCCESS;
5892}
5893
5894/**
5895 * Initialize the SVGA hardware state
5896 *
5897 * @returns VBox status code.
5898 * @param pDevIns The device instance.
5899 */
5900int vmsvgaR3Init(PPDMDEVINS pDevIns)
5901{
5902 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
5903 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
5904 PVMSVGAR3STATE pSVGAState;
5905 int rc;
5906
5907 pThis->svga.cScratchRegion = VMSVGA_SCRATCH_SIZE;
5908 memset(pThis->svga.au32ScratchRegion, 0, sizeof(pThis->svga.au32ScratchRegion));
5909
5910 pThis->svga.cGMR = VMSVGA_MAX_GMR_IDS;
5911
5912 /* Necessary for creating a backup of the text mode frame buffer when switching into svga mode. */
5913 pThisCC->svga.pbVgaFrameBufferR3 = (uint8_t *)RTMemAllocZ(VMSVGA_VGA_FB_BACKUP_SIZE);
5914 AssertReturn(pThisCC->svga.pbVgaFrameBufferR3, VERR_NO_MEMORY);
5915
5916 /* Create event semaphore. */
5917 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->svga.hFIFORequestSem);
5918 AssertRCReturn(rc, rc);
5919
5920 /* Create event semaphore. */
5921 rc = RTSemEventCreate(&pThisCC->svga.hFIFOExtCmdSem);
5922 AssertRCReturn(rc, rc);
5923
5924 pThisCC->svga.pSvgaR3State = (PVMSVGAR3STATE)RTMemAlloc(sizeof(VMSVGAR3STATE));
5925 AssertReturn(pThisCC->svga.pSvgaR3State, VERR_NO_MEMORY);
5926
5927 rc = vmsvgaR3StateInit(pThis, pThisCC->svga.pSvgaR3State);
5928 AssertMsgRCReturn(rc, ("Failed to create pSvgaR3State.\n"), rc);
5929
5930 pSVGAState = pThisCC->svga.pSvgaR3State;
5931
5932 /* Initialize FIFO and register capabilities. */
5933 vmsvgaR3InitCaps(pThis, pThisCC);
5934
5935# ifdef VBOX_WITH_VMSVGA3D
5936 if (pThis->svga.f3DEnabled)
5937 {
5938 rc = vmsvga3dInit(pDevIns, pThis, pThisCC);
5939 if (RT_FAILURE(rc))
5940 {
5941 LogRel(("VMSVGA3d: 3D support disabled! (vmsvga3dInit -> %Rrc)\n", rc));
5942 pThis->svga.f3DEnabled = false;
5943 }
5944 }
5945# endif
5946 /* VRAM tracking is enabled by default during bootup. */
5947 pThis->svga.fVRAMTracking = true;
5948
5949 /* Set up the host bpp. This value is as a default for the programmable
5950 * bpp value. On old implementations, SVGA_REG_HOST_BITS_PER_PIXEL did not
5951 * exist and SVGA_REG_BITS_PER_PIXEL was read-only, returning what was later
5952 * separated as SVGA_REG_HOST_BITS_PER_PIXEL.
5953 *
5954 * NB: The driver cBits value is currently constant for the lifetime of the
5955 * VM. If that changes, the host bpp logic might need revisiting.
5956 */
5957 pThis->svga.uHostBpp = (pThisCC->pDrv->cBits + 7) & ~7;
5958
5959 /* Invalidate current settings. */
5960 pThis->svga.uWidth = VMSVGA_VAL_UNINITIALIZED;
5961 pThis->svga.uHeight = VMSVGA_VAL_UNINITIALIZED;
5962 pThis->svga.uBpp = pThis->svga.uHostBpp;
5963 pThis->svga.cbScanline = 0;
5964
5965 pThis->svga.u32MaxWidth = VBE_DISPI_MAX_YRES;
5966 pThis->svga.u32MaxHeight = VBE_DISPI_MAX_XRES;
5967 while (pThis->svga.u32MaxWidth * pThis->svga.u32MaxHeight * 4 /* 32 bpp */ > pThis->vram_size)
5968 {
5969 pThis->svga.u32MaxWidth -= 256;
5970 pThis->svga.u32MaxHeight -= 256;
5971 }
5972 Log(("VMSVGA: Maximum size (%d,%d)\n", pThis->svga.u32MaxWidth, pThis->svga.u32MaxHeight));
5973
5974# ifdef DEBUG_GMR_ACCESS
5975 /* Register the GMR access handler type. */
5976 rc = PGMR3HandlerPhysicalTypeRegister(PDMDevHlpGetVM(pDevIns), PGMPHYSHANDLERKIND_WRITE,
5977 vmsvgaR3GmrAccessHandler,
5978 NULL, NULL, NULL,
5979 NULL, NULL, NULL,
5980 "VMSVGA GMR", &pThis->svga.hGmrAccessHandlerType);
5981 AssertRCReturn(rc, rc);
5982# endif
5983
5984# if defined(VMSVGA_USE_FIFO_ACCESS_HANDLER) || defined(DEBUG_FIFO_ACCESS)
5985 /* Register the FIFO access handler type. In addition to
5986 debugging FIFO access, this is also used to facilitate
5987 extended fifo thread sleeps. */
5988 rc = PGMR3HandlerPhysicalTypeRegister(PDMDevHlpGetVM(pDevIns),
5989# ifdef DEBUG_FIFO_ACCESS
5990 PGMPHYSHANDLERKIND_ALL,
5991# else
5992 PGMPHYSHANDLERKIND_WRITE,
5993# endif
5994 vmsvgaR3FifoAccessHandler,
5995 NULL, NULL, NULL,
5996 NULL, NULL, NULL,
5997 "VMSVGA FIFO", &pThis->svga.hFifoAccessHandlerType);
5998 AssertRCReturn(rc, rc);
5999# endif
6000
6001 /* Create the async IO thread. */
6002 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->svga.pFIFOIOThread, pThis, vmsvgaR3FifoLoop, vmsvgaR3FifoLoopWakeUp, 0,
6003 RTTHREADTYPE_IO, "VMSVGA FIFO");
6004 if (RT_FAILURE(rc))
6005 {
6006 AssertMsgFailed(("%s: Async IO Thread creation for FIFO handling failed rc=%d\n", __FUNCTION__, rc));
6007 return rc;
6008 }
6009
6010 /*
6011 * Statistics.
6012 */
6013# define REG_CNT(a_pvSample, a_pszName, a_pszDesc) \
6014 PDMDevHlpSTAMRegister(pDevIns, (a_pvSample), STAMTYPE_COUNTER, a_pszName, STAMUNIT_OCCURENCES, a_pszDesc)
6015# define REG_PRF(a_pvSample, a_pszName, a_pszDesc) \
6016 PDMDevHlpSTAMRegister(pDevIns, (a_pvSample), STAMTYPE_PROFILE, a_pszName, STAMUNIT_TICKS_PER_CALL, a_pszDesc)
6017# ifdef VBOX_WITH_STATISTICS
6018 REG_PRF(&pSVGAState->StatR3Cmd3dDrawPrimitivesProf, "VMSVGA/Cmd/3dDrawPrimitivesProf", "Profiling of SVGA_3D_CMD_DRAW_PRIMITIVES.");
6019 REG_PRF(&pSVGAState->StatR3Cmd3dPresentProf, "VMSVGA/Cmd/3dPresentProfBoth", "Profiling of SVGA_3D_CMD_PRESENT and SVGA_3D_CMD_PRESENT_READBACK.");
6020 REG_PRF(&pSVGAState->StatR3Cmd3dSurfaceDmaProf, "VMSVGA/Cmd/3dSurfaceDmaProf", "Profiling of SVGA_3D_CMD_SURFACE_DMA.");
6021# endif
6022 REG_PRF(&pSVGAState->StatR3Cmd3dBlitSurfaceToScreenProf, "VMSVGA/Cmd/3dBlitSurfaceToScreenProf", "Profiling of SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN.");
6023 REG_CNT(&pSVGAState->StatR3Cmd3dActivateSurface, "VMSVGA/Cmd/3dActivateSurface", "SVGA_3D_CMD_ACTIVATE_SURFACE");
6024 REG_CNT(&pSVGAState->StatR3Cmd3dBeginQuery, "VMSVGA/Cmd/3dBeginQuery", "SVGA_3D_CMD_BEGIN_QUERY");
6025 REG_CNT(&pSVGAState->StatR3Cmd3dClear, "VMSVGA/Cmd/3dClear", "SVGA_3D_CMD_CLEAR");
6026 REG_CNT(&pSVGAState->StatR3Cmd3dContextDefine, "VMSVGA/Cmd/3dContextDefine", "SVGA_3D_CMD_CONTEXT_DEFINE");
6027 REG_CNT(&pSVGAState->StatR3Cmd3dContextDestroy, "VMSVGA/Cmd/3dContextDestroy", "SVGA_3D_CMD_CONTEXT_DESTROY");
6028 REG_CNT(&pSVGAState->StatR3Cmd3dDeactivateSurface, "VMSVGA/Cmd/3dDeactivateSurface", "SVGA_3D_CMD_DEACTIVATE_SURFACE");
6029 REG_CNT(&pSVGAState->StatR3Cmd3dDrawPrimitives, "VMSVGA/Cmd/3dDrawPrimitives", "SVGA_3D_CMD_DRAW_PRIMITIVES");
6030 REG_CNT(&pSVGAState->StatR3Cmd3dEndQuery, "VMSVGA/Cmd/3dEndQuery", "SVGA_3D_CMD_END_QUERY");
6031 REG_CNT(&pSVGAState->StatR3Cmd3dGenerateMipmaps, "VMSVGA/Cmd/3dGenerateMipmaps", "SVGA_3D_CMD_GENERATE_MIPMAPS");
6032 REG_CNT(&pSVGAState->StatR3Cmd3dPresent, "VMSVGA/Cmd/3dPresent", "SVGA_3D_CMD_PRESENT");
6033 REG_CNT(&pSVGAState->StatR3Cmd3dPresentReadBack, "VMSVGA/Cmd/3dPresentReadBack", "SVGA_3D_CMD_PRESENT_READBACK");
6034 REG_CNT(&pSVGAState->StatR3Cmd3dSetClipPlane, "VMSVGA/Cmd/3dSetClipPlane", "SVGA_3D_CMD_SETCLIPPLANE");
6035 REG_CNT(&pSVGAState->StatR3Cmd3dSetLightData, "VMSVGA/Cmd/3dSetLightData", "SVGA_3D_CMD_SETLIGHTDATA");
6036 REG_CNT(&pSVGAState->StatR3Cmd3dSetLightEnable, "VMSVGA/Cmd/3dSetLightEnable", "SVGA_3D_CMD_SETLIGHTENABLE");
6037 REG_CNT(&pSVGAState->StatR3Cmd3dSetMaterial, "VMSVGA/Cmd/3dSetMaterial", "SVGA_3D_CMD_SETMATERIAL");
6038 REG_CNT(&pSVGAState->StatR3Cmd3dSetRenderState, "VMSVGA/Cmd/3dSetRenderState", "SVGA_3D_CMD_SETRENDERSTATE");
6039 REG_CNT(&pSVGAState->StatR3Cmd3dSetRenderTarget, "VMSVGA/Cmd/3dSetRenderTarget", "SVGA_3D_CMD_SETRENDERTARGET");
6040 REG_CNT(&pSVGAState->StatR3Cmd3dSetScissorRect, "VMSVGA/Cmd/3dSetScissorRect", "SVGA_3D_CMD_SETSCISSORRECT");
6041 REG_CNT(&pSVGAState->StatR3Cmd3dSetShader, "VMSVGA/Cmd/3dSetShader", "SVGA_3D_CMD_SET_SHADER");
6042 REG_CNT(&pSVGAState->StatR3Cmd3dSetShaderConst, "VMSVGA/Cmd/3dSetShaderConst", "SVGA_3D_CMD_SET_SHADER_CONST");
6043 REG_CNT(&pSVGAState->StatR3Cmd3dSetTextureState, "VMSVGA/Cmd/3dSetTextureState", "SVGA_3D_CMD_SETTEXTURESTATE");
6044 REG_CNT(&pSVGAState->StatR3Cmd3dSetTransform, "VMSVGA/Cmd/3dSetTransform", "SVGA_3D_CMD_SETTRANSFORM");
6045 REG_CNT(&pSVGAState->StatR3Cmd3dSetViewPort, "VMSVGA/Cmd/3dSetViewPort", "SVGA_3D_CMD_SETVIEWPORT");
6046 REG_CNT(&pSVGAState->StatR3Cmd3dSetZRange, "VMSVGA/Cmd/3dSetZRange", "SVGA_3D_CMD_SETZRANGE");
6047 REG_CNT(&pSVGAState->StatR3Cmd3dShaderDefine, "VMSVGA/Cmd/3dShaderDefine", "SVGA_3D_CMD_SHADER_DEFINE");
6048 REG_CNT(&pSVGAState->StatR3Cmd3dShaderDestroy, "VMSVGA/Cmd/3dShaderDestroy", "SVGA_3D_CMD_SHADER_DESTROY");
6049 REG_CNT(&pSVGAState->StatR3Cmd3dSurfaceCopy, "VMSVGA/Cmd/3dSurfaceCopy", "SVGA_3D_CMD_SURFACE_COPY");
6050 REG_CNT(&pSVGAState->StatR3Cmd3dSurfaceDefine, "VMSVGA/Cmd/3dSurfaceDefine", "SVGA_3D_CMD_SURFACE_DEFINE");
6051 REG_CNT(&pSVGAState->StatR3Cmd3dSurfaceDefineV2, "VMSVGA/Cmd/3dSurfaceDefineV2", "SVGA_3D_CMD_SURFACE_DEFINE_V2");
6052 REG_CNT(&pSVGAState->StatR3Cmd3dSurfaceDestroy, "VMSVGA/Cmd/3dSurfaceDestroy", "SVGA_3D_CMD_SURFACE_DESTROY");
6053 REG_CNT(&pSVGAState->StatR3Cmd3dSurfaceDma, "VMSVGA/Cmd/3dSurfaceDma", "SVGA_3D_CMD_SURFACE_DMA");
6054 REG_CNT(&pSVGAState->StatR3Cmd3dSurfaceScreen, "VMSVGA/Cmd/3dSurfaceScreen", "SVGA_3D_CMD_SURFACE_SCREEN");
6055 REG_CNT(&pSVGAState->StatR3Cmd3dSurfaceStretchBlt, "VMSVGA/Cmd/3dSurfaceStretchBlt", "SVGA_3D_CMD_SURFACE_STRETCHBLT");
6056 REG_CNT(&pSVGAState->StatR3Cmd3dWaitForQuery, "VMSVGA/Cmd/3dWaitForQuery", "SVGA_3D_CMD_WAIT_FOR_QUERY");
6057 REG_CNT(&pSVGAState->StatR3CmdAnnotationCopy, "VMSVGA/Cmd/AnnotationCopy", "SVGA_CMD_ANNOTATION_COPY");
6058 REG_CNT(&pSVGAState->StatR3CmdAnnotationFill, "VMSVGA/Cmd/AnnotationFill", "SVGA_CMD_ANNOTATION_FILL");
6059 REG_CNT(&pSVGAState->StatR3CmdBlitGmrFbToScreen, "VMSVGA/Cmd/BlitGmrFbToScreen", "SVGA_CMD_BLIT_GMRFB_TO_SCREEN");
6060 REG_CNT(&pSVGAState->StatR3CmdBlitScreentoGmrFb, "VMSVGA/Cmd/BlitScreentoGmrFb", "SVGA_CMD_BLIT_SCREEN_TO_GMRFB");
6061 REG_CNT(&pSVGAState->StatR3CmdDefineAlphaCursor, "VMSVGA/Cmd/DefineAlphaCursor", "SVGA_CMD_DEFINE_ALPHA_CURSOR");
6062 REG_CNT(&pSVGAState->StatR3CmdDefineCursor, "VMSVGA/Cmd/DefineCursor", "SVGA_CMD_DEFINE_CURSOR");
6063 REG_CNT(&pSVGAState->StatR3CmdMoveCursor, "VMSVGA/Cmd/MoveCursor", "SVGA_CMD_MOVE_CURSOR");
6064 REG_CNT(&pSVGAState->StatR3CmdDisplayCursor, "VMSVGA/Cmd/DisplayCursor", "SVGA_CMD_DISPLAY_CURSOR");
6065 REG_CNT(&pSVGAState->StatR3CmdRectFill, "VMSVGA/Cmd/RectFill", "SVGA_CMD_RECT_FILL");
6066 REG_CNT(&pSVGAState->StatR3CmdRectCopy, "VMSVGA/Cmd/RectCopy", "SVGA_CMD_RECT_COPY");
6067 REG_CNT(&pSVGAState->StatR3CmdRectRopCopy, "VMSVGA/Cmd/RectRopCopy", "SVGA_CMD_RECT_ROP_COPY");
6068 REG_CNT(&pSVGAState->StatR3CmdDefineGmr2, "VMSVGA/Cmd/DefineGmr2", "SVGA_CMD_DEFINE_GMR2");
6069 REG_CNT(&pSVGAState->StatR3CmdDefineGmr2Free, "VMSVGA/Cmd/DefineGmr2/Free", "Number of SVGA_CMD_DEFINE_GMR2 commands that only frees.");
6070 REG_CNT(&pSVGAState->StatR3CmdDefineGmr2Modify, "VMSVGA/Cmd/DefineGmr2/Modify", "Number of SVGA_CMD_DEFINE_GMR2 commands that redefines a non-free GMR.");
6071 REG_CNT(&pSVGAState->StatR3CmdDefineGmrFb, "VMSVGA/Cmd/DefineGmrFb", "SVGA_CMD_DEFINE_GMRFB");
6072 REG_CNT(&pSVGAState->StatR3CmdDefineScreen, "VMSVGA/Cmd/DefineScreen", "SVGA_CMD_DEFINE_SCREEN");
6073 REG_CNT(&pSVGAState->StatR3CmdDestroyScreen, "VMSVGA/Cmd/DestroyScreen", "SVGA_CMD_DESTROY_SCREEN");
6074 REG_CNT(&pSVGAState->StatR3CmdEscape, "VMSVGA/Cmd/Escape", "SVGA_CMD_ESCAPE");
6075 REG_CNT(&pSVGAState->StatR3CmdFence, "VMSVGA/Cmd/Fence", "SVGA_CMD_FENCE");
6076 REG_CNT(&pSVGAState->StatR3CmdInvalidCmd, "VMSVGA/Cmd/InvalidCmd", "SVGA_CMD_INVALID_CMD");
6077 REG_CNT(&pSVGAState->StatR3CmdRemapGmr2, "VMSVGA/Cmd/RemapGmr2", "SVGA_CMD_REMAP_GMR2");
6078 REG_CNT(&pSVGAState->StatR3CmdRemapGmr2Modify, "VMSVGA/Cmd/RemapGmr2/Modify", "Number of SVGA_CMD_REMAP_GMR2 commands that modifies rather than complete the definition of a GMR.");
6079 REG_CNT(&pSVGAState->StatR3CmdUpdate, "VMSVGA/Cmd/Update", "SVGA_CMD_UPDATE");
6080 REG_CNT(&pSVGAState->StatR3CmdUpdateVerbose, "VMSVGA/Cmd/UpdateVerbose", "SVGA_CMD_UPDATE_VERBOSE");
6081
6082 REG_CNT(&pSVGAState->StatR3RegConfigDoneWr, "VMSVGA/Reg/ConfigDoneWrite", "SVGA_REG_CONFIG_DONE writes");
6083 REG_CNT(&pSVGAState->StatR3RegGmrDescriptorWr, "VMSVGA/Reg/GmrDescriptorWrite", "SVGA_REG_GMR_DESCRIPTOR writes");
6084 REG_CNT(&pSVGAState->StatR3RegGmrDescriptorWrErrors, "VMSVGA/Reg/GmrDescriptorWrite/Errors", "Number of erroneous SVGA_REG_GMR_DESCRIPTOR commands.");
6085 REG_CNT(&pSVGAState->StatR3RegGmrDescriptorWrFree, "VMSVGA/Reg/GmrDescriptorWrite/Free", "Number of SVGA_REG_GMR_DESCRIPTOR commands only freeing the GMR.");
6086 REG_CNT(&pThis->svga.StatRegBitsPerPixelWr, "VMSVGA/Reg/BitsPerPixelWrite", "SVGA_REG_BITS_PER_PIXEL writes.");
6087 REG_CNT(&pThis->svga.StatRegBusyWr, "VMSVGA/Reg/BusyWrite", "SVGA_REG_BUSY writes.");
6088 REG_CNT(&pThis->svga.StatRegCursorXWr, "VMSVGA/Reg/CursorXWrite", "SVGA_REG_CURSOR_X writes.");
6089 REG_CNT(&pThis->svga.StatRegCursorYWr, "VMSVGA/Reg/CursorYWrite", "SVGA_REG_CURSOR_Y writes.");
6090 REG_CNT(&pThis->svga.StatRegCursorIdWr, "VMSVGA/Reg/CursorIdWrite", "SVGA_REG_CURSOR_ID writes.");
6091 REG_CNT(&pThis->svga.StatRegCursorOnWr, "VMSVGA/Reg/CursorOnWrite", "SVGA_REG_CURSOR_ON writes.");
6092 REG_CNT(&pThis->svga.StatRegDepthWr, "VMSVGA/Reg/DepthWrite", "SVGA_REG_DEPTH writes.");
6093 REG_CNT(&pThis->svga.StatRegDisplayHeightWr, "VMSVGA/Reg/DisplayHeightWrite", "SVGA_REG_DISPLAY_HEIGHT writes.");
6094 REG_CNT(&pThis->svga.StatRegDisplayIdWr, "VMSVGA/Reg/DisplayIdWrite", "SVGA_REG_DISPLAY_ID writes.");
6095 REG_CNT(&pThis->svga.StatRegDisplayIsPrimaryWr, "VMSVGA/Reg/DisplayIsPrimaryWrite", "SVGA_REG_DISPLAY_IS_PRIMARY writes.");
6096 REG_CNT(&pThis->svga.StatRegDisplayPositionXWr, "VMSVGA/Reg/DisplayPositionXWrite", "SVGA_REG_DISPLAY_POSITION_X writes.");
6097 REG_CNT(&pThis->svga.StatRegDisplayPositionYWr, "VMSVGA/Reg/DisplayPositionYWrite", "SVGA_REG_DISPLAY_POSITION_Y writes.");
6098 REG_CNT(&pThis->svga.StatRegDisplayWidthWr, "VMSVGA/Reg/DisplayWidthWrite", "SVGA_REG_DISPLAY_WIDTH writes.");
6099 REG_CNT(&pThis->svga.StatRegEnableWr, "VMSVGA/Reg/EnableWrite", "SVGA_REG_ENABLE writes.");
6100 REG_CNT(&pThis->svga.StatRegGmrIdWr, "VMSVGA/Reg/GmrIdWrite", "SVGA_REG_GMR_ID writes.");
6101 REG_CNT(&pThis->svga.StatRegGuestIdWr, "VMSVGA/Reg/GuestIdWrite", "SVGA_REG_GUEST_ID writes.");
6102 REG_CNT(&pThis->svga.StatRegHeightWr, "VMSVGA/Reg/HeightWrite", "SVGA_REG_HEIGHT writes.");
6103 REG_CNT(&pThis->svga.StatRegIdWr, "VMSVGA/Reg/IdWrite", "SVGA_REG_ID writes.");
6104 REG_CNT(&pThis->svga.StatRegIrqMaskWr, "VMSVGA/Reg/IrqMaskWrite", "SVGA_REG_IRQMASK writes.");
6105 REG_CNT(&pThis->svga.StatRegNumDisplaysWr, "VMSVGA/Reg/NumDisplaysWrite", "SVGA_REG_NUM_DISPLAYS writes.");
6106 REG_CNT(&pThis->svga.StatRegNumGuestDisplaysWr, "VMSVGA/Reg/NumGuestDisplaysWrite", "SVGA_REG_NUM_GUEST_DISPLAYS writes.");
6107 REG_CNT(&pThis->svga.StatRegPaletteWr, "VMSVGA/Reg/PaletteWrite", "SVGA_PALETTE_XXXX writes.");
6108 REG_CNT(&pThis->svga.StatRegPitchLockWr, "VMSVGA/Reg/PitchLockWrite", "SVGA_REG_PITCHLOCK writes.");
6109 REG_CNT(&pThis->svga.StatRegPseudoColorWr, "VMSVGA/Reg/PseudoColorWrite", "SVGA_REG_PSEUDOCOLOR writes.");
6110 REG_CNT(&pThis->svga.StatRegReadOnlyWr, "VMSVGA/Reg/ReadOnlyWrite", "Read-only SVGA_REG_XXXX writes.");
6111 REG_CNT(&pThis->svga.StatRegScratchWr, "VMSVGA/Reg/ScratchWrite", "SVGA_REG_SCRATCH_XXXX writes.");
6112 REG_CNT(&pThis->svga.StatRegSyncWr, "VMSVGA/Reg/SyncWrite", "SVGA_REG_SYNC writes.");
6113 REG_CNT(&pThis->svga.StatRegTopWr, "VMSVGA/Reg/TopWrite", "SVGA_REG_TOP writes.");
6114 REG_CNT(&pThis->svga.StatRegTracesWr, "VMSVGA/Reg/TracesWrite", "SVGA_REG_TRACES writes.");
6115 REG_CNT(&pThis->svga.StatRegUnknownWr, "VMSVGA/Reg/UnknownWrite", "Writes to unknown register.");
6116 REG_CNT(&pThis->svga.StatRegWidthWr, "VMSVGA/Reg/WidthWrite", "SVGA_REG_WIDTH writes.");
6117 REG_CNT(&pThis->svga.StatRegCommandLowWr, "VMSVGA/Reg/CommandLowWrite", "SVGA_REG_COMMAND_LOW writes.");
6118 REG_CNT(&pThis->svga.StatRegCommandHighWr, "VMSVGA/Reg/CommandHighWrite", "SVGA_REG_COMMAND_HIGH writes.");
6119 REG_CNT(&pThis->svga.StatRegDevCapWr, "VMSVGA/Reg/DevCapWrite", "SVGA_REG_DEV_CAP writes.");
6120 REG_CNT(&pThis->svga.StatRegCmdPrependLowWr, "VMSVGA/Reg/CmdPrependLowWrite", "SVGA_REG_CMD_PREPEND_LOW writes.");
6121 REG_CNT(&pThis->svga.StatRegCmdPrependHighWr, "VMSVGA/Reg/CmdPrependHighWrite", "SVGA_REG_iCMD_PREPEND_HIGH writes.");
6122
6123 REG_CNT(&pThis->svga.StatRegBitsPerPixelRd, "VMSVGA/Reg/BitsPerPixelRead", "SVGA_REG_BITS_PER_PIXEL reads.");
6124 REG_CNT(&pThis->svga.StatRegBlueMaskRd, "VMSVGA/Reg/BlueMaskRead", "SVGA_REG_BLUE_MASK reads.");
6125 REG_CNT(&pThis->svga.StatRegBusyRd, "VMSVGA/Reg/BusyRead", "SVGA_REG_BUSY reads.");
6126 REG_CNT(&pThis->svga.StatRegBytesPerLineRd, "VMSVGA/Reg/BytesPerLineRead", "SVGA_REG_BYTES_PER_LINE reads.");
6127 REG_CNT(&pThis->svga.StatRegCapabilitesRd, "VMSVGA/Reg/CapabilitesRead", "SVGA_REG_CAPABILITIES reads.");
6128 REG_CNT(&pThis->svga.StatRegConfigDoneRd, "VMSVGA/Reg/ConfigDoneRead", "SVGA_REG_CONFIG_DONE reads.");
6129 REG_CNT(&pThis->svga.StatRegCursorXRd, "VMSVGA/Reg/CursorXRead", "SVGA_REG_CURSOR_X reads.");
6130 REG_CNT(&pThis->svga.StatRegCursorYRd, "VMSVGA/Reg/CursorYRead", "SVGA_REG_CURSOR_Y reads.");
6131 REG_CNT(&pThis->svga.StatRegCursorIdRd, "VMSVGA/Reg/CursorIdRead", "SVGA_REG_CURSOR_ID reads.");
6132 REG_CNT(&pThis->svga.StatRegCursorOnRd, "VMSVGA/Reg/CursorOnRead", "SVGA_REG_CURSOR_ON reads.");
6133 REG_CNT(&pThis->svga.StatRegDepthRd, "VMSVGA/Reg/DepthRead", "SVGA_REG_DEPTH reads.");
6134 REG_CNT(&pThis->svga.StatRegDisplayHeightRd, "VMSVGA/Reg/DisplayHeightRead", "SVGA_REG_DISPLAY_HEIGHT reads.");
6135 REG_CNT(&pThis->svga.StatRegDisplayIdRd, "VMSVGA/Reg/DisplayIdRead", "SVGA_REG_DISPLAY_ID reads.");
6136 REG_CNT(&pThis->svga.StatRegDisplayIsPrimaryRd, "VMSVGA/Reg/DisplayIsPrimaryRead", "SVGA_REG_DISPLAY_IS_PRIMARY reads.");
6137 REG_CNT(&pThis->svga.StatRegDisplayPositionXRd, "VMSVGA/Reg/DisplayPositionXRead", "SVGA_REG_DISPLAY_POSITION_X reads.");
6138 REG_CNT(&pThis->svga.StatRegDisplayPositionYRd, "VMSVGA/Reg/DisplayPositionYRead", "SVGA_REG_DISPLAY_POSITION_Y reads.");
6139 REG_CNT(&pThis->svga.StatRegDisplayWidthRd, "VMSVGA/Reg/DisplayWidthRead", "SVGA_REG_DISPLAY_WIDTH reads.");
6140 REG_CNT(&pThis->svga.StatRegEnableRd, "VMSVGA/Reg/EnableRead", "SVGA_REG_ENABLE reads.");
6141 REG_CNT(&pThis->svga.StatRegFbOffsetRd, "VMSVGA/Reg/FbOffsetRead", "SVGA_REG_FB_OFFSET reads.");
6142 REG_CNT(&pThis->svga.StatRegFbSizeRd, "VMSVGA/Reg/FbSizeRead", "SVGA_REG_FB_SIZE reads.");
6143 REG_CNT(&pThis->svga.StatRegFbStartRd, "VMSVGA/Reg/FbStartRead", "SVGA_REG_FB_START reads.");
6144 REG_CNT(&pThis->svga.StatRegGmrIdRd, "VMSVGA/Reg/GmrIdRead", "SVGA_REG_GMR_ID reads.");
6145 REG_CNT(&pThis->svga.StatRegGmrMaxDescriptorLengthRd, "VMSVGA/Reg/GmrMaxDescriptorLengthRead", "SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH reads.");
6146 REG_CNT(&pThis->svga.StatRegGmrMaxIdsRd, "VMSVGA/Reg/GmrMaxIdsRead", "SVGA_REG_GMR_MAX_IDS reads.");
6147 REG_CNT(&pThis->svga.StatRegGmrsMaxPagesRd, "VMSVGA/Reg/GmrsMaxPagesRead", "SVGA_REG_GMRS_MAX_PAGES reads.");
6148 REG_CNT(&pThis->svga.StatRegGreenMaskRd, "VMSVGA/Reg/GreenMaskRead", "SVGA_REG_GREEN_MASK reads.");
6149 REG_CNT(&pThis->svga.StatRegGuestIdRd, "VMSVGA/Reg/GuestIdRead", "SVGA_REG_GUEST_ID reads.");
6150 REG_CNT(&pThis->svga.StatRegHeightRd, "VMSVGA/Reg/HeightRead", "SVGA_REG_HEIGHT reads.");
6151 REG_CNT(&pThis->svga.StatRegHostBitsPerPixelRd, "VMSVGA/Reg/HostBitsPerPixelRead", "SVGA_REG_HOST_BITS_PER_PIXEL reads.");
6152 REG_CNT(&pThis->svga.StatRegIdRd, "VMSVGA/Reg/IdRead", "SVGA_REG_ID reads.");
6153 REG_CNT(&pThis->svga.StatRegIrqMaskRd, "VMSVGA/Reg/IrqMaskRead", "SVGA_REG_IRQ_MASK reads.");
6154 REG_CNT(&pThis->svga.StatRegMaxHeightRd, "VMSVGA/Reg/MaxHeightRead", "SVGA_REG_MAX_HEIGHT reads.");
6155 REG_CNT(&pThis->svga.StatRegMaxWidthRd, "VMSVGA/Reg/MaxWidthRead", "SVGA_REG_MAX_WIDTH reads.");
6156 REG_CNT(&pThis->svga.StatRegMemorySizeRd, "VMSVGA/Reg/MemorySizeRead", "SVGA_REG_MEMORY_SIZE reads.");
6157 REG_CNT(&pThis->svga.StatRegMemRegsRd, "VMSVGA/Reg/MemRegsRead", "SVGA_REG_MEM_REGS reads.");
6158 REG_CNT(&pThis->svga.StatRegMemSizeRd, "VMSVGA/Reg/MemSizeRead", "SVGA_REG_MEM_SIZE reads.");
6159 REG_CNT(&pThis->svga.StatRegMemStartRd, "VMSVGA/Reg/MemStartRead", "SVGA_REG_MEM_START reads.");
6160 REG_CNT(&pThis->svga.StatRegNumDisplaysRd, "VMSVGA/Reg/NumDisplaysRead", "SVGA_REG_NUM_DISPLAYS reads.");
6161 REG_CNT(&pThis->svga.StatRegNumGuestDisplaysRd, "VMSVGA/Reg/NumGuestDisplaysRead", "SVGA_REG_NUM_GUEST_DISPLAYS reads.");
6162 REG_CNT(&pThis->svga.StatRegPaletteRd, "VMSVGA/Reg/PaletteRead", "SVGA_REG_PLAETTE_XXXX reads.");
6163 REG_CNT(&pThis->svga.StatRegPitchLockRd, "VMSVGA/Reg/PitchLockRead", "SVGA_REG_PITCHLOCK reads.");
6164 REG_CNT(&pThis->svga.StatRegPsuedoColorRd, "VMSVGA/Reg/PsuedoColorRead", "SVGA_REG_PSEUDOCOLOR reads.");
6165 REG_CNT(&pThis->svga.StatRegRedMaskRd, "VMSVGA/Reg/RedMaskRead", "SVGA_REG_RED_MASK reads.");
6166 REG_CNT(&pThis->svga.StatRegScratchRd, "VMSVGA/Reg/ScratchRead", "SVGA_REG_SCRATCH reads.");
6167 REG_CNT(&pThis->svga.StatRegScratchSizeRd, "VMSVGA/Reg/ScratchSizeRead", "SVGA_REG_SCRATCH_SIZE reads.");
6168 REG_CNT(&pThis->svga.StatRegSyncRd, "VMSVGA/Reg/SyncRead", "SVGA_REG_SYNC reads.");
6169 REG_CNT(&pThis->svga.StatRegTopRd, "VMSVGA/Reg/TopRead", "SVGA_REG_TOP reads.");
6170 REG_CNT(&pThis->svga.StatRegTracesRd, "VMSVGA/Reg/TracesRead", "SVGA_REG_TRACES reads.");
6171 REG_CNT(&pThis->svga.StatRegUnknownRd, "VMSVGA/Reg/UnknownRead", "SVGA_REG_UNKNOWN reads.");
6172 REG_CNT(&pThis->svga.StatRegVramSizeRd, "VMSVGA/Reg/VramSizeRead", "SVGA_REG_VRAM_SIZE reads.");
6173 REG_CNT(&pThis->svga.StatRegWidthRd, "VMSVGA/Reg/WidthRead", "SVGA_REG_WIDTH reads.");
6174 REG_CNT(&pThis->svga.StatRegWriteOnlyRd, "VMSVGA/Reg/WriteOnlyRead", "Write-only SVGA_REG_XXXX reads.");
6175 REG_CNT(&pThis->svga.StatRegCommandLowRd, "VMSVGA/Reg/CommandLowRead", "SVGA_REG_COMMAND_LOW reads.");
6176 REG_CNT(&pThis->svga.StatRegCommandHighRd, "VMSVGA/Reg/CommandHighRead", "SVGA_REG_COMMAND_HIGH reads.");
6177 REG_CNT(&pThis->svga.StatRegMaxPrimBBMemRd, "VMSVGA/Reg/MaxPrimBBMemRead", "SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM reads.");
6178 REG_CNT(&pThis->svga.StatRegGBMemSizeRd, "VMSVGA/Reg/GBMemSizeRead", "SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB reads.");
6179 REG_CNT(&pThis->svga.StatRegDevCapRd, "VMSVGA/Reg/DevCapRead", "SVGA_REG_DEV_CAP reads.");
6180 REG_CNT(&pThis->svga.StatRegCmdPrependLowRd, "VMSVGA/Reg/CmdPrependLowRead", "SVGA_REG_CMD_PREPEND_LOW reads.");
6181 REG_CNT(&pThis->svga.StatRegCmdPrependHighRd, "VMSVGA/Reg/CmdPrependHighRead", "SVGA_REG_iCMD_PREPEND_HIGH reads.");
6182 REG_CNT(&pThis->svga.StatRegScrnTgtMaxWidthRd, "VMSVGA/Reg/ScrnTgtMaxWidthRead", "SVGA_REG_SCREENTARGET_MAX_WIDTH reads.");
6183 REG_CNT(&pThis->svga.StatRegScrnTgtMaxHeightRd, "VMSVGA/Reg/ScrnTgtMaxHeightRead", "SVGA_REG_SCREENTARGET_MAX_HEIGHT reads.");
6184 REG_CNT(&pThis->svga.StatRegMobMaxSizeRd, "VMSVGA/Reg/MobMaxSizeRead", "SVGA_REG_MOB_MAX_SIZE reads.");
6185
6186 REG_PRF(&pSVGAState->StatBusyDelayEmts, "VMSVGA/EmtDelayOnBusyFifo", "Time we've delayed EMTs because of busy FIFO thread.");
6187 REG_CNT(&pSVGAState->StatFifoCommands, "VMSVGA/FifoCommands", "FIFO command counter.");
6188 REG_CNT(&pSVGAState->StatFifoErrors, "VMSVGA/FifoErrors", "FIFO error counter.");
6189 REG_CNT(&pSVGAState->StatFifoUnkCmds, "VMSVGA/FifoUnknownCommands", "FIFO unknown command counter.");
6190 REG_CNT(&pSVGAState->StatFifoTodoTimeout, "VMSVGA/FifoTodoTimeout", "Number of times we discovered pending work after a wait timeout.");
6191 REG_CNT(&pSVGAState->StatFifoTodoWoken, "VMSVGA/FifoTodoWoken", "Number of times we discovered pending work after being woken up.");
6192 REG_PRF(&pSVGAState->StatFifoStalls, "VMSVGA/FifoStalls", "Profiling of FIFO stalls (waiting for guest to finish copying data).");
6193 REG_PRF(&pSVGAState->StatFifoExtendedSleep, "VMSVGA/FifoExtendedSleep", "Profiling FIFO sleeps relying on the refresh timer and/or access handler.");
6194# if defined(VMSVGA_USE_FIFO_ACCESS_HANDLER) || defined(DEBUG_FIFO_ACCESS)
6195 REG_CNT(&pSVGAState->StatFifoAccessHandler, "VMSVGA/FifoAccessHandler", "Number of times the FIFO access handler triggered.");
6196# endif
6197 REG_CNT(&pSVGAState->StatFifoCursorFetchAgain, "VMSVGA/FifoCursorFetchAgain", "Times the cursor update counter changed while reading.");
6198 REG_CNT(&pSVGAState->StatFifoCursorNoChange, "VMSVGA/FifoCursorNoChange", "No cursor position change event though the update counter was modified.");
6199 REG_CNT(&pSVGAState->StatFifoCursorPosition, "VMSVGA/FifoCursorPosition", "Cursor position and visibility changes.");
6200 REG_CNT(&pSVGAState->StatFifoCursorVisiblity, "VMSVGA/FifoCursorVisiblity", "Cursor visibility changes.");
6201 REG_CNT(&pSVGAState->StatFifoWatchdogWakeUps, "VMSVGA/FifoWatchdogWakeUps", "Number of times the FIFO refresh poller/watchdog woke up the FIFO thread.");
6202
6203# undef REG_CNT
6204# undef REG_PRF
6205
6206 /*
6207 * Info handlers.
6208 */
6209 PDMDevHlpDBGFInfoRegister(pDevIns, "vmsvga", "Basic VMSVGA device state details", vmsvgaR3Info);
6210# ifdef VBOX_WITH_VMSVGA3D
6211 PDMDevHlpDBGFInfoRegister(pDevIns, "vmsvga3dctx", "VMSVGA 3d context details. Accepts 'terse'.", vmsvgaR3Info3dContext);
6212 PDMDevHlpDBGFInfoRegister(pDevIns, "vmsvga3dsfc",
6213 "VMSVGA 3d surface details. "
6214 "Accepts 'terse', 'invy', and one of 'tiny', 'medium', 'normal', 'big', 'huge', or 'gigantic'.",
6215 vmsvgaR3Info3dSurface);
6216 PDMDevHlpDBGFInfoRegister(pDevIns, "vmsvga3dsurf",
6217 "VMSVGA 3d surface details and bitmap: "
6218 "sid[>dir]",
6219 vmsvgaR3Info3dSurfaceBmp);
6220# endif
6221
6222 return VINF_SUCCESS;
6223}
6224
6225/**
6226 * Power On notification.
6227 *
6228 * @returns VBox status code.
6229 * @param pDevIns The device instance data.
6230 *
6231 * @remarks Caller enters the device critical section.
6232 */
6233DECLCALLBACK(void) vmsvgaR3PowerOn(PPDMDEVINS pDevIns)
6234{
6235# ifdef VBOX_WITH_VMSVGA3D
6236 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
6237 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
6238 if (pThis->svga.f3DEnabled)
6239 {
6240 int rc = vmsvga3dPowerOn(pDevIns, pThis, pThisCC);
6241 if (RT_SUCCESS(rc))
6242 {
6243 /* Initialize FIFO 3D capabilities. */
6244 vmsvgaR3InitFifo3DCaps(pThis, pThisCC);
6245 }
6246 }
6247# else /* !VBOX_WITH_VMSVGA3D */
6248 RT_NOREF(pDevIns);
6249# endif /* !VBOX_WITH_VMSVGA3D */
6250}
6251
6252/**
6253 * Power Off notification.
6254 *
6255 * @param pDevIns The device instance data.
6256 *
6257 * @remarks Caller enters the device critical section.
6258 */
6259DECLCALLBACK(void) vmsvgaR3PowerOff(PPDMDEVINS pDevIns)
6260{
6261 PVGASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVGASTATE);
6262 PVGASTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVGASTATECC);
6263
6264 /*
6265 * Notify the FIFO thread.
6266 */
6267 if (pThisCC->svga.pFIFOIOThread)
6268 {
6269 int rc = vmsvgaR3RunExtCmdOnFifoThread(pDevIns, pThis, pThisCC, VMSVGA_FIFO_EXTCMD_POWEROFF,
6270 NULL /*pvParam*/, 30000 /*ms*/);
6271 AssertLogRelRC(rc);
6272 }
6273}
6274
6275#endif /* IN_RING3 */
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