VirtualBox

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

Last change on this file since 86265 was 86265, checked in by vboxsync, 5 years ago

Devices/Graphics: Split DevVGA-SVGA.cpp to two source files (device and command implementation) and an internal header file. bugref:9830

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

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