VirtualBox

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

Last change on this file since 15711 was 15680, checked in by vboxsync, 16 years ago

Remap MMIO memory as well for recompiler writes

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