VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA.cpp@ 40472

Last change on this file since 40472 was 40472, checked in by vboxsync, 13 years ago

Print LFB base, too.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 220.3 KB
Line 
1/* $Id: DevVGA.cpp 40472 2012-03-15 08:26:21Z vboxsync $ */
2/** @file
3 * DevVGA - VBox VGA/VESA device.
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on:
19 *
20 * QEMU VGA Emulator.
21 *
22 * Copyright (c) 2003 Fabrice Bellard
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a copy
25 * of this software and associated documentation files (the "Software"), to deal
26 * in the Software without restriction, including without limitation the rights
27 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28 * copies of the Software, and to permit persons to whom the Software is
29 * furnished to do so, subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be included in
32 * all copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40 * THE SOFTWARE.
41 */
42
43/*******************************************************************************
44* Defined Constants And Macros *
45*******************************************************************************/
46
47/* WARNING!!! All defines that affect VGAState should be placed to DevVGA.h !!!
48 * NEVER place them here as this would lead to VGAState inconsistency
49 * across different .cpp files !!!
50 */
51/** The size of the VGA GC mapping.
52 * This is supposed to be all the VGA memory accessible to the guest.
53 * The initial value was 256KB but NTAllInOne.iso appears to access more
54 * thus the limit was upped to 512KB.
55 *
56 * @todo Someone with some VGA knowhow should make a better guess at this value.
57 */
58#define VGA_MAPPING_SIZE _512K
59
60#ifdef VBOX_WITH_HGSMI
61#define PCIDEV_2_VGASTATE(pPciDev) ((VGAState *)((uintptr_t)pPciDev - RT_OFFSETOF(VGAState, Dev)))
62#endif /* VBOX_WITH_HGSMI */
63/** Converts a vga adaptor state pointer to a device instance pointer. */
64#define VGASTATE2DEVINS(pVgaState) ((pVgaState)->CTX_SUFF(pDevIns))
65
66/** Check that the video modes fit into virtual video memory.
67 * Only works when VBE_NEW_DYN_LIST is defined! */
68#define VRAM_SIZE_FIX
69
70/** Check buffer if an VRAM offset is within the right range or not. */
71#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
72# define VERIFY_VRAM_WRITE_OFF_RETURN(pThis, off) \
73 do { \
74 if ((off) >= VGA_MAPPING_SIZE) \
75 { \
76 AssertMsgReturn((off) < (pThis)->vram_size, ("%RX32 !< %RX32\n", (uint32_t)(off), (pThis)->vram_size), VINF_SUCCESS); \
77 Log2(("%Rfn[%d]: %RX32 -> R3\n", __PRETTY_FUNCTION__, __LINE__, (off))); \
78 return VINF_IOM_R3_MMIO_WRITE; \
79 } \
80 } while (0)
81#else
82# define VERIFY_VRAM_WRITE_OFF_RETURN(pThis, off) \
83 AssertMsgReturn((off) < (pThis)->vram_size, ("%RX32 !< %RX32\n", (uint32_t)(off), (pThis)->vram_size), VINF_SUCCESS)
84#endif
85
86/** Check buffer if an VRAM offset is within the right range or not. */
87#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
88# define VERIFY_VRAM_READ_OFF_RETURN(pThis, off, rcVar) \
89 do { \
90 if ((off) >= VGA_MAPPING_SIZE) \
91 { \
92 AssertMsgReturn((off) < (pThis)->vram_size, ("%RX32 !< %RX32\n", (uint32_t)(off), (pThis)->vram_size), 0xff); \
93 Log2(("%Rfn[%d]: %RX32 -> R3\n", __PRETTY_FUNCTION__, __LINE__, (off))); \
94 (rcVar) = VINF_IOM_R3_MMIO_READ; \
95 return 0; \
96 } \
97 } while (0)
98#else
99# define VERIFY_VRAM_READ_OFF_RETURN(pThis, off, rcVar) \
100 do { \
101 AssertMsgReturn((off) < (pThis)->vram_size, ("%RX32 !< %RX32\n", (uint32_t)(off), (pThis)->vram_size), 0xff); \
102 NOREF(rcVar); \
103 } while (0)
104#endif
105
106
107/*******************************************************************************
108* Header Files *
109*******************************************************************************/
110#define LOG_GROUP LOG_GROUP_DEV_VGA
111#include <VBox/vmm/pdmdev.h>
112#include <VBox/vmm/pgm.h>
113#ifdef IN_RING3
114# include <iprt/alloc.h>
115# include <iprt/ctype.h>
116#endif /* IN_RING3 */
117#include <iprt/assert.h>
118#include <iprt/asm.h>
119#include <iprt/file.h>
120#include <iprt/time.h>
121#include <iprt/string.h>
122#include <iprt/uuid.h>
123
124#include <VBox/VMMDev.h>
125#include <VBox/VBoxVideo.h>
126#include <VBox/bioslogo.h>
127
128/* should go BEFORE any other DevVGA include to make all DevVGA.h config defines be visible */
129#include "DevVGA.h"
130
131#if defined(VBE_NEW_DYN_LIST) && defined(IN_RING3) && !defined(VBOX_DEVICE_STRUCT_TESTCASE)
132# include "DevVGAModes.h"
133# include <stdio.h> /* sscan */
134#endif
135
136#include "vl_vbox.h"
137#include "VBoxDD.h"
138#include "VBoxDD2.h"
139
140
141/*******************************************************************************
142* Structures and Typedefs *
143*******************************************************************************/
144#pragma pack(1)
145
146/** BMP File Format Bitmap Header. */
147typedef struct
148{
149 uint16_t Type; /* File Type Identifier */
150 uint32_t FileSize; /* Size of File */
151 uint16_t Reserved1; /* Reserved (should be 0) */
152 uint16_t Reserved2; /* Reserved (should be 0) */
153 uint32_t Offset; /* Offset to bitmap data */
154} BMPINFO;
155
156/** Pointer to a bitmap header*/
157typedef BMPINFO *PBMPINFO;
158
159/** OS/2 1.x Information Header Format. */
160typedef struct
161{
162 uint32_t Size; /* Size of Remaining Header */
163 uint16_t Width; /* Width of Bitmap in Pixels */
164 uint16_t Height; /* Height of Bitmap in Pixels */
165 uint16_t Planes; /* Number of Planes */
166 uint16_t BitCount; /* Color Bits Per Pixel */
167} OS2HDR;
168
169/** Pointer to a OS/2 1.x header format */
170typedef OS2HDR *POS2HDR;
171
172/** OS/2 2.0 Information Header Format. */
173typedef struct
174{
175 uint32_t Size; /* Size of Remaining Header */
176 uint32_t Width; /* Width of Bitmap in Pixels */
177 uint32_t Height; /* Height of Bitmap in Pixels */
178 uint16_t Planes; /* Number of Planes */
179 uint16_t BitCount; /* Color Bits Per Pixel */
180 uint32_t Compression; /* Compression Scheme (0=none) */
181 uint32_t SizeImage; /* Size of bitmap in bytes */
182 uint32_t XPelsPerMeter; /* Horz. Resolution in Pixels/Meter */
183 uint32_t YPelsPerMeter; /* Vert. Resolution in Pixels/Meter */
184 uint32_t ClrUsed; /* Number of Colors in Color Table */
185 uint32_t ClrImportant; /* Number of Important Colors */
186 uint16_t Units; /* Resolution Measurement Used */
187 uint16_t Reserved; /* Reserved FIelds (always 0) */
188 uint16_t Recording; /* Orientation of Bitmap */
189 uint16_t Rendering; /* Halftone Algorithm Used on Image */
190 uint32_t Size1; /* Halftone Algorithm Data */
191 uint32_t Size2; /* Halftone Algorithm Data */
192 uint32_t ColorEncoding; /* Color Table Format (always 0) */
193 uint32_t Identifier; /* Misc. Field for Application Use */
194} OS22HDR;
195
196/** Pointer to a OS/2 2.0 header format */
197typedef OS22HDR *POS22HDR;
198
199/** Windows 3.x Information Header Format. */
200typedef struct
201{
202 uint32_t Size; /* Size of Remaining Header */
203 uint32_t Width; /* Width of Bitmap in Pixels */
204 uint32_t Height; /* Height of Bitmap in Pixels */
205 uint16_t Planes; /* Number of Planes */
206 uint16_t BitCount; /* Bits Per Pixel */
207 uint32_t Compression; /* Compression Scheme (0=none) */
208 uint32_t SizeImage; /* Size of bitmap in bytes */
209 uint32_t XPelsPerMeter; /* Horz. Resolution in Pixels/Meter */
210 uint32_t YPelsPerMeter; /* Vert. Resolution in Pixels/Meter */
211 uint32_t ClrUsed; /* Number of Colors in Color Table */
212 uint32_t ClrImportant; /* Number of Important Colors */
213} WINHDR;
214
215/** Pointer to a Windows 3.x header format */
216typedef WINHDR *PWINHDR;
217
218#pragma pack()
219
220#define BMP_ID 0x4D42
221
222/** @name BMP compressions.
223 * @{ */
224#define BMP_COMPRESS_NONE 0
225#define BMP_COMPRESS_RLE8 1
226#define BMP_COMPRESS_RLE4 2
227/** @} */
228
229/** @name BMP header sizes.
230 * @{ */
231#define BMP_HEADER_OS21 12
232#define BMP_HEADER_OS22 64
233#define BMP_HEADER_WIN3 40
234/** @} */
235
236/** The BIOS boot menu text position, X. */
237#define LOGO_F12TEXT_X 304
238/** The BIOS boot menu text position, Y. */
239#define LOGO_F12TEXT_Y 464
240
241/** Width of the "Press F12 to select boot device." bitmap.
242 Anything that exceeds the limit of F12BootText below is filled with
243 background. */
244#define LOGO_F12TEXT_WIDTH 286
245/** Height of the boot device selection bitmap, see LOGO_F12TEXT_WIDTH. */
246#define LOGO_F12TEXT_HEIGHT 12
247
248/** The BIOS logo delay time (msec). */
249#define LOGO_DELAY_TIME 2000
250
251#define LOGO_MAX_WIDTH 640
252#define LOGO_MAX_HEIGHT 480
253#define LOGO_MAX_SIZE LOGO_MAX_WIDTH * LOGO_MAX_HEIGHT * 4
254
255
256/*******************************************************************************
257* Global Variables *
258*******************************************************************************/
259/* "Press F12 to select boot device." bitmap. */
260static const uint8_t g_abLogoF12BootText[] =
261{
262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x0F, 0x7C,
265 0xF8, 0xF0, 0x01, 0xE0, 0x81, 0x9F, 0x3F, 0x00, 0x70, 0xF8, 0x00, 0xE0, 0xC3,
266 0x07, 0x0F, 0x1F, 0x3E, 0x70, 0x00, 0xF0, 0xE1, 0xC3, 0x07, 0x0E, 0x00, 0x6E,
267 0x7C, 0x60, 0xE0, 0xE1, 0xC3, 0x07, 0xC6, 0x80, 0x81, 0x31, 0x63, 0xC6, 0x00,
268 0x30, 0x80, 0x61, 0x0C, 0x00, 0x36, 0x63, 0x00, 0x8C, 0x19, 0x83, 0x61, 0xCC,
269 0x18, 0x36, 0x00, 0xCC, 0x8C, 0x19, 0xC3, 0x06, 0xC0, 0x8C, 0x31, 0x3C, 0x30,
270 0x8C, 0x19, 0x83, 0x31, 0x60, 0x60, 0x00, 0x0C, 0x18, 0x00, 0x0C, 0x60, 0x18,
271 0x00, 0x80, 0xC1, 0x18, 0x00, 0x30, 0x06, 0x60, 0x18, 0x30, 0x80, 0x01, 0x00,
272 0x33, 0x63, 0xC6, 0x30, 0x00, 0x30, 0x63, 0x80, 0x19, 0x0C, 0x03, 0x06, 0x00,
273 0x0C, 0x18, 0x18, 0xC0, 0x81, 0x03, 0x00, 0x03, 0x18, 0x0C, 0x00, 0x60, 0x30,
274 0x06, 0x00, 0x87, 0x01, 0x18, 0x06, 0x0C, 0x60, 0x00, 0xC0, 0xCC, 0x98, 0x31,
275 0x0C, 0x00, 0xCC, 0x18, 0x30, 0x0C, 0xC3, 0x80, 0x01, 0x00, 0x03, 0x66, 0xFE,
276 0x18, 0x30, 0x00, 0xC0, 0x02, 0x06, 0x06, 0x00, 0x18, 0x8C, 0x01, 0x60, 0xE0,
277 0x0F, 0x86, 0x3F, 0x03, 0x18, 0x00, 0x30, 0x33, 0x66, 0x0C, 0x03, 0x00, 0x33,
278 0xFE, 0x0C, 0xC3, 0x30, 0xE0, 0x0F, 0xC0, 0x87, 0x9B, 0x31, 0x63, 0xC6, 0x00,
279 0xF0, 0x80, 0x01, 0x03, 0x00, 0x06, 0x63, 0x00, 0x8C, 0x19, 0x83, 0x61, 0xCC,
280 0x18, 0x06, 0x00, 0x6C, 0x8C, 0x19, 0xC3, 0x00, 0x80, 0x8D, 0x31, 0xC3, 0x30,
281 0x8C, 0x19, 0x03, 0x30, 0xB3, 0xC3, 0x87, 0x0F, 0x1F, 0x00, 0x2C, 0x60, 0x80,
282 0x01, 0xE0, 0x87, 0x0F, 0x00, 0x3E, 0x7C, 0x60, 0xF0, 0xE1, 0xE3, 0x07, 0x00,
283 0x0F, 0x3E, 0x7C, 0xFC, 0x00, 0xC0, 0xC3, 0xC7, 0x30, 0x0E, 0x3E, 0x7C, 0x00,
284 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x1E, 0xC0, 0x00, 0x60, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00,
286 0x0C, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x87, 0x31, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x30,
289 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0xF8, 0x83, 0xC1, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00,
291 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x30,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
295};
296
297
298#ifndef VBOX_DEVICE_STRUCT_TESTCASE
299
300
301/**
302 * Set a VRAM page dirty.
303 *
304 * @param pThis VGA instance data.
305 * @param offVRAM The VRAM offset of the page to set.
306 */
307DECLINLINE(void) vga_set_dirty(VGAState *pThis, RTGCPHYS offVRAM)
308{
309 AssertMsg(offVRAM < pThis->vram_size, ("offVRAM = %p, pThis->vram_size = %p\n", offVRAM, pThis->vram_size));
310 ASMBitSet(&pThis->au32DirtyBitmap[0], offVRAM >> PAGE_SHIFT);
311 pThis->fHasDirtyBits = true;
312}
313
314/**
315 * Tests if a VRAM page is dirty.
316 *
317 * @returns true if dirty.
318 * @returns false if clean.
319 * @param pThis VGA instance data.
320 * @param offVRAM The VRAM offset of the page to check.
321 */
322DECLINLINE(bool) vga_is_dirty(VGAState *pThis, RTGCPHYS offVRAM)
323{
324 AssertMsg(offVRAM < pThis->vram_size, ("offVRAM = %p, pThis->vram_size = %p\n", offVRAM, pThis->vram_size));
325 return ASMBitTest(&pThis->au32DirtyBitmap[0], offVRAM >> PAGE_SHIFT);
326}
327
328/**
329 * Reset dirty flags in a give range.
330 *
331 * @param pThis VGA instance data.
332 * @param offVRAMStart Offset into the VRAM buffer of the first page.
333 * @param offVRAMEnd Offset into the VRAM buffer of the last page - exclusive.
334 */
335DECLINLINE(void) vga_reset_dirty(VGAState *pThis, RTGCPHYS offVRAMStart, RTGCPHYS offVRAMEnd)
336{
337 Assert(offVRAMStart < pThis->vram_size);
338 Assert(offVRAMEnd <= pThis->vram_size);
339 Assert(offVRAMStart < offVRAMEnd);
340 ASMBitClearRange(&pThis->au32DirtyBitmap[0], offVRAMStart >> PAGE_SHIFT, offVRAMEnd >> PAGE_SHIFT);
341}
342
343/* force some bits to zero */
344static const uint8_t sr_mask[8] = {
345 (uint8_t)~0xfc,
346 (uint8_t)~0xc2,
347 (uint8_t)~0xf0,
348 (uint8_t)~0xc0,
349 (uint8_t)~0xf1,
350 (uint8_t)~0xff,
351 (uint8_t)~0xff,
352 (uint8_t)~0x01,
353};
354
355static const uint8_t gr_mask[16] = {
356 (uint8_t)~0xf0, /* 0x00 */
357 (uint8_t)~0xf0, /* 0x01 */
358 (uint8_t)~0xf0, /* 0x02 */
359 (uint8_t)~0xe0, /* 0x03 */
360 (uint8_t)~0xfc, /* 0x04 */
361 (uint8_t)~0x84, /* 0x05 */
362 (uint8_t)~0xf0, /* 0x06 */
363 (uint8_t)~0xf0, /* 0x07 */
364 (uint8_t)~0x00, /* 0x08 */
365 (uint8_t)~0xff, /* 0x09 */
366 (uint8_t)~0xff, /* 0x0a */
367 (uint8_t)~0xff, /* 0x0b */
368 (uint8_t)~0xff, /* 0x0c */
369 (uint8_t)~0xff, /* 0x0d */
370 (uint8_t)~0xff, /* 0x0e */
371 (uint8_t)~0xff, /* 0x0f */
372};
373
374#define cbswap_32(__x) \
375((uint32_t)( \
376 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
377 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
378 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
379 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
380
381#ifdef WORDS_BIGENDIAN
382#define PAT(x) cbswap_32(x)
383#else
384#define PAT(x) (x)
385#endif
386
387#ifdef WORDS_BIGENDIAN
388#define BIG 1
389#else
390#define BIG 0
391#endif
392
393#ifdef WORDS_BIGENDIAN
394#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
395#else
396#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
397#endif
398
399static const uint32_t mask16[16] = {
400 PAT(0x00000000),
401 PAT(0x000000ff),
402 PAT(0x0000ff00),
403 PAT(0x0000ffff),
404 PAT(0x00ff0000),
405 PAT(0x00ff00ff),
406 PAT(0x00ffff00),
407 PAT(0x00ffffff),
408 PAT(0xff000000),
409 PAT(0xff0000ff),
410 PAT(0xff00ff00),
411 PAT(0xff00ffff),
412 PAT(0xffff0000),
413 PAT(0xffff00ff),
414 PAT(0xffffff00),
415 PAT(0xffffffff),
416};
417
418#undef PAT
419
420#ifdef WORDS_BIGENDIAN
421#define PAT(x) (x)
422#else
423#define PAT(x) cbswap_32(x)
424#endif
425
426static const uint32_t dmask16[16] = {
427 PAT(0x00000000),
428 PAT(0x000000ff),
429 PAT(0x0000ff00),
430 PAT(0x0000ffff),
431 PAT(0x00ff0000),
432 PAT(0x00ff00ff),
433 PAT(0x00ffff00),
434 PAT(0x00ffffff),
435 PAT(0xff000000),
436 PAT(0xff0000ff),
437 PAT(0xff00ff00),
438 PAT(0xff00ffff),
439 PAT(0xffff0000),
440 PAT(0xffff00ff),
441 PAT(0xffffff00),
442 PAT(0xffffffff),
443};
444
445static const uint32_t dmask4[4] = {
446 PAT(0x00000000),
447 PAT(0x0000ffff),
448 PAT(0xffff0000),
449 PAT(0xffffffff),
450};
451
452#if defined(IN_RING3)
453static uint32_t expand4[256];
454static uint16_t expand2[256];
455static uint8_t expand4to8[16];
456#endif /* IN_RING3 */
457
458/* Update the values needed for calculating Vertical Retrace and
459 * Display Enable status bits more or less accurately. The Display Enable
460 * bit is set (indicating *disabled* display signal) when either the
461 * horizontal (hblank) or vertical (vblank) blanking is active. The
462 * Vertical Retrace bit is set when vertical retrace (vsync) is active.
463 * Unless the CRTC is horribly misprogrammed, vsync implies vblank.
464 */
465static void vga_update_retrace_state(VGAState *s)
466{
467 unsigned htotal_cclks, vtotal_lines, chars_per_sec;
468 unsigned hblank_start_cclk, hblank_end_cclk, hblank_width, hblank_skew_cclks;
469 unsigned vsync_start_line, vsync_end, vsync_width;
470 unsigned vblank_start_line, vblank_end, vblank_width;
471 unsigned char_dots, clock_doubled, clock_index;
472 const int clocks[] = {25175000, 28322000, 25175000, 25175000};
473 vga_retrace_s *r = &s->retrace_state;
474
475 /* For horizontal timings, we only care about the blanking start/end. */
476 htotal_cclks = s->cr[0x00] + 5;
477 hblank_start_cclk = s->cr[0x02];
478 hblank_end_cclk = (s->cr[0x03] & 0x1f) + ((s->cr[0x05] & 0x80) >> 2);
479 hblank_skew_cclks = (s->cr[0x03] >> 5) & 3;
480
481 /* For vertical timings, we need both the blanking start/end... */
482 vtotal_lines = s->cr[0x06] + ((s->cr[0x07] & 1) << 8) + ((s->cr[0x07] & 0x20) << 4) + 2;
483 vblank_start_line = s->cr[0x15] + ((s->cr[0x07] & 8) << 5) + ((s->cr[0x09] & 0x20) << 4);
484 vblank_end = s->cr[0x16];
485 /* ... and the vertical retrace (vsync) start/end. */
486 vsync_start_line = s->cr[0x10] + ((s->cr[0x07] & 4) << 6) + ((s->cr[0x07] & 0x80) << 2);
487 vsync_end = s->cr[0x11] & 0xf;
488
489 /* Calculate the blanking and sync widths. The way it's implemented in
490 * the VGA with limited-width compare counters is quite a piece of work.
491 */
492 hblank_width = (hblank_end_cclk - hblank_start_cclk) & 0x3f;/* 6 bits */
493 vblank_width = (vblank_end - vblank_start_line) & 0xff; /* 8 bits */
494 vsync_width = (vsync_end - vsync_start_line) & 0xf; /* 4 bits */
495
496 /* Calculate the dot and character clock rates. */
497 clock_doubled = (s->sr[0x01] >> 3) & 1; /* Clock doubling bit. */
498 clock_index = (s->msr >> 2) & 3;
499 char_dots = (s->sr[0x01] & 1) ? 8 : 9; /* 8 or 9 dots per cclk. */
500
501 chars_per_sec = clocks[clock_index] / char_dots;
502 Assert(chars_per_sec); /* Can't possibly be zero. */
503
504 htotal_cclks <<= clock_doubled;
505
506 /* Calculate the number of cclks per entire frame. */
507 r->frame_cclks = vtotal_lines * htotal_cclks;
508 Assert(r->frame_cclks); /* Can't possibly be zero. */
509
510 if (r->v_freq_hz) { /* Could be set to emulate a specific rate. */
511 r->cclk_ns = 1000000000 / (r->frame_cclks * r->v_freq_hz);
512 } else {
513 r->cclk_ns = 1000000000 / chars_per_sec;
514 }
515 Assert(r->cclk_ns);
516 r->frame_ns = r->frame_cclks * r->cclk_ns;
517
518 /* Calculate timings in cclks/lines. Stored but not directly used. */
519 r->hb_start = hblank_start_cclk + hblank_skew_cclks;
520 r->hb_end = hblank_start_cclk + hblank_width + hblank_skew_cclks;
521 r->h_total = htotal_cclks;
522 Assert(r->h_total); /* Can't possibly be zero. */
523
524 r->vb_start = vblank_start_line;
525 r->vb_end = vblank_start_line + vblank_width + 1;
526 r->vs_start = vsync_start_line;
527 r->vs_end = vsync_start_line + vsync_width + 1;
528
529 /* Calculate timings in nanoseconds. For easier comparisons, the frame
530 * is considered to start at the beginning of the vertical and horizontal
531 * blanking period.
532 */
533 r->h_total_ns = htotal_cclks * r->cclk_ns;
534 r->hb_end_ns = hblank_width * r->cclk_ns;
535 r->vb_end_ns = vblank_width * r->h_total_ns;
536 r->vs_start_ns = (r->vs_start - r->vb_start) * r->h_total_ns;
537 r->vs_end_ns = (r->vs_end - r->vb_start) * r->h_total_ns;
538 Assert(r->h_total_ns); /* See h_total. */
539}
540
541static uint8_t vga_retrace(VGAState *s)
542{
543 vga_retrace_s *r = &s->retrace_state;
544
545 if (r->frame_ns) {
546 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
547 unsigned cur_frame_ns, cur_line_ns;
548 uint64_t time_ns;
549
550 time_ns = PDMDevHlpTMTimeVirtGetNano(VGASTATE2DEVINS(s));
551
552 /* Determine the time within the frame. */
553 cur_frame_ns = time_ns % r->frame_ns;
554
555 /* See if we're in the vertical blanking period... */
556 if (cur_frame_ns < r->vb_end_ns) {
557 val |= ST01_DISP_ENABLE;
558 /* ... and additionally in the vertical sync period. */
559 if (cur_frame_ns >= r->vs_start_ns && cur_frame_ns <= r->vs_end_ns)
560 val |= ST01_V_RETRACE;
561 } else {
562 /* Determine the time within the current scanline. */
563 cur_line_ns = cur_frame_ns % r->h_total_ns;
564 /* See if we're in the horizontal blanking period. */
565 if (cur_line_ns < r->hb_end_ns)
566 val |= ST01_DISP_ENABLE;
567 }
568 return val;
569 } else {
570 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
571 }
572}
573
574int vga_ioport_invalid(VGAState *s, uint32_t addr)
575{
576 if (s->msr & MSR_COLOR_EMULATION) {
577 /* Color */
578 return (addr >= 0x3b0 && addr <= 0x3bf);
579 } else {
580 /* Monochrome */
581 return (addr >= 0x3d0 && addr <= 0x3df);
582 }
583}
584
585static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
586{
587 VGAState *s = (VGAState*)opaque;
588 int val, index;
589
590 /* check port range access depending on color/monochrome mode */
591 if (vga_ioport_invalid(s, addr)) {
592 val = 0xff;
593 Log(("VGA: following read ignored\n"));
594 } else {
595 switch(addr) {
596 case 0x3c0:
597 if (s->ar_flip_flop == 0) {
598 val = s->ar_index;
599 } else {
600 val = 0;
601 }
602 break;
603 case 0x3c1:
604 index = s->ar_index & 0x1f;
605 if (index < 21)
606 val = s->ar[index];
607 else
608 val = 0;
609 break;
610 case 0x3c2:
611 val = s->st00;
612 break;
613 case 0x3c4:
614 val = s->sr_index;
615 break;
616 case 0x3c5:
617 val = s->sr[s->sr_index];
618 Log2(("vga: read SR%x = 0x%02x\n", s->sr_index, val));
619 break;
620 case 0x3c7:
621 val = s->dac_state;
622 break;
623 case 0x3c8:
624 val = s->dac_write_index;
625 break;
626 case 0x3c9:
627 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
628 if (++s->dac_sub_index == 3) {
629 s->dac_sub_index = 0;
630 s->dac_read_index++;
631 }
632 break;
633 case 0x3ca:
634 val = s->fcr;
635 break;
636 case 0x3cc:
637 val = s->msr;
638 break;
639 case 0x3ce:
640 val = s->gr_index;
641 break;
642 case 0x3cf:
643 val = s->gr[s->gr_index];
644 Log2(("vga: read GR%x = 0x%02x\n", s->gr_index, val));
645 break;
646 case 0x3b4:
647 case 0x3d4:
648 val = s->cr_index;
649 break;
650 case 0x3b5:
651 case 0x3d5:
652 val = s->cr[s->cr_index];
653 Log2(("vga: read CR%x = 0x%02x\n", s->cr_index, val));
654 break;
655 case 0x3ba:
656 case 0x3da:
657 val = s->st01 = vga_retrace(s);
658 s->ar_flip_flop = 0;
659 break;
660 default:
661 val = 0x00;
662 break;
663 }
664 }
665 Log(("VGA: read addr=0x%04x data=0x%02x\n", addr, val));
666 return val;
667}
668
669static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
670{
671 VGAState *s = (VGAState*)opaque;
672 int index;
673
674 Log(("VGA: write addr=0x%04x data=0x%02x\n", addr, val));
675
676 /* check port range access depending on color/monochrome mode */
677 if (vga_ioport_invalid(s, addr)) {
678 Log(("VGA: previous write ignored\n"));
679 return;
680 }
681
682 switch(addr) {
683 case 0x3c0:
684 if (s->ar_flip_flop == 0) {
685 val &= 0x3f;
686 s->ar_index = val;
687 } else {
688 index = s->ar_index & 0x1f;
689 switch(index) {
690 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
691 case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
692 s->ar[index] = val & 0x3f;
693 break;
694 case 0x10:
695 s->ar[index] = val & ~0x10;
696 break;
697 case 0x11:
698 s->ar[index] = val;
699 break;
700 case 0x12:
701 s->ar[index] = val & ~0xc0;
702 break;
703 case 0x13:
704 s->ar[index] = val & ~0xf0;
705 break;
706 case 0x14:
707 s->ar[index] = val & ~0xf0;
708 break;
709 default:
710 break;
711 }
712 }
713 s->ar_flip_flop ^= 1;
714 break;
715 case 0x3c2:
716 s->msr = val & ~0x10;
717 if (s->fRealRetrace)
718 vga_update_retrace_state(s);
719 s->st00 = (s->st00 & ~0x10) | (0x90 >> ((val >> 2) & 0x3));
720 break;
721 case 0x3c4:
722 s->sr_index = val & 7;
723 break;
724 case 0x3c5:
725 Log2(("vga: write SR%x = 0x%02x\n", s->sr_index, val));
726 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
727 /* Allow SR07 to disable VBE. */
728 if (s->sr_index == 0x07 && !(val & 1))
729 {
730 s->vbe_regs[VBE_DISPI_INDEX_ENABLE] = VBE_DISPI_DISABLED;
731 s->bank_offset = 0;
732 }
733 if (s->fRealRetrace && s->sr_index == 0x01)
734 vga_update_retrace_state(s);
735#ifndef IN_RC
736 /* The VGA region is (could be) affected by this change; reset all aliases we've created. */
737 if ( s->sr_index == 4 /* mode */
738 || s->sr_index == 2 /* plane mask */)
739 {
740 if (s->fRemappedVGA)
741 {
742 IOMMMIOResetRegion(PDMDevHlpGetVM(s->CTX_SUFF(pDevIns)), 0x000a0000);
743 s->fRemappedVGA = false;
744 }
745 }
746#endif
747 break;
748 case 0x3c7:
749 s->dac_read_index = val;
750 s->dac_sub_index = 0;
751 s->dac_state = 3;
752 break;
753 case 0x3c8:
754 s->dac_write_index = val;
755 s->dac_sub_index = 0;
756 s->dac_state = 0;
757 break;
758 case 0x3c9:
759 s->dac_cache[s->dac_sub_index] = val;
760 if (++s->dac_sub_index == 3) {
761 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
762 s->dac_sub_index = 0;
763 s->dac_write_index++;
764 }
765 break;
766 case 0x3ce:
767 s->gr_index = val & 0x0f;
768 break;
769 case 0x3cf:
770 Log2(("vga: write GR%x = 0x%02x\n", s->gr_index, val));
771 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
772
773#ifndef IN_RC
774 /* The VGA region is (could be) affected by this change; reset all aliases we've created. */
775 if (s->gr_index == 6 /* memory map mode */)
776 {
777 if (s->fRemappedVGA)
778 {
779 IOMMMIOResetRegion(PDMDevHlpGetVM(s->CTX_SUFF(pDevIns)), 0x000a0000);
780 s->fRemappedVGA = false;
781 }
782 }
783#endif
784 break;
785
786 case 0x3b4:
787 case 0x3d4:
788 s->cr_index = val;
789 break;
790 case 0x3b5:
791 case 0x3d5:
792 Log2(("vga: write CR%x = 0x%02x\n", s->cr_index, val));
793 /* handle CR0-7 protection */
794 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
795 /* can always write bit 4 of CR7 */
796 if (s->cr_index == 7)
797 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
798 return;
799 }
800 s->cr[s->cr_index] = val;
801
802 if (s->fRealRetrace) {
803 /* The following registers are only updated during a mode set. */
804 switch(s->cr_index) {
805 case 0x00:
806 case 0x02:
807 case 0x03:
808 case 0x05:
809 case 0x06:
810 case 0x07:
811 case 0x09:
812 case 0x10:
813 case 0x11:
814 case 0x15:
815 case 0x16:
816 vga_update_retrace_state(s);
817 break;
818 }
819 }
820 break;
821 case 0x3ba:
822 case 0x3da:
823 s->fcr = val & 0x10;
824 break;
825 }
826}
827
828#ifdef CONFIG_BOCHS_VBE
829static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
830{
831 VGAState *s = (VGAState*)opaque;
832 uint32_t val = s->vbe_index;
833 NOREF(addr);
834 return val;
835}
836
837static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
838{
839 VGAState *s = (VGAState*)opaque;
840 uint32_t val;
841 NOREF(addr);
842
843 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
844 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
845 switch(s->vbe_index) {
846 /* XXX: do not hardcode ? */
847 case VBE_DISPI_INDEX_XRES:
848 val = VBE_DISPI_MAX_XRES;
849 break;
850 case VBE_DISPI_INDEX_YRES:
851 val = VBE_DISPI_MAX_YRES;
852 break;
853 case VBE_DISPI_INDEX_BPP:
854 val = VBE_DISPI_MAX_BPP;
855 break;
856 default:
857 Assert(s->vbe_index < VBE_DISPI_INDEX_NB);
858 val = s->vbe_regs[s->vbe_index];
859 break;
860 }
861 } else {
862 switch(s->vbe_index) {
863 case VBE_DISPI_INDEX_VBOX_VIDEO:
864 /* Reading from the port means that the old additions are requesting the number of monitors. */
865 val = 1;
866 break;
867 default:
868 Assert(s->vbe_index < VBE_DISPI_INDEX_NB);
869 val = s->vbe_regs[s->vbe_index];
870 break;
871 }
872 }
873 } else {
874 val = 0;
875 }
876 Log(("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val));
877 return val;
878}
879
880#define VBE_PITCH_ALIGN 4 /* Align pitch to 32 bits - Qt requires that. */
881
882/* Calculate scanline pitch based on bit depth and width in pixels. */
883static uint32_t calc_line_pitch(uint16_t bpp, uint16_t width)
884{
885 uint32_t pitch, aligned_pitch;
886
887 if (bpp <= 4)
888 pitch = width >> 1;
889 else
890 pitch = width * ((bpp + 7) >> 3);
891
892 /* Align the pitch to some sensible value. */
893 aligned_pitch = (pitch + (VBE_PITCH_ALIGN - 1)) & ~(VBE_PITCH_ALIGN - 1);
894 if (aligned_pitch != pitch)
895 Log(("VBE: Line pitch %d aligned to %d bytes\n", pitch, aligned_pitch));
896
897 return aligned_pitch;
898}
899
900#ifdef SOME_UNUSED_FUNCTION
901/* Calculate line width in pixels based on bit depth and pitch. */
902static uint32_t calc_line_width(uint16_t bpp, uint32_t pitch)
903{
904 uint32_t width;
905
906 if (bpp <= 4)
907 width = pitch << 1;
908 else
909 width = pitch / ((bpp + 7) >> 3);
910
911 return width;
912}
913#endif
914
915static void recaltulate_data(VGAState *s, bool fVirtHeightOnly)
916{
917 uint16_t cBPP = s->vbe_regs[VBE_DISPI_INDEX_BPP];
918 uint16_t cVirtWidth = s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH];
919 uint16_t cX = s->vbe_regs[VBE_DISPI_INDEX_XRES];
920 if (!cBPP || !cX)
921 return; /* Not enough data has been set yet. */
922 uint32_t cbLinePitch = calc_line_pitch(cBPP, cVirtWidth);
923 if (!cbLinePitch)
924 cbLinePitch = calc_line_pitch(cBPP, cX);
925 Assert(cbLinePitch != 0);
926 uint32_t cVirtHeight = s->vram_size / cbLinePitch;
927 if (!fVirtHeightOnly)
928 {
929 uint16_t offX = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
930 uint16_t offY = s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
931 uint32_t offStart = cbLinePitch * offY;
932 if (cBPP == 4)
933 offStart += offX >> 1;
934 else
935 offStart += offX * ((cBPP + 7) >> 3);
936 offStart >>= 2;
937 s->vbe_line_offset = RT_MIN(cbLinePitch, s->vram_size);
938 s->vbe_start_addr = RT_MIN(offStart, s->vram_size);
939 }
940
941 /* The VBE_DISPI_INDEX_VIRT_HEIGHT is used to prevent setting resolution bigger than VRAM permits
942 * it is used instead of VBE_DISPI_INDEX_YRES *only* in case
943 * s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] < s->vbe_regs[VBE_DISPI_INDEX_YRES]
944 * We can not simply do s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = cVirtHeight since
945 * the cVirtHeight we calculated can exceed the 16bit value range
946 * instead we'll check if it's bigger than s->vbe_regs[VBE_DISPI_INDEX_YRES], and if yes,
947 * assign the s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] with a dummy UINT16_MAX value
948 * that is always bigger than s->vbe_regs[VBE_DISPI_INDEX_YRES]
949 * to just ensure the s->vbe_regs[VBE_DISPI_INDEX_YRES] is always used */
950 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = (cVirtHeight >= (uint32_t)s->vbe_regs[VBE_DISPI_INDEX_YRES]) ? UINT16_MAX : (uint16_t)cVirtHeight;
951}
952
953static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
954{
955 VGAState *s = (VGAState*)opaque;
956 s->vbe_index = val;
957 NOREF(addr);
958}
959
960static int vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
961{
962 VGAState *s = (VGAState*)opaque;
963 uint32_t max_bank;
964 NOREF(addr);
965
966 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
967 bool fRecalculate = false;
968 Log(("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val));
969 switch(s->vbe_index) {
970 case VBE_DISPI_INDEX_ID:
971 if (val == VBE_DISPI_ID0 ||
972 val == VBE_DISPI_ID1 ||
973 val == VBE_DISPI_ID2 ||
974 val == VBE_DISPI_ID3 ||
975 val == VBE_DISPI_ID4) {
976 s->vbe_regs[s->vbe_index] = val;
977 }
978 if (val == VBE_DISPI_ID_VBOX_VIDEO) {
979 s->vbe_regs[s->vbe_index] = val;
980 } else if (val == VBE_DISPI_ID_ANYX) {
981 s->vbe_regs[s->vbe_index] = val;
982 }
983#ifdef VBOX_WITH_HGSMI
984 else if (val == VBE_DISPI_ID_HGSMI) {
985 s->vbe_regs[s->vbe_index] = val;
986 }
987#endif /* VBOX_WITH_HGSMI */
988 break;
989 case VBE_DISPI_INDEX_XRES:
990 if (val <= VBE_DISPI_MAX_XRES)
991 {
992 s->vbe_regs[s->vbe_index] = val;
993 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = val;
994 fRecalculate = true;
995 }
996 break;
997 case VBE_DISPI_INDEX_YRES:
998 if (val <= VBE_DISPI_MAX_YRES)
999 s->vbe_regs[s->vbe_index] = val;
1000 break;
1001 case VBE_DISPI_INDEX_BPP:
1002 if (val == 0)
1003 val = 8;
1004 if (val == 4 || val == 8 || val == 15 ||
1005 val == 16 || val == 24 || val == 32) {
1006 s->vbe_regs[s->vbe_index] = val;
1007 fRecalculate = true;
1008 }
1009 break;
1010 case VBE_DISPI_INDEX_BANK:
1011 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] <= 4)
1012 max_bank = s->vbe_bank_max >> 2; /* Each bank really covers 256K */
1013 else
1014 max_bank = s->vbe_bank_max;
1015 /* Old software may pass garbage in the high byte of bank. If the maximum
1016 * bank fits into a single byte, toss the high byte the user supplied.
1017 */
1018 if (max_bank < 0x100)
1019 val &= 0xff;
1020 if (val > max_bank)
1021 val = max_bank;
1022 s->vbe_regs[s->vbe_index] = val;
1023 s->bank_offset = (val << 16);
1024
1025#ifndef IN_RC
1026 /* The VGA region is (could be) affected by this change; reset all aliases we've created. */
1027 if (s->fRemappedVGA)
1028 {
1029 IOMMMIOResetRegion(PDMDevHlpGetVM(s->CTX_SUFF(pDevIns)), 0x000a0000);
1030 s->fRemappedVGA = false;
1031 }
1032#endif
1033 break;
1034
1035 case VBE_DISPI_INDEX_ENABLE:
1036#ifndef IN_RING3
1037 return VINF_IOM_R3_IOPORT_WRITE;
1038#else
1039 if ((val & VBE_DISPI_ENABLED) &&
1040 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
1041 int h, shift_control;
1042 /* Check the values before we screw up with a resolution which is too big or small. */
1043 size_t cb = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1044 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
1045 cb = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
1046 else
1047 cb = s->vbe_regs[VBE_DISPI_INDEX_XRES] * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
1048 cb *= s->vbe_regs[VBE_DISPI_INDEX_YRES];
1049 uint16_t cVirtWidth = s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH];
1050 if (!cVirtWidth)
1051 cVirtWidth = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1052 if ( !cVirtWidth
1053 || !s->vbe_regs[VBE_DISPI_INDEX_YRES]
1054 || cb > s->vram_size)
1055 {
1056 AssertMsgFailed(("VIRT WIDTH=%d YRES=%d cb=%d vram_size=%d\n",
1057 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH], s->vbe_regs[VBE_DISPI_INDEX_YRES], cb, s->vram_size));
1058 return VINF_SUCCESS; /* Note: silent failure like before */
1059 }
1060
1061 /* When VBE interface is enabled, it is reset. */
1062 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
1063 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
1064 fRecalculate = true;
1065
1066 /* clear the screen (should be done in BIOS) */
1067 if (!(val & VBE_DISPI_NOCLEARMEM)) {
1068 uint16_t cY = RT_MIN(s->vbe_regs[VBE_DISPI_INDEX_YRES],
1069 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT]);
1070 uint16_t cbLinePitch = s->vbe_line_offset;
1071 memset(s->CTX_SUFF(vram_ptr), 0,
1072 cY * cbLinePitch);
1073 }
1074
1075 /* we initialize the VGA graphic mode (should be done
1076 in BIOS) */
1077 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
1078 s->cr[0x17] |= 3; /* no CGA modes */
1079 s->cr[0x13] = s->vbe_line_offset >> 3;
1080 /* width */
1081 s->cr[0x01] = (cVirtWidth >> 3) - 1;
1082 /* height (only meaningful if < 1024) */
1083 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
1084 s->cr[0x12] = h;
1085 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
1086 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
1087 /* line compare to 1023 */
1088 s->cr[0x18] = 0xff;
1089 s->cr[0x07] |= 0x10;
1090 s->cr[0x09] |= 0x40;
1091
1092 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
1093 shift_control = 0;
1094 s->sr[0x01] &= ~8; /* no double line */
1095 } else {
1096 shift_control = 2;
1097 s->sr[4] |= 0x08; /* set chain 4 mode */
1098 s->sr[2] |= 0x0f; /* activate all planes */
1099 /* Indicate non-VGA mode in SR07. */
1100 s->sr[7] |= 1;
1101 }
1102 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
1103 s->cr[0x09] &= ~0x9f; /* no double scan */
1104 /* sunlover 30.05.2007
1105 * The ar_index remains with bit 0x20 cleared after a switch from fullscreen
1106 * DOS mode on Windows XP guest. That leads to GMODE_BLANK in vga_update_display.
1107 * But the VBE mode is graphics, so not a blank anymore.
1108 */
1109 s->ar_index |= 0x20;
1110 } else {
1111 /* XXX: the bios should do that */
1112 /* sunlover 21.12.2006
1113 * Here is probably more to reset. When this was executed in GC
1114 * then the *update* functions could not detect a mode change.
1115 * Or may be these update function should take the s->vbe_regs[s->vbe_index]
1116 * into account when detecting a mode change.
1117 *
1118 * The 'mode reset not detected' problem is now fixed by executing the
1119 * VBE_DISPI_INDEX_ENABLE case always in RING3 in order to call the
1120 * LFBChange callback.
1121 */
1122 s->bank_offset = 0;
1123 }
1124 s->vbe_regs[s->vbe_index] = val;
1125 /*
1126 * LFB video mode is either disabled or changed. This notification
1127 * is used by the display to disable VBVA.
1128 */
1129 s->pDrv->pfnLFBModeChange(s->pDrv, (val & VBE_DISPI_ENABLED) != 0);
1130
1131 /* The VGA region is (could be) affected by this change; reset all aliases we've created. */
1132 if (s->fRemappedVGA)
1133 {
1134 IOMMMIOResetRegion(PDMDevHlpGetVM(s->CTX_SUFF(pDevIns)), 0x000a0000);
1135 s->fRemappedVGA = false;
1136 }
1137 break;
1138#endif /* IN_RING3 */
1139 case VBE_DISPI_INDEX_VIRT_WIDTH:
1140 case VBE_DISPI_INDEX_X_OFFSET:
1141 case VBE_DISPI_INDEX_Y_OFFSET:
1142 {
1143 s->vbe_regs[s->vbe_index] = val;
1144 fRecalculate = true;
1145 }
1146 break;
1147 case VBE_DISPI_INDEX_VBOX_VIDEO:
1148#ifndef IN_RING3
1149 return VINF_IOM_R3_IOPORT_WRITE;
1150#else
1151 /* Changes in the VGA device are minimal. The device is bypassed. The driver does all work. */
1152 if (val == VBOX_VIDEO_DISABLE_ADAPTER_MEMORY)
1153 {
1154 s->pDrv->pfnProcessAdapterData(s->pDrv, NULL, 0);
1155 }
1156 else if (val == VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY)
1157 {
1158 s->pDrv->pfnProcessAdapterData(s->pDrv, s->CTX_SUFF(vram_ptr), s->vram_size);
1159 }
1160 else if ((val & 0xFFFF0000) == VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE)
1161 {
1162 s->pDrv->pfnProcessDisplayData(s->pDrv, s->CTX_SUFF(vram_ptr), val & 0xFFFF);
1163 }
1164#endif /* IN_RING3 */
1165 break;
1166 default:
1167 break;
1168 }
1169 if (fRecalculate)
1170 {
1171 recaltulate_data(s, false);
1172 }
1173 }
1174 return VINF_SUCCESS;
1175}
1176#endif
1177
1178/* called for accesses between 0xa0000 and 0xc0000 */
1179static uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr, int *prc)
1180{
1181 VGAState *s = (VGAState*)opaque;
1182 int memory_map_mode, plane;
1183 uint32_t ret;
1184
1185 Log3(("vga: read [0x%x] -> ", addr));
1186 /* convert to VGA memory offset */
1187 memory_map_mode = (s->gr[6] >> 2) & 3;
1188#ifndef IN_RC
1189 RTGCPHYS GCPhys = addr; /* save original address */
1190#endif
1191
1192 addr &= 0x1ffff;
1193 switch(memory_map_mode) {
1194 case 0:
1195 break;
1196 case 1:
1197 if (addr >= 0x10000)
1198 return 0xff;
1199 addr += s->bank_offset;
1200 break;
1201 case 2:
1202 addr -= 0x10000;
1203 if (addr >= 0x8000)
1204 return 0xff;
1205 break;
1206 default:
1207 case 3:
1208 addr -= 0x18000;
1209 if (addr >= 0x8000)
1210 return 0xff;
1211 break;
1212 }
1213
1214 if (s->sr[4] & 0x08) {
1215 /* chain 4 mode : simplest access */
1216# ifndef IN_RC
1217 /* If all planes are accessible, then map the page to the frame buffer and make it writable. */
1218 if ( (s->sr[2] & 3) == 3
1219 && !vga_is_dirty(s, addr))
1220 {
1221 /** @todo only allow read access (doesn't work now) */
1222 STAM_COUNTER_INC(&s->StatMapPage);
1223 IOMMMIOMapMMIO2Page(PDMDevHlpGetVM(s->CTX_SUFF(pDevIns)), GCPhys, s->GCPhysVRAM + addr, X86_PTE_RW|X86_PTE_P);
1224 /* Set as dirty as write accesses won't be noticed now. */
1225 vga_set_dirty(s, addr);
1226 s->fRemappedVGA = true;
1227 }
1228# endif /* IN_RC */
1229 VERIFY_VRAM_READ_OFF_RETURN(s, addr, *prc);
1230 ret = s->CTX_SUFF(vram_ptr)[addr];
1231 } else if (!(s->sr[4] & 0x04)) { /* Host access is controlled by SR4, not GR5! */
1232 /* odd/even mode (aka text mode mapping) */
1233 plane = (s->gr[4] & 2) | (addr & 1);
1234 /* See the comment for a similar line in vga_mem_writeb. */
1235 RTGCPHYS off = ((addr & ~1) << 2) | plane;
1236 VERIFY_VRAM_READ_OFF_RETURN(s, off, *prc);
1237 ret = s->CTX_SUFF(vram_ptr)[off];
1238 } else {
1239 /* standard VGA latched access */
1240 VERIFY_VRAM_READ_OFF_RETURN(s, addr, *prc);
1241 s->latch = ((uint32_t *)s->CTX_SUFF(vram_ptr))[addr];
1242
1243 if (!(s->gr[5] & 0x08)) {
1244 /* read mode 0 */
1245 plane = s->gr[4];
1246 ret = GET_PLANE(s->latch, plane);
1247 } else {
1248 /* read mode 1 */
1249 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
1250 ret |= ret >> 16;
1251 ret |= ret >> 8;
1252 ret = (~ret) & 0xff;
1253 }
1254 }
1255 Log3((" 0x%02x\n", ret));
1256 return ret;
1257}
1258
1259/* called for accesses between 0xa0000 and 0xc0000 */
1260static int vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
1261{
1262 VGAState *s = (VGAState*)opaque;
1263 int memory_map_mode, plane, write_mode, b, func_select, mask;
1264 uint32_t write_mask, bit_mask, set_mask;
1265
1266 Log3(("vga: [0x%x] = 0x%02x\n", addr, val));
1267 /* convert to VGA memory offset */
1268 memory_map_mode = (s->gr[6] >> 2) & 3;
1269#ifndef IN_RC
1270 RTGCPHYS GCPhys = addr; /* save original address */
1271#endif
1272
1273 addr &= 0x1ffff;
1274 switch(memory_map_mode) {
1275 case 0:
1276 break;
1277 case 1:
1278 if (addr >= 0x10000)
1279 return VINF_SUCCESS;
1280 addr += s->bank_offset;
1281 break;
1282 case 2:
1283 addr -= 0x10000;
1284 if (addr >= 0x8000)
1285 return VINF_SUCCESS;
1286 break;
1287 default:
1288 case 3:
1289 addr -= 0x18000;
1290 if (addr >= 0x8000)
1291 return VINF_SUCCESS;
1292 break;
1293 }
1294
1295 if (s->sr[4] & 0x08) {
1296 /* chain 4 mode : simplest access */
1297 plane = addr & 3;
1298 mask = (1 << plane);
1299 if (s->sr[2] & mask) {
1300# ifndef IN_RC
1301 /* If all planes are accessible, then map the page to the frame buffer and make it writable. */
1302 if ( (s->sr[2] & 3) == 3
1303 && !vga_is_dirty(s, addr))
1304 {
1305 STAM_COUNTER_INC(&s->StatMapPage);
1306 IOMMMIOMapMMIO2Page(PDMDevHlpGetVM(s->CTX_SUFF(pDevIns)), GCPhys, s->GCPhysVRAM + addr, X86_PTE_RW | X86_PTE_P);
1307 s->fRemappedVGA = true;
1308 }
1309# endif /* IN_RC */
1310
1311 VERIFY_VRAM_WRITE_OFF_RETURN(s, addr);
1312 s->CTX_SUFF(vram_ptr)[addr] = val;
1313 Log3(("vga: chain4: [0x%x]\n", addr));
1314 s->plane_updated |= mask; /* only used to detect font change */
1315 vga_set_dirty(s, addr);
1316 }
1317 } else if (!(s->sr[4] & 0x04)) { /* Host access is controlled by SR4, not GR5! */
1318 /* odd/even mode (aka text mode mapping) */
1319 plane = (s->gr[4] & 2) | (addr & 1);
1320 mask = (1 << plane);
1321 if (s->sr[2] & mask) {
1322 /* 'addr' is offset in a plane, bit 0 selects the plane.
1323 * Mask the bit 0, convert plane index to vram offset,
1324 * that is multiply by the number of planes,
1325 * and select the plane byte in the vram offset.
1326 */
1327 addr = ((addr & ~1) << 2) | plane;
1328 VERIFY_VRAM_WRITE_OFF_RETURN(s, addr);
1329 s->CTX_SUFF(vram_ptr)[addr] = val;
1330 Log3(("vga: odd/even: [0x%x]\n", addr));
1331 s->plane_updated |= mask; /* only used to detect font change */
1332 vga_set_dirty(s, addr);
1333 }
1334 } else {
1335 /* standard VGA latched access */
1336 VERIFY_VRAM_WRITE_OFF_RETURN(s, addr * 4 + 3);
1337
1338#ifdef IN_RING0
1339 if (((++s->cLatchAccesses) & s->uMaskLatchAccess) == s->uMaskLatchAccess)
1340 {
1341 static uint32_t const s_aMask[5] = { 0x3ff, 0x1ff, 0x7f, 0x3f, 0x1f};
1342 static uint64_t const s_aDelta[5] = {10000000, 5000000, 2500000, 1250000, 625000};
1343 if (PDMDevHlpCanEmulateIoBlock(s->CTX_SUFF(pDevIns)))
1344 {
1345 uint64_t u64CurTime = RTTimeSystemNanoTS();
1346
1347 /* About 1000 (or more) accesses per 10 ms will trigger a reschedule
1348 * to the recompiler
1349 */
1350 if (u64CurTime - s->u64LastLatchedAccess < s_aDelta[s->iMask])
1351 {
1352 s->u64LastLatchedAccess = 0;
1353 s->iMask = RT_MIN(s->iMask + 1U, RT_ELEMENTS(s_aMask) - 1U);
1354 s->uMaskLatchAccess = s_aMask[s->iMask];
1355 s->cLatchAccesses = s->uMaskLatchAccess - 1;
1356 return VINF_EM_RAW_EMULATE_IO_BLOCK;
1357 }
1358 if (s->u64LastLatchedAccess)
1359 {
1360 Log2(("Reset mask (was %d) delta %RX64 (limit %x)\n", s->iMask, u64CurTime - s->u64LastLatchedAccess, s_aDelta[s->iMask]));
1361 if (s->iMask)
1362 s->iMask--;
1363 s->uMaskLatchAccess = s_aMask[s->iMask];
1364 }
1365 s->u64LastLatchedAccess = u64CurTime;
1366 }
1367 else
1368 {
1369 s->u64LastLatchedAccess = 0;
1370 s->iMask = 0;
1371 s->uMaskLatchAccess = s_aMask[s->iMask];
1372 s->cLatchAccesses = 0;
1373 }
1374 }
1375#endif
1376
1377 write_mode = s->gr[5] & 3;
1378 switch(write_mode) {
1379 default:
1380 case 0:
1381 /* rotate */
1382 b = s->gr[3] & 7;
1383 val = ((val >> b) | (val << (8 - b))) & 0xff;
1384 val |= val << 8;
1385 val |= val << 16;
1386
1387 /* apply set/reset mask */
1388 set_mask = mask16[s->gr[1]];
1389 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
1390 bit_mask = s->gr[8];
1391 break;
1392 case 1:
1393 val = s->latch;
1394 goto do_write;
1395 case 2:
1396 val = mask16[val & 0x0f];
1397 bit_mask = s->gr[8];
1398 break;
1399 case 3:
1400 /* rotate */
1401 b = s->gr[3] & 7;
1402 val = (val >> b) | (val << (8 - b));
1403
1404 bit_mask = s->gr[8] & val;
1405 val = mask16[s->gr[0]];
1406 break;
1407 }
1408
1409 /* apply logical operation */
1410 func_select = s->gr[3] >> 3;
1411 switch(func_select) {
1412 case 0:
1413 default:
1414 /* nothing to do */
1415 break;
1416 case 1:
1417 /* and */
1418 val &= s->latch;
1419 break;
1420 case 2:
1421 /* or */
1422 val |= s->latch;
1423 break;
1424 case 3:
1425 /* xor */
1426 val ^= s->latch;
1427 break;
1428 }
1429
1430 /* apply bit mask */
1431 bit_mask |= bit_mask << 8;
1432 bit_mask |= bit_mask << 16;
1433 val = (val & bit_mask) | (s->latch & ~bit_mask);
1434
1435 do_write:
1436 /* mask data according to sr[2] */
1437 mask = s->sr[2];
1438 s->plane_updated |= mask; /* only used to detect font change */
1439 write_mask = mask16[mask];
1440 ((uint32_t *)s->CTX_SUFF(vram_ptr))[addr] =
1441 (((uint32_t *)s->CTX_SUFF(vram_ptr))[addr] & ~write_mask) |
1442 (val & write_mask);
1443 Log3(("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
1444 addr * 4, write_mask, val));
1445 vga_set_dirty(s, (addr << 2));
1446 }
1447
1448 return VINF_SUCCESS;
1449}
1450
1451#if defined(IN_RING3)
1452typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
1453 const uint8_t *font_ptr, int h,
1454 uint32_t fgcol, uint32_t bgcol,
1455 int dscan);
1456typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
1457 const uint8_t *font_ptr, int h,
1458 uint32_t fgcol, uint32_t bgcol, int dup9);
1459typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
1460 const uint8_t *s, int width);
1461
1462static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
1463{
1464 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
1465}
1466
1467static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
1468{
1469 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
1470}
1471
1472static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
1473{
1474 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1475}
1476
1477static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
1478{
1479 return (r << 16) | (g << 8) | b;
1480}
1481
1482#define DEPTH 8
1483#include "DevVGATmpl.h"
1484
1485#define DEPTH 15
1486#include "DevVGATmpl.h"
1487
1488#define DEPTH 16
1489#include "DevVGATmpl.h"
1490
1491#define DEPTH 32
1492#include "DevVGATmpl.h"
1493
1494static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
1495{
1496 unsigned int col;
1497 col = rgb_to_pixel8(r, g, b);
1498 col |= col << 8;
1499 col |= col << 16;
1500 return col;
1501}
1502
1503static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
1504{
1505 unsigned int col;
1506 col = rgb_to_pixel15(r, g, b);
1507 col |= col << 16;
1508 return col;
1509}
1510
1511static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1512{
1513 unsigned int col;
1514 col = rgb_to_pixel16(r, g, b);
1515 col |= col << 16;
1516 return col;
1517}
1518
1519static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1520{
1521 unsigned int col;
1522 col = rgb_to_pixel32(r, g, b);
1523 return col;
1524}
1525
1526/* return true if the palette was modified */
1527static bool update_palette16(VGAState *s)
1528{
1529 bool full_update = false;
1530 int i;
1531 uint32_t v, col, *palette;
1532
1533 palette = s->last_palette;
1534 for(i = 0; i < 16; i++) {
1535 v = s->ar[i];
1536 if (s->ar[0x10] & 0x80)
1537 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1538 else
1539 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1540 v = v * 3;
1541 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1542 c6_to_8(s->palette[v + 1]),
1543 c6_to_8(s->palette[v + 2]));
1544 if (col != palette[i]) {
1545 full_update = true;
1546 palette[i] = col;
1547 }
1548 }
1549 return full_update;
1550}
1551
1552/* return true if the palette was modified */
1553static bool update_palette256(VGAState *s)
1554{
1555 bool full_update = false;
1556 int i;
1557 uint32_t v, col, *palette;
1558 int wide_dac;
1559
1560 palette = s->last_palette;
1561 v = 0;
1562 wide_dac = (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & (VBE_DISPI_ENABLED | VBE_DISPI_8BIT_DAC))
1563 == (VBE_DISPI_ENABLED | VBE_DISPI_8BIT_DAC);
1564 for(i = 0; i < 256; i++) {
1565 if (wide_dac)
1566 col = s->rgb_to_pixel(s->palette[v],
1567 s->palette[v + 1],
1568 s->palette[v + 2]);
1569 else
1570 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1571 c6_to_8(s->palette[v + 1]),
1572 c6_to_8(s->palette[v + 2]));
1573 if (col != palette[i]) {
1574 full_update = true;
1575 palette[i] = col;
1576 }
1577 v += 3;
1578 }
1579 return full_update;
1580}
1581
1582static void vga_get_offsets(VGAState *s,
1583 uint32_t *pline_offset,
1584 uint32_t *pstart_addr,
1585 uint32_t *pline_compare)
1586{
1587 uint32_t start_addr, line_offset, line_compare;
1588#ifdef CONFIG_BOCHS_VBE
1589 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1590 line_offset = s->vbe_line_offset;
1591 start_addr = s->vbe_start_addr;
1592 line_compare = 65535;
1593 } else
1594#endif
1595 {
1596 /* compute line_offset in bytes */
1597 line_offset = s->cr[0x13];
1598 line_offset <<= 3;
1599 if (!(s->cr[0x14] & 0x40) && !(s->cr[0x17] & 0x40))
1600 {
1601 /* Word mode. Used for odd/even modes. */
1602 line_offset *= 2;
1603 }
1604
1605 /* starting address */
1606 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1607
1608 /* line compare */
1609 line_compare = s->cr[0x18] |
1610 ((s->cr[0x07] & 0x10) << 4) |
1611 ((s->cr[0x09] & 0x40) << 3);
1612 }
1613 *pline_offset = line_offset;
1614 *pstart_addr = start_addr;
1615 *pline_compare = line_compare;
1616}
1617
1618/* update start_addr and line_offset. Return TRUE if modified */
1619static bool update_basic_params(VGAState *s)
1620{
1621 bool full_update = false;
1622 uint32_t start_addr, line_offset, line_compare;
1623
1624 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1625
1626 if (line_offset != s->line_offset ||
1627 start_addr != s->start_addr ||
1628 line_compare != s->line_compare) {
1629 s->line_offset = line_offset;
1630 s->start_addr = start_addr;
1631 s->line_compare = line_compare;
1632 full_update = true;
1633 }
1634 return full_update;
1635}
1636
1637static inline int get_depth_index(int depth)
1638{
1639 switch(depth) {
1640 default:
1641 case 8:
1642 return 0;
1643 case 15:
1644 return 1;
1645 case 16:
1646 return 2;
1647 case 32:
1648 return 3;
1649 }
1650}
1651
1652static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1653 vga_draw_glyph8_8,
1654 vga_draw_glyph8_16,
1655 vga_draw_glyph8_16,
1656 vga_draw_glyph8_32,
1657};
1658
1659static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1660 vga_draw_glyph16_8,
1661 vga_draw_glyph16_16,
1662 vga_draw_glyph16_16,
1663 vga_draw_glyph16_32,
1664};
1665
1666static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1667 vga_draw_glyph9_8,
1668 vga_draw_glyph9_16,
1669 vga_draw_glyph9_16,
1670 vga_draw_glyph9_32,
1671};
1672
1673static const uint8_t cursor_glyph[32 * 4] = {
1674 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1675 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1676 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1677 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1678 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1679 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1680 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1681 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1682 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1683 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1684 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1685 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1686 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1687 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1688 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1689 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1690};
1691
1692/*
1693 * Text mode update
1694 * Missing:
1695 * - underline
1696 * - flashing
1697 */
1698static int vga_draw_text(VGAState *s, bool full_update, bool fFailOnResize, bool reset_dirty)
1699{
1700 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1701 int cx_min, cx_max, linesize, x_incr;
1702 int cx_min_upd, cx_max_upd, cy_start;
1703 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1704 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1705 const uint8_t *font_ptr, *font_base[2];
1706 int dup9, line_offset, depth_index, dscan;
1707 uint32_t *palette;
1708 uint32_t *ch_attr_ptr;
1709 vga_draw_glyph8_func *vga_draw_glyph8;
1710 vga_draw_glyph9_func *vga_draw_glyph9;
1711
1712 full_update |= update_palette16(s);
1713 palette = s->last_palette;
1714
1715 /* compute font data address (in plane 2) */
1716 v = s->sr[3];
1717 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1718 if (offset != s->font_offsets[0]) {
1719 s->font_offsets[0] = offset;
1720 full_update = true;
1721 }
1722 font_base[0] = s->CTX_SUFF(vram_ptr) + offset;
1723
1724 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1725 font_base[1] = s->CTX_SUFF(vram_ptr) + offset;
1726 if (offset != s->font_offsets[1]) {
1727 s->font_offsets[1] = offset;
1728 full_update = true;
1729 }
1730 if (s->plane_updated & (1 << 2)) {
1731 /* if the plane 2 was modified since the last display, it
1732 indicates the font may have been modified */
1733 s->plane_updated = 0;
1734 full_update = true;
1735 }
1736 full_update |= update_basic_params(s);
1737
1738 line_offset = s->line_offset;
1739 s1 = s->CTX_SUFF(vram_ptr) + (s->start_addr * 8); /** @todo r=bird: Add comment why we do *8 instead of *4, it's not so obvious... */
1740
1741 /* double scanning - not for 9-wide modes */
1742 dscan = (s->cr[9] >> 7) & 1;
1743
1744 /* total width & height */
1745 cheight = (s->cr[9] & 0x1f) + 1;
1746 cw = 8;
1747 if (!(s->sr[1] & 0x01))
1748 cw = 9;
1749 if (s->sr[1] & 0x08)
1750 cw = 16; /* NOTE: no 18 pixel wide */
1751 x_incr = cw * ((s->pDrv->cBits + 7) >> 3);
1752 width = (s->cr[0x01] + 1);
1753 if (s->cr[0x06] == 100) {
1754 /* ugly hack for CGA 160x100x16 - explain me the logic */
1755 height = 100;
1756 } else {
1757 height = s->cr[0x12] |
1758 ((s->cr[0x07] & 0x02) << 7) |
1759 ((s->cr[0x07] & 0x40) << 3);
1760 height = (height + 1) / cheight;
1761 }
1762 if ((height * width) > CH_ATTR_SIZE) {
1763 /* better than nothing: exit if transient size is too big */
1764 return VINF_SUCCESS;
1765 }
1766
1767 if (width != (int)s->last_width || height != (int)s->last_height ||
1768 cw != s->last_cw || cheight != s->last_ch) {
1769 if (fFailOnResize)
1770 {
1771 /* The caller does not want to call the pfnResize. */
1772 return VERR_TRY_AGAIN;
1773 }
1774 s->last_scr_width = width * cw;
1775 s->last_scr_height = height * cheight;
1776 /* For text modes the direct use of guest VRAM is not implemented, so bpp and cbLine are 0 here. */
1777 int rc = s->pDrv->pfnResize(s->pDrv, 0, NULL, 0, s->last_scr_width, s->last_scr_height);
1778 s->last_width = width;
1779 s->last_height = height;
1780 s->last_ch = cheight;
1781 s->last_cw = cw;
1782 full_update = true;
1783 if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
1784 return rc;
1785 AssertRC(rc);
1786 }
1787 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1788 if (cursor_offset != s->cursor_offset ||
1789 s->cr[0xa] != s->cursor_start ||
1790 s->cr[0xb] != s->cursor_end) {
1791 /* if the cursor position changed, we update the old and new
1792 chars */
1793 if (s->cursor_offset < CH_ATTR_SIZE)
1794 s->last_ch_attr[s->cursor_offset] = ~0;
1795 if (cursor_offset < CH_ATTR_SIZE)
1796 s->last_ch_attr[cursor_offset] = ~0;
1797 s->cursor_offset = cursor_offset;
1798 s->cursor_start = s->cr[0xa];
1799 s->cursor_end = s->cr[0xb];
1800 }
1801 cursor_ptr = s->CTX_SUFF(vram_ptr) + (s->start_addr + cursor_offset) * 8;
1802 depth_index = get_depth_index(s->pDrv->cBits);
1803 if (cw == 16)
1804 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1805 else
1806 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1807 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1808
1809 dest = s->pDrv->pu8Data;
1810 linesize = s->pDrv->cbScanline;
1811 ch_attr_ptr = s->last_ch_attr;
1812 cy_start = -1;
1813 cx_max_upd = -1;
1814 cx_min_upd = width;
1815
1816 for(cy = 0; cy < height; cy = cy + (1 << dscan)) {
1817 d1 = dest;
1818 src = s1;
1819 cx_min = width;
1820 cx_max = -1;
1821 for(cx = 0; cx < width; cx++) {
1822 ch_attr = *(uint16_t *)src;
1823 if (full_update || ch_attr != (int)*ch_attr_ptr) {
1824 if (cx < cx_min)
1825 cx_min = cx;
1826 if (cx > cx_max)
1827 cx_max = cx;
1828 if (reset_dirty)
1829 *ch_attr_ptr = ch_attr;
1830#ifdef WORDS_BIGENDIAN
1831 ch = ch_attr >> 8;
1832 cattr = ch_attr & 0xff;
1833#else
1834 ch = ch_attr & 0xff;
1835 cattr = ch_attr >> 8;
1836#endif
1837 font_ptr = font_base[(cattr >> 3) & 1];
1838 font_ptr += 32 * 4 * ch;
1839 bgcol = palette[cattr >> 4];
1840 fgcol = palette[cattr & 0x0f];
1841 if (cw != 9) {
1842 vga_draw_glyph8(d1, linesize,
1843 font_ptr, cheight, fgcol, bgcol, dscan);
1844 } else {
1845 dup9 = 0;
1846 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1847 dup9 = 1;
1848 vga_draw_glyph9(d1, linesize,
1849 font_ptr, cheight, fgcol, bgcol, dup9);
1850 }
1851 if (src == cursor_ptr &&
1852 !(s->cr[0x0a] & 0x20)) {
1853 int line_start, line_last, h;
1854 /* draw the cursor */
1855 line_start = s->cr[0x0a] & 0x1f;
1856 line_last = s->cr[0x0b] & 0x1f;
1857 /* XXX: check that */
1858 if (line_last > cheight - 1)
1859 line_last = cheight - 1;
1860 if (line_last >= line_start && line_start < cheight) {
1861 h = line_last - line_start + 1;
1862 d = d1 + (linesize * line_start << dscan);
1863 if (cw != 9) {
1864 vga_draw_glyph8(d, linesize,
1865 cursor_glyph, h, fgcol, bgcol, dscan);
1866 } else {
1867 vga_draw_glyph9(d, linesize,
1868 cursor_glyph, h, fgcol, bgcol, 1);
1869 }
1870 }
1871 }
1872 }
1873 d1 += x_incr;
1874 src += 8; /* Every second byte of a plane is used in text mode. */
1875 ch_attr_ptr++;
1876 }
1877 if (cx_max != -1) {
1878 /* Keep track of the bounding rectangle for updates. */
1879 if (cy_start == -1)
1880 cy_start = cy;
1881 if (cx_min_upd > cx_min)
1882 cx_min_upd = cx_min;
1883 if (cx_max_upd < cx_max)
1884 cx_max_upd = cx_max;
1885 } else if (cy_start >= 0) {
1886 /* Flush updates to display. */
1887 s->pDrv->pfnUpdateRect(s->pDrv, cx_min_upd * cw, cy_start * cheight,
1888 (cx_max_upd - cx_min_upd + 1) * cw, (cy - cy_start) * cheight);
1889 cy_start = -1;
1890 cx_max_upd = -1;
1891 cx_min_upd = width;
1892 }
1893 dest += linesize * cheight << dscan;
1894 s1 += line_offset;
1895 }
1896 if (cy_start >= 0)
1897 /* Flush any remaining changes to display. */
1898 s->pDrv->pfnUpdateRect(s->pDrv, cx_min_upd * cw, cy_start * cheight,
1899 (cx_max_upd - cx_min_upd + 1) * cw, (cy - cy_start) * cheight);
1900 return VINF_SUCCESS;
1901}
1902
1903enum {
1904 VGA_DRAW_LINE2,
1905 VGA_DRAW_LINE2D2,
1906 VGA_DRAW_LINE4,
1907 VGA_DRAW_LINE4D2,
1908 VGA_DRAW_LINE8D2,
1909 VGA_DRAW_LINE8,
1910 VGA_DRAW_LINE15,
1911 VGA_DRAW_LINE16,
1912 VGA_DRAW_LINE24,
1913 VGA_DRAW_LINE32,
1914 VGA_DRAW_LINE_NB
1915};
1916
1917static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1918 vga_draw_line2_8,
1919 vga_draw_line2_16,
1920 vga_draw_line2_16,
1921 vga_draw_line2_32,
1922
1923 vga_draw_line2d2_8,
1924 vga_draw_line2d2_16,
1925 vga_draw_line2d2_16,
1926 vga_draw_line2d2_32,
1927
1928 vga_draw_line4_8,
1929 vga_draw_line4_16,
1930 vga_draw_line4_16,
1931 vga_draw_line4_32,
1932
1933 vga_draw_line4d2_8,
1934 vga_draw_line4d2_16,
1935 vga_draw_line4d2_16,
1936 vga_draw_line4d2_32,
1937
1938 vga_draw_line8d2_8,
1939 vga_draw_line8d2_16,
1940 vga_draw_line8d2_16,
1941 vga_draw_line8d2_32,
1942
1943 vga_draw_line8_8,
1944 vga_draw_line8_16,
1945 vga_draw_line8_16,
1946 vga_draw_line8_32,
1947
1948 vga_draw_line15_8,
1949 vga_draw_line15_15,
1950 vga_draw_line15_16,
1951 vga_draw_line15_32,
1952
1953 vga_draw_line16_8,
1954 vga_draw_line16_15,
1955 vga_draw_line16_16,
1956 vga_draw_line16_32,
1957
1958 vga_draw_line24_8,
1959 vga_draw_line24_15,
1960 vga_draw_line24_16,
1961 vga_draw_line24_32,
1962
1963 vga_draw_line32_8,
1964 vga_draw_line32_15,
1965 vga_draw_line32_16,
1966 vga_draw_line32_32,
1967};
1968
1969static int vga_get_bpp(VGAState *s)
1970{
1971 int ret;
1972#ifdef CONFIG_BOCHS_VBE
1973 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1974 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1975 } else
1976#endif
1977 {
1978 ret = 0;
1979 }
1980 return ret;
1981}
1982
1983static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1984{
1985 int width, height;
1986#ifdef CONFIG_BOCHS_VBE
1987 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1988 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1989 height = RT_MIN(s->vbe_regs[VBE_DISPI_INDEX_YRES],
1990 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT]);
1991 } else
1992#endif
1993 {
1994 width = (s->cr[0x01] + 1) * 8;
1995 height = s->cr[0x12] |
1996 ((s->cr[0x07] & 0x02) << 7) |
1997 ((s->cr[0x07] & 0x40) << 3);
1998 height = (height + 1);
1999 }
2000 *pwidth = width;
2001 *pheight = height;
2002}
2003
2004/**
2005 * Performs the display driver resizing when in graphics mode.
2006 *
2007 * This will recalc / update any status data depending on the driver
2008 * properties (bit depth mostly).
2009 *
2010 * @returns VINF_SUCCESS on success.
2011 * @returns VINF_VGA_RESIZE_IN_PROGRESS if the operation wasn't complete.
2012 * @param s Pointer to the vga status.
2013 * @param cx The width.
2014 * @param cy The height.
2015 */
2016static int vga_resize_graphic(VGAState *s, int cx, int cy)
2017{
2018 const unsigned cBits = s->get_bpp(s);
2019
2020 int rc;
2021 AssertReturn(cx, VERR_INVALID_PARAMETER);
2022 AssertReturn(cy, VERR_INVALID_PARAMETER);
2023 AssertPtrReturn(s, VERR_INVALID_POINTER);
2024 AssertReturn(s->line_offset, VERR_INTERNAL_ERROR);
2025
2026#if 0 //def VBOX_WITH_VDMA
2027 /* @todo: we get a second resize here when VBVA is on, while we actually should not */
2028 /* do not do pfnResize in case VBVA is on since all mode changes are performed over VBVA
2029 * we are checking for VDMA state here to ensure this code works only for WDDM driver,
2030 * although we should avoid calling pfnResize for XPDM as well, since pfnResize is actually an extra resize
2031 * event and generally only pfnVBVAxxx calls should be used with HGSMI + VBVA
2032 *
2033 * The reason for doing this for WDDM driver only now is to avoid regressions of the current code */
2034 PVBOXVDMAHOST pVdma = s->pVdma;
2035 if (pVdma && vboxVDMAIsEnabled(pVdma))
2036 rc = VINF_SUCCESS;
2037 else
2038#endif
2039 {
2040 /* Skip the resize if the values are not valid. */
2041 if (s->start_addr * 4 + s->line_offset * cy < s->vram_size)
2042 /* Take into account the programmed start address (in DWORDs) of the visible screen. */
2043 rc = s->pDrv->pfnResize(s->pDrv, cBits, s->CTX_SUFF(vram_ptr) + s->start_addr * 4, s->line_offset, cx, cy);
2044 else
2045 {
2046 /* Change nothing in the VGA state. Lets hope the guest will eventually programm correct values. */
2047 return VERR_TRY_AGAIN;
2048 }
2049 }
2050
2051 /* last stuff */
2052 s->last_bpp = cBits;
2053 s->last_scr_width = cx;
2054 s->last_scr_height = cy;
2055 s->last_width = cx;
2056 s->last_height = cy;
2057
2058 if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
2059 return rc;
2060 AssertRC(rc);
2061
2062 /* update palette */
2063 switch (s->pDrv->cBits)
2064 {
2065 case 32: s->rgb_to_pixel = rgb_to_pixel32_dup; break;
2066 case 16:
2067 default: s->rgb_to_pixel = rgb_to_pixel16_dup; break;
2068 case 15: s->rgb_to_pixel = rgb_to_pixel15_dup; break;
2069 case 8: s->rgb_to_pixel = rgb_to_pixel8_dup; break;
2070 }
2071 if (s->shift_control == 0)
2072 update_palette16(s);
2073 else if (s->shift_control == 1)
2074 update_palette16(s);
2075 return VINF_SUCCESS;
2076}
2077
2078/*
2079 * graphic modes
2080 */
2081static int vga_draw_graphic(VGAState *s, bool full_update, bool fFailOnResize, bool reset_dirty)
2082{
2083 int y1, y2, y, page_min, page_max, linesize, y_start, double_scan;
2084 int width, height, shift_control, line_offset, page0, page1, bwidth, bits;
2085 int disp_width, multi_run;
2086 uint8_t *d;
2087 uint32_t v, addr1, addr;
2088 vga_draw_line_func *vga_draw_line;
2089
2090 bool offsets_changed = update_basic_params(s);
2091
2092 full_update |= offsets_changed;
2093
2094 s->get_resolution(s, &width, &height);
2095 disp_width = width;
2096
2097 shift_control = (s->gr[0x05] >> 5) & 3;
2098 double_scan = (s->cr[0x09] >> 7);
2099 multi_run = double_scan;
2100 if (shift_control != s->shift_control ||
2101 double_scan != s->double_scan) {
2102 full_update = true;
2103 s->shift_control = shift_control;
2104 s->double_scan = double_scan;
2105 }
2106
2107 if (shift_control == 0) {
2108 full_update |= update_palette16(s);
2109 if (s->sr[0x01] & 8) {
2110 v = VGA_DRAW_LINE4D2;
2111 disp_width <<= 1;
2112 } else {
2113 v = VGA_DRAW_LINE4;
2114 }
2115 bits = 4;
2116 } else if (shift_control == 1) {
2117 full_update |= update_palette16(s);
2118 if (s->sr[0x01] & 8) {
2119 v = VGA_DRAW_LINE2D2;
2120 disp_width <<= 1;
2121 } else {
2122 v = VGA_DRAW_LINE2;
2123 }
2124 bits = 4;
2125 } else {
2126 switch(s->get_bpp(s)) {
2127 default:
2128 case 0:
2129 full_update |= update_palette256(s);
2130 v = VGA_DRAW_LINE8D2;
2131 bits = 4;
2132 break;
2133 case 8:
2134 full_update |= update_palette256(s);
2135 v = VGA_DRAW_LINE8;
2136 bits = 8;
2137 break;
2138 case 15:
2139 v = VGA_DRAW_LINE15;
2140 bits = 16;
2141 break;
2142 case 16:
2143 v = VGA_DRAW_LINE16;
2144 bits = 16;
2145 break;
2146 case 24:
2147 v = VGA_DRAW_LINE24;
2148 bits = 24;
2149 break;
2150 case 32:
2151 v = VGA_DRAW_LINE32;
2152 bits = 32;
2153 break;
2154 }
2155 }
2156 if ( disp_width != (int)s->last_width
2157 || height != (int)s->last_height
2158 || s->get_bpp(s) != (int)s->last_bpp
2159 || (offsets_changed && !s->fRenderVRAM))
2160 {
2161 if (fFailOnResize)
2162 {
2163 /* The caller does not want to call the pfnResize. */
2164 return VERR_TRY_AGAIN;
2165 }
2166 int rc = vga_resize_graphic(s, disp_width, height);
2167 if (rc != VINF_SUCCESS) /* Return any rc, particularly VINF_VGA_RESIZE_IN_PROGRESS, to the caller. */
2168 return rc;
2169 full_update = true;
2170 }
2171 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->pDrv->cBits)];
2172
2173 if (s->cursor_invalidate)
2174 s->cursor_invalidate(s);
2175
2176 line_offset = s->line_offset;
2177#if 0
2178 Log(("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
2179 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]));
2180#endif
2181 addr1 = (s->start_addr * 4);
2182 bwidth = (width * bits + 7) / 8; /* The visible width of a scanline. */
2183 y_start = -1;
2184 page_min = 0x7fffffff;
2185 page_max = -1;
2186 d = s->pDrv->pu8Data;
2187 linesize = s->pDrv->cbScanline;
2188
2189 y1 = 0;
2190 y2 = s->cr[0x09] & 0x1F; /* starting row scan count */
2191 for(y = 0; y < height; y++) {
2192 addr = addr1;
2193 /* CGA/MDA compatibility. Note that these addresses are all
2194 * shifted left by two compared to VGA specs.
2195 */
2196 if (!(s->cr[0x17] & 1)) {
2197 addr = (addr & ~(1 << 15)) | ((y1 & 1) << 15);
2198 }
2199 if (!(s->cr[0x17] & 2)) {
2200 addr = (addr & ~(1 << 16)) | ((y1 & 2) << 15);
2201 }
2202 page0 = addr & TARGET_PAGE_MASK;
2203 page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
2204 bool update = full_update | vga_is_dirty(s, page0) | vga_is_dirty(s, page1);
2205 if (page1 - page0 > TARGET_PAGE_SIZE) {
2206 /* if wide line, can use another page */
2207 update |= vga_is_dirty(s, page0 + TARGET_PAGE_SIZE);
2208 }
2209 /* explicit invalidation for the hardware cursor */
2210 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
2211 if (update) {
2212 if (y_start < 0)
2213 y_start = y;
2214 if (page0 < page_min)
2215 page_min = page0;
2216 if (page1 > page_max)
2217 page_max = page1;
2218 if (s->fRenderVRAM)
2219 vga_draw_line(s, d, s->CTX_SUFF(vram_ptr) + addr, width);
2220 if (s->cursor_draw_line)
2221 s->cursor_draw_line(s, d, y);
2222 } else {
2223 if (y_start >= 0) {
2224 /* flush to display */
2225 s->pDrv->pfnUpdateRect(s->pDrv, 0, y_start, disp_width, y - y_start);
2226 y_start = -1;
2227 }
2228 }
2229 if (!multi_run) {
2230 y1++;
2231 multi_run = double_scan;
2232
2233 if (y2 == 0) {
2234 y2 = s->cr[0x09] & 0x1F;
2235 addr1 += line_offset;
2236 } else {
2237 --y2;
2238 }
2239 } else {
2240 multi_run--;
2241 }
2242 /* line compare acts on the displayed lines */
2243 if ((uint32_t)y == s->line_compare)
2244 addr1 = 0;
2245 d += linesize;
2246 }
2247 if (y_start >= 0) {
2248 /* flush to display */
2249 s->pDrv->pfnUpdateRect(s->pDrv, 0, y_start, disp_width, y - y_start);
2250 }
2251 /* reset modified pages */
2252 if (page_max != -1 && reset_dirty) {
2253 vga_reset_dirty(s, page_min, page_max + TARGET_PAGE_SIZE);
2254 }
2255 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
2256 return VINF_SUCCESS;
2257}
2258
2259static void vga_draw_blank(VGAState *s, int full_update)
2260{
2261 int i, w, val;
2262 uint8_t *d;
2263 uint32_t cbScanline = s->pDrv->cbScanline;
2264
2265 if (s->pDrv->pu8Data == s->vram_ptrR3) /* Do not clear the VRAM itself. */
2266 return;
2267 if (!full_update)
2268 return;
2269 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
2270 return;
2271 if (s->pDrv->cBits == 8)
2272 val = s->rgb_to_pixel(0, 0, 0);
2273 else
2274 val = 0;
2275 w = s->last_scr_width * ((s->pDrv->cBits + 7) >> 3);
2276 d = s->pDrv->pu8Data;
2277 for(i = 0; i < (int)s->last_scr_height; i++) {
2278 memset(d, val, w);
2279 d += cbScanline;
2280 }
2281 s->pDrv->pfnUpdateRect(s->pDrv, 0, 0, s->last_scr_width, s->last_scr_height);
2282}
2283
2284static DECLCALLBACK(void) voidUpdateRect(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
2285{
2286 NOREF(pInterface); NOREF(x); NOREF(y); NOREF(cx); NOREF(cy);
2287}
2288
2289
2290#define GMODE_TEXT 0
2291#define GMODE_GRAPH 1
2292#define GMODE_BLANK 2
2293
2294static int vga_update_display(PVGASTATE s, bool fUpdateAll, bool fFailOnResize, bool reset_dirty)
2295{
2296 int rc = VINF_SUCCESS;
2297 int graphic_mode;
2298
2299 if (s->pDrv->cBits == 0) {
2300 /* nothing to do */
2301 } else {
2302 switch(s->pDrv->cBits) {
2303 case 8:
2304 s->rgb_to_pixel = rgb_to_pixel8_dup;
2305 break;
2306 case 15:
2307 s->rgb_to_pixel = rgb_to_pixel15_dup;
2308 break;
2309 default:
2310 case 16:
2311 s->rgb_to_pixel = rgb_to_pixel16_dup;
2312 break;
2313 case 32:
2314 s->rgb_to_pixel = rgb_to_pixel32_dup;
2315 break;
2316 }
2317
2318 if (fUpdateAll) {
2319 /* A full update is requested. Special processing for a "blank" mode is required, because
2320 * the request must process all pending resolution changes.
2321 *
2322 * Appropriate vga_draw_graphic or vga_draw_text function, which checks the resolution change,
2323 * must be called even if the screen has been blanked, but then the function should do no actual
2324 * screen update. To do this, pfnUpdateRect is replaced with a nop.
2325 */
2326 typedef DECLCALLBACK(void) FNUPDATERECT(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy);
2327 typedef FNUPDATERECT *PFNUPDATERECT;
2328
2329 PFNUPDATERECT pfnUpdateRect = NULL;
2330
2331 /* Detect the "screen blank" conditions. */
2332 int fBlank = 0;
2333 if (!(s->ar_index & 0x20) || (s->sr[0x01] & 0x20)) {
2334 fBlank = 1;
2335 }
2336
2337 if (fBlank) {
2338 /* Provide a void pfnUpdateRect callback. */
2339 if (s->pDrv) {
2340 pfnUpdateRect = s->pDrv->pfnUpdateRect;
2341 s->pDrv->pfnUpdateRect = voidUpdateRect;
2342 }
2343 }
2344
2345 /* Do a complete redraw, which will pick up a new screen resolution. */
2346 if (s->gr[6] & 1) {
2347 s->graphic_mode = GMODE_GRAPH;
2348 rc = vga_draw_graphic(s, 1, false, reset_dirty);
2349 } else {
2350 s->graphic_mode = GMODE_TEXT;
2351 rc = vga_draw_text(s, 1, false, reset_dirty);
2352 }
2353
2354 if (fBlank) {
2355 /* Set the current mode and restore the callback. */
2356 s->graphic_mode = GMODE_BLANK;
2357 if (s->pDrv) {
2358 s->pDrv->pfnUpdateRect = pfnUpdateRect;
2359 }
2360 }
2361 return rc;
2362 }
2363
2364 if (!(s->ar_index & 0x20) || (s->sr[0x01] & 0x20)) {
2365 graphic_mode = GMODE_BLANK;
2366 } else {
2367 graphic_mode = s->gr[6] & 1;
2368 }
2369 bool full_update = graphic_mode != s->graphic_mode;
2370 if (full_update) {
2371 s->graphic_mode = graphic_mode;
2372 }
2373 switch(graphic_mode) {
2374 case GMODE_TEXT:
2375 rc = vga_draw_text(s, full_update, fFailOnResize, reset_dirty);
2376 break;
2377 case GMODE_GRAPH:
2378 rc = vga_draw_graphic(s, full_update, fFailOnResize, reset_dirty);
2379 break;
2380 case GMODE_BLANK:
2381 default:
2382 vga_draw_blank(s, full_update);
2383 break;
2384 }
2385 }
2386 return rc;
2387}
2388
2389static void vga_save(QEMUFile *f, void *opaque)
2390{
2391 VGAState *s = (VGAState*)opaque;
2392 int i;
2393
2394 qemu_put_be32s(f, &s->latch);
2395 qemu_put_8s(f, &s->sr_index);
2396 qemu_put_buffer(f, s->sr, 8);
2397 qemu_put_8s(f, &s->gr_index);
2398 qemu_put_buffer(f, s->gr, 16);
2399 qemu_put_8s(f, &s->ar_index);
2400 qemu_put_buffer(f, s->ar, 21);
2401 qemu_put_be32s(f, &s->ar_flip_flop);
2402 qemu_put_8s(f, &s->cr_index);
2403 qemu_put_buffer(f, s->cr, 256);
2404 qemu_put_8s(f, &s->msr);
2405 qemu_put_8s(f, &s->fcr);
2406 qemu_put_8s(f, &s->st00);
2407 qemu_put_8s(f, &s->st01);
2408
2409 qemu_put_8s(f, &s->dac_state);
2410 qemu_put_8s(f, &s->dac_sub_index);
2411 qemu_put_8s(f, &s->dac_read_index);
2412 qemu_put_8s(f, &s->dac_write_index);
2413 qemu_put_buffer(f, s->dac_cache, 3);
2414 qemu_put_buffer(f, s->palette, 768);
2415
2416 qemu_put_be32s(f, &s->bank_offset);
2417#ifdef CONFIG_BOCHS_VBE
2418 qemu_put_byte(f, 1);
2419 qemu_put_be16s(f, &s->vbe_index);
2420 for(i = 0; i < VBE_DISPI_INDEX_NB_SAVED; i++)
2421 qemu_put_be16s(f, &s->vbe_regs[i]);
2422 qemu_put_be32s(f, &s->vbe_start_addr);
2423 qemu_put_be32s(f, &s->vbe_line_offset);
2424#else
2425 qemu_put_byte(f, 0);
2426#endif
2427}
2428
2429static int vga_load(QEMUFile *f, void *opaque, int version_id)
2430{
2431 VGAState *s = (VGAState*)opaque;
2432 int is_vbe, i;
2433 uint32_t u32Dummy;
2434
2435 qemu_get_be32s(f, &s->latch);
2436 qemu_get_8s(f, &s->sr_index);
2437 qemu_get_buffer(f, s->sr, 8);
2438 qemu_get_8s(f, &s->gr_index);
2439 qemu_get_buffer(f, s->gr, 16);
2440 qemu_get_8s(f, &s->ar_index);
2441 qemu_get_buffer(f, s->ar, 21);
2442 qemu_get_be32s(f, (uint32_t *)&s->ar_flip_flop);
2443 qemu_get_8s(f, &s->cr_index);
2444 qemu_get_buffer(f, s->cr, 256);
2445 qemu_get_8s(f, &s->msr);
2446 qemu_get_8s(f, &s->fcr);
2447 qemu_get_8s(f, &s->st00);
2448 qemu_get_8s(f, &s->st01);
2449
2450 qemu_get_8s(f, &s->dac_state);
2451 qemu_get_8s(f, &s->dac_sub_index);
2452 qemu_get_8s(f, &s->dac_read_index);
2453 qemu_get_8s(f, &s->dac_write_index);
2454 qemu_get_buffer(f, s->dac_cache, 3);
2455 qemu_get_buffer(f, s->palette, 768);
2456
2457 qemu_get_be32s(f, (uint32_t *)&s->bank_offset);
2458 is_vbe = qemu_get_byte(f);
2459#ifdef CONFIG_BOCHS_VBE
2460 if (!is_vbe)
2461 {
2462 Log(("vga_load: !is_vbe !!\n"));
2463 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2464 }
2465 qemu_get_be16s(f, &s->vbe_index);
2466 for(i = 0; i < VBE_DISPI_INDEX_NB_SAVED; i++)
2467 qemu_get_be16s(f, &s->vbe_regs[i]);
2468 if (version_id <= VGA_SAVEDSTATE_VERSION_INV_VHEIGHT)
2469 recaltulate_data(s, false); /* <- re-calculate the s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] since it might be invalid */
2470 qemu_get_be32s(f, &s->vbe_start_addr);
2471 qemu_get_be32s(f, &s->vbe_line_offset);
2472 if (version_id < 2)
2473 qemu_get_be32s(f, &u32Dummy);
2474 s->vbe_bank_max = (s->vram_size >> 16) - 1;
2475#else
2476 if (is_vbe)
2477 {
2478 Log(("vga_load: is_vbe !!\n"));
2479 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2480 }
2481#endif
2482
2483 /* force refresh */
2484 s->graphic_mode = -1;
2485 return 0;
2486}
2487
2488/* see vgaR3Construct */
2489static void vga_init_expand(void)
2490{
2491 int i, j, v, b;
2492
2493 for(i = 0;i < 256; i++) {
2494 v = 0;
2495 for(j = 0; j < 8; j++) {
2496 v |= ((i >> j) & 1) << (j * 4);
2497 }
2498 expand4[i] = v;
2499
2500 v = 0;
2501 for(j = 0; j < 4; j++) {
2502 v |= ((i >> (2 * j)) & 3) << (j * 4);
2503 }
2504 expand2[i] = v;
2505 }
2506 for(i = 0; i < 16; i++) {
2507 v = 0;
2508 for(j = 0; j < 4; j++) {
2509 b = ((i >> j) & 1);
2510 v |= b << (2 * j);
2511 v |= b << (2 * j + 1);
2512 }
2513 expand4to8[i] = v;
2514 }
2515}
2516
2517#endif /* !IN_RING0 */
2518
2519
2520
2521/* -=-=-=-=-=- all contexts -=-=-=-=-=- */
2522
2523/**
2524 * Port I/O Handler for VGA OUT operations.
2525 *
2526 * @returns VBox status code.
2527 *
2528 * @param pDevIns The device instance.
2529 * @param pvUser User argument - ignored.
2530 * @param Port Port number used for the IN operation.
2531 * @param u32 The value to output.
2532 * @param cb The value size in bytes.
2533 */
2534PDMBOTHCBDECL(int) vgaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2535{
2536 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
2537
2538 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_R3_IOPORT_WRITE);
2539 if (rc != VINF_SUCCESS)
2540 return rc;
2541
2542 NOREF(pvUser);
2543 if (cb == 1)
2544 vga_ioport_write(s, Port, u32);
2545 else if (cb == 2)
2546 {
2547 vga_ioport_write(s, Port, u32 & 0xff);
2548 vga_ioport_write(s, Port + 1, u32 >> 8);
2549 }
2550 PDMCritSectLeave(&s->lock);
2551 return VINF_SUCCESS;
2552}
2553
2554
2555/**
2556 * Port I/O Handler for VGA IN operations.
2557 *
2558 * @returns VBox status code.
2559 *
2560 * @param pDevIns The device instance.
2561 * @param pvUser User argument - ignored.
2562 * @param Port Port number used for the IN operation.
2563 * @param pu32 Where to store the result.
2564 * @param cb Number of bytes read.
2565 */
2566PDMBOTHCBDECL(int) vgaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2567{
2568 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
2569 NOREF(pvUser);
2570
2571 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_R3_IOPORT_READ);
2572 if (rc != VINF_SUCCESS)
2573 return rc;
2574
2575 rc = VERR_IOM_IOPORT_UNUSED;
2576 if (cb == 1)
2577 {
2578 *pu32 = vga_ioport_read(s, Port);
2579 rc = VINF_SUCCESS;
2580 }
2581 else if (cb == 2)
2582 {
2583 *pu32 = vga_ioport_read(s, Port)
2584 | (vga_ioport_read(s, Port + 1) << 8);
2585 rc = VINF_SUCCESS;
2586 }
2587 PDMCritSectLeave(&s->lock);
2588 return rc;
2589}
2590
2591
2592/**
2593 * Port I/O Handler for VBE OUT operations.
2594 *
2595 * @returns VBox status code.
2596 *
2597 * @param pDevIns The device instance.
2598 * @param pvUser User argument - ignored.
2599 * @param Port Port number used for the IN operation.
2600 * @param u32 The value to output.
2601 * @param cb The value size in bytes.
2602 */
2603PDMBOTHCBDECL(int) vgaIOPortWriteVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2604{
2605 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
2606
2607 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_R3_IOPORT_WRITE);
2608 if (rc != VINF_SUCCESS)
2609 return rc;
2610
2611 NOREF(pvUser);
2612
2613#ifndef IN_RING3
2614 /*
2615 * This has to be done on the host in order to execute the connector callbacks.
2616 */
2617 if ( s->vbe_index == VBE_DISPI_INDEX_ENABLE
2618 || s->vbe_index == VBE_DISPI_INDEX_VBOX_VIDEO)
2619 {
2620 Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE - Switching to host...\n"));
2621 PDMCritSectLeave(&s->lock);
2622 return VINF_IOM_R3_IOPORT_WRITE;
2623 }
2624#endif
2625#ifdef VBE_BYTEWISE_IO
2626 if (cb == 1)
2627 {
2628 if (!s->fWriteVBEData)
2629 {
2630 if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
2631 && (u32 & VBE_DISPI_ENABLED))
2632 {
2633 s->fWriteVBEData = false;
2634 rc = vbe_ioport_write_data(s, Port, u32 & 0xFF);
2635 PDMCritSectLeave(&s->lock);
2636 return rc;
2637 }
2638 else
2639 {
2640 s->cbWriteVBEData = u32 & 0xFF;
2641 s->fWriteVBEData = true;
2642 PDMCritSectLeave(&s->lock);
2643 return VINF_SUCCESS;
2644 }
2645 }
2646 else
2647 {
2648 u32 = (s->cbWriteVBEData << 8) | (u32 & 0xFF);
2649 s->fWriteVBEData = false;
2650 cb = 2;
2651 }
2652 }
2653#endif
2654 if (cb == 2 || cb == 4)
2655 {
2656//#ifdef IN_RC
2657// /*
2658// * The VBE_DISPI_INDEX_ENABLE memsets the entire frame buffer.
2659// * Since we're not mapping the entire framebuffer any longer that
2660// * has to be done on the host.
2661// */
2662// if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
2663// && (u32 & VBE_DISPI_ENABLED))
2664// {
2665// Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE & VBE_DISPI_ENABLED - Switching to host...\n"));
2666// return VINF_IOM_R3_IOPORT_WRITE;
2667// }
2668//#endif
2669 rc = vbe_ioport_write_data(s, Port, u32);
2670 PDMCritSectLeave(&s->lock);
2671 return rc;
2672 }
2673 else
2674 AssertMsgFailed(("vgaIOPortWriteVBEData: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2675
2676 PDMCritSectLeave(&s->lock);
2677 return VINF_SUCCESS;
2678}
2679
2680
2681/**
2682 * Port I/O Handler for VBE OUT operations.
2683 *
2684 * @returns VBox status code.
2685 *
2686 * @param pDevIns The device instance.
2687 * @param pvUser User argument - ignored.
2688 * @param Port Port number used for the IN operation.
2689 * @param u32 The value to output.
2690 * @param cb The value size in bytes.
2691 */
2692PDMBOTHCBDECL(int) vgaIOPortWriteVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2693{
2694 NOREF(pvUser);
2695 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
2696
2697 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_R3_IOPORT_WRITE);
2698 if (rc != VINF_SUCCESS)
2699 return rc;
2700
2701#ifdef VBE_BYTEWISE_IO
2702 if (cb == 1)
2703 {
2704 if (!s->fWriteVBEIndex)
2705 {
2706 s->cbWriteVBEIndex = u32 & 0x00FF;
2707 s->fWriteVBEIndex = true;
2708 PDMCritSectLeave(&s->lock);
2709 return VINF_SUCCESS;
2710 }
2711 else
2712 {
2713 s->fWriteVBEIndex = false;
2714 vbe_ioport_write_index(s, Port, (s->cbWriteVBEIndex << 8) | (u32 & 0x00FF));
2715 PDMCritSectLeave(&s->lock);
2716 return VINF_SUCCESS;
2717 }
2718 }
2719 else
2720#endif
2721 if (cb == 2)
2722 vbe_ioport_write_index(s, Port, u32);
2723 else
2724 AssertMsgFailed(("vgaIOPortWriteVBEIndex: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2725 PDMCritSectLeave(&s->lock);
2726 return VINF_SUCCESS;
2727}
2728
2729
2730/**
2731 * Port I/O Handler for VBE IN operations.
2732 *
2733 * @returns VBox status code.
2734 *
2735 * @param pDevIns The device instance.
2736 * @param pvUser User argument - ignored.
2737 * @param Port Port number used for the IN operation.
2738 * @param pu32 Where to store the result.
2739 * @param cb Number of bytes to read.
2740 */
2741PDMBOTHCBDECL(int) vgaIOPortReadVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2742{
2743 NOREF(pvUser);
2744 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
2745
2746 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_R3_IOPORT_READ);
2747 if (rc != VINF_SUCCESS)
2748 return rc;
2749
2750#ifdef VBE_BYTEWISE_IO
2751 if (cb == 1)
2752 {
2753 if (!s->fReadVBEData)
2754 {
2755 *pu32 = (vbe_ioport_read_data(s, Port) >> 8) & 0xFF;
2756 s->fReadVBEData = true;
2757 PDMCritSectLeave(&s->lock);
2758 return VINF_SUCCESS;
2759 }
2760 else
2761 {
2762 *pu32 = vbe_ioport_read_data(s, Port) & 0xFF;
2763 s->fReadVBEData = false;
2764 PDMCritSectLeave(&s->lock);
2765 return VINF_SUCCESS;
2766 }
2767 }
2768 else
2769#endif
2770 if (cb == 2)
2771 {
2772 *pu32 = vbe_ioport_read_data(s, Port);
2773 PDMCritSectLeave(&s->lock);
2774 return VINF_SUCCESS;
2775 }
2776 else if (cb == 4)
2777 {
2778 /* Quick hack for getting the vram size. */
2779 *pu32 = s->vram_size;
2780 PDMCritSectLeave(&s->lock);
2781 return VINF_SUCCESS;
2782 }
2783 AssertMsgFailed(("vgaIOPortReadVBEData: Port=%#x cb=%d\n", Port, cb));
2784 PDMCritSectLeave(&s->lock);
2785 return VERR_IOM_IOPORT_UNUSED;
2786}
2787
2788
2789/**
2790 * Port I/O Handler for VBE IN operations.
2791 *
2792 * @returns VBox status code.
2793 *
2794 * @param pDevIns The device instance.
2795 * @param pvUser User argument - ignored.
2796 * @param Port Port number used for the IN operation.
2797 * @param pu32 Where to store the result.
2798 * @param cb Number of bytes to read.
2799 */
2800PDMBOTHCBDECL(int) vgaIOPortReadVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2801{
2802 NOREF(pvUser);
2803 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
2804
2805 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_R3_IOPORT_READ);
2806 if (rc != VINF_SUCCESS)
2807 return rc;
2808
2809#ifdef VBE_BYTEWISE_IO
2810 if (cb == 1)
2811 {
2812 if (!s->fReadVBEIndex)
2813 {
2814 *pu32 = (vbe_ioport_read_index(s, Port) >> 8) & 0xFF;
2815 s->fReadVBEIndex = true;
2816 PDMCritSectLeave(&s->lock);
2817 return VINF_SUCCESS;
2818 }
2819 else
2820 {
2821 *pu32 = vbe_ioport_read_index(s, Port) & 0xFF;
2822 s->fReadVBEIndex = false;
2823 PDMCritSectLeave(&s->lock);
2824 return VINF_SUCCESS;
2825 }
2826 }
2827 else
2828#endif
2829 if (cb == 2)
2830 {
2831 *pu32 = vbe_ioport_read_index(s, Port);
2832 PDMCritSectLeave(&s->lock);
2833 return VINF_SUCCESS;
2834 }
2835 PDMCritSectLeave(&s->lock);
2836 AssertMsgFailed(("vgaIOPortReadVBEIndex: Port=%#x cb=%d\n", Port, cb));
2837 return VERR_IOM_IOPORT_UNUSED;
2838}
2839
2840#ifdef VBOX_WITH_HGSMI
2841#ifdef IN_RING3
2842/**
2843 * Port I/O Handler for HGSMI OUT operations.
2844 *
2845 * @returns VBox status code.
2846 *
2847 * @param pDevIns The device instance.
2848 * @param pvUser User argument - ignored.
2849 * @param Port Port number used for the operation.
2850 * @param u32 The value to output.
2851 * @param cb The value size in bytes.
2852 */
2853static DECLCALLBACK(int) vgaR3IOPortHGSMIWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2854{
2855 LogFlowFunc(("Port 0x%x, u32 0x%x, cb %d\n", Port, u32, cb));
2856 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
2857
2858 int rc = PDMCritSectEnter(&s->lock, VERR_SEM_BUSY);
2859 if (rc != VINF_SUCCESS)
2860 return rc;
2861
2862 NOREF(pvUser);
2863
2864 if (cb == 4)
2865 {
2866 switch (Port)
2867 {
2868 case VGA_PORT_HGSMI_HOST: /* Host */
2869 {
2870#if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM)
2871 if(u32 == HGSMIOFFSET_VOID)
2872 {
2873 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_LOW);
2874 HGSMIClearHostGuestFlags(s->pHGSMI, HGSMIHOSTFLAGS_IRQ);
2875 }
2876 else
2877#endif
2878 {
2879 HGSMIHostWrite(s->pHGSMI, u32);
2880 }
2881 } break;
2882
2883 case VGA_PORT_HGSMI_GUEST: /* Guest */
2884 {
2885 HGSMIGuestWrite(s->pHGSMI, u32);
2886 } break;
2887
2888 default:
2889 {
2890#ifdef DEBUG_sunlover
2891 AssertMsgFailed(("vgaR3IOPortHGSMIWrite: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2892#endif
2893 } break;
2894 }
2895 }
2896 else
2897 {
2898#ifdef DEBUG_sunlover
2899 AssertMsgFailed(("vgaR3IOPortHGSMIWrite: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2900#endif
2901 }
2902
2903 PDMCritSectLeave(&s->lock);
2904 return VINF_SUCCESS;
2905}
2906
2907/**
2908 * Port I/O Handler for HGSMI IN operations.
2909 *
2910 * @returns VBox status code.
2911 *
2912 * @param pDevIns The device instance.
2913 * @param pvUser User argument - ignored.
2914 * @param Port Port number used for the operation.
2915 * @param pu32 Where to store the result.
2916 * @param cb Number of bytes to read.
2917 */
2918static DECLCALLBACK(int) vgaR3IOPortHGSMIRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2919{
2920 LogFlowFunc(("Port 0x%x, cb %d\n", Port, cb));
2921 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
2922
2923 int rc = PDMCritSectEnter(&s->lock, VERR_SEM_BUSY);
2924 if (rc != VINF_SUCCESS)
2925 return rc;
2926
2927 NOREF(pvUser);
2928
2929 if (cb == 4)
2930 {
2931 switch (Port)
2932 {
2933 case VGA_PORT_HGSMI_HOST: /* Host */
2934 {
2935 *pu32 = HGSMIHostRead(s->pHGSMI);
2936 } break;
2937 case VGA_PORT_HGSMI_GUEST: /* Guest */
2938 {
2939 *pu32 = HGSMIGuestRead(s->pHGSMI);
2940 } break;
2941 default:
2942 {
2943#ifdef DEBUG_sunlover
2944 AssertMsgFailed(("vgaR3IOPortHGSMIRead: Port=%#x cb=%d\n", Port, cb));
2945#endif
2946 rc = VERR_IOM_IOPORT_UNUSED;
2947 } break;
2948 }
2949 }
2950 else
2951 {
2952#ifdef DEBUG_sunlover
2953 Log(("vgaR3IOPortHGSMIRead: Port=%#x cb=%d\n", Port, cb));
2954#endif
2955 rc = VERR_IOM_IOPORT_UNUSED;
2956 }
2957
2958 PDMCritSectLeave(&s->lock);
2959 return rc;
2960}
2961#endif /* IN_RING3 */
2962#endif /* VBOX_WITH_HGSMI */
2963
2964
2965
2966
2967/* -=-=-=-=-=- Guest Context -=-=-=-=-=- */
2968
2969/*
2970 * Internal. For use inside VGAGCMemoryFillWrite only.
2971 * Macro for apply logical operation and bit mask.
2972 */
2973#define APPLY_LOGICAL_AND_MASK(s, val, bit_mask) \
2974 /* apply logical operation */ \
2975 switch(s->gr[3] >> 3) \
2976 { \
2977 case 0: \
2978 default: \
2979 /* nothing to do */ \
2980 break; \
2981 case 1: \
2982 /* and */ \
2983 val &= s->latch; \
2984 break; \
2985 case 2: \
2986 /* or */ \
2987 val |= s->latch; \
2988 break; \
2989 case 3: \
2990 /* xor */ \
2991 val ^= s->latch; \
2992 break; \
2993 } \
2994 /* apply bit mask */ \
2995 val = (val & bit_mask) | (s->latch & ~bit_mask)
2996
2997/**
2998 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM and from the inside of VGADeviceGC.cpp.
2999 * This is the advanced version of vga_mem_writeb function.
3000 *
3001 * @returns VBox status code.
3002 * @param pThis VGA device structure
3003 * @param pvUser User argument - ignored.
3004 * @param GCPhysAddr Physical address of memory to write.
3005 * @param u32Item Data to write, up to 4 bytes.
3006 * @param cbItem Size of data Item, only 1/2/4 bytes is allowed for now.
3007 * @param cItems Number of data items to write.
3008 */
3009static int vgaInternalMMIOFill(PVGASTATE pThis, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems)
3010{
3011 uint32_t b;
3012 uint32_t write_mask, bit_mask, set_mask;
3013 uint32_t aVal[4];
3014 unsigned i;
3015 NOREF(pvUser);
3016
3017 for (i = 0; i < cbItem; i++)
3018 {
3019 aVal[i] = u32Item & 0xff;
3020 u32Item >>= 8;
3021 }
3022
3023 /* convert to VGA memory offset */
3024 /// @todo add check for the end of region
3025 GCPhysAddr &= 0x1ffff;
3026 switch((pThis->gr[6] >> 2) & 3) {
3027 case 0:
3028 break;
3029 case 1:
3030 if (GCPhysAddr >= 0x10000)
3031 return VINF_SUCCESS;
3032 GCPhysAddr += pThis->bank_offset;
3033 break;
3034 case 2:
3035 GCPhysAddr -= 0x10000;
3036 if (GCPhysAddr >= 0x8000)
3037 return VINF_SUCCESS;
3038 break;
3039 default:
3040 case 3:
3041 GCPhysAddr -= 0x18000;
3042 if (GCPhysAddr >= 0x8000)
3043 return VINF_SUCCESS;
3044 break;
3045 }
3046
3047 if (pThis->sr[4] & 0x08) {
3048 /* chain 4 mode : simplest access */
3049 VERIFY_VRAM_WRITE_OFF_RETURN(pThis, GCPhysAddr + cItems * cbItem - 1);
3050
3051 while (cItems-- > 0)
3052 for (i = 0; i < cbItem; i++)
3053 {
3054 if (pThis->sr[2] & (1 << (GCPhysAddr & 3)))
3055 {
3056 pThis->CTX_SUFF(vram_ptr)[GCPhysAddr] = aVal[i];
3057 vga_set_dirty(pThis, GCPhysAddr);
3058 }
3059 GCPhysAddr++;
3060 }
3061 } else if (pThis->gr[5] & 0x10) {
3062 /* odd/even mode (aka text mode mapping) */
3063 VERIFY_VRAM_WRITE_OFF_RETURN(pThis, GCPhysAddr * 2 + cItems * cbItem - 1);
3064 while (cItems-- > 0)
3065 for (i = 0; i < cbItem; i++)
3066 {
3067 unsigned plane = (pThis->gr[4] & 2) | (GCPhysAddr & 1);
3068 if (pThis->sr[2] & (1 << plane)) {
3069 RTGCPHYS PhysAddr2 = ((GCPhysAddr & ~1) << 2) | plane;
3070 pThis->CTX_SUFF(vram_ptr)[PhysAddr2] = aVal[i];
3071 vga_set_dirty(pThis, PhysAddr2);
3072 }
3073 GCPhysAddr++;
3074 }
3075 } else {
3076 /* standard VGA latched access */
3077 VERIFY_VRAM_WRITE_OFF_RETURN(pThis, GCPhysAddr + cItems * cbItem - 1);
3078
3079 switch(pThis->gr[5] & 3) {
3080 default:
3081 case 0:
3082 /* rotate */
3083 b = pThis->gr[3] & 7;
3084 bit_mask = pThis->gr[8];
3085 bit_mask |= bit_mask << 8;
3086 bit_mask |= bit_mask << 16;
3087 set_mask = mask16[pThis->gr[1]];
3088
3089 for (i = 0; i < cbItem; i++)
3090 {
3091 aVal[i] = ((aVal[i] >> b) | (aVal[i] << (8 - b))) & 0xff;
3092 aVal[i] |= aVal[i] << 8;
3093 aVal[i] |= aVal[i] << 16;
3094
3095 /* apply set/reset mask */
3096 aVal[i] = (aVal[i] & ~set_mask) | (mask16[pThis->gr[0]] & set_mask);
3097
3098 APPLY_LOGICAL_AND_MASK(pThis, aVal[i], bit_mask);
3099 }
3100 break;
3101 case 1:
3102 for (i = 0; i < cbItem; i++)
3103 aVal[i] = pThis->latch;
3104 break;
3105 case 2:
3106 bit_mask = pThis->gr[8];
3107 bit_mask |= bit_mask << 8;
3108 bit_mask |= bit_mask << 16;
3109 for (i = 0; i < cbItem; i++)
3110 {
3111 aVal[i] = mask16[aVal[i] & 0x0f];
3112
3113 APPLY_LOGICAL_AND_MASK(pThis, aVal[i], bit_mask);
3114 }
3115 break;
3116 case 3:
3117 /* rotate */
3118 b = pThis->gr[3] & 7;
3119
3120 for (i = 0; i < cbItem; i++)
3121 {
3122 aVal[i] = (aVal[i] >> b) | (aVal[i] << (8 - b));
3123 bit_mask = pThis->gr[8] & aVal[i];
3124 bit_mask |= bit_mask << 8;
3125 bit_mask |= bit_mask << 16;
3126 aVal[i] = mask16[pThis->gr[0]];
3127
3128 APPLY_LOGICAL_AND_MASK(pThis, aVal[i], bit_mask);
3129 }
3130 break;
3131 }
3132
3133 /* mask data according to sr[2] */
3134 write_mask = mask16[pThis->sr[2]];
3135
3136 /* actually write data */
3137 if (cbItem == 1)
3138 {
3139 /* The most frequently case is 1 byte I/O. */
3140 while (cItems-- > 0)
3141 {
3142 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
3143 vga_set_dirty(pThis, GCPhysAddr << 2);
3144 GCPhysAddr++;
3145 }
3146 }
3147 else if (cbItem == 2)
3148 {
3149 /* The second case is 2 bytes I/O. */
3150 while (cItems-- > 0)
3151 {
3152 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
3153 vga_set_dirty(pThis, GCPhysAddr << 2);
3154 GCPhysAddr++;
3155
3156 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[1] & write_mask);
3157 vga_set_dirty(pThis, GCPhysAddr << 2);
3158 GCPhysAddr++;
3159 }
3160 }
3161 else
3162 {
3163 /* And the rest is 4 bytes. */
3164 Assert(cbItem == 4);
3165 while (cItems-- > 0)
3166 for (i = 0; i < cbItem; i++)
3167 {
3168 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[i] & write_mask);
3169 vga_set_dirty(pThis, GCPhysAddr << 2);
3170 GCPhysAddr++;
3171 }
3172 }
3173 }
3174 return VINF_SUCCESS;
3175}
3176
3177/**
3178 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM and from the inside of VGADeviceGC.cpp.
3179 * This is the advanced version of vga_mem_writeb function.
3180 *
3181 * @returns VBox status code.
3182 * @param pDevIns Pointer device instance.
3183 * @param pvUser User argument - ignored.
3184 * @param GCPhysAddr Physical address of memory to write.
3185 * @param u32Item Data to write, up to 4 bytes.
3186 * @param cbItem Size of data Item, only 1/2/4 bytes is allowed for now.
3187 * @param cItems Number of data items to write.
3188 */
3189PDMBOTHCBDECL(int) vgaMMIOFill(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems)
3190{
3191 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3192
3193 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_R3_MMIO_WRITE);
3194 if (rc != VINF_SUCCESS)
3195 return rc;
3196
3197 rc = vgaInternalMMIOFill(pThis, pvUser, GCPhysAddr, u32Item, cbItem, cItems);
3198 PDMCritSectLeave(&pThis->lock);
3199 return rc;
3200}
3201#undef APPLY_LOGICAL_AND_MASK
3202
3203
3204/**
3205 * Legacy VGA memory (0xa0000 - 0xbffff) read hook, to be called from IOM.
3206 *
3207 * @returns VBox status code.
3208 * @param pDevIns Pointer device instance.
3209 * @param pvUser User argument - ignored.
3210 * @param GCPhysAddr Physical address of memory to read.
3211 * @param pv Where to store read data.
3212 * @param cb Bytes to read.
3213 */
3214PDMBOTHCBDECL(int) vgaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3215{
3216 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3217 STAM_PROFILE_START(&pThis->CTX_MID_Z(Stat,MemoryRead), a);
3218 NOREF(pvUser);
3219
3220 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_R3_MMIO_READ);
3221 if (rc != VINF_SUCCESS)
3222 return rc;
3223
3224 switch (cb)
3225 {
3226 case 1:
3227 *(uint8_t *)pv = vga_mem_readb(pThis, GCPhysAddr, &rc); break;
3228 case 2:
3229 *(uint16_t *)pv = vga_mem_readb(pThis, GCPhysAddr, &rc)
3230 | (vga_mem_readb(pThis, GCPhysAddr + 1, &rc) << 8);
3231 break;
3232 case 4:
3233 *(uint32_t *)pv = vga_mem_readb(pThis, GCPhysAddr, &rc)
3234 | (vga_mem_readb(pThis, GCPhysAddr + 1, &rc) << 8)
3235 | (vga_mem_readb(pThis, GCPhysAddr + 2, &rc) << 16)
3236 | (vga_mem_readb(pThis, GCPhysAddr + 3, &rc) << 24);
3237 break;
3238
3239 case 8:
3240 *(uint64_t *)pv = (uint64_t)vga_mem_readb(pThis, GCPhysAddr, &rc)
3241 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 1, &rc) << 8)
3242 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 2, &rc) << 16)
3243 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 3, &rc) << 24)
3244 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 4, &rc) << 32)
3245 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 5, &rc) << 40)
3246 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 6, &rc) << 48)
3247 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 7, &rc) << 56);
3248 break;
3249
3250 default:
3251 {
3252 uint8_t *pu8Data = (uint8_t *)pv;
3253 while (cb-- > 0)
3254 {
3255 *pu8Data++ = vga_mem_readb(pThis, GCPhysAddr++, &rc);
3256 if (RT_UNLIKELY(rc != VINF_SUCCESS))
3257 break;
3258 }
3259 }
3260 }
3261 STAM_PROFILE_STOP(&pThis->CTX_MID_Z(Stat,MemoryRead), a);
3262 PDMCritSectLeave(&pThis->lock);
3263 return rc;
3264}
3265
3266/**
3267 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM.
3268 *
3269 * @returns VBox status code.
3270 * @param pDevIns Pointer device instance.
3271 * @param pvUser User argument - ignored.
3272 * @param GCPhysAddr Physical address of memory to write.
3273 * @param pv Pointer to data.
3274 * @param cb Bytes to write.
3275 */
3276PDMBOTHCBDECL(int) vgaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
3277{
3278 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3279 uint8_t *pu8 = (uint8_t *)pv;
3280 NOREF(pvUser);
3281 STAM_PROFILE_START(&pThis->CTX_MID_Z(Stat,MemoryWrite), a);
3282
3283 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_R3_MMIO_WRITE);
3284 if (rc != VINF_SUCCESS)
3285 return rc;
3286
3287 switch (cb)
3288 {
3289 case 1:
3290 rc = vga_mem_writeb(pThis, GCPhysAddr, *pu8);
3291 break;
3292#if 1
3293 case 2:
3294 rc = vga_mem_writeb(pThis, GCPhysAddr + 0, pu8[0]);
3295 if (RT_LIKELY(rc == VINF_SUCCESS))
3296 rc = vga_mem_writeb(pThis, GCPhysAddr + 1, pu8[1]);
3297 break;
3298 case 4:
3299 rc = vga_mem_writeb(pThis, GCPhysAddr + 0, pu8[0]);
3300 if (RT_LIKELY(rc == VINF_SUCCESS))
3301 rc = vga_mem_writeb(pThis, GCPhysAddr + 1, pu8[1]);
3302 if (RT_LIKELY(rc == VINF_SUCCESS))
3303 rc = vga_mem_writeb(pThis, GCPhysAddr + 2, pu8[2]);
3304 if (RT_LIKELY(rc == VINF_SUCCESS))
3305 rc = vga_mem_writeb(pThis, GCPhysAddr + 3, pu8[3]);
3306 break;
3307 case 8:
3308 rc = vga_mem_writeb(pThis, GCPhysAddr + 0, pu8[0]);
3309 if (RT_LIKELY(rc == VINF_SUCCESS))
3310 rc = vga_mem_writeb(pThis, GCPhysAddr + 1, pu8[1]);
3311 if (RT_LIKELY(rc == VINF_SUCCESS))
3312 rc = vga_mem_writeb(pThis, GCPhysAddr + 2, pu8[2]);
3313 if (RT_LIKELY(rc == VINF_SUCCESS))
3314 rc = vga_mem_writeb(pThis, GCPhysAddr + 3, pu8[3]);
3315 if (RT_LIKELY(rc == VINF_SUCCESS))
3316 rc = vga_mem_writeb(pThis, GCPhysAddr + 4, pu8[4]);
3317 if (RT_LIKELY(rc == VINF_SUCCESS))
3318 rc = vga_mem_writeb(pThis, GCPhysAddr + 5, pu8[5]);
3319 if (RT_LIKELY(rc == VINF_SUCCESS))
3320 rc = vga_mem_writeb(pThis, GCPhysAddr + 6, pu8[6]);
3321 if (RT_LIKELY(rc == VINF_SUCCESS))
3322 rc = vga_mem_writeb(pThis, GCPhysAddr + 7, pu8[7]);
3323 break;
3324#else
3325 case 2:
3326 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint16_t *)pv, 2, 1);
3327 break;
3328 case 4:
3329 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint32_t *)pv, 4, 1);
3330 break;
3331 case 8:
3332 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint64_t *)pv, 8, 1);
3333 break;
3334#endif
3335 default:
3336 while (cb-- > 0 && rc == VINF_SUCCESS)
3337 rc = vga_mem_writeb(pThis, GCPhysAddr++, *pu8++);
3338 break;
3339
3340 }
3341 STAM_PROFILE_STOP(&pThis->CTX_MID_Z(Stat,MemoryWrite), a);
3342 PDMCritSectLeave(&pThis->lock);
3343 return rc;
3344}
3345
3346
3347/**
3348 * Handle LFB access.
3349 * @returns VBox status code.
3350 * @param pVM VM handle.
3351 * @param pThis VGA device instance data.
3352 * @param GCPhys The access physical address.
3353 * @param GCPtr The access virtual address (only GC).
3354 */
3355static int vgaLFBAccess(PVM pVM, PVGASTATE pThis, RTGCPHYS GCPhys, RTGCPTR GCPtr)
3356{
3357 int rc = PDMCritSectEnter(&pThis->lock, VINF_EM_RAW_EMULATE_INSTR);
3358 if (rc != VINF_SUCCESS)
3359 return rc;
3360
3361 /*
3362 * Set page dirty bit.
3363 */
3364 vga_set_dirty(pThis, GCPhys - pThis->GCPhysVRAM);
3365 pThis->fLFBUpdated = true;
3366
3367 /*
3368 * Turn of the write handler for this particular page and make it R/W.
3369 * Then return telling the caller to restart the guest instruction.
3370 * ASSUME: the guest always maps video memory RW.
3371 */
3372 rc = PGMHandlerPhysicalPageTempOff(pVM, pThis->GCPhysVRAM, GCPhys);
3373 if (RT_SUCCESS(rc))
3374 {
3375#ifndef IN_RING3
3376 rc = PGMShwMakePageWritable(PDMDevHlpGetVMCPU(pThis->CTX_SUFF(pDevIns)), GCPtr,
3377 PGM_MK_PG_IS_MMIO2 | PGM_MK_PG_IS_WRITE_FAULT);
3378 PDMCritSectLeave(&pThis->lock);
3379 AssertMsgReturn( rc == VINF_SUCCESS
3380 /* In the SMP case the page table might be removed while we wait for the PGM lock in the trap handler. */
3381 || rc == VERR_PAGE_TABLE_NOT_PRESENT
3382 || rc == VERR_PAGE_NOT_PRESENT,
3383 ("PGMShwModifyPage -> GCPtr=%RGv rc=%d\n", GCPtr, rc),
3384 rc);
3385#else /* IN_RING3 : We don't have any virtual page address of the access here. */
3386 PDMCritSectLeave(&pThis->lock);
3387 Assert(GCPtr == 0);
3388#endif
3389 return VINF_SUCCESS;
3390 }
3391
3392 PDMCritSectLeave(&pThis->lock);
3393 AssertMsgFailed(("PGMHandlerPhysicalPageTempOff -> rc=%d\n", rc));
3394 return rc;
3395}
3396
3397
3398#ifdef IN_RC
3399/**
3400 * #PF Handler for VBE LFB access.
3401 *
3402 * @returns VBox status code (appropriate for GC return).
3403 * @param pVM VM Handle.
3404 * @param uErrorCode CPU Error code.
3405 * @param pRegFrame Trap register frame.
3406 * @param pvFault The fault address (cr2).
3407 * @param GCPhysFault The GC physical address corresponding to pvFault.
3408 * @param pvUser User argument, ignored.
3409 */
3410PDMBOTHCBDECL(int) vgaGCLFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
3411{
3412 PVGASTATE pThis = (PVGASTATE)pvUser;
3413 AssertPtr(pThis);
3414 Assert(GCPhysFault >= pThis->GCPhysVRAM);
3415 AssertMsg(uErrorCode & X86_TRAP_PF_RW, ("uErrorCode=%#x\n", uErrorCode));
3416 NOREF(pRegFrame);
3417
3418 return vgaLFBAccess(pVM, pThis, GCPhysFault, pvFault);
3419}
3420
3421#elif IN_RING0
3422
3423/**
3424 * #PF Handler for VBE LFB access.
3425 *
3426 * @returns VBox status code (appropriate for GC return).
3427 * @param pVM VM Handle.
3428 * @param uErrorCode CPU Error code.
3429 * @param pRegFrame Trap register frame.
3430 * @param pvFault The fault address (cr2).
3431 * @param GCPhysFault The GC physical address corresponding to pvFault.
3432 * @param pvUser User argument, ignored.
3433 */
3434PDMBOTHCBDECL(int) vgaR0LFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
3435{
3436 PVGASTATE pThis = (PVGASTATE)pvUser;
3437 Assert(pThis);
3438 Assert(GCPhysFault >= pThis->GCPhysVRAM);
3439 AssertMsg(uErrorCode & X86_TRAP_PF_RW, ("uErrorCode=%#x\n", uErrorCode));
3440 NOREF(pRegFrame);
3441
3442 return vgaLFBAccess(pVM, pThis, GCPhysFault, pvFault);
3443}
3444
3445#else /* IN_RING3 */
3446
3447/**
3448 * HC access handler for the LFB.
3449 *
3450 * @returns VINF_SUCCESS if the handler have carried out the operation.
3451 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
3452 * @param pVM VM Handle.
3453 * @param GCPhys The physical address the guest is writing to.
3454 * @param pvPhys The HC mapping of that address.
3455 * @param pvBuf What the guest is reading/writing.
3456 * @param cbBuf How much it's reading/writing.
3457 * @param enmAccessType The access type.
3458 * @param pvUser User argument.
3459 */
3460static DECLCALLBACK(int) vgaR3LFBAccessHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
3461{
3462 PVGASTATE pThis = (PVGASTATE)pvUser;
3463 int rc;
3464 Assert(pThis);
3465 Assert(GCPhys >= pThis->GCPhysVRAM);
3466 NOREF(pvPhys); NOREF(pvBuf); NOREF(cbBuf); NOREF(enmAccessType);
3467
3468 rc = vgaLFBAccess(pVM, pThis, GCPhys, 0);
3469 if (RT_SUCCESS(rc))
3470 return VINF_PGM_HANDLER_DO_DEFAULT;
3471 AssertMsg(rc <= VINF_SUCCESS, ("rc=%Rrc\n", rc));
3472 return rc;
3473}
3474#endif /* IN_RING3 */
3475
3476/* -=-=-=-=-=- All rings: VGA BIOS I/Os -=-=-=-=-=- */
3477
3478/**
3479 * Port I/O Handler for VGA BIOS IN operations.
3480 *
3481 * @returns VBox status code.
3482 *
3483 * @param pDevIns The device instance.
3484 * @param pvUser User argument - ignored.
3485 * @param Port Port number used for the IN operation.
3486 * @param pu32 Where to store the result.
3487 * @param cb Number of bytes read.
3488 */
3489PDMBOTHCBDECL(int) vgaIOPortReadBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3490{
3491 NOREF(pDevIns);
3492 NOREF(pvUser);
3493 NOREF(Port);
3494 NOREF(pu32);
3495 NOREF(cb);
3496 return VERR_IOM_IOPORT_UNUSED;
3497}
3498
3499/**
3500 * Port I/O Handler for VGA BIOS OUT operations.
3501 *
3502 * @returns VBox status code.
3503 *
3504 * @param pDevIns The device instance.
3505 * @param pvUser User argument - ignored.
3506 * @param Port Port number used for the IN operation.
3507 * @param u32 The value to output.
3508 * @param cb The value size in bytes.
3509 */
3510PDMBOTHCBDECL(int) vgaIOPortWriteBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3511{
3512 static int lastWasNotNewline = 0; /* We are only called in a single-threaded way */
3513 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3514 NOREF(pvUser);
3515
3516 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_R3_IOPORT_WRITE);
3517 if (rc != VINF_SUCCESS)
3518 return rc;
3519
3520 /*
3521 * VGA BIOS char printing.
3522 */
3523 if ( cb == 1
3524 && Port == VBE_PRINTF_PORT)
3525 {
3526#if 0
3527 switch (u32)
3528 {
3529 case '\r': Log(("vgabios: <return>\n")); break;
3530 case '\n': Log(("vgabios: <newline>\n")); break;
3531 case '\t': Log(("vgabios: <tab>\n")); break;
3532 default:
3533 Log(("vgabios: %c\n", u32));
3534 }
3535#else
3536 if (lastWasNotNewline == 0)
3537 Log(("vgabios: "));
3538 if (u32 != '\r') /* return - is only sent in conjunction with '\n' */
3539 Log(("%c", u32));
3540 if (u32 == '\n')
3541 lastWasNotNewline = 0;
3542 else
3543 lastWasNotNewline = 1;
3544#endif
3545 PDMCritSectLeave(&pThis->lock);
3546 return VINF_SUCCESS;
3547 }
3548
3549 PDMCritSectLeave(&pThis->lock);
3550 /* not in use. */
3551 return VERR_IOM_IOPORT_UNUSED;
3552}
3553
3554
3555/* -=-=-=-=-=- Ring 3 -=-=-=-=-=- */
3556
3557#ifdef IN_RING3
3558
3559# ifdef VBE_NEW_DYN_LIST
3560/**
3561 * Port I/O Handler for VBE Extra OUT operations.
3562 *
3563 * @returns VBox status code.
3564 *
3565 * @param pDevIns The device instance.
3566 * @param pvUser User argument - ignored.
3567 * @param Port Port number used for the IN operation.
3568 * @param u32 The value to output.
3569 * @param cb The value size in bytes.
3570 */
3571PDMBOTHCBDECL(int) vbeIOPortWriteVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3572{
3573 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3574 NOREF(pvUser);
3575 NOREF(Port);
3576
3577 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_R3_IOPORT_WRITE);
3578 if (rc != VINF_SUCCESS)
3579 return rc;
3580
3581 if (cb == 2)
3582 {
3583 Log(("vbeIOPortWriteVBEExtra: addr=%#RX32\n", u32));
3584 pThis->u16VBEExtraAddress = u32;
3585 }
3586 else
3587 Log(("vbeIOPortWriteVBEExtra: Ignoring invalid cb=%d writes to the VBE Extra port!!!\n", cb));
3588 PDMCritSectLeave(&pThis->lock);
3589
3590 return VINF_SUCCESS;
3591}
3592
3593
3594/**
3595 * Port I/O Handler for VBE Extra IN operations.
3596 *
3597 * @returns VBox status code.
3598 *
3599 * @param pDevIns The device instance.
3600 * @param pvUser User argument - ignored.
3601 * @param Port Port number used for the IN operation.
3602 * @param pu32 Where to store the result.
3603 * @param cb Number of bytes read.
3604 */
3605PDMBOTHCBDECL(int) vbeIOPortReadVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3606{
3607 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3608 NOREF(pvUser);
3609 NOREF(Port);
3610
3611 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_R3_IOPORT_READ);
3612 if (rc != VINF_SUCCESS)
3613 return rc;
3614
3615 if (pThis->u16VBEExtraAddress == 0xffff)
3616 {
3617 Log(("vbeIOPortReadVBEExtra: Requested number of 64k video banks\n"));
3618 *pu32 = pThis->vram_size / _64K;
3619 rc = VINF_SUCCESS;
3620 }
3621 else
3622 if ( pThis->u16VBEExtraAddress >= pThis->cbVBEExtraData
3623 || pThis->u16VBEExtraAddress + cb > pThis->cbVBEExtraData)
3624 {
3625 *pu32 = 0;
3626 Log(("vbeIOPortReadVBEExtra: Requested address is out of VBE data!!! Address=%#x(%d) cbVBEExtraData=%#x(%d)\n",
3627 pThis->u16VBEExtraAddress, pThis->u16VBEExtraAddress, pThis->cbVBEExtraData, pThis->cbVBEExtraData));
3628 rc = VINF_SUCCESS;
3629 }
3630 else
3631 if (cb == 1)
3632 {
3633 *pu32 = pThis->pu8VBEExtraData[pThis->u16VBEExtraAddress] & 0xFF;
3634
3635 Log(("vbeIOPortReadVBEExtra: cb=%#x %.*Rhxs\n", cb, cb, pu32));
3636 rc = VINF_SUCCESS;
3637 }
3638 else
3639 if (cb == 2)
3640 {
3641 *pu32 = pThis->pu8VBEExtraData[pThis->u16VBEExtraAddress]
3642 | pThis->pu8VBEExtraData[pThis->u16VBEExtraAddress + 1] << 8;
3643
3644 Log(("vbeIOPortReadVBEExtra: cb=%#x %.*Rhxs\n", cb, cb, pu32));
3645 rc = VINF_SUCCESS;
3646 }
3647 else
3648 {
3649 Log(("vbeIOPortReadVBEExtra: Invalid cb=%d read from the VBE Extra port!!!\n", cb));
3650 rc = VERR_IOM_IOPORT_UNUSED;
3651 }
3652
3653 PDMCritSectLeave(&pThis->lock);
3654 return rc;
3655}
3656# endif /* VBE_NEW_DYN_LIST */
3657
3658
3659/**
3660 * Parse the logo bitmap data at init time.
3661 *
3662 * @returns VBox status code.
3663 *
3664 * @param pThis The VGA instance data.
3665 */
3666static int vbeParseBitmap(PVGASTATE pThis)
3667{
3668 uint16_t i;
3669 PBMPINFO bmpInfo;
3670 POS2HDR pOs2Hdr;
3671 POS22HDR pOs22Hdr;
3672 PWINHDR pWinHdr;
3673
3674 /*
3675 * Get bitmap header data
3676 */
3677 bmpInfo = (PBMPINFO)(pThis->pu8Logo + sizeof(LOGOHDR));
3678 pWinHdr = (PWINHDR)(pThis->pu8Logo + sizeof(LOGOHDR) + sizeof(BMPINFO));
3679
3680 if (bmpInfo->Type == BMP_ID)
3681 {
3682 switch (pWinHdr->Size)
3683 {
3684 case BMP_HEADER_OS21:
3685 pOs2Hdr = (POS2HDR)pWinHdr;
3686 pThis->cxLogo = pOs2Hdr->Width;
3687 pThis->cyLogo = pOs2Hdr->Height;
3688 pThis->cLogoPlanes = pOs2Hdr->Planes;
3689 pThis->cLogoBits = pOs2Hdr->BitCount;
3690 pThis->LogoCompression = BMP_COMPRESS_NONE;
3691 pThis->cLogoUsedColors = 0;
3692 break;
3693
3694 case BMP_HEADER_OS22:
3695 pOs22Hdr = (POS22HDR)pWinHdr;
3696 pThis->cxLogo = pOs22Hdr->Width;
3697 pThis->cyLogo = pOs22Hdr->Height;
3698 pThis->cLogoPlanes = pOs22Hdr->Planes;
3699 pThis->cLogoBits = pOs22Hdr->BitCount;
3700 pThis->LogoCompression = pOs22Hdr->Compression;
3701 pThis->cLogoUsedColors = pOs22Hdr->ClrUsed;
3702 break;
3703
3704 case BMP_HEADER_WIN3:
3705 pThis->cxLogo = pWinHdr->Width;
3706 pThis->cyLogo = pWinHdr->Height;
3707 pThis->cLogoPlanes = pWinHdr->Planes;
3708 pThis->cLogoBits = pWinHdr->BitCount;
3709 pThis->LogoCompression = pWinHdr->Compression;
3710 pThis->cLogoUsedColors = pWinHdr->ClrUsed;
3711 break;
3712
3713 default:
3714 AssertMsgFailed(("Unsupported bitmap header.\n"));
3715 break;
3716 }
3717
3718 if (pThis->cxLogo > LOGO_MAX_WIDTH || pThis->cyLogo > LOGO_MAX_HEIGHT)
3719 {
3720 AssertMsgFailed(("Bitmap %ux%u is too big.\n", pThis->cxLogo, pThis->cyLogo));
3721 return VERR_INVALID_PARAMETER;
3722 }
3723
3724 if (pThis->cLogoPlanes != 1)
3725 {
3726 AssertMsgFailed(("Bitmap planes %u != 1.\n", pThis->cLogoPlanes));
3727 return VERR_INVALID_PARAMETER;
3728 }
3729
3730 if (pThis->cLogoBits != 4 && pThis->cLogoBits != 8 && pThis->cLogoBits != 24)
3731 {
3732 AssertMsgFailed(("Unsupported %u depth.\n", pThis->cLogoBits));
3733 return VERR_INVALID_PARAMETER;
3734 }
3735
3736 if (pThis->cLogoUsedColors > 256)
3737 {
3738 AssertMsgFailed(("Unsupported %u colors.\n", pThis->cLogoUsedColors));
3739 return VERR_INVALID_PARAMETER;
3740 }
3741
3742 if (pThis->LogoCompression != BMP_COMPRESS_NONE)
3743 {
3744 AssertMsgFailed(("Unsupported %u compression.\n", pThis->LogoCompression));
3745 return VERR_INVALID_PARAMETER;
3746 }
3747
3748 /*
3749 * Read bitmap palette
3750 */
3751 if (!pThis->cLogoUsedColors)
3752 pThis->cLogoPalEntries = 1 << (pThis->cLogoPlanes * pThis->cLogoBits);
3753 else
3754 pThis->cLogoPalEntries = pThis->cLogoUsedColors;
3755
3756 if (pThis->cLogoPalEntries)
3757 {
3758 const uint8_t *pu8Pal = pThis->pu8Logo + sizeof(LOGOHDR) + sizeof(BMPINFO) + pWinHdr->Size; /* ASSUMES Size location (safe) */
3759
3760 for (i = 0; i < pThis->cLogoPalEntries; i++)
3761 {
3762 uint16_t j;
3763 uint32_t u32Pal = 0;
3764
3765 for (j = 0; j < 3; j++)
3766 {
3767 uint8_t b = *pu8Pal++;
3768 u32Pal <<= 8;
3769 u32Pal |= b;
3770 }
3771
3772 pu8Pal++; /* skip unused byte */
3773 pThis->au32LogoPalette[i] = u32Pal;
3774 }
3775 }
3776
3777 /*
3778 * Bitmap data offset
3779 */
3780 pThis->pu8LogoBitmap = pThis->pu8Logo + sizeof(LOGOHDR) + bmpInfo->Offset;
3781 }
3782
3783 return VINF_SUCCESS;
3784}
3785
3786
3787/**
3788 * Show logo bitmap data.
3789 *
3790 * @returns VBox status code.
3791 *
3792 * @param cbDepth Logo depth.
3793 * @param xLogo Logo X position.
3794 * @param yLogo Logo Y position.
3795 * @param cxLogo Logo width.
3796 * @param cyLogo Logo height.
3797 * @param iStep Fade in/fade out step.
3798 * @param pu32Palette Palette data.
3799 * @param pu8Src Source buffer.
3800 * @param pu8Dst Destination buffer.
3801 */
3802static void vbeShowBitmap(uint16_t cBits, uint16_t xLogo, uint16_t yLogo, uint16_t cxLogo, uint16_t cyLogo, uint8_t iStep,
3803 const uint32_t *pu32Palette, const uint8_t *pu8Src, uint8_t *pu8Dst)
3804{
3805 uint16_t i;
3806 size_t cbPadBytes = 0;
3807 size_t cbLineDst = LOGO_MAX_WIDTH * 4;
3808 uint16_t cyLeft = cyLogo;
3809
3810 pu8Dst += xLogo * 4 + yLogo * cbLineDst;
3811
3812 switch (cBits)
3813 {
3814 case 1:
3815 pu8Dst += cyLogo * cbLineDst;
3816 cbPadBytes = 0;
3817 break;
3818
3819 case 4:
3820 if (((cxLogo % 8) == 0) || ((cxLogo % 8) > 6))
3821 cbPadBytes = 0;
3822 else if ((cxLogo % 8) <= 2)
3823 cbPadBytes = 3;
3824 else if ((cxLogo % 8) <= 4)
3825 cbPadBytes = 2;
3826 else
3827 cbPadBytes = 1;
3828 break;
3829
3830 case 8:
3831 cbPadBytes = ((cxLogo % 4) == 0) ? 0 : (4 - (cxLogo % 4));
3832 break;
3833
3834 case 24:
3835 cbPadBytes = cxLogo % 4;
3836 break;
3837 }
3838
3839 uint8_t j = 0, c = 0;
3840
3841 while (cyLeft-- > 0)
3842 {
3843 uint8_t *pu8TmpPtr = pu8Dst;
3844
3845 if (cBits != 1)
3846 j = 0;
3847
3848 for (i = 0; i < cxLogo; i++)
3849 {
3850 uint8_t pix;
3851
3852 switch (cBits)
3853 {
3854 case 1:
3855 {
3856 if (!j)
3857 c = *pu8Src++;
3858
3859 pix = (c & 1) ? 0xFF : 0;
3860 c >>= 1;
3861
3862 if (pix)
3863 {
3864 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
3865 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
3866 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
3867 *pu8TmpPtr++;
3868 }
3869 else
3870 {
3871 pu8TmpPtr += 4;
3872 }
3873
3874 j = (j + 1) % 8;
3875 break;
3876 }
3877
3878 case 4:
3879 {
3880 if (!j)
3881 c = *pu8Src++;
3882
3883 pix = (c >> 4) & 0xF;
3884 c <<= 4;
3885
3886 uint32_t u32Pal = pu32Palette[pix];
3887
3888 pix = (u32Pal >> 16) & 0xFF;
3889 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
3890 pix = (u32Pal >> 8) & 0xFF;
3891 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
3892 pix = u32Pal & 0xFF;
3893 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
3894 *pu8TmpPtr++;
3895
3896 j = (j + 1) % 2;
3897 break;
3898 }
3899
3900 case 8:
3901 {
3902 uint32_t u32Pal = pu32Palette[*pu8Src++];
3903
3904 pix = (u32Pal >> 16) & 0xFF;
3905 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
3906 pix = (u32Pal >> 8) & 0xFF;
3907 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
3908 pix = u32Pal & 0xFF;
3909 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
3910 *pu8TmpPtr++;
3911 break;
3912 }
3913
3914 case 24:
3915 *pu8TmpPtr++ = *pu8Src++ * iStep / LOGO_SHOW_STEPS;
3916 *pu8TmpPtr++ = *pu8Src++ * iStep / LOGO_SHOW_STEPS;
3917 *pu8TmpPtr++ = *pu8Src++ * iStep / LOGO_SHOW_STEPS;
3918 *pu8TmpPtr++;
3919 break;
3920 }
3921 }
3922
3923 pu8Dst -= cbLineDst;
3924 pu8Src += cbPadBytes;
3925 }
3926}
3927
3928
3929
3930
3931/**
3932 * Port I/O Handler for BIOS Logo OUT operations.
3933 *
3934 * @returns VBox status code.
3935 *
3936 * @param pDevIns The device instance.
3937 * @param pvUser User argument - ignored.
3938 * @param Port Port number used for the IN operation.
3939 * @param u32 The value to output.
3940 * @param cb The value size in bytes.
3941 */
3942PDMBOTHCBDECL(int) vbeIOPortWriteCMDLogo(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3943{
3944 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3945 NOREF(pvUser);
3946 NOREF(Port);
3947
3948 Log(("vbeIOPortWriteCMDLogo: cb=%d u32=%#04x(%#04d) (byte)\n", cb, u32, u32));
3949
3950 if (cb == 2)
3951 {
3952 /* Get the logo command */
3953 switch (u32 & 0xFF00)
3954 {
3955 case LOGO_CMD_SET_OFFSET:
3956 pThis->offLogoData = u32 & 0xFF;
3957 break;
3958
3959 case LOGO_CMD_SHOW_BMP:
3960 {
3961 uint8_t iStep = u32 & 0xFF;
3962 const uint8_t *pu8Src = pThis->pu8LogoBitmap;
3963 uint8_t *pu8Dst;
3964 PLOGOHDR pLogoHdr = (PLOGOHDR)pThis->pu8Logo;
3965 uint32_t offDirty = 0;
3966 uint16_t xLogo = (LOGO_MAX_WIDTH - pThis->cxLogo) / 2;
3967 uint16_t yLogo = LOGO_MAX_HEIGHT - (LOGO_MAX_HEIGHT - pThis->cyLogo) / 2;
3968
3969 /* Check VRAM size */
3970 if (pThis->vram_size < LOGO_MAX_SIZE)
3971 break;
3972
3973 if (pThis->vram_size >= LOGO_MAX_SIZE * 2)
3974 pu8Dst = pThis->vram_ptrR3 + LOGO_MAX_SIZE;
3975 else
3976 pu8Dst = pThis->vram_ptrR3;
3977
3978 /* Clear screen - except on power on... */
3979 if (!pThis->fLogoClearScreen)
3980 {
3981 uint32_t *pu32TmpPtr = (uint32_t *)pu8Dst;
3982
3983 /* Clear vram */
3984 for (int i = 0; i < LOGO_MAX_WIDTH; i++)
3985 {
3986 for (int j = 0; j < LOGO_MAX_HEIGHT; j++)
3987 *pu32TmpPtr++ = 0;
3988 }
3989 pThis->fLogoClearScreen = true;
3990 }
3991
3992 /* Show the bitmap. */
3993 vbeShowBitmap(pThis->cLogoBits, xLogo, yLogo,
3994 pThis->cxLogo, pThis->cyLogo,
3995 iStep, &pThis->au32LogoPalette[0],
3996 pu8Src, pu8Dst);
3997
3998 /* Show the 'Press F12...' text. */
3999 if (pLogoHdr->fu8ShowBootMenu == 2)
4000 vbeShowBitmap(1, LOGO_F12TEXT_X, LOGO_F12TEXT_Y,
4001 LOGO_F12TEXT_WIDTH, LOGO_F12TEXT_HEIGHT,
4002 iStep, &pThis->au32LogoPalette[0],
4003 &g_abLogoF12BootText[0], pu8Dst);
4004
4005 /* Blit the offscreen buffer. */
4006 if (pThis->vram_size >= LOGO_MAX_SIZE * 2)
4007 {
4008 uint32_t *pu32TmpDst = (uint32_t *)pThis->vram_ptrR3;
4009 uint32_t *pu32TmpSrc = (uint32_t *)(pThis->vram_ptrR3 + LOGO_MAX_SIZE);
4010 for (int i = 0; i < LOGO_MAX_WIDTH; i++)
4011 {
4012 for (int j = 0; j < LOGO_MAX_HEIGHT; j++)
4013 *pu32TmpDst++ = *pu32TmpSrc++;
4014 }
4015 }
4016
4017 /* Set the dirty flags. */
4018 while (offDirty <= LOGO_MAX_SIZE)
4019 {
4020 vga_set_dirty(pThis, offDirty);
4021 offDirty += PAGE_SIZE;
4022 }
4023 break;
4024 }
4025
4026 default:
4027 Log(("vbeIOPortWriteCMDLogo: invalid command %d\n", u32));
4028 pThis->LogoCommand = LOGO_CMD_NOP;
4029 break;
4030 }
4031
4032 return VINF_SUCCESS;
4033 }
4034
4035 Log(("vbeIOPortWriteCMDLogo: Ignoring invalid cb=%d writes to the VBE Extra port!!!\n", cb));
4036 return VINF_SUCCESS;
4037}
4038
4039
4040/**
4041 * Port I/O Handler for BIOS Logo IN operations.
4042 *
4043 * @returns VBox status code.
4044 *
4045 * @param pDevIns The device instance.
4046 * @param pvUser User argument - ignored.
4047 * @param Port Port number used for the IN operation.
4048 * @param pu32 Where to store the result.
4049 * @param cb Number of bytes read.
4050 */
4051PDMBOTHCBDECL(int) vbeIOPortReadCMDLogo(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
4052{
4053 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4054 NOREF(pvUser);
4055 NOREF(Port);
4056
4057 PRTUINT64U p;
4058
4059 if (pThis->offLogoData + cb > pThis->cbLogo)
4060 {
4061 Log(("vbeIOPortReadCMDLogo: Requested address is out of Logo data!!! offLogoData=%#x(%d) cbLogo=%#x(%d)\n",
4062 pThis->offLogoData, pThis->offLogoData, pThis->cbLogo, pThis->cbLogo));
4063 return VINF_SUCCESS;
4064 }
4065 p = (PRTUINT64U)&pThis->pu8Logo[pThis->offLogoData];
4066
4067 switch (cb)
4068 {
4069 case 1: *pu32 = p->au8[0]; break;
4070 case 2: *pu32 = p->au16[0]; break;
4071 case 4: *pu32 = p->au32[0]; break;
4072 //case 8: *pu32 = p->au64[0]; break;
4073 default: AssertFailed(); break;
4074 }
4075 Log(("vbeIOPortReadCMDLogo: LogoOffset=%#x(%d) cb=%#x %.*Rhxs\n", pThis->offLogoData, pThis->offLogoData, cb, cb, pu32));
4076
4077 pThis->LogoCommand = LOGO_CMD_NOP;
4078 pThis->offLogoData += cb;
4079
4080 return VINF_SUCCESS;
4081}
4082
4083/**
4084 * Info handler, device version. Dumps several interesting bits of the
4085 * VGA state that are difficult to decode from the registers.
4086 *
4087 * @param pDevIns Device instance which registered the info.
4088 * @param pHlp Callback functions for doing output.
4089 * @param pszArgs Argument string. Optional and specific to the handler.
4090 */
4091static DECLCALLBACK(void) vgaInfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4092{
4093 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4094 int is_graph, double_scan;
4095 int w, h, char_height, char_dots;
4096 int val, vfreq_hz, hfreq_hz;
4097 vga_retrace_s *r = &s->retrace_state;
4098 const char *clocks[] = { "25.175 MHz", "28.322 MHz", "External", "Reserved?!" };
4099 NOREF(pszArgs);
4100
4101 is_graph = s->gr[6] & 1;
4102 char_dots = (s->sr[0x01] & 1) ? 8 : 9;
4103 double_scan = s->cr[9] >> 7;
4104 pHlp->pfnPrintf(pHlp, "pixel clock: %s\n", clocks[(s->msr >> 2) & 3]);
4105 pHlp->pfnPrintf(pHlp, "double scanning %s\n", double_scan ? "on" : "off");
4106 pHlp->pfnPrintf(pHlp, "double clocking %s\n", s->sr[1] & 0x08 ? "on" : "off");
4107 val = s->cr[0] + 5;
4108 pHlp->pfnPrintf(pHlp, "htotal: %d px (%d cclk)\n", val * char_dots, val);
4109 val = s->cr[6] + ((s->cr[7] & 1) << 8) + ((s->cr[7] & 0x20) << 4) + 2;
4110 pHlp->pfnPrintf(pHlp, "vtotal: %d px\n", val);
4111 val = s->cr[1] + 1;
4112 w = val * char_dots;
4113 pHlp->pfnPrintf(pHlp, "hdisp : %d px (%d cclk)\n", w, val);
4114 val = s->cr[0x12] + ((s->cr[7] & 2) << 7) + ((s->cr[7] & 0x40) << 4) + 1;
4115 h = val;
4116 pHlp->pfnPrintf(pHlp, "vdisp : %d px\n", val);
4117 val = (s->cr[0xc] << 8) + s->cr[0xd];
4118 pHlp->pfnPrintf(pHlp, "start : %#x\n", val);
4119 if (!is_graph)
4120 {
4121 val = (s->cr[9] & 0x1f) + 1;
4122 char_height = val;
4123 pHlp->pfnPrintf(pHlp, "char height %d\n", val);
4124 pHlp->pfnPrintf(pHlp, "text mode %dx%d\n", w / char_dots, h / (char_height << double_scan));
4125 }
4126 if (s->fRealRetrace)
4127 {
4128 val = r->hb_start;
4129 pHlp->pfnPrintf(pHlp, "hblank start: %d px (%d cclk)\n", val * char_dots, val);
4130 val = r->hb_end;
4131 pHlp->pfnPrintf(pHlp, "hblank end : %d px (%d cclk)\n", val * char_dots, val);
4132 pHlp->pfnPrintf(pHlp, "vblank start: %d px, end: %d px\n", r->vb_start, r->vb_end);
4133 pHlp->pfnPrintf(pHlp, "vsync start : %d px, end: %d px\n", r->vs_start, r->vs_end);
4134 pHlp->pfnPrintf(pHlp, "cclks per frame: %d\n", r->frame_cclks);
4135 pHlp->pfnPrintf(pHlp, "cclk time (ns) : %d\n", r->cclk_ns);
4136 vfreq_hz = 1000000000 / r->frame_ns;
4137 hfreq_hz = 1000000000 / r->h_total_ns;
4138 pHlp->pfnPrintf(pHlp, "vfreq: %d Hz, hfreq: %d.%03d kHz\n",
4139 vfreq_hz, hfreq_hz / 1000, hfreq_hz % 1000);
4140 }
4141 pHlp->pfnPrintf(pHlp, "display refresh interval: %u ms\n", s->cMilliesRefreshInterval);
4142}
4143
4144
4145/**
4146 * Prints a separator line.
4147 *
4148 * @param pHlp Callback functions for doing output.
4149 * @param cCols The number of columns.
4150 * @param pszTitle The title text, NULL if none.
4151 */
4152static void vgaInfoTextPrintSeparatorLine(PCDBGFINFOHLP pHlp, size_t cCols, const char *pszTitle)
4153{
4154 if (pszTitle)
4155 {
4156 size_t cchTitle = strlen(pszTitle);
4157 if (cchTitle + 6 >= cCols)
4158 {
4159 pHlp->pfnPrintf(pHlp, "-- %s --", pszTitle);
4160 cCols = 0;
4161 }
4162 else
4163 {
4164 size_t cchLeft = (cCols - cchTitle - 2) / 2;
4165 cCols -= cchLeft + cchTitle + 2;
4166 while (cchLeft-- > 0)
4167 pHlp->pfnPrintf(pHlp, "-");
4168 pHlp->pfnPrintf(pHlp, " %s ", pszTitle);
4169 }
4170 }
4171
4172 while (cCols-- > 0)
4173 pHlp->pfnPrintf(pHlp, "-");
4174 pHlp->pfnPrintf(pHlp, "\n");
4175}
4176
4177
4178/**
4179 * Worker for vgaInfoText.
4180 *
4181 * @param pThis The vga state.
4182 * @param pHlp Callback functions for doing output.
4183 * @param offStart Where to start dumping (relative to the VRAM).
4184 * @param cbLine The source line length (aka line_offset).
4185 * @param cCols The number of columns on the screen.
4186 * @param cRows The number of rows to dump.
4187 * @param iScrBegin The row at which the current screen output starts.
4188 * @param iScrEnd The row at which the current screen output end
4189 * (exclusive).
4190 */
4191static void vgaInfoTextWorker(PVGASTATE pThis, PCDBGFINFOHLP pHlp,
4192 uint32_t offStart, uint32_t cbLine,
4193 uint32_t cCols, uint32_t cRows,
4194 uint32_t iScrBegin, uint32_t iScrEnd)
4195{
4196 /* Title, */
4197 char szTitle[32];
4198 if (iScrBegin || iScrEnd < cRows)
4199 RTStrPrintf(szTitle, sizeof(szTitle), "%ux%u (+%u before, +%u after)",
4200 cCols, iScrEnd - iScrBegin, iScrBegin, cRows - iScrEnd);
4201 else
4202 RTStrPrintf(szTitle, sizeof(szTitle), "%ux%u", cCols, iScrEnd - iScrBegin);
4203
4204 /* Do the dumping. */
4205 uint8_t const *pbSrcOuter = pThis->CTX_SUFF(vram_ptr) + offStart;
4206 uint32_t iRow;
4207 for (iRow = 0; iRow < cRows; iRow++, pbSrcOuter += cbLine)
4208 {
4209 if ((uintptr_t)(pbSrcOuter + cbLine - pThis->CTX_SUFF(vram_ptr)) > pThis->vram_size) {
4210 pHlp->pfnPrintf(pHlp, "The last %u row/rows is/are outside the VRAM.\n", cRows - iRow);
4211 break;
4212 }
4213
4214 if (iRow == 0)
4215 vgaInfoTextPrintSeparatorLine(pHlp, cCols, szTitle);
4216 else if (iRow == iScrBegin)
4217 vgaInfoTextPrintSeparatorLine(pHlp, cCols, "screen start");
4218 else if (iRow == iScrEnd)
4219 vgaInfoTextPrintSeparatorLine(pHlp, cCols, "screen end");
4220
4221 uint8_t const *pbSrc = pbSrcOuter;
4222 for (uint32_t iCol = 0; iCol < cCols; ++iCol)
4223 {
4224 if (RT_C_IS_PRINT(*pbSrc))
4225 pHlp->pfnPrintf(pHlp, "%c", *pbSrc);
4226 else
4227 pHlp->pfnPrintf(pHlp, ".");
4228 pbSrc += 8; /* chars are spaced 8 bytes apart */
4229 }
4230 pHlp->pfnPrintf(pHlp, "\n");
4231 }
4232
4233 /* Final separator. */
4234 vgaInfoTextPrintSeparatorLine(pHlp, cCols, NULL);
4235}
4236
4237
4238/**
4239 * Info handler, device version. Dumps VGA memory formatted as
4240 * ASCII text, no attributes. Only looks at the first page.
4241 *
4242 * @param pDevIns Device instance which registered the info.
4243 * @param pHlp Callback functions for doing output.
4244 * @param pszArgs Argument string. Optional and specific to the handler.
4245 */
4246static DECLCALLBACK(void) vgaInfoText(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4247{
4248 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4249
4250 /*
4251 * Parse args.
4252 */
4253 bool fAll = true;
4254 if (pszArgs && *pszArgs)
4255 {
4256 if (!strcmp(pszArgs, "all"))
4257 fAll = true;
4258 else if (!strcmp(pszArgs, "scr") || !strcmp(pszArgs, "screen"))
4259 fAll = false;
4260 else
4261 {
4262 pHlp->pfnPrintf(pHlp, "Invalid argument: '%s'\n", pszArgs);
4263 return;
4264 }
4265 }
4266
4267 /*
4268 * Check that we're in text mode and that the VRAM is accessible.
4269 */
4270 if (!(pThis->gr[6] & 1))
4271 {
4272 uint8_t *pbSrc = pThis->vram_ptrR3;
4273 if (pbSrc)
4274 {
4275 /*
4276 * Figure out the display size and where the text is.
4277 *
4278 * Note! We're cutting quite a few corners here and this code could
4279 * do with some brushing up. Dumping from the start of the
4280 * frame buffer is done intentionally so that we're more
4281 * likely to obtain the full scrollback of a linux panic.
4282 */
4283 uint32_t cbLine;
4284 uint32_t offStart;
4285 uint32_t uLineCompareIgn;
4286 vga_get_offsets(pThis, &cbLine, &offStart, &uLineCompareIgn);
4287 if (!cbLine)
4288 cbLine = 80 * 8;
4289 offStart *= 8;
4290
4291 uint32_t uVDisp = pThis->cr[0x12] + ((pThis->cr[7] & 2) << 7) + ((pThis->cr[7] & 0x40) << 4) + 1;
4292 uint32_t uCharHeight = (pThis->cr[9] & 0x1f) + 1;
4293 uint32_t uDblScan = pThis->cr[9] >> 7;
4294 uint32_t cScrRows = uVDisp / (uCharHeight << uDblScan);
4295 if (cScrRows < 25)
4296 cScrRows = 25;
4297 uint32_t iScrBegin = offStart / cbLine;
4298 uint32_t cRows = iScrBegin + cScrRows;
4299 uint32_t cCols = cbLine / 8;
4300
4301 if (fAll) {
4302 vgaInfoTextWorker(pThis, pHlp, offStart - iScrBegin * cbLine, cbLine,
4303 cCols, cRows, iScrBegin, iScrBegin + cScrRows);
4304 } else {
4305 vgaInfoTextWorker(pThis, pHlp, offStart, cbLine, cCols, cScrRows, 0, cScrRows);
4306 }
4307 }
4308 else
4309 pHlp->pfnPrintf(pHlp, "VGA memory not available!\n");
4310 }
4311 else
4312 pHlp->pfnPrintf(pHlp, "Not in text mode!\n");
4313}
4314
4315
4316/**
4317 * Info handler, device version. Dumps VGA Sequencer registers.
4318 *
4319 * @param pDevIns Device instance which registered the info.
4320 * @param pHlp Callback functions for doing output.
4321 * @param pszArgs Argument string. Optional and specific to the handler.
4322 */
4323static DECLCALLBACK(void) vgaInfoSR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4324{
4325 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4326 unsigned i;
4327 NOREF(pszArgs);
4328
4329 pHlp->pfnPrintf(pHlp, "VGA Sequencer (3C5): SR index 3C4:%02X\n", s->sr_index);
4330 Assert(sizeof(s->sr) >= 8);
4331 for (i = 0; i < 5; ++i)
4332 pHlp->pfnPrintf(pHlp, " SR%02X:%02X", i, s->sr[i]);
4333 pHlp->pfnPrintf(pHlp, "\n");
4334}
4335
4336
4337/**
4338 * Info handler, device version. Dumps VGA CRTC registers.
4339 *
4340 * @param pDevIns Device instance which registered the info.
4341 * @param pHlp Callback functions for doing output.
4342 * @param pszArgs Argument string. Optional and specific to the handler.
4343 */
4344static DECLCALLBACK(void) vgaInfoCR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4345{
4346 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4347 unsigned i;
4348 NOREF(pszArgs);
4349
4350 pHlp->pfnPrintf(pHlp, "VGA CRTC (3D5): CRTC index 3D4:%02X\n", s->cr_index);
4351 Assert(sizeof(s->cr) >= 24);
4352 for (i = 0; i < 10; ++i)
4353 {
4354 pHlp->pfnPrintf(pHlp, " CR%02X:%02X", i, s->cr[i]);
4355 }
4356 pHlp->pfnPrintf(pHlp, "\n");
4357 for (i = 10; i < 20; ++i)
4358 {
4359 pHlp->pfnPrintf(pHlp, " CR%02X:%02X", i, s->cr[i]);
4360 }
4361 pHlp->pfnPrintf(pHlp, "\n");
4362 for (i = 20; i < 25; ++i)
4363 {
4364 pHlp->pfnPrintf(pHlp, " CR%02X:%02X", i, s->cr[i]);
4365 }
4366 pHlp->pfnPrintf(pHlp, "\n");
4367}
4368
4369
4370/**
4371 * Info handler, device version. Dumps VGA Graphics Controller registers.
4372 *
4373 * @param pDevIns Device instance which registered the info.
4374 * @param pHlp Callback functions for doing output.
4375 * @param pszArgs Argument string. Optional and specific to the handler.
4376 */
4377static DECLCALLBACK(void) vgaInfoGR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4378{
4379 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4380 unsigned i;
4381 NOREF(pszArgs);
4382
4383 pHlp->pfnPrintf(pHlp, "VGA Graphics Controller (3CF): GR index 3CE:%02X\n", s->gr_index);
4384 Assert(sizeof(s->gr) >= 9);
4385 for (i = 0; i < 9; ++i)
4386 {
4387 pHlp->pfnPrintf(pHlp, " GR%02X:%02X", i, s->gr[i]);
4388 }
4389 pHlp->pfnPrintf(pHlp, "\n");
4390}
4391
4392
4393/**
4394 * Info handler, device version. Dumps VGA Sequencer registers.
4395 *
4396 * @param pDevIns Device instance which registered the info.
4397 * @param pHlp Callback functions for doing output.
4398 * @param pszArgs Argument string. Optional and specific to the handler.
4399 */
4400static DECLCALLBACK(void) vgaInfoAR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4401{
4402 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4403 unsigned i;
4404 NOREF(pszArgs);
4405
4406 pHlp->pfnPrintf(pHlp, "VGA Attribute Controller (3C0): index reg %02X, flip-flop: %d (%s)\n",
4407 s->ar_index, s->ar_flip_flop, s->ar_flip_flop ? "data" : "index" );
4408 Assert(sizeof(s->ar) >= 0x14);
4409 pHlp->pfnPrintf(pHlp, " Palette:");
4410 for (i = 0; i < 0x10; ++i)
4411 {
4412 pHlp->pfnPrintf(pHlp, " %02X", i, s->ar[i]);
4413 }
4414 pHlp->pfnPrintf(pHlp, "\n");
4415 for (i = 0x10; i <= 0x14; ++i)
4416 {
4417 pHlp->pfnPrintf(pHlp, " AR%02X:%02X", i, s->ar[i]);
4418 }
4419 pHlp->pfnPrintf(pHlp, "\n");
4420}
4421
4422/**
4423 * Info handler, device version. Dumps VGA DAC registers.
4424 *
4425 * @param pDevIns Device instance which registered the info.
4426 * @param pHlp Callback functions for doing output.
4427 * @param pszArgs Argument string. Optional and specific to the handler.
4428 */
4429static DECLCALLBACK(void) vgaInfoDAC(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4430{
4431 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4432 unsigned i;
4433 NOREF(pszArgs);
4434
4435 pHlp->pfnPrintf(pHlp, "VGA DAC contents:\n");
4436 for (i = 0; i < 0x100; ++i)
4437 {
4438 pHlp->pfnPrintf(pHlp, " %02X: %02X %02X %02X\n",
4439 i, s->palette[i*3+0], s->palette[i*3+1], s->palette[i*3+2]);
4440 }
4441}
4442
4443
4444/**
4445 * Info handler, device version. Dumps VBE registers.
4446 *
4447 * @param pDevIns Device instance which registered the info.
4448 * @param pHlp Callback functions for doing output.
4449 * @param pszArgs Argument string. Optional and specific to the handler.
4450 */
4451static DECLCALLBACK(void) vgaInfoVBE(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4452{
4453 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4454 NOREF(pszArgs);
4455
4456 pHlp->pfnPrintf(pHlp, "LFB at %RGp\n", s->GCPhysVRAM);
4457
4458 if (!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED))
4459 {
4460 pHlp->pfnPrintf(pHlp, "VBE disabled\n");
4461 return;
4462 }
4463
4464 pHlp->pfnPrintf(pHlp, "VBE state (chip ID 0x%04x):\n", s->vbe_regs[VBE_DISPI_INDEX_ID]);
4465 pHlp->pfnPrintf(pHlp, " Display resolution: %d x %d @ %dbpp\n",
4466 s->vbe_regs[VBE_DISPI_INDEX_XRES], s->vbe_regs[VBE_DISPI_INDEX_YRES],
4467 s->vbe_regs[VBE_DISPI_INDEX_BPP]);
4468 pHlp->pfnPrintf(pHlp, " Virtual resolution: %d x %d\n",
4469 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH], s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT]);
4470 pHlp->pfnPrintf(pHlp, " Display start addr: %d, %d\n",
4471 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET], s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET]);
4472 pHlp->pfnPrintf(pHlp, " Linear scanline pitch: 0x%04x\n", s->vbe_line_offset);
4473 pHlp->pfnPrintf(pHlp, " Linear display start : 0x%04x\n", s->vbe_start_addr);
4474 pHlp->pfnPrintf(pHlp, " Selected bank: 0x%04x\n", s->vbe_regs[VBE_DISPI_INDEX_BANK]);
4475}
4476
4477
4478/* -=-=-=-=-=- Ring 3: IBase -=-=-=-=-=- */
4479
4480/**
4481 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4482 */
4483static DECLCALLBACK(void *) vgaPortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4484{
4485 PVGASTATE pThis = RT_FROM_MEMBER(pInterface, VGASTATE, IBase);
4486 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
4487 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYPORT, &pThis->IPort);
4488#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI))
4489 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYVBVACALLBACKS, &pThis->IVBVACallbacks);
4490#endif
4491 return NULL;
4492}
4493
4494
4495/* -=-=-=-=-=- Ring 3: Dummy IDisplayConnector -=-=-=-=-=- */
4496
4497/**
4498 * Resize the display.
4499 * This is called when the resolution changes. This usually happens on
4500 * request from the guest os, but may also happen as the result of a reset.
4501 *
4502 * @param pInterface Pointer to this interface.
4503 * @param cx New display width.
4504 * @param cy New display height
4505 * @thread The emulation thread.
4506 */
4507static DECLCALLBACK(int) vgaDummyResize(PPDMIDISPLAYCONNECTOR pInterface, uint32_t bpp, void *pvVRAM,
4508 uint32_t cbLine, uint32_t cx, uint32_t cy)
4509{
4510 NOREF(pInterface); NOREF(bpp); NOREF(pvVRAM); NOREF(cbLine); NOREF(cx); NOREF(cy);
4511 return VINF_SUCCESS;
4512}
4513
4514
4515/**
4516 * Update a rectangle of the display.
4517 * PDMIDISPLAYPORT::pfnUpdateDisplay is the caller.
4518 *
4519 * @param pInterface Pointer to this interface.
4520 * @param x The upper left corner x coordinate of the rectangle.
4521 * @param y The upper left corner y coordinate of the rectangle.
4522 * @param cx The width of the rectangle.
4523 * @param cy The height of the rectangle.
4524 * @thread The emulation thread.
4525 */
4526static DECLCALLBACK(void) vgaDummyUpdateRect(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
4527{
4528 NOREF(pInterface); NOREF(x); NOREF(y); NOREF(cx); NOREF(cy);
4529}
4530
4531
4532/**
4533 * Refresh the display.
4534 *
4535 * The interval between these calls is set by
4536 * PDMIDISPLAYPORT::pfnSetRefreshRate(). The driver should call
4537 * PDMIDISPLAYPORT::pfnUpdateDisplay() if it wishes to refresh the
4538 * display. PDMIDISPLAYPORT::pfnUpdateDisplay calls pfnUpdateRect with
4539 * the changed rectangles.
4540 *
4541 * @param pInterface Pointer to this interface.
4542 * @thread The emulation thread.
4543 */
4544static DECLCALLBACK(void) vgaDummyRefresh(PPDMIDISPLAYCONNECTOR pInterface)
4545{
4546 NOREF(pInterface);
4547}
4548
4549
4550/* -=-=-=-=-=- Ring 3: IDisplayPort -=-=-=-=-=- */
4551
4552/** Converts a display port interface pointer to a vga state pointer. */
4553#define IDISPLAYPORT_2_VGASTATE(pInterface) ( (PVGASTATE)((uintptr_t)pInterface - RT_OFFSETOF(VGASTATE, IPort)) )
4554
4555
4556/**
4557 * Update the display with any changed regions.
4558 *
4559 * @param pInterface Pointer to this interface.
4560 * @see PDMIKEYBOARDPORT::pfnUpdateDisplay() for details.
4561 */
4562static DECLCALLBACK(int) vgaPortUpdateDisplay(PPDMIDISPLAYPORT pInterface)
4563{
4564 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4565 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4566 PPDMDEVINS pDevIns = pThis->CTX_SUFF(pDevIns);
4567
4568 int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
4569 AssertRC(rc);
4570
4571#ifndef VBOX_WITH_HGSMI
4572 /* This should be called only in non VBVA mode. */
4573#else
4574 if (VBVAUpdateDisplay (pThis) == VINF_SUCCESS)
4575 {
4576 PDMCritSectLeave(&pThis->lock);
4577 return VINF_SUCCESS;
4578 }
4579#endif /* VBOX_WITH_HGSMI */
4580
4581 STAM_COUNTER_INC(&pThis->StatUpdateDisp);
4582 if (pThis->fHasDirtyBits && pThis->GCPhysVRAM && pThis->GCPhysVRAM != NIL_RTGCPHYS32)
4583 {
4584 PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
4585 pThis->fHasDirtyBits = false;
4586 }
4587 if (pThis->fRemappedVGA)
4588 {
4589 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000);
4590 pThis->fRemappedVGA = false;
4591 }
4592
4593 rc = vga_update_display(pThis, false, false, true);
4594 if (rc != VINF_SUCCESS)
4595 {
4596 PDMCritSectLeave(&pThis->lock);
4597 return rc;
4598 }
4599 PDMCritSectLeave(&pThis->lock);
4600 return VINF_SUCCESS;
4601}
4602
4603
4604/**
4605 * Internal vgaPortUpdateDisplayAll worker called under pThis->lock.
4606 */
4607static int updateDisplayAll(PVGASTATE pThis)
4608{
4609 PPDMDEVINS pDevIns = pThis->CTX_SUFF(pDevIns);
4610
4611 /* The dirty bits array has been just cleared, reset handlers as well. */
4612 if (pThis->GCPhysVRAM && pThis->GCPhysVRAM != NIL_RTGCPHYS32)
4613 PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
4614 if (pThis->fRemappedVGA)
4615 {
4616 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000);
4617 pThis->fRemappedVGA = false;
4618 }
4619
4620 pThis->graphic_mode = -1; /* force full update */
4621
4622 return vga_update_display(pThis, true, false, true);
4623}
4624
4625
4626/**
4627 * Update the entire display.
4628 *
4629 * @param pInterface Pointer to this interface.
4630 * @see PDMIKEYBOARDPORT::pfnUpdateDisplayAll() for details.
4631 */
4632static DECLCALLBACK(int) vgaPortUpdateDisplayAll(PPDMIDISPLAYPORT pInterface)
4633{
4634 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4635 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4636
4637 /* This is called both in VBVA mode and normal modes. */
4638
4639#ifdef DEBUG_sunlover
4640 LogFlow(("vgaPortUpdateDisplayAll\n"));
4641#endif /* DEBUG_sunlover */
4642
4643 int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
4644 AssertRC(rc);
4645
4646 rc = updateDisplayAll(pThis);
4647
4648 PDMCritSectLeave(&pThis->lock);
4649 return rc;
4650}
4651
4652
4653/**
4654 * Sets the refresh rate and restart the timer.
4655 *
4656 * @returns VBox status code.
4657 * @param pInterface Pointer to this interface.
4658 * @param cMilliesInterval Number of millis between two refreshes.
4659 * @see PDMIKEYBOARDPORT::pfnSetRefreshRate() for details.
4660 */
4661static DECLCALLBACK(int) vgaPortSetRefreshRate(PPDMIDISPLAYPORT pInterface, uint32_t cMilliesInterval)
4662{
4663 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4664
4665 pThis->cMilliesRefreshInterval = cMilliesInterval;
4666 if (cMilliesInterval)
4667 return TMTimerSetMillies(pThis->RefreshTimer, cMilliesInterval);
4668 return TMTimerStop(pThis->RefreshTimer);
4669}
4670
4671
4672/** @copydoc PDMIDISPLAYPORT::pfnQueryColorDepth */
4673static DECLCALLBACK(int) vgaPortQueryColorDepth(PPDMIDISPLAYPORT pInterface, uint32_t *pcBits)
4674{
4675 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4676
4677 if (!pcBits)
4678 return VERR_INVALID_PARAMETER;
4679 *pcBits = vga_get_bpp(pThis);
4680 return VINF_SUCCESS;
4681}
4682
4683
4684/**
4685 * Create a 32-bbp screenshot of the display. Size of the bitmap scanline in bytes is 4*width.
4686 *
4687 * @param pInterface Pointer to this interface.
4688 * @param ppu8Data Where to store the pointer to the allocated buffer.
4689 * @param pcbData Where to store the actual size of the bitmap.
4690 * @param pcx Where to store the width of the bitmap.
4691 * @param pcy Where to store the height of the bitmap.
4692 * @see PDMIDISPLAYPORT::pfnTakeScreenshot() for details.
4693 */
4694static DECLCALLBACK(int) vgaPortTakeScreenshot(PPDMIDISPLAYPORT pInterface, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pcx, uint32_t *pcy)
4695{
4696 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4697 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4698
4699 LogFlow(("vgaPortTakeScreenshot: ppu8Data=%p pcbData=%p pcx=%p pcy=%p\n", ppu8Data, pcbData, pcx, pcy));
4700
4701 /*
4702 * Validate input.
4703 */
4704 if (!RT_VALID_PTR(ppu8Data) || !RT_VALID_PTR(pcbData) || !RT_VALID_PTR(pcx) || !RT_VALID_PTR(pcy))
4705 return VERR_INVALID_PARAMETER;
4706
4707 int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
4708 AssertRCReturn(rc, rc);
4709
4710 /*
4711 * Get screenshot. This function will fail if a resize is required.
4712 * So there is not need to do a 'updateDisplayAll' before taking screenshot.
4713 */
4714
4715 /*
4716 * Allocate the buffer for 32 bits per pixel bitmap
4717 *
4718 * Note! The size can't be zero or greater than the size of the VRAM.
4719 * Inconsistent VGA device state can cause the incorrect size values.
4720 */
4721 size_t cbRequired = pThis->last_scr_width * 4 * pThis->last_scr_height;
4722 if (cbRequired && cbRequired <= pThis->vram_size)
4723 {
4724 uint8_t *pu8Data = (uint8_t *)RTMemAlloc(cbRequired);
4725 if (pu8Data != NULL)
4726 {
4727 /*
4728 * Only 3 methods, assigned below, will be called during the screenshot update.
4729 * All other are already set to NULL.
4730 */
4731 /* The display connector interface is temporarily replaced with the fake one. */
4732 PDMIDISPLAYCONNECTOR Connector;
4733 RT_ZERO(Connector);
4734 Connector.pu8Data = pu8Data;
4735 Connector.cBits = 32;
4736 Connector.cx = pThis->last_scr_width;
4737 Connector.cy = pThis->last_scr_height;
4738 Connector.cbScanline = Connector.cx * 4;
4739 Connector.pfnRefresh = vgaDummyRefresh;
4740 Connector.pfnResize = vgaDummyResize;
4741 Connector.pfnUpdateRect = vgaDummyUpdateRect;
4742
4743 /* Save & replace state data. */
4744 PPDMIDISPLAYCONNECTOR pConnectorSaved = pThis->pDrv;
4745 int32_t graphic_mode_saved = pThis->graphic_mode;
4746 bool fRenderVRAMSaved = pThis->fRenderVRAM;
4747
4748 pThis->pDrv = &Connector;
4749 pThis->graphic_mode = -1; /* force a full refresh. */
4750 pThis->fRenderVRAM = 1; /* force the guest VRAM rendering to the given buffer. */
4751
4752 /*
4753 * Make the screenshot.
4754 *
4755 * The second parameter is 'false' because the current display state is being rendered to an
4756 * external buffer using a fake connector. That is if display is blanked, we expect a black
4757 * screen in the external buffer.
4758 * If there is a pending resize, the function will fail.
4759 */
4760 rc = vga_update_display(pThis, false, true, false);
4761
4762 /* Restore. */
4763 pThis->pDrv = pConnectorSaved;
4764 pThis->graphic_mode = graphic_mode_saved;
4765 pThis->fRenderVRAM = fRenderVRAMSaved;
4766
4767 if (rc == VINF_SUCCESS)
4768 {
4769 /*
4770 * Return the result.
4771 */
4772 *ppu8Data = pu8Data;
4773 *pcbData = cbRequired;
4774 *pcx = Connector.cx;
4775 *pcy = Connector.cy;
4776 }
4777 else
4778 {
4779 /* If we do not return a success, then the data buffer must be freed. */
4780 RTMemFree(pu8Data);
4781 if (RT_SUCCESS_NP(rc))
4782 {
4783 AssertMsgFailed(("%Rrc\n", rc));
4784 rc = VERR_INTERNAL_ERROR_5;
4785 }
4786 }
4787 }
4788 else
4789 rc = VERR_NO_MEMORY;
4790 }
4791 else
4792 rc = VERR_NOT_SUPPORTED;
4793
4794 PDMCritSectLeave(&pThis->lock);
4795
4796 LogFlow(("vgaPortTakeScreenshot: returns %Rrc (cbData=%d cx=%d cy=%d)\n", rc, *pcbData, *pcx, *pcy));
4797 return rc;
4798}
4799
4800/**
4801 * Free a screenshot buffer allocated in vgaPortTakeScreenshot.
4802 *
4803 * @param pInterface Pointer to this interface.
4804 * @param pu8Data Pointer returned by vgaPortTakeScreenshot.
4805 * @see PDMIDISPLAYPORT::pfnFreeScreenshot() for details.
4806 */
4807static DECLCALLBACK(void) vgaPortFreeScreenshot(PPDMIDISPLAYPORT pInterface, uint8_t *pu8Data)
4808{
4809 NOREF(pInterface);
4810
4811 LogFlow(("vgaPortFreeScreenshot: pu8Data=%p\n", pu8Data));
4812
4813 RTMemFree(pu8Data);
4814}
4815
4816/**
4817 * Copy bitmap to the display.
4818 *
4819 * @param pInterface Pointer to this interface.
4820 * @param pvData Pointer to the bitmap bits.
4821 * @param x The upper left corner x coordinate of the destination rectangle.
4822 * @param y The upper left corner y coordinate of the destination rectangle.
4823 * @param cx The width of the source and destination rectangles.
4824 * @param cy The height of the source and destination rectangles.
4825 * @see PDMIDISPLAYPORT::pfnDisplayBlt() for details.
4826 */
4827static DECLCALLBACK(int) vgaPortDisplayBlt(PPDMIDISPLAYPORT pInterface, const void *pvData, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
4828{
4829 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4830 int rc = VINF_SUCCESS;
4831 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4832 LogFlow(("vgaPortDisplayBlt: pvData=%p x=%d y=%d cx=%d cy=%d\n", pvData, x, y, cx, cy));
4833
4834 rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
4835 AssertRC(rc);
4836
4837 /*
4838 * Validate input.
4839 */
4840 if ( pvData
4841 && x < pThis->pDrv->cx
4842 && cx <= pThis->pDrv->cx
4843 && cx + x <= pThis->pDrv->cx
4844 && y < pThis->pDrv->cy
4845 && cy <= pThis->pDrv->cy
4846 && cy + y <= pThis->pDrv->cy)
4847 {
4848 /*
4849 * Determine bytes per pixel in the destination buffer.
4850 */
4851 size_t cbPixelDst = 0;
4852 switch (pThis->pDrv->cBits)
4853 {
4854 case 8:
4855 cbPixelDst = 1;
4856 break;
4857 case 15:
4858 case 16:
4859 cbPixelDst = 2;
4860 break;
4861 case 24:
4862 cbPixelDst = 3;
4863 break;
4864 case 32:
4865 cbPixelDst = 4;
4866 break;
4867 default:
4868 rc = VERR_INVALID_PARAMETER;
4869 break;
4870 }
4871 if (RT_SUCCESS(rc))
4872 {
4873 /*
4874 * The blitting loop.
4875 */
4876 size_t cbLineSrc = cx * 4; /* 32 bits per pixel. */
4877 uint8_t *pu8Src = (uint8_t *)pvData;
4878 size_t cbLineDst = pThis->pDrv->cbScanline;
4879 uint8_t *pu8Dst = pThis->pDrv->pu8Data + y * cbLineDst + x * cbPixelDst;
4880 uint32_t cyLeft = cy;
4881 vga_draw_line_func *pfnVgaDrawLine = vga_draw_line_table[VGA_DRAW_LINE32 * 4 + get_depth_index(pThis->pDrv->cBits)];
4882 Assert(pfnVgaDrawLine);
4883 while (cyLeft-- > 0)
4884 {
4885 pfnVgaDrawLine(pThis, pu8Dst, pu8Src, cx);
4886 pu8Dst += cbLineDst;
4887 pu8Src += cbLineSrc;
4888 }
4889
4890 /*
4891 * Invalidate the area.
4892 */
4893 pThis->pDrv->pfnUpdateRect(pThis->pDrv, x, y, cx, cy);
4894 }
4895 }
4896 else
4897 rc = VERR_INVALID_PARAMETER;
4898
4899 PDMCritSectLeave(&pThis->lock);
4900
4901 LogFlow(("vgaPortDisplayBlt: returns %Rrc\n", rc));
4902 return rc;
4903}
4904
4905static DECLCALLBACK(void) vgaPortUpdateDisplayRect (PPDMIDISPLAYPORT pInterface, int32_t x, int32_t y, uint32_t w, uint32_t h)
4906{
4907 uint32_t v;
4908 vga_draw_line_func *vga_draw_line;
4909
4910 uint32_t cbPixelDst;
4911 uint32_t cbLineDst;
4912 uint8_t *pu8Dst;
4913
4914 uint32_t cbPixelSrc;
4915 uint32_t cbLineSrc;
4916 uint8_t *pu8Src;
4917
4918 uint32_t u32OffsetSrc, u32Dummy;
4919
4920 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
4921
4922#ifdef DEBUG_sunlover
4923 LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d\n", x, y, w, h));
4924#endif /* DEBUG_sunlover */
4925
4926 Assert(pInterface);
4927 Assert(s->pDrv);
4928 Assert(s->pDrv->pu8Data);
4929
4930 /* Check if there is something to do at all. */
4931 if (!s->fRenderVRAM)
4932 {
4933 /* The framebuffer uses the guest VRAM directly. */
4934#ifdef DEBUG_sunlover
4935 LogFlow(("vgaPortUpdateDisplayRect: nothing to do fRender is false.\n"));
4936#endif /* DEBUG_sunlover */
4937 return;
4938 }
4939
4940 int rc = PDMCritSectEnter(&s->lock, VERR_SEM_BUSY);
4941 AssertRC(rc);
4942
4943 /* Correct negative x and y coordinates. */
4944 if (x < 0)
4945 {
4946 x += w; /* Compute xRight which is also the new width. */
4947 w = (x < 0) ? 0 : x;
4948 x = 0;
4949 }
4950
4951 if (y < 0)
4952 {
4953 y += h; /* Compute yBottom, which is also the new height. */
4954 h = (y < 0) ? 0 : y;
4955 y = 0;
4956 }
4957
4958 /* Also check if coords are greater than the display resolution. */
4959 if (x + w > s->pDrv->cx)
4960 {
4961 // x < 0 is not possible here
4962 w = s->pDrv->cx > (uint32_t)x? s->pDrv->cx - x: 0;
4963 }
4964
4965 if (y + h > s->pDrv->cy)
4966 {
4967 // y < 0 is not possible here
4968 h = s->pDrv->cy > (uint32_t)y? s->pDrv->cy - y: 0;
4969 }
4970
4971#ifdef DEBUG_sunlover
4972 LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d (corrected coords)\n", x, y, w, h));
4973#endif /* DEBUG_sunlover */
4974
4975 /* Check if there is something to do at all. */
4976 if (w == 0 || h == 0)
4977 {
4978 /* Empty rectangle. */
4979#ifdef DEBUG_sunlover
4980 LogFlow(("vgaPortUpdateDisplayRect: nothing to do: %dx%d\n", w, h));
4981#endif /* DEBUG_sunlover */
4982 PDMCritSectLeave(&s->lock);
4983 return;
4984 }
4985
4986 /** @todo This method should be made universal and not only for VBVA.
4987 * VGA_DRAW_LINE* must be selected and src/dst address calculation
4988 * changed.
4989 */
4990
4991 /* Choose the rendering function. */
4992 switch(s->get_bpp(s))
4993 {
4994 default:
4995 case 0:
4996 /* A LFB mode is already disabled, but the callback is still called
4997 * by Display because VBVA buffer is being flushed.
4998 * Nothing to do, just return.
4999 */
5000 PDMCritSectLeave(&s->lock);
5001 return;
5002 case 8:
5003 v = VGA_DRAW_LINE8;
5004 break;
5005 case 15:
5006 v = VGA_DRAW_LINE15;
5007 break;
5008 case 16:
5009 v = VGA_DRAW_LINE16;
5010 break;
5011 case 24:
5012 v = VGA_DRAW_LINE24;
5013 break;
5014 case 32:
5015 v = VGA_DRAW_LINE32;
5016 break;
5017 }
5018
5019 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->pDrv->cBits)];
5020
5021 /* Compute source and destination addresses and pitches. */
5022 cbPixelDst = (s->pDrv->cBits + 7) / 8;
5023 cbLineDst = s->pDrv->cbScanline;
5024 pu8Dst = s->pDrv->pu8Data + y * cbLineDst + x * cbPixelDst;
5025
5026 cbPixelSrc = (s->get_bpp(s) + 7) / 8;
5027 s->get_offsets(s, &cbLineSrc, &u32OffsetSrc, &u32Dummy);
5028
5029 /* Assume that rendering is performed only on visible part of VRAM.
5030 * This is true because coordinates were verified.
5031 */
5032 pu8Src = s->vram_ptrR3;
5033 pu8Src += u32OffsetSrc * 4 + y * cbLineSrc + x * cbPixelSrc;
5034
5035 /* Render VRAM to framebuffer. */
5036
5037#ifdef DEBUG_sunlover
5038 LogFlow(("vgaPortUpdateDisplayRect: dst: %p, %d, %d. src: %p, %d, %d\n", pu8Dst, cbLineDst, cbPixelDst, pu8Src, cbLineSrc, cbPixelSrc));
5039#endif /* DEBUG_sunlover */
5040
5041 while (h-- > 0)
5042 {
5043 vga_draw_line (s, pu8Dst, pu8Src, w);
5044 pu8Dst += cbLineDst;
5045 pu8Src += cbLineSrc;
5046 }
5047 PDMCritSectLeave(&s->lock);
5048
5049#ifdef DEBUG_sunlover
5050 LogFlow(("vgaPortUpdateDisplayRect: completed.\n"));
5051#endif /* DEBUG_sunlover */
5052}
5053
5054static DECLCALLBACK(int) vgaPortCopyRect (PPDMIDISPLAYPORT pInterface,
5055 uint32_t w,
5056 uint32_t h,
5057 const uint8_t *pu8Src,
5058 int32_t xSrc,
5059 int32_t ySrc,
5060 uint32_t u32SrcWidth,
5061 uint32_t u32SrcHeight,
5062 uint32_t u32SrcLineSize,
5063 uint32_t u32SrcBitsPerPixel,
5064 uint8_t *pu8Dst,
5065 int32_t xDst,
5066 int32_t yDst,
5067 uint32_t u32DstWidth,
5068 uint32_t u32DstHeight,
5069 uint32_t u32DstLineSize,
5070 uint32_t u32DstBitsPerPixel)
5071{
5072 uint32_t v;
5073 vga_draw_line_func *vga_draw_line;
5074
5075 uint32_t cbPixelDst;
5076 uint32_t cbLineDst;
5077 uint8_t *pu8DstPtr;
5078
5079 uint32_t cbPixelSrc;
5080 uint32_t cbLineSrc;
5081 const uint8_t *pu8SrcPtr;
5082
5083#ifdef DEBUG_sunlover
5084 LogFlow(("vgaPortCopyRect: %d,%d %dx%d -> %d,%d\n", xSrc, ySrc, w, h, xDst, yDst));
5085#endif /* DEBUG_sunlover */
5086
5087 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
5088
5089 Assert(pInterface);
5090 Assert(s->pDrv);
5091
5092 int32_t xSrcCorrected = xSrc;
5093 int32_t ySrcCorrected = ySrc;
5094 uint32_t wCorrected = w;
5095 uint32_t hCorrected = h;
5096
5097 /* Correct source coordinates to be within the source bitmap. */
5098 if (xSrcCorrected < 0)
5099 {
5100 xSrcCorrected += wCorrected; /* Compute xRight which is also the new width. */
5101 wCorrected = (xSrcCorrected < 0) ? 0 : xSrcCorrected;
5102 xSrcCorrected = 0;
5103 }
5104
5105 if (ySrcCorrected < 0)
5106 {
5107 ySrcCorrected += hCorrected; /* Compute yBottom, which is also the new height. */
5108 hCorrected = (ySrcCorrected < 0) ? 0 : ySrcCorrected;
5109 ySrcCorrected = 0;
5110 }
5111
5112 /* Also check if coords are greater than the display resolution. */
5113 if (xSrcCorrected + wCorrected > u32SrcWidth)
5114 {
5115 /* xSrcCorrected < 0 is not possible here */
5116 wCorrected = u32SrcWidth > (uint32_t)xSrcCorrected? u32SrcWidth - xSrcCorrected: 0;
5117 }
5118
5119 if (ySrcCorrected + hCorrected > u32SrcHeight)
5120 {
5121 /* y < 0 is not possible here */
5122 hCorrected = u32SrcHeight > (uint32_t)ySrcCorrected? u32SrcHeight - ySrcCorrected: 0;
5123 }
5124
5125#ifdef DEBUG_sunlover
5126 LogFlow(("vgaPortCopyRect: %d,%d %dx%d (corrected coords)\n", xSrcCorrected, ySrcCorrected, wCorrected, hCorrected));
5127#endif /* DEBUG_sunlover */
5128
5129 /* Check if there is something to do at all. */
5130 if (wCorrected == 0 || hCorrected == 0)
5131 {
5132 /* Empty rectangle. */
5133#ifdef DEBUG_sunlover
5134 LogFlow(("vgaPortUpdateDisplayRectEx: nothing to do: %dx%d\n", wCorrected, hCorrected));
5135#endif /* DEBUG_sunlover */
5136 return VINF_SUCCESS;
5137 }
5138
5139 /* Check that the corrected source rectangle is within the destination.
5140 * Note: source rectangle is adjusted, but the target must be large enough.
5141 */
5142 if ( xDst < 0
5143 || yDst < 0
5144 || xDst + wCorrected > u32DstWidth
5145 || yDst + hCorrected > u32DstHeight)
5146 {
5147 return VERR_INVALID_PARAMETER;
5148 }
5149
5150 /* Choose the rendering function. */
5151 switch(u32SrcBitsPerPixel)
5152 {
5153 default:
5154 case 0:
5155 /* Nothing to do, just return. */
5156 return VINF_SUCCESS;
5157 case 8:
5158 v = VGA_DRAW_LINE8;
5159 break;
5160 case 15:
5161 v = VGA_DRAW_LINE15;
5162 break;
5163 case 16:
5164 v = VGA_DRAW_LINE16;
5165 break;
5166 case 24:
5167 v = VGA_DRAW_LINE24;
5168 break;
5169 case 32:
5170 v = VGA_DRAW_LINE32;
5171 break;
5172 }
5173
5174 int rc = PDMCritSectEnter(&s->lock, VERR_SEM_BUSY);
5175 AssertRC(rc);
5176
5177 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(u32DstBitsPerPixel)];
5178
5179 /* Compute source and destination addresses and pitches. */
5180 cbPixelDst = (u32DstBitsPerPixel + 7) / 8;
5181 cbLineDst = u32DstLineSize;
5182 pu8DstPtr = pu8Dst + yDst * cbLineDst + xDst * cbPixelDst;
5183
5184 cbPixelSrc = (u32SrcBitsPerPixel + 7) / 8;
5185 cbLineSrc = u32SrcLineSize;
5186 pu8SrcPtr = pu8Src + ySrcCorrected * cbLineSrc + xSrcCorrected * cbPixelSrc;
5187
5188#ifdef DEBUG_sunlover
5189 LogFlow(("vgaPortCopyRect: dst: %p, %d, %d. src: %p, %d, %d\n", pu8DstPtr, cbLineDst, cbPixelDst, pu8SrcPtr, cbLineSrc, cbPixelSrc));
5190#endif /* DEBUG_sunlover */
5191
5192 while (hCorrected-- > 0)
5193 {
5194 vga_draw_line (s, pu8DstPtr, pu8SrcPtr, wCorrected);
5195 pu8DstPtr += cbLineDst;
5196 pu8SrcPtr += cbLineSrc;
5197 }
5198 PDMCritSectLeave(&s->lock);
5199
5200#ifdef DEBUG_sunlover
5201 LogFlow(("vgaPortCopyRect: completed.\n"));
5202#endif /* DEBUG_sunlover */
5203
5204 return VINF_SUCCESS;
5205}
5206
5207static DECLCALLBACK(void) vgaPortSetRenderVRAM(PPDMIDISPLAYPORT pInterface, bool fRender)
5208{
5209 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
5210
5211 LogFlow(("vgaPortSetRenderVRAM: fRender = %d\n", fRender));
5212
5213 s->fRenderVRAM = fRender;
5214}
5215
5216
5217static DECLCALLBACK(void) vgaTimerRefresh(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
5218{
5219 PVGASTATE pThis = (PVGASTATE)pvUser;
5220 NOREF(pDevIns);
5221
5222 if (pThis->pDrv)
5223 pThis->pDrv->pfnRefresh(pThis->pDrv);
5224
5225 if (pThis->cMilliesRefreshInterval)
5226 TMTimerSetMillies(pTimer, pThis->cMilliesRefreshInterval);
5227}
5228
5229
5230/* -=-=-=-=-=- Ring 3: PCI Device -=-=-=-=-=- */
5231
5232/**
5233 * Callback function for unmapping and/or mapping the VRAM MMIO2 region (called by the PCI bus).
5234 *
5235 * @return VBox status code.
5236 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
5237 * @param iRegion The region number.
5238 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
5239 * I/O port, else it's a physical address.
5240 * This address is *NOT* relative to pci_mem_base like earlier!
5241 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
5242 */
5243static DECLCALLBACK(int) vgaR3IORegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
5244{
5245 int rc;
5246 PPDMDEVINS pDevIns = pPciDev->pDevIns;
5247 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5248 LogFlow(("vgaR3IORegionMap: iRegion=%d GCPhysAddress=%RGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
5249 AssertReturn(iRegion == 0 && enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
5250
5251 if (GCPhysAddress != NIL_RTGCPHYS)
5252 {
5253 /*
5254 * Mapping the VRAM.
5255 */
5256 rc = PDMDevHlpMMIO2Map(pDevIns, iRegion, GCPhysAddress);
5257 AssertRC(rc);
5258 if (RT_SUCCESS(rc))
5259 {
5260 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
5261 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
5262 GCPhysAddress, GCPhysAddress + (pThis->vram_size - 1),
5263 vgaR3LFBAccessHandler, pThis,
5264 g_DeviceVga.szR0Mod, "vgaR0LFBAccessHandler", pDevIns->pvInstanceDataR0,
5265 g_DeviceVga.szRCMod, "vgaGCLFBAccessHandler", pDevIns->pvInstanceDataRC,
5266 "VGA LFB");
5267 AssertRC(rc);
5268 if (RT_SUCCESS(rc))
5269 {
5270 pThis->GCPhysVRAM = GCPhysAddress;
5271 pThis->vbe_regs[VBE_DISPI_INDEX_FB_BASE_HI] = GCPhysAddress >> 16;
5272 }
5273 }
5274 }
5275 else
5276 {
5277 /*
5278 * Unmapping of the VRAM in progress.
5279 * Deregister the access handler so PGM doesn't get upset.
5280 */
5281 Assert(pThis->GCPhysVRAM);
5282 rc = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
5283 AssertRC(rc);
5284 pThis->GCPhysVRAM = 0;
5285 pThis->vbe_regs[VBE_DISPI_INDEX_FB_BASE_HI];
5286 }
5287 return rc;
5288}
5289
5290
5291/* -=-=-=-=-=- Ring3: Misc Wrappers & Sidekicks -=-=-=-=-=- */
5292
5293/**
5294 * Saves a important bits of the VGA device config.
5295 *
5296 * @param pThis The VGA instance data.
5297 * @param pSSM The saved state handle.
5298 */
5299static void vgaR3SaveConfig(PVGASTATE pThis, PSSMHANDLE pSSM)
5300{
5301 SSMR3PutU32(pSSM, pThis->vram_size);
5302 SSMR3PutU32(pSSM, pThis->cMonitors);
5303}
5304
5305
5306/**
5307 * @copydoc FNSSMDEVLIVEEXEC
5308 */
5309static DECLCALLBACK(int) vgaR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
5310{
5311 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5312 Assert(uPass == 0); NOREF(uPass);
5313 vgaR3SaveConfig(pThis, pSSM);
5314 return VINF_SSM_DONT_CALL_AGAIN;
5315}
5316
5317
5318/**
5319 * @copydoc FNSSMDEVSAVEPREP
5320 */
5321static DECLCALLBACK(int) vgaR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5322{
5323#ifdef VBOX_WITH_VIDEOHWACCEL
5324 return vboxVBVASaveStatePrep(pDevIns, pSSM);
5325#else
5326 return VINF_SUCCESS;
5327#endif
5328}
5329
5330static DECLCALLBACK(int) vgaR3SaveDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5331{
5332#ifdef VBOX_WITH_VIDEOHWACCEL
5333 return vboxVBVASaveStateDone(pDevIns, pSSM);
5334#else
5335 return VINF_SUCCESS;
5336#endif
5337}
5338
5339/**
5340 * @copydoc FNSSMDEVSAVEEXEC
5341 */
5342static DECLCALLBACK(int) vgaR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5343{
5344 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5345#ifdef VBOX_WITH_VDMA
5346 vboxVDMASaveStateExecPrep(pThis->pVdma, pSSM);
5347#endif
5348 vgaR3SaveConfig(pThis, pSSM);
5349 vga_save(pSSM, PDMINS_2_DATA(pDevIns, PVGASTATE));
5350#ifdef VBOX_WITH_HGSMI
5351 SSMR3PutBool(pSSM, true);
5352 int rc = vboxVBVASaveStateExec(pDevIns, pSSM);
5353# ifdef VBOX_WITH_VDMA
5354 vboxVDMASaveStateExecDone(pThis->pVdma, pSSM);
5355# endif
5356 return rc;
5357#else
5358 SSMR3PutBool(pSSM, false);
5359 return VINF_SUCCESS;
5360#endif
5361}
5362
5363
5364/**
5365 * @copydoc FNSSMDEVSAVEEXEC
5366 */
5367static DECLCALLBACK(int) vgaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
5368{
5369 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5370 int rc;
5371
5372 if (uVersion < VGA_SAVEDSTATE_VERSION_ANCIENT || uVersion > VGA_SAVEDSTATE_VERSION)
5373 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
5374
5375 if (uVersion > VGA_SAVEDSTATE_VERSION_HGSMI)
5376 {
5377 /* Check the config */
5378 uint32_t cbVRam;
5379 rc = SSMR3GetU32(pSSM, &cbVRam);
5380 AssertRCReturn(rc, rc);
5381 if (pThis->vram_size != cbVRam)
5382 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("VRAM size changed: config=%#x state=%#x"), pThis->vram_size, cbVRam);
5383
5384 uint32_t cMonitors;
5385 rc = SSMR3GetU32(pSSM, &cMonitors);
5386 AssertRCReturn(rc, rc);
5387 if (pThis->cMonitors != cMonitors)
5388 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Monitor count changed: config=%u state=%u"), pThis->cMonitors, cMonitors);
5389 }
5390
5391 if (uPass == SSM_PASS_FINAL)
5392 {
5393 rc = vga_load(pSSM, pThis, uVersion);
5394 if (RT_FAILURE(rc))
5395 return rc;
5396 bool fWithHgsmi = uVersion == VGA_SAVEDSTATE_VERSION_HGSMI;
5397 if (uVersion > VGA_SAVEDSTATE_VERSION_HGSMI)
5398 {
5399 rc = SSMR3GetBool(pSSM, &fWithHgsmi);
5400 AssertRCReturn(rc, rc);
5401 }
5402 if (fWithHgsmi)
5403 {
5404#ifdef VBOX_WITH_HGSMI
5405 rc = vboxVBVALoadStateExec(pDevIns, pSSM, uVersion);
5406 AssertRCReturn(rc, rc);
5407#else
5408 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("HGSMI is not compiled in, but it is present in the saved state"));
5409#endif
5410 }
5411 }
5412 return VINF_SUCCESS;
5413}
5414
5415
5416/**
5417 * @copydoc FNSSMDEVLOADDONE
5418 */
5419static DECLCALLBACK(int) vgaR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5420{
5421#ifdef VBOX_WITH_HGSMI
5422 return vboxVBVALoadStateDone(pDevIns, pSSM);
5423#else
5424 return VINF_SUCCESS;
5425#endif
5426}
5427
5428
5429/* -=-=-=-=-=- Ring 3: Device callbacks -=-=-=-=-=- */
5430
5431/**
5432 * Reset notification.
5433 *
5434 * @returns VBox status.
5435 * @param pDevIns The device instance data.
5436 */
5437static DECLCALLBACK(void) vgaR3Reset(PPDMDEVINS pDevIns)
5438{
5439 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5440 char *pchStart;
5441 char *pchEnd;
5442 LogFlow(("vgaReset\n"));
5443
5444#ifdef VBOX_WITH_HGSMI
5445 VBVAReset(pThis);
5446#endif /* VBOX_WITH_HGSMI */
5447
5448
5449 /* Clear the VRAM ourselves. */
5450 if (pThis->vram_ptrR3 && pThis->vram_size)
5451 memset(pThis->vram_ptrR3, 0, pThis->vram_size);
5452
5453 /*
5454 * Zero most of it.
5455 *
5456 * Unlike vga_reset we're leaving out a few members which we believe
5457 * must remain unchanged....
5458 */
5459 /* 1st part. */
5460 pchStart = (char *)&pThis->latch;
5461 pchEnd = (char *)&pThis->invalidated_y_table;
5462 memset(pchStart, 0, pchEnd - pchStart);
5463
5464 /* 2nd part. */
5465 pchStart = (char *)&pThis->last_palette;
5466 pchEnd = (char *)&pThis->u32Marker;
5467 memset(pchStart, 0, pchEnd - pchStart);
5468
5469
5470 /*
5471 * Restore and re-init some bits.
5472 */
5473 pThis->get_bpp = vga_get_bpp;
5474 pThis->get_offsets = vga_get_offsets;
5475 pThis->get_resolution = vga_get_resolution;
5476 pThis->graphic_mode = -1; /* Force full update. */
5477#ifdef CONFIG_BOCHS_VBE
5478 pThis->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
5479 pThis->vbe_regs[VBE_DISPI_INDEX_VBOX_VIDEO] = 0;
5480 pThis->vbe_bank_max = (pThis->vram_size >> 16) - 1;
5481#endif /* CONFIG_BOCHS_VBE */
5482
5483 /*
5484 * Reset the LBF mapping.
5485 */
5486 pThis->fLFBUpdated = false;
5487 if ( ( pThis->fGCEnabled
5488 || pThis->fR0Enabled)
5489 && pThis->GCPhysVRAM
5490 && pThis->GCPhysVRAM != NIL_RTGCPHYS32)
5491 {
5492 int rc = PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
5493 AssertRC(rc);
5494 }
5495 if (pThis->fRemappedVGA)
5496 {
5497 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000);
5498 pThis->fRemappedVGA = false;
5499 }
5500
5501 /*
5502 * Reset the logo data.
5503 */
5504 pThis->LogoCommand = LOGO_CMD_NOP;
5505 pThis->offLogoData = 0;
5506
5507 /* notify port handler */
5508 if (pThis->pDrv)
5509 pThis->pDrv->pfnReset(pThis->pDrv);
5510
5511 /* Reset latched access mask. */
5512 pThis->uMaskLatchAccess = 0x3ff;
5513 pThis->cLatchAccesses = 0;
5514 pThis->u64LastLatchedAccess = 0;
5515 pThis->iMask = 0;
5516
5517 /* Reset retrace emulation. */
5518 memset(&pThis->retrace_state, 0, sizeof(pThis->retrace_state));
5519}
5520
5521
5522/**
5523 * Device relocation callback.
5524 *
5525 * @param pDevIns Pointer to the device instance.
5526 * @param offDelta The relocation delta relative to the old location.
5527 *
5528 * @see FNPDMDEVRELOCATE for details.
5529 */
5530static DECLCALLBACK(void) vgaR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
5531{
5532 if (offDelta)
5533 {
5534 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5535 LogFlow(("vgaRelocate: offDelta = %08X\n", offDelta));
5536
5537 pThis->RCPtrLFBHandler += offDelta;
5538 pThis->vram_ptrRC += offDelta;
5539 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5540 }
5541}
5542
5543
5544/**
5545 * Attach command.
5546 *
5547 * This is called to let the device attach to a driver for a specified LUN
5548 * during runtime. This is not called during VM construction, the device
5549 * constructor have to attach to all the available drivers.
5550 *
5551 * This is like plugging in the monitor after turning on the PC.
5552 *
5553 * @returns VBox status code.
5554 * @param pDevIns The device instance.
5555 * @param iLUN The logical unit which is being detached.
5556 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
5557 */
5558static DECLCALLBACK(int) vgaAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5559{
5560 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5561
5562 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
5563 ("VGA device does not support hotplugging\n"),
5564 VERR_INVALID_PARAMETER);
5565
5566 switch (iLUN)
5567 {
5568 /* LUN #0: Display port. */
5569 case 0:
5570 {
5571 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &pThis->pDrvBase, "Display Port");
5572 if (RT_SUCCESS(rc))
5573 {
5574 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIDISPLAYCONNECTOR);
5575 if (pThis->pDrv)
5576 {
5577 /* pThis->pDrv->pu8Data can be NULL when there is no framebuffer. */
5578 if ( pThis->pDrv->pfnRefresh
5579 && pThis->pDrv->pfnResize
5580 && pThis->pDrv->pfnUpdateRect)
5581 rc = VINF_SUCCESS;
5582 else
5583 {
5584 Assert(pThis->pDrv->pfnRefresh);
5585 Assert(pThis->pDrv->pfnResize);
5586 Assert(pThis->pDrv->pfnUpdateRect);
5587 pThis->pDrv = NULL;
5588 pThis->pDrvBase = NULL;
5589 rc = VERR_INTERNAL_ERROR;
5590 }
5591#ifdef VBOX_WITH_VIDEOHWACCEL
5592 if(rc == VINF_SUCCESS)
5593 {
5594 rc = vbvaVHWAConstruct(pThis);
5595 if (rc != VERR_NOT_IMPLEMENTED)
5596 AssertRC(rc);
5597 }
5598#endif
5599 }
5600 else
5601 {
5602 AssertMsgFailed(("LUN #0 doesn't have a display connector interface! rc=%Rrc\n", rc));
5603 pThis->pDrvBase = NULL;
5604 rc = VERR_PDM_MISSING_INTERFACE;
5605 }
5606 }
5607 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5608 {
5609 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
5610 rc = VINF_SUCCESS;
5611 }
5612 else
5613 AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
5614 return rc;
5615 }
5616
5617 default:
5618 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
5619 return VERR_PDM_NO_SUCH_LUN;
5620 }
5621}
5622
5623
5624/**
5625 * Detach notification.
5626 *
5627 * This is called when a driver is detaching itself from a LUN of the device.
5628 * The device should adjust it's state to reflect this.
5629 *
5630 * This is like unplugging the monitor while the PC is still running.
5631 *
5632 * @param pDevIns The device instance.
5633 * @param iLUN The logical unit which is being detached.
5634 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
5635 */
5636static DECLCALLBACK(void) vgaDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5637{
5638 /*
5639 * Reset the interfaces and update the controller state.
5640 */
5641 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5642
5643 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
5644 ("VGA device does not support hotplugging\n"));
5645
5646 switch (iLUN)
5647 {
5648 /* LUN #0: Display port. */
5649 case 0:
5650 pThis->pDrv = NULL;
5651 pThis->pDrvBase = NULL;
5652 break;
5653
5654 default:
5655 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
5656 break;
5657 }
5658}
5659
5660
5661/**
5662 * Destruct a device instance.
5663 *
5664 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
5665 * resources can be freed correctly.
5666 *
5667 * @param pDevIns The device instance data.
5668 */
5669static DECLCALLBACK(int) vgaR3Destruct(PPDMDEVINS pDevIns)
5670{
5671 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
5672
5673#ifdef VBE_NEW_DYN_LIST
5674 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5675 LogFlow(("vgaR3Destruct:\n"));
5676
5677#ifdef VBOX_WITH_VDMA
5678 vboxVDMADestruct(pThis->pVdma);
5679#endif
5680
5681 /*
5682 * Free MM heap pointers.
5683 */
5684 if (pThis->pu8VBEExtraData)
5685 {
5686 MMR3HeapFree(pThis->pu8VBEExtraData);
5687 pThis->pu8VBEExtraData = NULL;
5688 }
5689#endif
5690 if (pThis->pu8VgaBios)
5691 {
5692 MMR3HeapFree(pThis->pu8VgaBios);
5693 pThis->pu8VgaBios = NULL;
5694 }
5695
5696 if (pThis->pszVgaBiosFile)
5697 {
5698 MMR3HeapFree(pThis->pszVgaBiosFile);
5699 pThis->pszVgaBiosFile = NULL;
5700 }
5701
5702 if (pThis->pszLogoFile)
5703 {
5704 MMR3HeapFree(pThis->pszLogoFile);
5705 pThis->pszLogoFile = NULL;
5706 }
5707
5708 PDMR3CritSectDelete(&pThis->lock);
5709 return VINF_SUCCESS;
5710}
5711
5712/**
5713 * Adjust VBE mode information
5714 *
5715 * Depending on the configured VRAM size, certain parts of VBE mode
5716 * information must be updated.
5717 *
5718 * @param pThis The device instance data.
5719 * @param pMode The mode information structure.
5720 */
5721static void vgaAdjustModeInfo(PVGASTATE pThis, ModeInfoListItem *pMode)
5722{
5723 int maxPage;
5724 int bpl;
5725
5726
5727 /* For 4bpp modes, the planes are "stacked" on top of each other. */
5728 bpl = pMode->info.BytesPerScanLine * pMode->info.NumberOfPlanes;
5729 /* The "number of image pages" is really the max page index... */
5730 maxPage = pThis->vram_size / (pMode->info.YResolution * bpl) - 1;
5731 Assert(maxPage >= 0);
5732 if (maxPage > 255)
5733 maxPage = 255; /* 8-bit value. */
5734 pMode->info.NumberOfImagePages = maxPage;
5735 pMode->info.LinNumberOfPages = maxPage;
5736}
5737
5738/**
5739 * @interface_method_impl{PDMDEVREG,pfnConstruct}
5740 */
5741static DECLCALLBACK(int) vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
5742{
5743
5744 static bool s_fExpandDone = false;
5745 int rc;
5746 unsigned i;
5747#ifdef VBE_NEW_DYN_LIST
5748 uint32_t cCustomModes;
5749 uint32_t cyReduction;
5750 uint32_t cbPitch;
5751 PVBEHEADER pVBEDataHdr;
5752 ModeInfoListItem *pCurMode;
5753 unsigned cb;
5754#endif
5755 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5756 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5757 PVM pVM = PDMDevHlpGetVM(pDevIns);
5758
5759 Assert(iInstance == 0);
5760 Assert(pVM);
5761
5762 /*
5763 * Init static data.
5764 */
5765 if (!s_fExpandDone)
5766 {
5767 s_fExpandDone = true;
5768 vga_init_expand();
5769 }
5770
5771 /*
5772 * Validate configuration.
5773 */
5774 if (!CFGMR3AreValuesValid(pCfg, "VRamSize\0"
5775 "MonitorCount\0"
5776 "GCEnabled\0"
5777 "R0Enabled\0"
5778 "FadeIn\0"
5779 "FadeOut\0"
5780 "LogoTime\0"
5781 "LogoFile\0"
5782 "ShowBootMenu\0"
5783 "BiosRom\0"
5784 "RealRetrace\0"
5785 "CustomVideoModes\0"
5786 "HeightReduction\0"
5787 "CustomVideoMode1\0"
5788 "CustomVideoMode2\0"
5789 "CustomVideoMode3\0"
5790 "CustomVideoMode4\0"
5791 "CustomVideoMode5\0"
5792 "CustomVideoMode6\0"
5793 "CustomVideoMode7\0"
5794 "CustomVideoMode8\0"
5795 "CustomVideoMode9\0"
5796 "CustomVideoMode10\0"
5797 "CustomVideoMode11\0"
5798 "CustomVideoMode12\0"
5799 "CustomVideoMode13\0"
5800 "CustomVideoMode14\0"
5801 "CustomVideoMode15\0"
5802 "CustomVideoMode16\0"
5803 "MaxBiosXRes\0"
5804 "MaxBiosYRes\0"))
5805 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
5806 N_("Invalid configuration for vga device"));
5807
5808 /*
5809 * Init state data.
5810 */
5811 rc = CFGMR3QueryU32Def(pCfg, "VRamSize", &pThis->vram_size, VGA_VRAM_DEFAULT);
5812 AssertLogRelRCReturn(rc, rc);
5813 if (pThis->vram_size > VGA_VRAM_MAX)
5814 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
5815 "VRamSize is too large, %#x, max %#x", pThis->vram_size, VGA_VRAM_MAX);
5816 if (pThis->vram_size < VGA_VRAM_MIN)
5817 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
5818 "VRamSize is too small, %#x, max %#x", pThis->vram_size, VGA_VRAM_MIN);
5819 if (pThis->vram_size & (_256K - 1)) /* Make sure there are no partial banks even in planar modes. */
5820 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
5821 "VRamSize is not a multiple of 256K (%#x)", pThis->vram_size);
5822
5823 rc = CFGMR3QueryU32Def(pCfg, "MonitorCount", &pThis->cMonitors, 1);
5824 AssertLogRelRCReturn(rc, rc);
5825
5826 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
5827 AssertLogRelRCReturn(rc, rc);
5828
5829 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
5830 AssertLogRelRCReturn(rc, rc);
5831 Log(("VGA: VRamSize=%#x fGCenabled=%RTbool fR0Enabled=%RTbool\n", pThis->vram_size, pThis->fGCEnabled, pThis->fR0Enabled));
5832
5833 pThis->pDevInsR3 = pDevIns;
5834 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
5835 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5836
5837 vgaR3Reset(pDevIns);
5838
5839 /* The PCI devices configuration. */
5840 PCIDevSetVendorId( &pThis->Dev, 0x80ee); /* PCI vendor, just a free bogus value */
5841 PCIDevSetDeviceId( &pThis->Dev, 0xbeef);
5842 PCIDevSetClassSub( &pThis->Dev, 0x00); /* VGA controller */
5843 PCIDevSetClassBase( &pThis->Dev, 0x03);
5844 PCIDevSetHeaderType(&pThis->Dev, 0x00);
5845#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
5846 PCIDevSetInterruptPin(&pThis->Dev, 1);
5847#endif
5848
5849 /* The LBF access handler - error handling is better here than in the map function. */
5850 rc = PDMR3LdrGetSymbolRCLazy(pVM, pDevIns->pReg->szRCMod, NULL, "vgaGCLFBAccessHandler", &pThis->RCPtrLFBHandler);
5851 if (RT_FAILURE(rc))
5852 {
5853 AssertReleaseMsgFailed(("PDMR3LdrGetSymbolRC(, %s, \"vgaGCLFBAccessHandler\",) -> %Rrc\n", pDevIns->pReg->szRCMod, rc));
5854 return rc;
5855 }
5856
5857 /* the interfaces. */
5858 pThis->IBase.pfnQueryInterface = vgaPortQueryInterface;
5859
5860 pThis->IPort.pfnUpdateDisplay = vgaPortUpdateDisplay;
5861 pThis->IPort.pfnUpdateDisplayAll = vgaPortUpdateDisplayAll;
5862 pThis->IPort.pfnQueryColorDepth = vgaPortQueryColorDepth;
5863 pThis->IPort.pfnSetRefreshRate = vgaPortSetRefreshRate;
5864 pThis->IPort.pfnTakeScreenshot = vgaPortTakeScreenshot;
5865 pThis->IPort.pfnFreeScreenshot = vgaPortFreeScreenshot;
5866 pThis->IPort.pfnDisplayBlt = vgaPortDisplayBlt;
5867 pThis->IPort.pfnUpdateDisplayRect = vgaPortUpdateDisplayRect;
5868 pThis->IPort.pfnCopyRect = vgaPortCopyRect;
5869 pThis->IPort.pfnSetRenderVRAM = vgaPortSetRenderVRAM;
5870
5871#if defined(VBOX_WITH_HGSMI)
5872# if defined(VBOX_WITH_VIDEOHWACCEL)
5873 pThis->IVBVACallbacks.pfnVHWACommandCompleteAsynch = vbvaVHWACommandCompleteAsynch;
5874# endif
5875#if defined(VBOX_WITH_CRHGSMI)
5876 pThis->IVBVACallbacks.pfnCrHgsmiCommandCompleteAsync = vboxVDMACrHgsmiCommandCompleteAsync;
5877 pThis->IVBVACallbacks.pfnCrHgsmiControlCompleteAsync = vboxVDMACrHgsmiControlCompleteAsync;
5878# endif
5879#endif
5880
5881 /*
5882 * Allocate the VRAM and map the first 512KB of it into GC so we can speed up VGA support.
5883 */
5884 rc = PDMDevHlpMMIO2Register(pDevIns, 0 /* iRegion */, pThis->vram_size, 0, (void **)&pThis->vram_ptrR3, "VRam");
5885 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMIO2Register(%#x,) -> %Rrc\n", pThis->vram_size, rc), rc);
5886 pThis->vram_ptrR0 = (RTR0PTR)pThis->vram_ptrR3; /** @todo #1865 Map parts into R0 or just use PGM access (Mac only). */
5887
5888 if (pThis->fGCEnabled)
5889 {
5890 RTRCPTR pRCMapping = 0;
5891 rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, 0 /* iRegion */, 0 /* off */, VGA_MAPPING_SIZE, "VGA VRam", &pRCMapping);
5892 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMHyperMapMMIO2(%#x,) -> %Rrc\n", VGA_MAPPING_SIZE, rc), rc);
5893 pThis->vram_ptrRC = pRCMapping;
5894 }
5895
5896#if defined(VBOX_WITH_2X_4GB_ADDR_SPACE)
5897 if (pThis->fR0Enabled)
5898 {
5899 RTR0PTR pR0Mapping = 0;
5900 rc = PDMDevHlpMMIO2MapKernel(pDevIns, 0 /* iRegion */, 0 /* off */, VGA_MAPPING_SIZE, "VGA VRam", &pR0Mapping);
5901 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMapMMIO2IntoR0(%#x,) -> %Rrc\n", VGA_MAPPING_SIZE, rc), rc);
5902 pThis->vram_ptrR0 = pR0Mapping;
5903 }
5904#endif
5905
5906 /*
5907 * Register I/O ports, ROM and save state.
5908 */
5909 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3c0, 16, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3c0");
5910 if (RT_FAILURE(rc))
5911 return rc;
5912 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3b4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3b4");
5913 if (RT_FAILURE(rc))
5914 return rc;
5915 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3ba, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3ba");
5916 if (RT_FAILURE(rc))
5917 return rc;
5918 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3d4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3d4");
5919 if (RT_FAILURE(rc))
5920 return rc;
5921 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3da, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3da");
5922 if (RT_FAILURE(rc))
5923 return rc;
5924#ifdef VBOX_WITH_HGSMI
5925 /* Use reserved VGA IO ports for HGSMI. */
5926 rc = PDMDevHlpIOPortRegister(pDevIns, VGA_PORT_HGSMI_HOST, 4, NULL, vgaR3IOPortHGSMIWrite, vgaR3IOPortHGSMIRead, NULL, NULL, "VGA - 3b0 (HGSMI host)");
5927 if (RT_FAILURE(rc))
5928 return rc;
5929 rc = PDMDevHlpIOPortRegister(pDevIns, VGA_PORT_HGSMI_GUEST, 4, NULL, vgaR3IOPortHGSMIWrite, vgaR3IOPortHGSMIRead, NULL, NULL, "VGA - 3d0 (HGSMI guest)");
5930 if (RT_FAILURE(rc))
5931 return rc;
5932#endif /* VBOX_WITH_HGSMI */
5933
5934#ifdef CONFIG_BOCHS_VBE
5935 rc = PDMDevHlpIOPortRegister(pDevIns, 0x1ce, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, NULL, NULL, "VGA/VBE - Index");
5936 if (RT_FAILURE(rc))
5937 return rc;
5938 rc = PDMDevHlpIOPortRegister(pDevIns, 0x1cf, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, NULL, NULL, "VGA/VBE - Data");
5939 if (RT_FAILURE(rc))
5940 return rc;
5941#endif /* CONFIG_BOCHS_VBE */
5942
5943 /* guest context extension */
5944 if (pThis->fGCEnabled)
5945 {
5946 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
5947 if (RT_FAILURE(rc))
5948 return rc;
5949 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
5950 if (RT_FAILURE(rc))
5951 return rc;
5952 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
5953 if (RT_FAILURE(rc))
5954 return rc;
5955 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
5956 if (RT_FAILURE(rc))
5957 return rc;
5958 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
5959 if (RT_FAILURE(rc))
5960 return rc;
5961#ifdef CONFIG_BOCHS_VBE
5962 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
5963 if (RT_FAILURE(rc))
5964 return rc;
5965 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
5966 if (RT_FAILURE(rc))
5967 return rc;
5968#endif /* CONFIG_BOCHS_VBE */
5969 }
5970
5971 /* R0 context extension */
5972 if (pThis->fR0Enabled)
5973 {
5974 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
5975 if (RT_FAILURE(rc))
5976 return rc;
5977 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
5978 if (RT_FAILURE(rc))
5979 return rc;
5980 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
5981 if (RT_FAILURE(rc))
5982 return rc;
5983 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
5984 if (RT_FAILURE(rc))
5985 return rc;
5986 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
5987 if (RT_FAILURE(rc))
5988 return rc;
5989#ifdef CONFIG_BOCHS_VBE
5990 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
5991 if (RT_FAILURE(rc))
5992 return rc;
5993 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
5994 if (RT_FAILURE(rc))
5995 return rc;
5996#endif /* CONFIG_BOCHS_VBE */
5997 }
5998
5999 /* vga mmio */
6000 rc = PDMDevHlpMMIORegisterEx(pDevIns, 0x000a0000, 0x00020000, NULL /*pvUser*/,
6001 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
6002 vgaMMIOWrite, vgaMMIORead, vgaMMIOFill, "VGA - VGA Video Buffer");
6003 if (RT_FAILURE(rc))
6004 return rc;
6005 if (pThis->fGCEnabled)
6006 {
6007 rc = PDMDevHlpMMIORegisterRCEx(pDevIns, 0x000a0000, 0x00020000, NIL_RTRCPTR /*pvUser*/,
6008 "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill");
6009 if (RT_FAILURE(rc))
6010 return rc;
6011 }
6012 if (pThis->fR0Enabled)
6013 {
6014 rc = PDMDevHlpMMIORegisterR0Ex(pDevIns, 0x000a0000, 0x00020000, NIL_RTR0PTR /*pvUser*/,
6015 "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill");
6016 if (RT_FAILURE(rc))
6017 return rc;
6018 }
6019
6020 /* vga bios */
6021 rc = PDMDevHlpIOPortRegister(pDevIns, VBE_PRINTF_PORT, 1, NULL, vgaIOPortWriteBIOS, vgaIOPortReadBIOS, NULL, NULL, "VGA BIOS debug/panic");
6022 if (RT_FAILURE(rc))
6023 return rc;
6024 if (pThis->fR0Enabled)
6025 {
6026 rc = PDMDevHlpIOPortRegisterR0(pDevIns, VBE_PRINTF_PORT, 1, 0, "vgaIOPortWriteBIOS", "vgaIOPortReadBIOS", NULL, NULL, "VGA BIOS debug/panic");
6027 if (RT_FAILURE(rc))
6028 return rc;
6029 }
6030
6031 /*
6032 * Get the VGA BIOS ROM file name.
6033 */
6034 rc = CFGMR3QueryStringAlloc(pCfg, "BiosRom", &pThis->pszVgaBiosFile);
6035 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6036 {
6037 pThis->pszVgaBiosFile = NULL;
6038 rc = VINF_SUCCESS;
6039 }
6040 else if (RT_FAILURE(rc))
6041 return PDMDEV_SET_ERROR(pDevIns, rc,
6042 N_("Configuration error: Querying \"BiosRom\" as a string failed"));
6043 else if (!*pThis->pszVgaBiosFile)
6044 {
6045 MMR3HeapFree(pThis->pszVgaBiosFile);
6046 pThis->pszVgaBiosFile = NULL;
6047 }
6048
6049 const uint8_t *pu8VgaBiosBinary = NULL;
6050 uint64_t cbVgaBiosBinary;
6051 /*
6052 * Determine the VGA BIOS ROM size, open specified ROM file in the process.
6053 */
6054 RTFILE FileVgaBios = NIL_RTFILE;
6055 if (pThis->pszVgaBiosFile)
6056 {
6057 rc = RTFileOpen(&FileVgaBios, pThis->pszVgaBiosFile,
6058 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
6059 if (RT_SUCCESS(rc))
6060 {
6061 rc = RTFileGetSize(FileVgaBios, &pThis->cbVgaBios);
6062 if (RT_SUCCESS(rc))
6063 {
6064 if ( RT_ALIGN(pThis->cbVgaBios, _4K) != pThis->cbVgaBios
6065 || pThis->cbVgaBios > _64K
6066 || pThis->cbVgaBios < 16 * _1K)
6067 rc = VERR_TOO_MUCH_DATA;
6068 }
6069 }
6070 if (RT_FAILURE(rc))
6071 {
6072 /*
6073 * In case of failure simply fall back to the built-in VGA BIOS ROM.
6074 */
6075 Log(("vgaConstruct: Failed to open VGA BIOS ROM file '%s', rc=%Rrc!\n", pThis->pszVgaBiosFile, rc));
6076 RTFileClose(FileVgaBios);
6077 FileVgaBios = NIL_RTFILE;
6078 MMR3HeapFree(pThis->pszVgaBiosFile);
6079 pThis->pszVgaBiosFile = NULL;
6080 }
6081 }
6082
6083 /*
6084 * Attempt to get the VGA BIOS ROM data from file.
6085 */
6086 if (pThis->pszVgaBiosFile)
6087 {
6088 /*
6089 * Allocate buffer for the VGA BIOS ROM data.
6090 */
6091 pThis->pu8VgaBios = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbVgaBios);
6092 if (pThis->pu8VgaBios)
6093 {
6094 rc = RTFileRead(FileVgaBios, pThis->pu8VgaBios, pThis->cbVgaBios, NULL);
6095 if (RT_FAILURE(rc))
6096 {
6097 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbVgaBios, rc));
6098 MMR3HeapFree(pThis->pu8VgaBios);
6099 pThis->pu8VgaBios = NULL;
6100 }
6101 rc = VINF_SUCCESS;
6102 }
6103 else
6104 rc = VERR_NO_MEMORY;
6105 }
6106 else
6107 pThis->pu8VgaBios = NULL;
6108
6109 /* cleanup */
6110 if (FileVgaBios != NIL_RTFILE)
6111 RTFileClose(FileVgaBios);
6112
6113 /* If we were unable to get the data from file for whatever reason, fall
6114 back to the built-in ROM image. */
6115 uint32_t fFlags = 0;
6116 if (pThis->pu8VgaBios == NULL)
6117 {
6118 pu8VgaBiosBinary = g_abVgaBiosBinary;
6119 cbVgaBiosBinary = g_cbVgaBiosBinary;
6120 fFlags = PGMPHYS_ROM_FLAGS_PERMANENT_BINARY;
6121 }
6122 else
6123 {
6124 pu8VgaBiosBinary = pThis->pu8VgaBios;
6125 cbVgaBiosBinary = pThis->cbVgaBios;
6126 }
6127
6128 AssertReleaseMsg(g_cbVgaBiosBinary <= _64K && g_cbVgaBiosBinary >= 32*_1K, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
6129 AssertReleaseMsg(RT_ALIGN_Z(g_cbVgaBiosBinary, PAGE_SIZE) == g_cbVgaBiosBinary, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
6130 rc = PDMDevHlpROMRegister(pDevIns, 0x000c0000, cbVgaBiosBinary, pu8VgaBiosBinary, cbVgaBiosBinary,
6131 fFlags, "VGA BIOS");
6132 if (RT_FAILURE(rc))
6133 return rc;
6134
6135 /* save */
6136 rc = PDMDevHlpSSMRegisterEx(pDevIns, VGA_SAVEDSTATE_VERSION, sizeof(*pThis), NULL,
6137 NULL, vgaR3LiveExec, NULL,
6138 vgaR3SavePrep, vgaR3SaveExec, vgaR3SaveDone,
6139 NULL, vgaR3LoadExec, vgaR3LoadDone);
6140 if (RT_FAILURE(rc))
6141 return rc;
6142
6143 /* PCI */
6144 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->Dev);
6145 if (RT_FAILURE(rc))
6146 return rc;
6147 /*AssertMsg(pThis->Dev.devfn == 16 || iInstance != 0, ("pThis->Dev.devfn=%d\n", pThis->Dev.devfn));*/
6148 if (pThis->Dev.devfn != 16 && iInstance == 0)
6149 Log(("!!WARNING!!: pThis->dev.devfn=%d (ignore if testcase or not started by Main)\n", pThis->Dev.devfn));
6150
6151 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0 /* iRegion */, pThis->vram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vgaR3IORegionMap);
6152 if (RT_FAILURE(rc))
6153 return rc;
6154
6155 /* Initialize the PDM lock. */
6156 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "VGA#u", iInstance);
6157 if (RT_FAILURE(rc))
6158 {
6159 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
6160 return rc;
6161 }
6162
6163 /*
6164 * Create the refresh timer.
6165 */
6166 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, vgaTimerRefresh,
6167 pThis, TMTIMER_FLAGS_NO_CRIT_SECT,
6168 "VGA Refresh Timer", &pThis->RefreshTimer);
6169 if (RT_FAILURE(rc))
6170 return rc;
6171
6172 /*
6173 * Attach to the display.
6174 */
6175 rc = vgaAttach(pDevIns, 0 /* display LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
6176 if (RT_FAILURE(rc))
6177 return rc;
6178
6179 /*
6180 * Initialize the retrace flag.
6181 */
6182 rc = CFGMR3QueryBoolDef(pCfg, "RealRetrace", &pThis->fRealRetrace, false);
6183 AssertLogRelRCReturn(rc, rc);
6184
6185#ifdef VBE_NEW_DYN_LIST
6186
6187 uint16_t maxBiosXRes;
6188 rc = CFGMR3QueryU16Def(pCfg, "MaxBiosXRes", &maxBiosXRes, UINT16_MAX);
6189 AssertLogRelRCReturn(rc, rc);
6190 uint16_t maxBiosYRes;
6191 rc = CFGMR3QueryU16Def(pCfg, "MaxBiosYRes", &maxBiosYRes, UINT16_MAX);
6192 AssertLogRelRCReturn(rc, rc);
6193
6194 /*
6195 * Compute buffer size for the VBE BIOS Extra Data.
6196 */
6197 cb = sizeof(mode_info_list) + sizeof(ModeInfoListItem);
6198
6199 rc = CFGMR3QueryU32(pCfg, "HeightReduction", &cyReduction);
6200 if (RT_SUCCESS(rc) && cyReduction)
6201 cb *= 2; /* Default mode list will be twice long */
6202 else
6203 cyReduction = 0;
6204
6205 rc = CFGMR3QueryU32(pCfg, "CustomVideoModes", &cCustomModes);
6206 if (RT_SUCCESS(rc) && cCustomModes)
6207 cb += sizeof(ModeInfoListItem) * cCustomModes;
6208 else
6209 cCustomModes = 0;
6210
6211 /*
6212 * Allocate and initialize buffer for the VBE BIOS Extra Data.
6213 */
6214 AssertRelease(sizeof(VBEHEADER) + cb < 65536);
6215 pThis->cbVBEExtraData = (uint16_t)(sizeof(VBEHEADER) + cb);
6216 pThis->pu8VBEExtraData = (uint8_t *)PDMDevHlpMMHeapAllocZ(pDevIns, pThis->cbVBEExtraData);
6217 if (!pThis->pu8VBEExtraData)
6218 return VERR_NO_MEMORY;
6219
6220 pVBEDataHdr = (PVBEHEADER)pThis->pu8VBEExtraData;
6221 pVBEDataHdr->u16Signature = VBEHEADER_MAGIC;
6222 pVBEDataHdr->cbData = cb;
6223
6224# ifndef VRAM_SIZE_FIX
6225 pCurMode = memcpy(pVBEDataHdr + 1, &mode_info_list, sizeof(mode_info_list));
6226 pCurMode = (ModeInfoListItem *)((uintptr_t)pCurMode + sizeof(mode_info_list));
6227# else /* VRAM_SIZE_FIX defined */
6228 pCurMode = (ModeInfoListItem *)(pVBEDataHdr + 1);
6229 for (i = 0; i < MODE_INFO_SIZE; i++)
6230 {
6231 uint32_t pixelWidth, reqSize;
6232 if (mode_info_list[i].info.MemoryModel == VBE_MEMORYMODEL_TEXT_MODE)
6233 pixelWidth = 2;
6234 else
6235 pixelWidth = (mode_info_list[i].info.BitsPerPixel +7) / 8;
6236 reqSize = mode_info_list[i].info.XResolution
6237 * mode_info_list[i].info.YResolution
6238 * pixelWidth;
6239 if (reqSize >= pThis->vram_size)
6240 continue;
6241 if ( mode_info_list[i].info.XResolution > maxBiosXRes
6242 || mode_info_list[i].info.YResolution > maxBiosYRes)
6243 continue;
6244 *pCurMode = mode_info_list[i];
6245 vgaAdjustModeInfo(pThis, pCurMode);
6246 pCurMode++;
6247 }
6248# endif /* VRAM_SIZE_FIX defined */
6249
6250 /*
6251 * Copy default modes with subtracted YResolution.
6252 */
6253 if (cyReduction)
6254 {
6255 ModeInfoListItem *pDefMode = mode_info_list;
6256 Log(("vgaR3Construct: cyReduction=%u\n", cyReduction));
6257# ifndef VRAM_SIZE_FIX
6258 for (i = 0; i < MODE_INFO_SIZE; i++, pCurMode++, pDefMode++)
6259 {
6260 *pCurMode = *pDefMode;
6261 pCurMode->mode += 0x30;
6262 pCurMode->info.YResolution -= cyReduction;
6263 }
6264# else /* VRAM_SIZE_FIX defined */
6265 for (i = 0; i < MODE_INFO_SIZE; i++, pDefMode++)
6266 {
6267 uint32_t pixelWidth, reqSize;
6268 if (pDefMode->info.MemoryModel == VBE_MEMORYMODEL_TEXT_MODE)
6269 pixelWidth = 2;
6270 else
6271 pixelWidth = (pDefMode->info.BitsPerPixel + 7) / 8;
6272 reqSize = pDefMode->info.XResolution * pDefMode->info.YResolution * pixelWidth;
6273 if (reqSize >= pThis->vram_size)
6274 continue;
6275 if ( pDefMode->info.XResolution > maxBiosXRes
6276 || pDefMode->info.YResolution - cyReduction > maxBiosYRes)
6277 continue;
6278 *pCurMode = *pDefMode;
6279 pCurMode->mode += 0x30;
6280 pCurMode->info.YResolution -= cyReduction;
6281 pCurMode++;
6282 }
6283# endif /* VRAM_SIZE_FIX defined */
6284 }
6285
6286
6287 /*
6288 * Add custom modes.
6289 */
6290 if (cCustomModes)
6291 {
6292 uint16_t u16CurMode = 0x160;
6293 for (i = 1; i <= cCustomModes; i++)
6294 {
6295 char szExtraDataKey[sizeof("CustomVideoModeXX")];
6296 char *pszExtraData = NULL;
6297
6298 /* query and decode the custom mode string. */
6299 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%d", i);
6300 rc = CFGMR3QueryStringAlloc(pCfg, szExtraDataKey, &pszExtraData);
6301 if (RT_SUCCESS(rc))
6302 {
6303 ModeInfoListItem *pDefMode = mode_info_list;
6304 unsigned int cx, cy, cBits, cParams, j;
6305 uint16_t u16DefMode;
6306
6307 cParams = sscanf(pszExtraData, "%ux%ux%u", &cx, &cy, &cBits);
6308 if ( cParams != 3
6309 || (cBits != 16 && cBits != 24 && cBits != 32))
6310 {
6311 AssertMsgFailed(("Configuration error: Invalid mode data '%s' for '%s'! cBits=%d\n", pszExtraData, szExtraDataKey, cBits));
6312 return VERR_VGA_INVALID_CUSTOM_MODE;
6313 }
6314 cbPitch = calc_line_pitch(cBits, cx);
6315# ifdef VRAM_SIZE_FIX
6316 if (cy * cbPitch >= pThis->vram_size)
6317 {
6318 AssertMsgFailed(("Configuration error: custom video mode %dx%dx%dbits is too large for the virtual video memory of %dMb. Please increase the video memory size.\n",
6319 cx, cy, cBits, pThis->vram_size / _1M));
6320 return VERR_VGA_INVALID_CUSTOM_MODE;
6321 }
6322# endif /* VRAM_SIZE_FIX defined */
6323 MMR3HeapFree(pszExtraData);
6324
6325 /* Use defaults from max@bpp mode. */
6326 switch (cBits)
6327 {
6328 case 16:
6329 u16DefMode = VBE_VESA_MODE_1024X768X565;
6330 break;
6331
6332 case 24:
6333 u16DefMode = VBE_VESA_MODE_1024X768X888;
6334 break;
6335
6336 case 32:
6337 u16DefMode = VBE_OWN_MODE_1024X768X8888;
6338 break;
6339
6340 default: /* gcc, shut up! */
6341 AssertMsgFailed(("gone postal!\n"));
6342 continue;
6343 }
6344
6345 /* mode_info_list is not terminated */
6346 for (j = 0; j < MODE_INFO_SIZE && pDefMode->mode != u16DefMode; j++)
6347 pDefMode++;
6348 Assert(j < MODE_INFO_SIZE);
6349
6350 *pCurMode = *pDefMode;
6351 pCurMode->mode = u16CurMode++;
6352
6353 /* adjust defaults */
6354 pCurMode->info.XResolution = cx;
6355 pCurMode->info.YResolution = cy;
6356 pCurMode->info.BytesPerScanLine = cbPitch;
6357 pCurMode->info.LinBytesPerScanLine = cbPitch;
6358 vgaAdjustModeInfo(pThis, pCurMode);
6359
6360 /* commit it */
6361 pCurMode++;
6362 }
6363 else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
6364 {
6365 AssertMsgFailed(("CFGMR3QueryStringAlloc(,'%s',) -> %Rrc\n", szExtraDataKey, rc));
6366 return rc;
6367 }
6368 } /* foreach custom mode key */
6369 }
6370
6371 /*
6372 * Add the "End of list" mode.
6373 */
6374 memset(pCurMode, 0, sizeof(*pCurMode));
6375 pCurMode->mode = VBE_VESA_MODE_END_OF_LIST;
6376
6377 /*
6378 * Register I/O Port for the VBE BIOS Extra Data.
6379 */
6380 rc = PDMDevHlpIOPortRegister(pDevIns, VBE_EXTRA_PORT, 1, NULL, vbeIOPortWriteVBEExtra, vbeIOPortReadVBEExtra, NULL, NULL, "VBE BIOS Extra Data");
6381 if (RT_FAILURE(rc))
6382 return rc;
6383#endif /* VBE_NEW_DYN_LIST */
6384
6385 /*
6386 * Register I/O Port for the BIOS Logo.
6387 */
6388 rc = PDMDevHlpIOPortRegister(pDevIns, LOGO_IO_PORT, 1, NULL, vbeIOPortWriteCMDLogo, vbeIOPortReadCMDLogo, NULL, NULL, "BIOS Logo");
6389 if (RT_FAILURE(rc))
6390 return rc;
6391
6392 /*
6393 * Register debugger info callbacks.
6394 */
6395 PDMDevHlpDBGFInfoRegister(pDevIns, "vga", "Display basic VGA state.", vgaInfoState);
6396 PDMDevHlpDBGFInfoRegister(pDevIns, "vgatext", "Display VGA memory formatted as text.", vgaInfoText);
6397 PDMDevHlpDBGFInfoRegister(pDevIns, "vgacr", "Dump VGA CRTC registers.", vgaInfoCR);
6398 PDMDevHlpDBGFInfoRegister(pDevIns, "vgagr", "Dump VGA Graphics Controller registers.", vgaInfoGR);
6399 PDMDevHlpDBGFInfoRegister(pDevIns, "vgasr", "Dump VGA Sequencer registers.", vgaInfoSR);
6400 PDMDevHlpDBGFInfoRegister(pDevIns, "vgaar", "Dump VGA Attribute Controller registers.", vgaInfoAR);
6401 PDMDevHlpDBGFInfoRegister(pDevIns, "vgadac", "Dump VGA DAC registers.", vgaInfoDAC);
6402 PDMDevHlpDBGFInfoRegister(pDevIns, "vbe", "Dump VGA VBE registers.", vgaInfoVBE);
6403
6404 /*
6405 * Construct the logo header.
6406 */
6407 LOGOHDR LogoHdr = { LOGO_HDR_MAGIC, 0, 0, 0, 0, 0, 0 };
6408
6409 rc = CFGMR3QueryU8(pCfg, "FadeIn", &LogoHdr.fu8FadeIn);
6410 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6411 LogoHdr.fu8FadeIn = 1;
6412 else if (RT_FAILURE(rc))
6413 return PDMDEV_SET_ERROR(pDevIns, rc,
6414 N_("Configuration error: Querying \"FadeIn\" as integer failed"));
6415
6416 rc = CFGMR3QueryU8(pCfg, "FadeOut", &LogoHdr.fu8FadeOut);
6417 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6418 LogoHdr.fu8FadeOut = 1;
6419 else if (RT_FAILURE(rc))
6420 return PDMDEV_SET_ERROR(pDevIns, rc,
6421 N_("Configuration error: Querying \"FadeOut\" as integer failed"));
6422
6423 rc = CFGMR3QueryU16(pCfg, "LogoTime", &LogoHdr.u16LogoMillies);
6424 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6425 LogoHdr.u16LogoMillies = 0;
6426 else if (RT_FAILURE(rc))
6427 return PDMDEV_SET_ERROR(pDevIns, rc,
6428 N_("Configuration error: Querying \"LogoTime\" as integer failed"));
6429
6430 rc = CFGMR3QueryU8(pCfg, "ShowBootMenu", &LogoHdr.fu8ShowBootMenu);
6431 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6432 LogoHdr.fu8ShowBootMenu = 0;
6433 else if (RT_FAILURE(rc))
6434 return PDMDEV_SET_ERROR(pDevIns, rc,
6435 N_("Configuration error: Querying \"ShowBootMenu\" as integer failed"));
6436
6437#if defined(DEBUG) && !defined(DEBUG_sunlover)
6438 /* Disable the logo abd menu if all default settings. */
6439 if ( LogoHdr.fu8FadeIn
6440 && LogoHdr.fu8FadeOut
6441 && LogoHdr.u16LogoMillies == 0
6442 && LogoHdr.fu8ShowBootMenu == 2)
6443 LogoHdr.fu8FadeIn = LogoHdr.fu8FadeOut = LogoHdr.fu8ShowBootMenu = 0;
6444#endif
6445
6446 /* Delay the logo a little bit */
6447 if (LogoHdr.fu8FadeIn && LogoHdr.fu8FadeOut && !LogoHdr.u16LogoMillies)
6448 LogoHdr.u16LogoMillies = RT_MAX(LogoHdr.u16LogoMillies, LOGO_DELAY_TIME);
6449
6450 /*
6451 * Get the Logo file name.
6452 */
6453 rc = CFGMR3QueryStringAlloc(pCfg, "LogoFile", &pThis->pszLogoFile);
6454 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6455 pThis->pszLogoFile = NULL;
6456 else if (RT_FAILURE(rc))
6457 return PDMDEV_SET_ERROR(pDevIns, rc,
6458 N_("Configuration error: Querying \"LogoFile\" as a string failed"));
6459 else if (!*pThis->pszLogoFile)
6460 {
6461 MMR3HeapFree(pThis->pszLogoFile);
6462 pThis->pszLogoFile = NULL;
6463 }
6464
6465 /*
6466 * Determine the logo size, open any specified logo file in the process.
6467 */
6468 LogoHdr.cbLogo = g_cbVgaDefBiosLogo;
6469 RTFILE FileLogo = NIL_RTFILE;
6470 if (pThis->pszLogoFile)
6471 {
6472 rc = RTFileOpen(&FileLogo, pThis->pszLogoFile,
6473 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
6474 if (RT_SUCCESS(rc))
6475 {
6476 uint64_t cbFile;
6477 rc = RTFileGetSize(FileLogo, &cbFile);
6478 if (RT_SUCCESS(rc))
6479 {
6480 if (cbFile > 0 && cbFile < 32*_1M)
6481 LogoHdr.cbLogo = (uint32_t)cbFile;
6482 else
6483 rc = VERR_TOO_MUCH_DATA;
6484 }
6485 }
6486 if (RT_FAILURE(rc))
6487 {
6488 /*
6489 * Ignore failure and fall back to the default logo.
6490 */
6491 LogRel(("vgaR3Construct: Failed to open logo file '%s', rc=%Rrc!\n", pThis->pszLogoFile, rc));
6492 if (FileLogo != NIL_RTFILE)
6493 RTFileClose(FileLogo);
6494 FileLogo = NIL_RTFILE;
6495 MMR3HeapFree(pThis->pszLogoFile);
6496 pThis->pszLogoFile = NULL;
6497 }
6498 }
6499
6500 /*
6501 * Disable graphic splash screen if it doesn't fit into VRAM.
6502 */
6503 if (pThis->vram_size < LOGO_MAX_SIZE)
6504 LogoHdr.fu8FadeIn = LogoHdr.fu8FadeOut = LogoHdr.u16LogoMillies = 0;
6505
6506 /*
6507 * Allocate buffer for the logo data.
6508 * RT_MAX() is applied to let us fall back to default logo on read failure.
6509 */
6510 pThis->cbLogo = sizeof(LogoHdr) + LogoHdr.cbLogo;
6511 pThis->pu8Logo = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, RT_MAX(pThis->cbLogo, g_cbVgaDefBiosLogo + sizeof(LogoHdr)));
6512 if (pThis->pu8Logo)
6513 {
6514 /*
6515 * Write the logo header.
6516 */
6517 PLOGOHDR pLogoHdr = (PLOGOHDR)pThis->pu8Logo;
6518 *pLogoHdr = LogoHdr;
6519
6520 /*
6521 * Write the logo bitmap.
6522 */
6523 if (pThis->pszLogoFile)
6524 {
6525 rc = RTFileRead(FileLogo, pLogoHdr + 1, LogoHdr.cbLogo, NULL);
6526 if (RT_FAILURE(rc))
6527 {
6528 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", LogoHdr.cbLogo, rc));
6529 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbVgaDefBiosLogo;
6530 memcpy(pLogoHdr + 1, g_abVgaDefBiosLogo, LogoHdr.cbLogo);
6531 }
6532 }
6533 else
6534 memcpy(pLogoHdr + 1, g_abVgaDefBiosLogo, LogoHdr.cbLogo);
6535
6536 rc = vbeParseBitmap(pThis);
6537 if (RT_FAILURE(rc))
6538 {
6539 AssertMsgFailed(("vbeParseBitmap() -> %Rrc\n", rc));
6540 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbVgaDefBiosLogo;
6541 memcpy(pLogoHdr + 1, g_abVgaDefBiosLogo, LogoHdr.cbLogo);
6542 }
6543
6544 rc = vbeParseBitmap(pThis);
6545 if (RT_FAILURE(rc))
6546 AssertReleaseMsgFailed(("Internal bitmap failed! vbeParseBitmap() -> %Rrc\n", rc));
6547
6548 rc = VINF_SUCCESS;
6549 }
6550 else
6551 rc = VERR_NO_MEMORY;
6552
6553 /*
6554 * Cleanup.
6555 */
6556 if (FileLogo != NIL_RTFILE)
6557 RTFileClose(FileLogo);
6558
6559#ifdef VBOX_WITH_HGSMI
6560 VBVAInit (pThis);
6561#endif /* VBOX_WITH_HGSMI */
6562
6563#ifdef VBOX_WITH_VDMA
6564 if(rc == VINF_SUCCESS)
6565 {
6566 rc = vboxVDMAConstruct(pThis, 1024);
6567 AssertRC(rc);
6568 }
6569#endif
6570 /*
6571 * Statistics.
6572 */
6573 STAM_REG(pVM, &pThis->StatRZMemoryRead, STAMTYPE_PROFILE, "/Devices/VGA/RZ/MMIO-Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryRead() body.");
6574 STAM_REG(pVM, &pThis->StatR3MemoryRead, STAMTYPE_PROFILE, "/Devices/VGA/R3/MMIO-Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryRead() body.");
6575 STAM_REG(pVM, &pThis->StatRZMemoryWrite, STAMTYPE_PROFILE, "/Devices/VGA/RZ/MMIO-Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryWrite() body.");
6576 STAM_REG(pVM, &pThis->StatR3MemoryWrite, STAMTYPE_PROFILE, "/Devices/VGA/R3/MMIO-Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryWrite() body.");
6577 STAM_REG(pVM, &pThis->StatMapPage, STAMTYPE_COUNTER, "/Devices/VGA/MapPageCalls", STAMUNIT_OCCURENCES, "Calls to IOMMMIOMapMMIO2Page.");
6578 STAM_REG(pVM, &pThis->StatUpdateDisp, STAMTYPE_COUNTER, "/Devices/VGA/UpdateDisplay", STAMUNIT_OCCURENCES, "Calls to vgaPortUpdateDisplay().");
6579
6580 /* Init latched access mask. */
6581 pThis->uMaskLatchAccess = 0x3ff;
6582 return rc;
6583}
6584
6585
6586/**
6587 * The device registration structure.
6588 */
6589const PDMDEVREG g_DeviceVga =
6590{
6591 /* u32Version */
6592 PDM_DEVREG_VERSION,
6593 /* szName */
6594 "vga",
6595 /* szRCMod */
6596 "VBoxDDGC.gc",
6597 /* szR0Mod */
6598 "VBoxDDR0.r0",
6599 /* pszDescription */
6600 "VGA Adaptor with VESA extensions.",
6601 /* fFlags */
6602 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
6603 /* fClass */
6604 PDM_DEVREG_CLASS_GRAPHICS,
6605 /* cMaxInstances */
6606 1,
6607 /* cbInstance */
6608 sizeof(VGASTATE),
6609 /* pfnConstruct */
6610 vgaR3Construct,
6611 /* pfnDestruct */
6612 vgaR3Destruct,
6613 /* pfnRelocate */
6614 vgaR3Relocate,
6615 /* pfnIOCtl */
6616 NULL,
6617 /* pfnPowerOn */
6618 NULL,
6619 /* pfnReset */
6620 vgaR3Reset,
6621 /* pfnSuspend */
6622 NULL,
6623 /* pfnResume */
6624 NULL,
6625 /* pfnAttach */
6626 vgaAttach,
6627 /* pfnDetach */
6628 vgaDetach,
6629 /* pfnQueryInterface */
6630 NULL,
6631 /* pfnInitComplete */
6632 NULL,
6633 /* pfnPowerOff */
6634 NULL,
6635 /* pfnSoftReset */
6636 NULL,
6637 /* u32VersionEnd */
6638 PDM_DEVREG_VERSION
6639};
6640
6641#endif /* !IN_RING3 */
6642#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
6643
6644/*
6645 * Local Variables:
6646 * nuke-trailing-whitespace-p:nil
6647 * End:
6648 */
Note: See TracBrowser for help on using the repository browser.

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