VirtualBox

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

Last change on this file since 15874 was 15872, checked in by vboxsync, 16 years ago

Removed a DEBUG_sunlover log statement.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 198.8 KB
Line 
1#ifdef VBOX
2/* $Id: DevVGA.cpp 15872 2009-01-08 15:56:50Z 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# ifndef IN_RC
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_RC */
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
2108 /* Take into account the programmed start address (in DWORDs) of the visible screen. */
2109 int rc = s->pDrv->pfnResize(s->pDrv, cBits, s->CTX_SUFF(vram_ptr) + s->start_addr * 4, s->line_offset, cx, cy);
2110
2111 /* last stuff */
2112 s->last_bpp = cBits;
2113 s->last_scr_width = cx;
2114 s->last_scr_height = cy;
2115 s->last_width = cx;
2116 s->last_height = cy;
2117
2118 if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
2119 return rc;
2120 AssertRC(rc);
2121
2122 /* update palette */
2123 switch (s->pDrv->cBits)
2124 {
2125 case 32: s->rgb_to_pixel = rgb_to_pixel32_dup; break;
2126 case 16:
2127 default: s->rgb_to_pixel = rgb_to_pixel16_dup; break;
2128 case 15: s->rgb_to_pixel = rgb_to_pixel15_dup; break;
2129 case 8: s->rgb_to_pixel = rgb_to_pixel8_dup; break;
2130 }
2131 if (s->shift_control == 0)
2132 update_palette16(s);
2133 else if (s->shift_control == 1)
2134 update_palette16(s);
2135 return VINF_SUCCESS;
2136}
2137#endif /* VBOX */
2138
2139/*
2140 * graphic modes
2141 */
2142#ifndef VBOX
2143static void vga_draw_graphic(VGAState *s, int full_update)
2144#else
2145static int vga_draw_graphic(VGAState *s, int full_update)
2146#endif /* !VBOX */
2147{
2148 int y1, y2, y, update, page_min, page_max, linesize, y_start, double_scan;
2149 int width, height, shift_control, line_offset, page0, page1, bwidth;
2150 int disp_width, multi_run;
2151 uint8_t *d;
2152 uint32_t v, addr1, addr;
2153 vga_draw_line_func *vga_draw_line;
2154 bool offsets_changed;
2155
2156 offsets_changed = update_basic_params(s);
2157
2158 full_update |= offsets_changed;
2159
2160 s->get_resolution(s, &width, &height);
2161 disp_width = width;
2162
2163 shift_control = (s->gr[0x05] >> 5) & 3;
2164 double_scan = (s->cr[0x09] >> 7);
2165 multi_run = double_scan;
2166 if (shift_control != s->shift_control ||
2167 double_scan != s->double_scan) {
2168 full_update = 1;
2169 s->shift_control = shift_control;
2170 s->double_scan = double_scan;
2171 }
2172
2173 if (shift_control == 0) {
2174 full_update |= update_palette16(s);
2175 if (s->sr[0x01] & 8) {
2176 v = VGA_DRAW_LINE4D2;
2177 disp_width <<= 1;
2178 } else {
2179 v = VGA_DRAW_LINE4;
2180 }
2181 } else if (shift_control == 1) {
2182 full_update |= update_palette16(s);
2183 if (s->sr[0x01] & 8) {
2184 v = VGA_DRAW_LINE2D2;
2185 disp_width <<= 1;
2186 } else {
2187 v = VGA_DRAW_LINE2;
2188 }
2189 } else {
2190 switch(s->get_bpp(s)) {
2191 default:
2192 case 0:
2193 full_update |= update_palette256(s);
2194 v = VGA_DRAW_LINE8D2;
2195 break;
2196 case 8:
2197 full_update |= update_palette256(s);
2198 v = VGA_DRAW_LINE8;
2199 break;
2200 case 15:
2201 v = VGA_DRAW_LINE15;
2202 break;
2203 case 16:
2204 v = VGA_DRAW_LINE16;
2205 break;
2206 case 24:
2207 v = VGA_DRAW_LINE24;
2208 break;
2209 case 32:
2210 v = VGA_DRAW_LINE32;
2211 break;
2212 }
2213 }
2214#ifndef VBOX
2215 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
2216
2217 if (disp_width != s->last_width ||
2218 height != s->last_height) {
2219 dpy_resize(s->ds, disp_width, height);
2220 s->last_scr_width = disp_width;
2221 s->last_scr_height = height;
2222 s->last_width = disp_width;
2223 s->last_height = height;
2224 full_update = 1;
2225 }
2226#else /* VBOX */
2227 if ( disp_width != (int)s->last_width
2228 || height != (int)s->last_height
2229 || s->get_bpp(s) != (int)s->last_bpp
2230 || offsets_changed)
2231 {
2232 int rc = vga_resize_graphic(s, disp_width, height, v);
2233 if (rc != VINF_SUCCESS) /* Return any rc, particularly VINF_VGA_RESIZE_IN_PROGRESS, to the caller. */
2234 return rc;
2235 full_update = 1;
2236 }
2237 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->pDrv->cBits)];
2238
2239#endif /* VBOX */
2240 if (s->cursor_invalidate)
2241 s->cursor_invalidate(s);
2242
2243 line_offset = s->line_offset;
2244#if 0
2245 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",
2246 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]));
2247#endif
2248 addr1 = (s->start_addr * 4);
2249#ifndef VBOX
2250 bwidth = width * 4;
2251#else /* VBOX */
2252 /* The width of VRAM scanline. */
2253 bwidth = s->line_offset;
2254 /* In some cases the variable is not yet set, probably due to incomplete
2255 * programming of the virtual hardware ports. Just return.
2256 */
2257 if (bwidth == 0) return VINF_SUCCESS;
2258#endif /* VBOX */
2259 y_start = -1;
2260 page_min = 0x7fffffff;
2261 page_max = -1;
2262#ifndef VBOX
2263 d = s->ds->data;
2264 linesize = s->ds->linesize;
2265#else /* VBOX */
2266 d = s->pDrv->pu8Data;
2267 linesize = s->pDrv->cbScanline;
2268#endif /* VBOX */
2269
2270 y1 = 0;
2271 y2 = s->cr[0x09] & 0x1F; /* starting row scan count */
2272 for(y = 0; y < height; y++) {
2273 addr = addr1;
2274 /* CGA/MDA compatibility. Note that these addresses are all
2275 * shifted left by two compared to VGA specs.
2276 */
2277 if (!(s->cr[0x17] & 1)) {
2278 addr = (addr & ~(1 << 15)) | ((y1 & 1) << 15);
2279 }
2280 if (!(s->cr[0x17] & 2)) {
2281 addr = (addr & ~(1 << 16)) | ((y1 & 2) << 15);
2282 }
2283#ifndef VBOX
2284 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
2285 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
2286 update = full_update |
2287 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
2288 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
2289 if ((page1 - page0) > TARGET_PAGE_SIZE) {
2290 /* if wide line, can use another page */
2291 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
2292 VGA_DIRTY_FLAG);
2293 }
2294#else /* VBOX */
2295 page0 = addr & TARGET_PAGE_MASK;
2296 page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
2297 update = full_update | vga_is_dirty(s, page0) | vga_is_dirty(s, page1);
2298 if (page1 - page0 > TARGET_PAGE_SIZE) {
2299 /* if wide line, can use another page */
2300 update |= vga_is_dirty(s, page0 + TARGET_PAGE_SIZE);
2301 }
2302#endif /* VBOX */
2303 /* explicit invalidation for the hardware cursor */
2304 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
2305 if (update) {
2306 if (y_start < 0)
2307 y_start = y;
2308 if (page0 < page_min)
2309 page_min = page0;
2310 if (page1 > page_max)
2311 page_max = page1;
2312#ifndef VBOX
2313 vga_draw_line(s, d, s->vram_ptr + addr, width);
2314#else /* VBOX */
2315 if (s->fRenderVRAM)
2316 vga_draw_line(s, d, s->CTX_SUFF(vram_ptr) + addr, width);
2317#endif /* VBOX */
2318 if (s->cursor_draw_line)
2319 s->cursor_draw_line(s, d, y);
2320 } else {
2321 if (y_start >= 0) {
2322 /* flush to display */
2323#ifndef VBOX
2324 dpy_update(s->ds, 0, y_start,
2325 disp_width, y - y_start);
2326#else /* VBOX */
2327 s->pDrv->pfnUpdateRect(s->pDrv, 0, y_start, disp_width, y - y_start);
2328#endif /* VBOX */
2329 y_start = -1;
2330 }
2331 }
2332 if (!multi_run) {
2333 y1++;
2334 multi_run = double_scan;
2335
2336 if (y2 == 0) {
2337 y2 = s->cr[0x09] & 0x1F;
2338 addr1 += line_offset;
2339 } else {
2340 --y2;
2341 }
2342 } else {
2343 multi_run--;
2344 }
2345 /* line compare acts on the displayed lines */
2346 if ((uint32_t)y == s->line_compare)
2347 addr1 = 0;
2348 d += linesize;
2349 }
2350 if (y_start >= 0) {
2351 /* flush to display */
2352#ifndef VBOX
2353 dpy_update(s->ds, 0, y_start,
2354 disp_width, y - y_start);
2355#else /* VBOX */
2356 s->pDrv->pfnUpdateRect(s->pDrv, 0, y_start, disp_width, y - y_start);
2357#endif /* VBOX */
2358 }
2359 /* reset modified pages */
2360 if (page_max != -1) {
2361#ifndef VBOX
2362 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
2363 VGA_DIRTY_FLAG);
2364#else /* VBOX */
2365 vga_reset_dirty(s, page_min, page_max + TARGET_PAGE_SIZE);
2366#endif /* VBOX */
2367 }
2368 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
2369#ifdef VBOX
2370 return VINF_SUCCESS;
2371#endif /* VBOX */
2372}
2373
2374static void vga_draw_blank(VGAState *s, int full_update)
2375{
2376#ifndef VBOX
2377 int i, w, val;
2378 uint8_t *d;
2379
2380 if (!full_update)
2381 return;
2382 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
2383 return;
2384 if (s->ds->depth == 8)
2385 val = s->rgb_to_pixel(0, 0, 0);
2386 else
2387 val = 0;
2388 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
2389 d = s->ds->data;
2390 for(i = 0; i < s->last_scr_height; i++) {
2391 memset(d, val, w);
2392 d += s->ds->linesize;
2393 }
2394 dpy_update(s->ds, 0, 0,
2395 s->last_scr_width, s->last_scr_height);
2396#else /* VBOX */
2397
2398 int i, w, val;
2399 uint8_t *d;
2400 uint32_t cbScanline = s->pDrv->cbScanline;
2401
2402 if (s->pDrv->pu8Data == s->vram_ptrR3) /* Do not clear the VRAM itself. */
2403 return;
2404 if (!full_update)
2405 return;
2406 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
2407 return;
2408 if (s->pDrv->cBits == 8)
2409 val = s->rgb_to_pixel(0, 0, 0);
2410 else
2411 val = 0;
2412 w = s->last_scr_width * ((s->pDrv->cBits + 7) >> 3);
2413 d = s->pDrv->pu8Data;
2414 for(i = 0; i < (int)s->last_scr_height; i++) {
2415 memset(d, val, w);
2416 d += cbScanline;
2417 }
2418 s->pDrv->pfnUpdateRect(s->pDrv, 0, 0, s->last_scr_width, s->last_scr_height);
2419#endif /* VBOX */
2420}
2421
2422#define GMODE_TEXT 0
2423#define GMODE_GRAPH 1
2424#define GMODE_BLANK 2
2425
2426#ifndef VBOX
2427void vga_update_display(void)
2428{
2429 VGAState *s = vga_state;
2430#else /* VBOX */
2431static int vga_update_display(PVGASTATE s)
2432{
2433 int rc = VINF_SUCCESS;
2434#endif /* VBOX */
2435 int full_update, graphic_mode;
2436
2437#ifndef VBOX
2438 if (s->ds->depth == 0) {
2439#else /* VBOX */
2440 if (s->pDrv->cBits == 0) {
2441#endif /* VBOX */
2442 /* nothing to do */
2443 } else {
2444#ifndef VBOX
2445 switch(s->ds->depth) {
2446#else /* VBOX */
2447 switch(s->pDrv->cBits) {
2448#endif /* VBOX */
2449 case 8:
2450 s->rgb_to_pixel = rgb_to_pixel8_dup;
2451 break;
2452 case 15:
2453 s->rgb_to_pixel = rgb_to_pixel15_dup;
2454 break;
2455 default:
2456 case 16:
2457 s->rgb_to_pixel = rgb_to_pixel16_dup;
2458 break;
2459 case 32:
2460 s->rgb_to_pixel = rgb_to_pixel32_dup;
2461 break;
2462 }
2463
2464 full_update = 0;
2465 if (!(s->ar_index & 0x20)) {
2466 graphic_mode = GMODE_BLANK;
2467 } else {
2468 graphic_mode = s->gr[6] & 1;
2469 }
2470 if (graphic_mode != s->graphic_mode) {
2471 s->graphic_mode = graphic_mode;
2472 full_update = 1;
2473 }
2474 switch(graphic_mode) {
2475 case GMODE_TEXT:
2476#ifdef VBOX
2477 rc =
2478#endif /* VBOX */
2479 vga_draw_text(s, full_update);
2480 break;
2481 case GMODE_GRAPH:
2482#ifdef VBOX
2483 rc =
2484#endif /* VBOX */
2485 vga_draw_graphic(s, full_update);
2486 break;
2487 case GMODE_BLANK:
2488 default:
2489 vga_draw_blank(s, full_update);
2490 break;
2491 }
2492 }
2493#ifdef VBOX
2494 return rc;
2495#endif /* VBOX */
2496}
2497
2498/* force a full display refresh */
2499#ifndef VBOX
2500void vga_invalidate_display(void)
2501{
2502 VGAState *s = vga_state;
2503
2504 s->last_width = -1;
2505 s->last_height = -1;
2506}
2507#endif /* !VBOX */
2508
2509#ifndef VBOX /* see vgaR3Reset() */
2510static void vga_reset(VGAState *s)
2511{
2512 memset(s, 0, sizeof(VGAState));
2513 s->graphic_mode = -1; /* force full update */
2514}
2515#endif /* !VBOX */
2516
2517#ifndef VBOX
2518static CPUReadMemoryFunc *vga_mem_read[3] = {
2519 vga_mem_readb,
2520 vga_mem_readw,
2521 vga_mem_readl,
2522};
2523
2524static CPUWriteMemoryFunc *vga_mem_write[3] = {
2525 vga_mem_writeb,
2526 vga_mem_writew,
2527 vga_mem_writel,
2528};
2529#endif /* !VBOX */
2530
2531static void vga_save(QEMUFile *f, void *opaque)
2532{
2533 VGAState *s = (VGAState*)opaque;
2534 int i;
2535
2536 qemu_put_be32s(f, &s->latch);
2537 qemu_put_8s(f, &s->sr_index);
2538 qemu_put_buffer(f, s->sr, 8);
2539 qemu_put_8s(f, &s->gr_index);
2540 qemu_put_buffer(f, s->gr, 16);
2541 qemu_put_8s(f, &s->ar_index);
2542 qemu_put_buffer(f, s->ar, 21);
2543 qemu_put_be32s(f, &s->ar_flip_flop);
2544 qemu_put_8s(f, &s->cr_index);
2545 qemu_put_buffer(f, s->cr, 256);
2546 qemu_put_8s(f, &s->msr);
2547 qemu_put_8s(f, &s->fcr);
2548 qemu_put_8s(f, &s->st00);
2549 qemu_put_8s(f, &s->st01);
2550
2551 qemu_put_8s(f, &s->dac_state);
2552 qemu_put_8s(f, &s->dac_sub_index);
2553 qemu_put_8s(f, &s->dac_read_index);
2554 qemu_put_8s(f, &s->dac_write_index);
2555 qemu_put_buffer(f, s->dac_cache, 3);
2556 qemu_put_buffer(f, s->palette, 768);
2557
2558 qemu_put_be32s(f, &s->bank_offset);
2559#ifdef CONFIG_BOCHS_VBE
2560 qemu_put_byte(f, 1);
2561 qemu_put_be16s(f, &s->vbe_index);
2562 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2563 qemu_put_be16s(f, &s->vbe_regs[i]);
2564 qemu_put_be32s(f, &s->vbe_start_addr);
2565 qemu_put_be32s(f, &s->vbe_line_offset);
2566#else
2567 qemu_put_byte(f, 0);
2568#endif
2569}
2570
2571static int vga_load(QEMUFile *f, void *opaque, int version_id)
2572{
2573 VGAState *s = (VGAState*)opaque;
2574 int is_vbe, i;
2575 uint32_t u32Dummy;
2576
2577 if (version_id > VGA_SAVEDSTATE_VERSION)
2578#ifndef VBOX
2579 return -EINVAL;
2580#else /* VBOX */
2581 {
2582 Log(("vga_load: version_id=%d - UNKNOWN\n", version_id));
2583 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2584 }
2585#endif /* VBOX */
2586
2587 qemu_get_be32s(f, &s->latch);
2588 qemu_get_8s(f, &s->sr_index);
2589 qemu_get_buffer(f, s->sr, 8);
2590 qemu_get_8s(f, &s->gr_index);
2591 qemu_get_buffer(f, s->gr, 16);
2592 qemu_get_8s(f, &s->ar_index);
2593 qemu_get_buffer(f, s->ar, 21);
2594 qemu_get_be32s(f, (uint32_t *)&s->ar_flip_flop);
2595 qemu_get_8s(f, &s->cr_index);
2596 qemu_get_buffer(f, s->cr, 256);
2597 qemu_get_8s(f, &s->msr);
2598 qemu_get_8s(f, &s->fcr);
2599 qemu_get_8s(f, &s->st00);
2600 qemu_get_8s(f, &s->st01);
2601
2602 qemu_get_8s(f, &s->dac_state);
2603 qemu_get_8s(f, &s->dac_sub_index);
2604 qemu_get_8s(f, &s->dac_read_index);
2605 qemu_get_8s(f, &s->dac_write_index);
2606 qemu_get_buffer(f, s->dac_cache, 3);
2607 qemu_get_buffer(f, s->palette, 768);
2608
2609 qemu_get_be32s(f, (uint32_t *)&s->bank_offset);
2610 is_vbe = qemu_get_byte(f);
2611#ifdef CONFIG_BOCHS_VBE
2612 if (!is_vbe)
2613#ifndef VBOX
2614 return -EINVAL;
2615#else /* VBOX */
2616 {
2617 Log(("vga_load: !is_vbe !!\n"));
2618 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2619 }
2620#endif /* VBOX */
2621 qemu_get_be16s(f, &s->vbe_index);
2622 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2623 qemu_get_be16s(f, &s->vbe_regs[i]);
2624 qemu_get_be32s(f, &s->vbe_start_addr);
2625 qemu_get_be32s(f, &s->vbe_line_offset);
2626 if (version_id < 2)
2627 qemu_get_be32s(f, &u32Dummy);
2628 s->vbe_bank_max = s->vram_size >> 16;
2629#else
2630 if (is_vbe)
2631#ifndef VBOX
2632 return -EINVAL;
2633#else /* VBOX */
2634 {
2635 Log(("vga_load: is_vbe !!\n"));
2636 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2637 }
2638#endif /* VBOX */
2639#endif
2640
2641 /* force refresh */
2642 s->graphic_mode = -1;
2643 return 0;
2644}
2645
2646#ifndef VBOX /* see vgaR3IORegionMap */
2647static void vga_map(PCIDevice *pci_dev, int region_num,
2648 uint32_t addr, uint32_t size, int type)
2649{
2650 VGAState *s = vga_state;
2651
2652 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
2653}
2654#endif
2655
2656#ifndef VBOX /* see vgaR3Construct */
2657void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
2658 unsigned long vga_ram_offset, int vga_ram_size)
2659#else
2660static void vga_init_expand(void)
2661#endif
2662{
2663 int i, j, v, b;
2664
2665 for(i = 0;i < 256; i++) {
2666 v = 0;
2667 for(j = 0; j < 8; j++) {
2668 v |= ((i >> j) & 1) << (j * 4);
2669 }
2670 expand4[i] = v;
2671
2672 v = 0;
2673 for(j = 0; j < 4; j++) {
2674 v |= ((i >> (2 * j)) & 3) << (j * 4);
2675 }
2676 expand2[i] = v;
2677 }
2678 for(i = 0; i < 16; i++) {
2679 v = 0;
2680 for(j = 0; j < 4; j++) {
2681 b = ((i >> j) & 1);
2682 v |= b << (2 * j);
2683 v |= b << (2 * j + 1);
2684 }
2685 expand4to8[i] = v;
2686 }
2687#ifdef VBOX
2688}
2689#else /* !VBOX */
2690 vga_reset(s);
2691
2692 s->vram_ptr = vga_ram_base;
2693 s->vram_offset = vga_ram_offset;
2694 s->vram_size = vga_ram_size;
2695 s->ds = ds;
2696 s->get_bpp = vga_get_bpp;
2697 s->get_offsets = vga_get_offsets;
2698 s->get_resolution = vga_get_resolution;
2699 /* XXX: currently needed for display */
2700 vga_state = s;
2701}
2702
2703
2704int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
2705 unsigned long vga_ram_offset, int vga_ram_size)
2706{
2707 VGAState *s;
2708
2709 s = qemu_mallocz(sizeof(VGAState));
2710 if (!s)
2711 return -1;
2712
2713 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2714
2715 register_savevm("vga", 0, 1, vga_save, vga_load, s);
2716
2717 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2718
2719 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2720 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2721 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2722 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2723
2724 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2725
2726 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2727 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2728 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2729 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2730 s->bank_offset = 0;
2731
2732#ifdef CONFIG_BOCHS_VBE
2733 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
2734 s->vbe_bank_max = s->vram_size >> 16;
2735#if defined (TARGET_I386)
2736 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2737 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2738
2739 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2740 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2741
2742 /* old Bochs IO ports */
2743 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2744 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2745
2746 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2747 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2748#else
2749 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2750 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2751
2752 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2753 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2754#endif
2755#endif /* CONFIG_BOCHS_VBE */
2756
2757 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2758 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2759 vga_io_memory);
2760
2761 if (bus) {
2762 PCIDevice *d;
2763 uint8_t *pci_conf;
2764
2765 d = pci_register_device(bus, "VGA",
2766 sizeof(PCIDevice),
2767 -1, NULL, NULL);
2768 pci_conf = d->config;
2769 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2770 pci_conf[0x01] = 0x12;
2771 pci_conf[0x02] = 0x11;
2772 pci_conf[0x03] = 0x11;
2773 pci_conf[0x0a] = 0x00; // VGA controller
2774 pci_conf[0x0b] = 0x03;
2775 pci_conf[0x0e] = 0x00; // header_type
2776
2777 /* XXX: vga_ram_size must be a power of two */
2778 pci_register_io_region(d, 0, vga_ram_size,
2779 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2780 } else {
2781#ifdef CONFIG_BOCHS_VBE
2782 /* XXX: use optimized standard vga accesses */
2783 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2784 vga_ram_size, vga_ram_offset);
2785#endif
2786 }
2787 return 0;
2788}
2789#endif /* !VBOX */
2790
2791
2792#ifndef VBOX
2793/********************************************************/
2794/* vga screen dump */
2795
2796static int vga_save_w, vga_save_h;
2797
2798static void vga_save_dpy_update(DisplayState *s,
2799 int x, int y, int w, int h)
2800{
2801}
2802
2803static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2804{
2805 s->linesize = w * 4;
2806#ifndef VBOX
2807 s->data = qemu_malloc(h * s->linesize);
2808#else /* VBOX */
2809 if (!s->data)
2810 {
2811 PPDMDEVINS pDevIns = VGASTATE2DEVINS((PVGASTATE)s->pvVgaState);
2812 s->data = PDMDevHlpMMHeapAlloc(pDevIns, h * s->linesize);
2813 }
2814 else // (32-bpp buffer is allocated by the caller)
2815 s->linesize = ((w * 32 + 31) / 32) * 4;
2816#endif /* VBOX */
2817 vga_save_w = w;
2818 vga_save_h = h;
2819}
2820
2821static void vga_save_dpy_refresh(DisplayState *s)
2822{
2823}
2824
2825static int ppm_save(const char *filename, uint8_t *data,
2826 int w, int h, int linesize)
2827{
2828 FILE *f;
2829 uint8_t *d, *d1;
2830 unsigned int v;
2831 int y, x;
2832
2833 f = fopen(filename, "wb");
2834 if (!f)
2835 return -1;
2836 fprintf(f, "P6\n%d %d\n%d\n",
2837 w, h, 255);
2838 d1 = data;
2839 for(y = 0; y < h; y++) {
2840 d = d1;
2841 for(x = 0; x < w; x++) {
2842 v = *(uint32_t *)d;
2843 fputc((v >> 16) & 0xff, f);
2844 fputc((v >> 8) & 0xff, f);
2845 fputc((v) & 0xff, f);
2846 d += 4;
2847 }
2848 d1 += linesize;
2849 }
2850 fclose(f);
2851 return 0;
2852}
2853
2854/* save the vga display in a PPM image even if no display is
2855 available */
2856void vga_screen_dump(const char *filename)
2857{
2858 VGAState *s = vga_state;
2859 DisplayState *saved_ds, ds1, *ds = &ds1;
2860
2861 /* XXX: this is a little hackish */
2862 vga_invalidate_display();
2863 saved_ds = s->ds;
2864
2865 memset(ds, 0, sizeof(DisplayState));
2866 ds->dpy_update = vga_save_dpy_update;
2867 ds->dpy_resize = vga_save_dpy_resize;
2868 ds->dpy_refresh = vga_save_dpy_refresh;
2869 ds->depth = 32;
2870
2871 s->ds = ds;
2872 s->graphic_mode = -1;
2873 vga_update_display();
2874
2875 if (ds->data) {
2876 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
2877 s->ds->linesize);
2878 qemu_free(ds->data);
2879 }
2880 s->ds = saved_ds;
2881}
2882#endif /* !VBOX */
2883
2884
2885#if 0 //def VBOX
2886/* copy the vga display contents to the given buffer. the size of the buffer
2887 must be sufficient to store the screen copy (see below). the width and height
2888 parameters determine the required dimensions of the copy. If they differ
2889 from the actual screen dimensions, then the returned copy is shrinked or
2890 stretched accordingly. The copy is always a 32-bit image, so the size of
2891 the buffer supplied must be at least (((width * 32 + 31) / 32) * 4) * height,
2892 i.e. dword-aligned. returns zero if the operation was successfull and -1
2893 otherwise. */
2894
2895static int vga_copy_screen_to(PVGASTATE s, uint8_t *buf, int width, int height)
2896{
2897 DisplayState *saved_ds, ds1, *ds = &ds1;
2898 if (!buf || width <= 0 || height <= 0)
2899 return -1;
2900
2901 /* XXX: this is a little hackish */
2902 vga_invalidate_display(s);
2903 saved_ds = s->ds;
2904
2905 memset(ds, 0, sizeof(DisplayState));
2906 ds->dpy_update = vga_save_dpy_update;
2907 ds->dpy_resize = vga_save_dpy_resize;
2908 ds->dpy_refresh = vga_save_dpy_refresh;
2909 ds->depth = 32;
2910 ds->data = buf;
2911 ds->pvVgaState = s;
2912
2913 s->ds = ds;
2914 s->graphic_mode = -1;
2915 vga_update_display(s);
2916
2917//@@TODO (dmik): implement stretching/shrinking!
2918
2919 s->ds = saved_ds;
2920 return 0;
2921}
2922
2923/* copy the given buffer to the vga display. width and height define the
2924 dimensions of the image in the buffer. x and y define the point on the
2925 vga display to copy the image to. the buffer is assumed to contain a 32-bit
2926 image, so the size of one scanline must be ((width * 32 + 31) / 32) * 4),
2927 i.e. dword-aligned. returns zero if the operation was successfull and -1
2928 otherwise. */
2929static int vga_copy_screen_from(PVGASTATE s, uint8_t *buf, int x, int y, int width, int height)
2930{
2931 int bpl = ((width * 32 + 31) / 32) * 4;
2932 int linesize = s->ds->linesize;
2933 uint8_t *dst;
2934 uint8_t *src;
2935 int bpp;
2936 vga_draw_line_func *vga_draw_line;
2937
2938 if (!buf || x < 0 || y < 0 || width <= 0 || height <= 0
2939 || x + width > s->ds->width || y + height > s->ds->height)
2940 return -1;
2941
2942 vga_draw_line = vga_draw_line_table[VGA_DRAW_LINE32 * 4 + get_depth_index(s->ds->depth)];
2943 switch (s->ds->depth) {
2944 case 8: bpp = 1; break;
2945 case 15:
2946 case 16: bpp = 2; break;
2947 case 32: bpp = 4; break;
2948 default: return -1;
2949 }
2950
2951 dst = s->ds->data + y * linesize + x * bpp;
2952 src = buf;
2953 for (y = 0; y < height; y ++)
2954 {
2955 vga_draw_line(s, dst, src, width);
2956 dst += linesize;
2957 src += bpl;
2958 }
2959
2960 return 0;
2961}
2962#endif
2963
2964#endif /* !VBOX || !IN_RC || !IN_RING0 */
2965
2966
2967
2968#ifdef VBOX /* VirtualBox code start */
2969
2970
2971/* -=-=-=-=-=- all contexts -=-=-=-=-=- */
2972
2973/**
2974 * Port I/O Handler for VGA OUT operations.
2975 *
2976 * @returns VBox status code.
2977 *
2978 * @param pDevIns The device instance.
2979 * @param pvUser User argument - ignored.
2980 * @param Port Port number used for the IN operation.
2981 * @param u32 The value to output.
2982 * @param cb The value size in bytes.
2983 */
2984PDMBOTHCBDECL(int) vgaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2985{
2986 NOREF(pvUser);
2987 if (cb == 1)
2988 vga_ioport_write(PDMINS_2_DATA(pDevIns, PVGASTATE), Port, u32);
2989 else if (cb == 2)
2990 {
2991 vga_ioport_write(PDMINS_2_DATA(pDevIns, PVGASTATE), Port, u32 & 0xff);
2992 vga_ioport_write(PDMINS_2_DATA(pDevIns, PVGASTATE), Port + 1, u32 >> 8);
2993 }
2994 return VINF_SUCCESS;
2995}
2996
2997
2998/**
2999 * Port I/O Handler for VGA IN operations.
3000 *
3001 * @returns VBox status code.
3002 *
3003 * @param pDevIns The device instance.
3004 * @param pvUser User argument - ignored.
3005 * @param Port Port number used for the IN operation.
3006 * @param pu32 Where to store the result.
3007 * @param cb Number of bytes read.
3008 */
3009PDMBOTHCBDECL(int) vgaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3010{
3011 NOREF(pvUser);
3012 if (cb == 1)
3013 {
3014 *pu32 = vga_ioport_read(PDMINS_2_DATA(pDevIns, PVGASTATE), Port);
3015 return VINF_SUCCESS;
3016 }
3017 else if (cb == 2)
3018 {
3019 *pu32 = vga_ioport_read(PDMINS_2_DATA(pDevIns, PVGASTATE), Port)
3020 | (vga_ioport_read(PDMINS_2_DATA(pDevIns, PVGASTATE), Port + 1) << 8);
3021 return VINF_SUCCESS;
3022 }
3023 return VERR_IOM_IOPORT_UNUSED;
3024}
3025
3026
3027/**
3028 * Port I/O Handler for VBE OUT operations.
3029 *
3030 * @returns VBox status code.
3031 *
3032 * @param pDevIns The device instance.
3033 * @param pvUser User argument - ignored.
3034 * @param Port Port number used for the IN operation.
3035 * @param u32 The value to output.
3036 * @param cb The value size in bytes.
3037 */
3038PDMBOTHCBDECL(int) vgaIOPortWriteVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3039{
3040 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3041
3042 NOREF(pvUser);
3043
3044#ifndef IN_RING3
3045 /*
3046 * This has to be done on the host in order to execute the connector callbacks.
3047 */
3048 if (s->vbe_index == VBE_DISPI_INDEX_ENABLE
3049 || s->vbe_index == VBE_DISPI_INDEX_VBOX_VIDEO)
3050 {
3051 Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE - Switching to host...\n"));
3052 return VINF_IOM_HC_IOPORT_WRITE;
3053 }
3054#endif
3055#ifdef VBE_BYTEWISE_IO
3056 if (cb == 1)
3057 {
3058 if (!s->fWriteVBEData)
3059 {
3060 if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
3061 && (u32 & VBE_DISPI_ENABLED))
3062 {
3063 s->fWriteVBEData = false;
3064 return vbe_ioport_write_data(s, Port, u32 & 0xFF);
3065 }
3066 else
3067 {
3068 s->cbWriteVBEData = u32 & 0xFF;
3069 s->fWriteVBEData = true;
3070 return VINF_SUCCESS;
3071 }
3072 }
3073 else
3074 {
3075 u32 = (s->cbWriteVBEData << 8) | (u32 & 0xFF);
3076 s->fWriteVBEData = false;
3077 cb = 2;
3078 }
3079 }
3080#endif
3081 if (cb == 2 || cb == 4)
3082 {
3083//#ifdef IN_RC
3084// /*
3085// * The VBE_DISPI_INDEX_ENABLE memsets the entire frame buffer.
3086// * Since we're not mapping the entire framebuffer any longer that
3087// * has to be done on the host.
3088// */
3089// if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
3090// && (u32 & VBE_DISPI_ENABLED))
3091// {
3092// Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE & VBE_DISPI_ENABLED - Switching to host...\n"));
3093// return VINF_IOM_HC_IOPORT_WRITE;
3094// }
3095//#endif
3096 return vbe_ioport_write_data(s, Port, u32);
3097 }
3098 else
3099 AssertMsgFailed(("vgaIOPortWriteVBEData: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3100 return VINF_SUCCESS;
3101}
3102
3103
3104/**
3105 * Port I/O Handler for VBE OUT operations.
3106 *
3107 * @returns VBox status code.
3108 *
3109 * @param pDevIns The device instance.
3110 * @param pvUser User argument - ignored.
3111 * @param Port Port number used for the IN operation.
3112 * @param u32 The value to output.
3113 * @param cb The value size in bytes.
3114 */
3115PDMBOTHCBDECL(int) vgaIOPortWriteVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3116{
3117 NOREF(pvUser);
3118#ifdef VBE_BYTEWISE_IO
3119 if (cb == 1)
3120 {
3121 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3122 if (!s->fWriteVBEIndex)
3123 {
3124 s->cbWriteVBEIndex = u32 & 0x00FF;
3125 s->fWriteVBEIndex = true;
3126 return VINF_SUCCESS;
3127 }
3128 else
3129 {
3130 s->fWriteVBEIndex = false;
3131 vbe_ioport_write_index(s, Port, (s->cbWriteVBEIndex << 8) | (u32 & 0x00FF));
3132 return VINF_SUCCESS;
3133 }
3134 }
3135 else
3136#endif
3137 if (cb == 2)
3138 vbe_ioport_write_index(PDMINS_2_DATA(pDevIns, PVGASTATE), Port, u32);
3139 else
3140 AssertMsgFailed(("vgaIOPortWriteVBEIndex: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3141 return VINF_SUCCESS;
3142}
3143
3144
3145/**
3146 * Port I/O Handler for VBE IN operations.
3147 *
3148 * @returns VBox status code.
3149 *
3150 * @param pDevIns The device instance.
3151 * @param pvUser User argument - ignored.
3152 * @param Port Port number used for the IN operation.
3153 * @param pu32 Where to store the result.
3154 * @param cb Number of bytes to read.
3155 */
3156PDMBOTHCBDECL(int) vgaIOPortReadVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3157{
3158 NOREF(pvUser);
3159#ifdef VBE_BYTEWISE_IO
3160 if (cb == 1)
3161 {
3162 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3163
3164 if (!s->fReadVBEData)
3165 {
3166 *pu32 = (vbe_ioport_read_data(s, Port) >> 8) & 0xFF;
3167 s->fReadVBEData = true;
3168 return VINF_SUCCESS;
3169 }
3170 else
3171 {
3172 *pu32 = vbe_ioport_read_data(s, Port) & 0xFF;
3173 s->fReadVBEData = false;
3174 return VINF_SUCCESS;
3175 }
3176 }
3177 else
3178#endif
3179 if (cb == 2)
3180 {
3181 *pu32 = vbe_ioport_read_data(PDMINS_2_DATA(pDevIns, PVGASTATE), Port);
3182 return VINF_SUCCESS;
3183 }
3184 else if (cb == 4)
3185 {
3186 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3187 /* Quick hack for getting the vram size. */
3188 *pu32 = s->vram_size;
3189 return VINF_SUCCESS;
3190 }
3191 AssertMsgFailed(("vgaIOPortReadVBEData: Port=%#x cb=%d\n", Port, cb));
3192 return VERR_IOM_IOPORT_UNUSED;
3193}
3194
3195
3196/**
3197 * Port I/O Handler for VBE IN operations.
3198 *
3199 * @returns VBox status code.
3200 *
3201 * @param pDevIns The device instance.
3202 * @param pvUser User argument - ignored.
3203 * @param Port Port number used for the IN operation.
3204 * @param pu32 Where to store the result.
3205 * @param cb Number of bytes to read.
3206 */
3207PDMBOTHCBDECL(int) vgaIOPortReadVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3208{
3209 NOREF(pvUser);
3210#ifdef VBE_BYTEWISE_IO
3211 if (cb == 1)
3212 {
3213 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3214
3215 if (!s->fReadVBEIndex)
3216 {
3217 *pu32 = (vbe_ioport_read_index(s, Port) >> 8) & 0xFF;
3218 s->fReadVBEIndex = true;
3219 return VINF_SUCCESS;
3220 }
3221 else
3222 {
3223 *pu32 = vbe_ioport_read_index(s, Port) & 0xFF;
3224 s->fReadVBEIndex = false;
3225 return VINF_SUCCESS;
3226 }
3227 }
3228 else
3229#endif
3230 if (cb == 2)
3231 {
3232 *pu32 = vbe_ioport_read_index(PDMINS_2_DATA(pDevIns, PVGASTATE), Port);
3233 return VINF_SUCCESS;
3234 }
3235 AssertMsgFailed(("vgaIOPortReadVBEIndex: Port=%#x cb=%d\n", Port, cb));
3236 return VERR_IOM_IOPORT_UNUSED;
3237}
3238
3239
3240
3241
3242
3243/* -=-=-=-=-=- Guest Context -=-=-=-=-=- */
3244
3245/*
3246 * Internal. For use inside VGAGCMemoryFillWrite only.
3247 * Macro for apply logical operation and bit mask.
3248 */
3249#define APPLY_LOGICAL_AND_MASK(s, val, bit_mask) \
3250 /* apply logical operation */ \
3251 switch(s->gr[3] >> 3) \
3252 { \
3253 case 0: \
3254 default: \
3255 /* nothing to do */ \
3256 break; \
3257 case 1: \
3258 /* and */ \
3259 val &= s->latch; \
3260 break; \
3261 case 2: \
3262 /* or */ \
3263 val |= s->latch; \
3264 break; \
3265 case 3: \
3266 /* xor */ \
3267 val ^= s->latch; \
3268 break; \
3269 } \
3270 /* apply bit mask */ \
3271 val = (val & bit_mask) | (s->latch & ~bit_mask)
3272
3273/**
3274 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM and from the inside of VGADeviceGC.cpp.
3275 * This is the advanced version of vga_mem_writeb function.
3276 *
3277 * @returns VBox status code.
3278 * @param pDevIns Pointer device instance.
3279 * @param pvUser User argument - ignored.
3280 * @param GCPhysAddr Physical address of memory to write.
3281 * @param u32Item Data to write, up to 4 bytes.
3282 * @param cbItem Size of data Item, only 1/2/4 bytes is allowed for now.
3283 * @param cItems Number of data items to write.
3284 */
3285PDMBOTHCBDECL(int) vgaMMIOFill(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems)
3286{
3287 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3288 uint32_t b;
3289 uint32_t write_mask, bit_mask, set_mask;
3290 uint32_t aVal[4];
3291 unsigned i;
3292 NOREF(pvUser);
3293 for (i = 0; i < cbItem; i++)
3294 {
3295 aVal[i] = u32Item & 0xff;
3296 u32Item >>= 8;
3297 }
3298
3299 /* convert to VGA memory offset */
3300 /// @todo add check for the end of region
3301 GCPhysAddr &= 0x1ffff;
3302 switch((pThis->gr[6] >> 2) & 3) {
3303 case 0:
3304 break;
3305 case 1:
3306 if (GCPhysAddr >= 0x10000)
3307 return VINF_SUCCESS;
3308 GCPhysAddr += pThis->bank_offset;
3309 break;
3310 case 2:
3311 GCPhysAddr -= 0x10000;
3312 if (GCPhysAddr >= 0x8000)
3313 return VINF_SUCCESS;
3314 break;
3315 default:
3316 case 3:
3317 GCPhysAddr -= 0x18000;
3318 if (GCPhysAddr >= 0x8000)
3319 return VINF_SUCCESS;
3320 break;
3321 }
3322
3323 if (pThis->sr[4] & 0x08) {
3324 /* chain 4 mode : simplest access */
3325 VERIFY_VRAM_WRITE_OFF_RETURN(pThis, GCPhysAddr + cItems * cbItem - 1);
3326
3327 while (cItems-- > 0)
3328 for (i = 0; i < cbItem; i++)
3329 {
3330 if (pThis->sr[2] & (1 << (GCPhysAddr & 3)))
3331 {
3332 pThis->CTX_SUFF(vram_ptr)[GCPhysAddr] = aVal[i];
3333 vga_set_dirty(pThis, GCPhysAddr);
3334 }
3335 GCPhysAddr++;
3336 }
3337 } else if (pThis->gr[5] & 0x10) {
3338 /* odd/even mode (aka text mode mapping) */
3339 VERIFY_VRAM_WRITE_OFF_RETURN(pThis, GCPhysAddr * 2 + cItems * cbItem - 1);
3340 while (cItems-- > 0)
3341 for (i = 0; i < cbItem; i++)
3342 {
3343 unsigned plane = (pThis->gr[4] & 2) | (GCPhysAddr & 1);
3344 if (pThis->sr[2] & (1 << plane)) {
3345 RTGCPHYS PhysAddr2 = ((GCPhysAddr & ~1) << 2) | plane;
3346 pThis->CTX_SUFF(vram_ptr)[PhysAddr2] = aVal[i];
3347 vga_set_dirty(pThis, PhysAddr2);
3348 }
3349 GCPhysAddr++;
3350 }
3351 } else {
3352 /* standard VGA latched access */
3353 VERIFY_VRAM_WRITE_OFF_RETURN(pThis, GCPhysAddr + cItems * cbItem - 1);
3354
3355 switch(pThis->gr[5] & 3) {
3356 default:
3357 case 0:
3358 /* rotate */
3359 b = pThis->gr[3] & 7;
3360 bit_mask = pThis->gr[8];
3361 bit_mask |= bit_mask << 8;
3362 bit_mask |= bit_mask << 16;
3363 set_mask = mask16[pThis->gr[1]];
3364
3365 for (i = 0; i < cbItem; i++)
3366 {
3367 aVal[i] = ((aVal[i] >> b) | (aVal[i] << (8 - b))) & 0xff;
3368 aVal[i] |= aVal[i] << 8;
3369 aVal[i] |= aVal[i] << 16;
3370
3371 /* apply set/reset mask */
3372 aVal[i] = (aVal[i] & ~set_mask) | (mask16[pThis->gr[0]] & set_mask);
3373
3374 APPLY_LOGICAL_AND_MASK(pThis, aVal[i], bit_mask);
3375 }
3376 break;
3377 case 1:
3378 for (i = 0; i < cbItem; i++)
3379 aVal[i] = pThis->latch;
3380 break;
3381 case 2:
3382 bit_mask = pThis->gr[8];
3383 bit_mask |= bit_mask << 8;
3384 bit_mask |= bit_mask << 16;
3385 for (i = 0; i < cbItem; i++)
3386 {
3387 aVal[i] = mask16[aVal[i] & 0x0f];
3388
3389 APPLY_LOGICAL_AND_MASK(pThis, aVal[i], bit_mask);
3390 }
3391 break;
3392 case 3:
3393 /* rotate */
3394 b = pThis->gr[3] & 7;
3395
3396 for (i = 0; i < cbItem; i++)
3397 {
3398 aVal[i] = (aVal[i] >> b) | (aVal[i] << (8 - b));
3399 bit_mask = pThis->gr[8] & aVal[i];
3400 bit_mask |= bit_mask << 8;
3401 bit_mask |= bit_mask << 16;
3402 aVal[i] = mask16[pThis->gr[0]];
3403
3404 APPLY_LOGICAL_AND_MASK(pThis, aVal[i], bit_mask);
3405 }
3406 break;
3407 }
3408
3409 /* mask data according to sr[2] */
3410 write_mask = mask16[pThis->sr[2]];
3411
3412 /* actually write data */
3413 if (cbItem == 1)
3414 {
3415 /* The most frequently case is 1 byte I/O. */
3416 while (cItems-- > 0)
3417 {
3418 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
3419 vga_set_dirty(pThis, GCPhysAddr << 2);
3420 GCPhysAddr++;
3421 }
3422 }
3423 else if (cbItem == 2)
3424 {
3425 /* The second case is 2 bytes I/O. */
3426 while (cItems-- > 0)
3427 {
3428 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
3429 vga_set_dirty(pThis, GCPhysAddr << 2);
3430 GCPhysAddr++;
3431
3432 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[1] & write_mask);
3433 vga_set_dirty(pThis, GCPhysAddr << 2);
3434 GCPhysAddr++;
3435 }
3436 }
3437 else
3438 {
3439 /* And the rest is 4 bytes. */
3440 Assert(cbItem == 4);
3441 while (cItems-- > 0)
3442 for (i = 0; i < cbItem; i++)
3443 {
3444 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[i] & write_mask);
3445 vga_set_dirty(pThis, GCPhysAddr << 2);
3446 GCPhysAddr++;
3447 }
3448 }
3449 }
3450 return VINF_SUCCESS;
3451}
3452#undef APPLY_LOGICAL_AND_MASK
3453
3454
3455/**
3456 * Legacy VGA memory (0xa0000 - 0xbffff) read hook, to be called from IOM.
3457 *
3458 * @returns VBox status code.
3459 * @param pDevIns Pointer device instance.
3460 * @param pvUser User argument - ignored.
3461 * @param GCPhysAddr Physical address of memory to read.
3462 * @param pv Where to store readed data.
3463 * @param cb Bytes to read.
3464 */
3465PDMBOTHCBDECL(int) vgaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3466{
3467 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3468 STAM_PROFILE_START(&pThis->CTX_MID_Z(Stat,MemoryRead), a);
3469 int rc = VINF_SUCCESS;
3470 NOREF(pvUser);
3471 switch (cb)
3472 {
3473 case 1:
3474 *(uint8_t *)pv = vga_mem_readb(pThis, GCPhysAddr, &rc); break;
3475 case 2:
3476 *(uint16_t *)pv = vga_mem_readb(pThis, GCPhysAddr, &rc)
3477 | (vga_mem_readb(pThis, GCPhysAddr + 1, &rc) << 8);
3478 break;
3479 case 4:
3480 *(uint32_t *)pv = vga_mem_readb(pThis, GCPhysAddr, &rc)
3481 | (vga_mem_readb(pThis, GCPhysAddr + 1, &rc) << 8)
3482 | (vga_mem_readb(pThis, GCPhysAddr + 2, &rc) << 16)
3483 | (vga_mem_readb(pThis, GCPhysAddr + 3, &rc) << 24);
3484 break;
3485
3486 case 8:
3487 *(uint64_t *)pv = (uint64_t)vga_mem_readb(pThis, GCPhysAddr, &rc)
3488 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 1, &rc) << 8)
3489 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 2, &rc) << 16)
3490 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 3, &rc) << 24)
3491 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 4, &rc) << 32)
3492 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 5, &rc) << 40)
3493 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 6, &rc) << 48)
3494 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 7, &rc) << 56);
3495 break;
3496
3497 default:
3498 {
3499 uint8_t *pu8Data = (uint8_t *)pv;
3500 while (cb-- > 0)
3501 {
3502 *pu8Data++ = vga_mem_readb(pThis, GCPhysAddr++, &rc);
3503 if (RT_UNLIKELY(rc != VINF_SUCCESS))
3504 break;
3505 }
3506 }
3507 }
3508 STAM_PROFILE_STOP(&pThis->CTX_MID_Z(Stat,MemoryRead), a);
3509 return rc;
3510}
3511
3512/**
3513 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM.
3514 *
3515 * @returns VBox status code.
3516 * @param pDevIns Pointer device instance.
3517 * @param pvUser User argument - ignored.
3518 * @param GCPhysAddr Physical address of memory to write.
3519 * @param pv Pointer to data.
3520 * @param cb Bytes to write.
3521 */
3522PDMBOTHCBDECL(int) vgaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3523{
3524 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3525 uint8_t *pu8 = (uint8_t *)pv;
3526 int rc = VINF_SUCCESS;
3527 STAM_PROFILE_START(&pThis->CTX_MID_Z(Stat,MemoryWrite), a);
3528
3529 switch (cb)
3530 {
3531 case 1:
3532 rc = vga_mem_writeb(pThis, GCPhysAddr, *pu8);
3533 break;
3534#if 1
3535 case 2:
3536 rc = vga_mem_writeb(pThis, GCPhysAddr + 0, pu8[0]);
3537 if (RT_LIKELY(rc == VINF_SUCCESS))
3538 rc = vga_mem_writeb(pThis, GCPhysAddr + 1, pu8[1]);
3539 break;
3540 case 4:
3541 rc = vga_mem_writeb(pThis, GCPhysAddr + 0, pu8[0]);
3542 if (RT_LIKELY(rc == VINF_SUCCESS))
3543 rc = vga_mem_writeb(pThis, GCPhysAddr + 1, pu8[1]);
3544 if (RT_LIKELY(rc == VINF_SUCCESS))
3545 rc = vga_mem_writeb(pThis, GCPhysAddr + 2, pu8[2]);
3546 if (RT_LIKELY(rc == VINF_SUCCESS))
3547 rc = vga_mem_writeb(pThis, GCPhysAddr + 3, pu8[3]);
3548 break;
3549 case 8:
3550 rc = vga_mem_writeb(pThis, GCPhysAddr + 0, pu8[0]);
3551 if (RT_LIKELY(rc == VINF_SUCCESS))
3552 rc = vga_mem_writeb(pThis, GCPhysAddr + 1, pu8[1]);
3553 if (RT_LIKELY(rc == VINF_SUCCESS))
3554 rc = vga_mem_writeb(pThis, GCPhysAddr + 2, pu8[2]);
3555 if (RT_LIKELY(rc == VINF_SUCCESS))
3556 rc = vga_mem_writeb(pThis, GCPhysAddr + 3, pu8[3]);
3557 if (RT_LIKELY(rc == VINF_SUCCESS))
3558 rc = vga_mem_writeb(pThis, GCPhysAddr + 4, pu8[4]);
3559 if (RT_LIKELY(rc == VINF_SUCCESS))
3560 rc = vga_mem_writeb(pThis, GCPhysAddr + 5, pu8[5]);
3561 if (RT_LIKELY(rc == VINF_SUCCESS))
3562 rc = vga_mem_writeb(pThis, GCPhysAddr + 6, pu8[6]);
3563 if (RT_LIKELY(rc == VINF_SUCCESS))
3564 rc = vga_mem_writeb(pThis, GCPhysAddr + 7, pu8[7]);
3565 break;
3566#else
3567 case 2:
3568 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint16_t *)pv, 2, 1);
3569 break;
3570 case 4:
3571 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint32_t *)pv, 4, 1);
3572 break;
3573 case 8:
3574 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint64_t *)pv, 8, 1);
3575 break;
3576#endif
3577 default:
3578 while (cb-- > 0 && rc == VINF_SUCCESS)
3579 rc = vga_mem_writeb(pThis, GCPhysAddr++, *pu8++);
3580 break;
3581
3582 }
3583 STAM_PROFILE_STOP(&pThis->CTX_MID_Z(Stat,MemoryWrite), a);
3584 return rc;
3585}
3586
3587
3588/**
3589 * Handle LFB access.
3590 * @returns VBox status code.
3591 * @param pVM VM handle.
3592 * @param pThis VGA device instance data.
3593 * @param GCPhys The access physical address.
3594 * @param GCPtr The access virtual address (only GC).
3595 */
3596static int vgaLFBAccess(PVM pVM, PVGASTATE pThis, RTGCPHYS GCPhys, RTGCPTR GCPtr)
3597{
3598 int rc;
3599
3600 /*
3601 * Set page dirty bit.
3602 */
3603 vga_set_dirty(pThis, GCPhys - pThis->GCPhysVRAM);
3604 pThis->fLFBUpdated = true;
3605
3606 /*
3607 * Turn of the write handler for this particular page and make it R/W.
3608 * Then return telling the caller to restart the guest instruction.
3609 * ASSUME: the guest always maps video memory RW.
3610 */
3611 rc = PGMHandlerPhysicalPageTempOff(pVM, pThis->GCPhysVRAM, GCPhys);
3612 if (RT_SUCCESS(rc))
3613 {
3614#ifndef IN_RING3
3615 rc = PGMShwModifyPage(pVM, GCPtr, 1, X86_PTE_RW, ~(uint64_t)X86_PTE_RW);
3616 if (RT_SUCCESS(rc))
3617 return VINF_SUCCESS;
3618 else
3619 AssertMsgFailed(("PGMShwModifyPage -> rc=%d\n", rc));
3620#else /* IN_RING3 : We don't have any virtual page address of the access here. */
3621 Assert(GCPtr == 0);
3622 return VINF_SUCCESS;
3623#endif
3624 }
3625 else
3626 AssertMsgFailed(("PGMHandlerPhysicalPageTempOff -> rc=%d\n", rc));
3627
3628 return rc;
3629}
3630
3631
3632#ifdef IN_RC
3633/**
3634 * #PF Handler for VBE LFB access.
3635 *
3636 * @returns VBox status code (appropriate for GC return).
3637 * @param pVM VM Handle.
3638 * @param uErrorCode CPU Error code.
3639 * @param pRegFrame Trap register frame.
3640 * @param pvFault The fault address (cr2).
3641 * @param GCPhysFault The GC physical address corresponding to pvFault.
3642 * @param pvUser User argument, ignored.
3643 */
3644PDMBOTHCBDECL(int) vgaGCLFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
3645{
3646 PVGASTATE pThis = (PVGASTATE)pvUser;
3647 Assert(pThis);
3648 Assert(GCPhysFault >= pThis->GCPhysVRAM);
3649 AssertMsg(uErrorCode & X86_TRAP_PF_RW, ("uErrorCode=%#x\n", uErrorCode));
3650
3651 return vgaLFBAccess(pVM, pThis, GCPhysFault, pvFault);
3652}
3653
3654#elif IN_RING0
3655
3656/**
3657 * #PF Handler for VBE LFB access.
3658 *
3659 * @returns VBox status code (appropriate for GC return).
3660 * @param pVM VM Handle.
3661 * @param uErrorCode CPU Error code.
3662 * @param pRegFrame Trap register frame.
3663 * @param pvFault The fault address (cr2).
3664 * @param GCPhysFault The GC physical address corresponding to pvFault.
3665 * @param pvUser User argument, ignored.
3666 */
3667PDMBOTHCBDECL(int) vgaR0LFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
3668{
3669 PVGASTATE pThis = (PVGASTATE)pvUser;
3670 Assert(pThis);
3671 Assert(GCPhysFault >= pThis->GCPhysVRAM);
3672 AssertMsg(uErrorCode & X86_TRAP_PF_RW, ("uErrorCode=%#x\n", uErrorCode));
3673
3674 return vgaLFBAccess(pVM, pThis, GCPhysFault, pvFault);
3675}
3676
3677#else /* IN_RING3 */
3678
3679/**
3680 * HC access handler for the LFB.
3681 *
3682 * @returns VINF_SUCCESS if the handler have carried out the operation.
3683 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
3684 * @param pVM VM Handle.
3685 * @param GCPhys The physical address the guest is writing to.
3686 * @param pvPhys The HC mapping of that address.
3687 * @param pvBuf What the guest is reading/writing.
3688 * @param cbBuf How much it's reading/writing.
3689 * @param enmAccessType The access type.
3690 * @param pvUser User argument.
3691 */
3692static DECLCALLBACK(int) vgaR3LFBAccessHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
3693{
3694 PVGASTATE pThis = (PVGASTATE)pvUser;
3695 int rc;
3696 Assert(pThis);
3697 Assert(GCPhys >= pThis->GCPhysVRAM);
3698 rc = vgaLFBAccess(pVM, pThis, GCPhys, 0);
3699 if (RT_SUCCESS(rc))
3700 return VINF_PGM_HANDLER_DO_DEFAULT;
3701 AssertMsg(rc <= VINF_SUCCESS, ("rc=%Rrc\n", rc));
3702 return rc;
3703}
3704#endif /* IN_RING3 */
3705
3706/* -=-=-=-=-=- All rings: VGA BIOS I/Os -=-=-=-=-=- */
3707
3708/**
3709 * Port I/O Handler for VGA BIOS IN operations.
3710 *
3711 * @returns VBox status code.
3712 *
3713 * @param pDevIns The device instance.
3714 * @param pvUser User argument - ignored.
3715 * @param Port Port number used for the IN operation.
3716 * @param pu32 Where to store the result.
3717 * @param cb Number of bytes read.
3718 */
3719PDMBOTHCBDECL(int) vgaIOPortReadBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3720{
3721 NOREF(pDevIns);
3722 NOREF(pvUser);
3723 NOREF(Port);
3724 NOREF(pu32);
3725 NOREF(cb);
3726 return VERR_IOM_IOPORT_UNUSED;
3727}
3728
3729/**
3730 * Port I/O Handler for VGA BIOS OUT operations.
3731 *
3732 * @returns VBox status code.
3733 *
3734 * @param pDevIns The device instance.
3735 * @param pvUser User argument - ignored.
3736 * @param Port Port number used for the IN operation.
3737 * @param u32 The value to output.
3738 * @param cb The value size in bytes.
3739 */
3740PDMBOTHCBDECL(int) vgaIOPortWriteBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3741{
3742 static int lastWasNotNewline = 0; /* We are only called in a single-threaded way */
3743 /*
3744 * VGA BIOS char printing.
3745 */
3746 if ( cb == 1
3747 && Port == VBE_PRINTF_PORT)
3748 {
3749#if 0
3750 switch (u32)
3751 {
3752 case '\r': Log(("vgabios: <return>\n")); break;
3753 case '\n': Log(("vgabios: <newline>\n")); break;
3754 case '\t': Log(("vgabios: <tab>\n")); break;
3755 default:
3756 Log(("vgabios: %c\n", u32));
3757 }
3758#else
3759 if (lastWasNotNewline == 0)
3760 Log(("vgabios: "));
3761 if (u32 != '\r') /* return - is only sent in conjunction with '\n' */
3762 Log(("%c", u32));
3763 if (u32 == '\n')
3764 lastWasNotNewline = 0;
3765 else
3766 lastWasNotNewline = 1;
3767#endif
3768 return VINF_SUCCESS;
3769 }
3770
3771 /* not in use. */
3772 return VINF_SUCCESS;
3773}
3774
3775
3776/* -=-=-=-=-=- Ring 3 -=-=-=-=-=- */
3777
3778#ifdef IN_RING3
3779
3780# ifdef VBE_NEW_DYN_LIST
3781/**
3782 * Port I/O Handler for VBE Extra OUT operations.
3783 *
3784 * @returns VBox status code.
3785 *
3786 * @param pDevIns The device instance.
3787 * @param pvUser User argument - ignored.
3788 * @param Port Port number used for the IN operation.
3789 * @param u32 The value to output.
3790 * @param cb The value size in bytes.
3791 */
3792PDMBOTHCBDECL(int) vbeIOPortWriteVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3793{
3794 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3795 NOREF(pvUser);
3796 NOREF(Port);
3797
3798 if (cb == 2)
3799 {
3800 Log(("vbeIOPortWriteVBEExtra: addr=%#RX32\n", u32));
3801 pThis->u16VBEExtraAddress = u32;
3802 return VINF_SUCCESS;
3803 }
3804
3805 Log(("vbeIOPortWriteVBEExtra: Ignoring invalid cb=%d writes to the VBE Extra port!!!\n", cb));
3806 return VINF_SUCCESS;
3807}
3808
3809
3810/**
3811 * Port I/O Handler for VBE Extra IN operations.
3812 *
3813 * @returns VBox status code.
3814 *
3815 * @param pDevIns The device instance.
3816 * @param pvUser User argument - ignored.
3817 * @param Port Port number used for the IN operation.
3818 * @param pu32 Where to store the result.
3819 * @param cb Number of bytes read.
3820 */
3821PDMBOTHCBDECL(int) vbeIOPortReadVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3822{
3823 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3824 NOREF(pvUser);
3825 NOREF(Port);
3826
3827 if (pThis->u16VBEExtraAddress == 0xffff)
3828 {
3829 Log(("vbeIOPortReadVBEExtra: Requested number of 64k video banks\n"));
3830 *pu32 = pThis->vram_size / _64K;
3831 return VINF_SUCCESS;
3832 }
3833
3834 if ( pThis->u16VBEExtraAddress >= pThis->cbVBEExtraData
3835 || pThis->u16VBEExtraAddress + cb > pThis->cbVBEExtraData)
3836 {
3837 *pu32 = 0;
3838 Log(("vbeIOPortReadVBEExtra: Requested address is out of VBE data!!! Address=%#x(%d) cbVBEExtraData=%#x(%d)\n",
3839 pThis->u16VBEExtraAddress, pThis->u16VBEExtraAddress, pThis->cbVBEExtraData, pThis->cbVBEExtraData));
3840 return VINF_SUCCESS;
3841 }
3842
3843 if (cb == 1)
3844 {
3845 *pu32 = pThis->pu8VBEExtraData[pThis->u16VBEExtraAddress] & 0xFF;
3846
3847 Log(("vbeIOPortReadVBEExtra: cb=%#x %.*Rhxs\n", cb, cb, pu32));
3848 return VINF_SUCCESS;
3849 }
3850
3851 if (cb == 2)
3852 {
3853 *pu32 = pThis->pu8VBEExtraData[pThis->u16VBEExtraAddress]
3854 | pThis->pu8VBEExtraData[pThis->u16VBEExtraAddress + 1] << 8;
3855
3856 Log(("vbeIOPortReadVBEExtra: cb=%#x %.*Rhxs\n", cb, cb, pu32));
3857 return VINF_SUCCESS;
3858 }
3859 Log(("vbeIOPortReadVBEExtra: Invalid cb=%d read from the VBE Extra port!!!\n", cb));
3860 return VERR_IOM_IOPORT_UNUSED;
3861}
3862# endif /* VBE_NEW_DYN_LIST */
3863
3864
3865/**
3866 * Parse the logo bitmap data at init time.
3867 *
3868 * @returns VBox status code.
3869 *
3870 * @param pThis The VGA instance data.
3871 */
3872static int vbeParseBitmap(PVGASTATE pThis)
3873{
3874 uint16_t i;
3875 PBMPINFO bmpInfo;
3876 POS2HDR pOs2Hdr;
3877 POS22HDR pOs22Hdr;
3878 PWINHDR pWinHdr;
3879
3880 /*
3881 * Get bitmap header data
3882 */
3883 bmpInfo = (PBMPINFO)(pThis->pu8Logo + sizeof(LOGOHDR));
3884 pWinHdr = (PWINHDR)(pThis->pu8Logo + sizeof(LOGOHDR) + sizeof(BMPINFO));
3885
3886 if (bmpInfo->Type == BMP_ID)
3887 {
3888 switch (pWinHdr->Size)
3889 {
3890 case BMP_HEADER_OS21:
3891 pOs2Hdr = (POS2HDR)pWinHdr;
3892 pThis->cxLogo = pOs2Hdr->Width;
3893 pThis->cyLogo = pOs2Hdr->Height;
3894 pThis->cLogoPlanes = pOs2Hdr->Planes;
3895 pThis->cLogoBits = pOs2Hdr->BitCount;
3896 pThis->LogoCompression = BMP_COMPRESS_NONE;
3897 pThis->cLogoUsedColors = 0;
3898 break;
3899
3900 case BMP_HEADER_OS22:
3901 pOs22Hdr = (POS22HDR)pWinHdr;
3902 pThis->cxLogo = pOs22Hdr->Width;
3903 pThis->cyLogo = pOs22Hdr->Height;
3904 pThis->cLogoPlanes = pOs22Hdr->Planes;
3905 pThis->cLogoBits = pOs22Hdr->BitCount;
3906 pThis->LogoCompression = pOs22Hdr->Compression;
3907 pThis->cLogoUsedColors = pOs22Hdr->ClrUsed;
3908 break;
3909
3910 case BMP_HEADER_WIN3:
3911 pThis->cxLogo = pWinHdr->Width;
3912 pThis->cyLogo = pWinHdr->Height;
3913 pThis->cLogoPlanes = pWinHdr->Planes;
3914 pThis->cLogoBits = pWinHdr->BitCount;
3915 pThis->LogoCompression = pWinHdr->Compression;
3916 pThis->cLogoUsedColors = pWinHdr->ClrUsed;
3917 break;
3918
3919 default:
3920 AssertMsgFailed(("Unsupported bitmap header.\n"));
3921 break;
3922 }
3923
3924 if (pThis->cxLogo > LOGO_MAX_WIDTH || pThis->cyLogo > LOGO_MAX_HEIGHT)
3925 {
3926 AssertMsgFailed(("Bitmap %ux%u is too big.\n", pThis->cxLogo, pThis->cyLogo));
3927 return VERR_INVALID_PARAMETER;
3928 }
3929
3930 if (pThis->cLogoPlanes != 1)
3931 {
3932 AssertMsgFailed(("Bitmap planes %u != 1.\n", pThis->cLogoPlanes));
3933 return VERR_INVALID_PARAMETER;
3934 }
3935
3936 if (pThis->cLogoBits != 4 && pThis->cLogoBits != 8 && pThis->cLogoBits != 24)
3937 {
3938 AssertMsgFailed(("Unsupported %u depth.\n", pThis->cLogoBits));
3939 return VERR_INVALID_PARAMETER;
3940 }
3941
3942 if (pThis->cLogoUsedColors > 256)
3943 {
3944 AssertMsgFailed(("Unsupported %u colors.\n", pThis->cLogoUsedColors));
3945 return VERR_INVALID_PARAMETER;
3946 }
3947
3948 if (pThis->LogoCompression != BMP_COMPRESS_NONE)
3949 {
3950 AssertMsgFailed(("Unsupported %u compression.\n", pThis->LogoCompression));
3951 return VERR_INVALID_PARAMETER;
3952 }
3953
3954 /*
3955 * Read bitmap palette
3956 */
3957 if (!pThis->cLogoUsedColors)
3958 pThis->cLogoPalEntries = 1 << (pThis->cLogoPlanes * pThis->cLogoBits);
3959 else
3960 pThis->cLogoPalEntries = pThis->cLogoUsedColors;
3961
3962 if (pThis->cLogoPalEntries)
3963 {
3964 const uint8_t *pu8Pal = pThis->pu8Logo + sizeof(LOGOHDR) + sizeof(BMPINFO) + pWinHdr->Size; /* ASSUMES Size location (safe) */
3965
3966 for (i = 0; i < pThis->cLogoPalEntries; i++)
3967 {
3968 uint16_t j;
3969 uint32_t u32Pal = 0;
3970
3971 for (j = 0; j < 3; j++)
3972 {
3973 uint8_t b = *pu8Pal++;
3974 u32Pal <<= 8;
3975 u32Pal |= b;
3976 }
3977
3978 pu8Pal++; /* skip unused byte */
3979 pThis->au32LogoPalette[i] = u32Pal;
3980 }
3981 }
3982
3983 /*
3984 * Bitmap data offset
3985 */
3986 pThis->pu8LogoBitmap = pThis->pu8Logo + sizeof(LOGOHDR) + bmpInfo->Offset;
3987 }
3988
3989 return VINF_SUCCESS;
3990}
3991
3992
3993/**
3994 * Show logo bitmap data.
3995 *
3996 * @returns VBox status code.
3997 *
3998 * @param cbDepth Logo depth.
3999 * @param xLogo Logo X position.
4000 * @param yLogo Logo Y position.
4001 * @param cxLogo Logo width.
4002 * @param cyLogo Logo height.
4003 * @param iStep Fade in/fade out step.
4004 * @param pu32Palette Palette data.
4005 * @param pu8Src Source buffer.
4006 * @param pu8Dst Destination buffer.
4007 */
4008static void vbeShowBitmap(uint16_t cBits, uint16_t xLogo, uint16_t yLogo, uint16_t cxLogo, uint16_t cyLogo, uint8_t iStep,
4009 const uint32_t *pu32Palette, const uint8_t *pu8Src, uint8_t *pu8Dst)
4010{
4011 uint16_t i;
4012 size_t cbPadBytes = 0;
4013 size_t cbLineDst = LOGO_MAX_WIDTH * 4;
4014 uint16_t cyLeft = cyLogo;
4015
4016 pu8Dst += xLogo * 4 + yLogo * cbLineDst;
4017
4018 switch (cBits)
4019 {
4020 case 1:
4021 pu8Dst += cyLogo * cbLineDst;
4022 cbPadBytes = 0;
4023 break;
4024
4025 case 4:
4026 if (((cxLogo % 8) == 0) || ((cxLogo % 8) > 6))
4027 cbPadBytes = 0;
4028 else if ((cxLogo % 8) <= 2)
4029 cbPadBytes = 3;
4030 else if ((cxLogo % 8) <= 4)
4031 cbPadBytes = 2;
4032 else
4033 cbPadBytes = 1;
4034 break;
4035
4036 case 8:
4037 cbPadBytes = ((cxLogo % 4) == 0) ? 0 : (4 - (cxLogo % 4));
4038 break;
4039
4040 case 24:
4041 cbPadBytes = cxLogo % 4;
4042 break;
4043 }
4044
4045 uint8_t j = 0, c = 0;
4046
4047 while (cyLeft-- > 0)
4048 {
4049 uint8_t *pu8TmpPtr = pu8Dst;
4050
4051 if (cBits != 1)
4052 j = 0;
4053
4054 for (i = 0; i < cxLogo; i++)
4055 {
4056 uint8_t pix;
4057
4058 switch (cBits)
4059 {
4060 case 1:
4061 {
4062 if (!j)
4063 c = *pu8Src++;
4064
4065 pix = (c & 1) ? 0xFF : 0;
4066 c >>= 1;
4067
4068 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4069 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4070 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4071 *pu8TmpPtr++;
4072
4073 j = (j + 1) % 8;
4074 break;
4075 }
4076
4077 case 4:
4078 {
4079 if (!j)
4080 c = *pu8Src++;
4081
4082 pix = (c >> 4) & 0xF;
4083 c <<= 4;
4084
4085 uint32_t u32Pal = pu32Palette[pix];
4086
4087 pix = (u32Pal >> 16) & 0xFF;
4088 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4089 pix = (u32Pal >> 8) & 0xFF;
4090 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4091 pix = u32Pal & 0xFF;
4092 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4093 *pu8TmpPtr++;
4094
4095 j = (j + 1) % 2;
4096 break;
4097 }
4098
4099 case 8:
4100 {
4101 uint32_t u32Pal = pu32Palette[*pu8Src++];
4102
4103 pix = (u32Pal >> 16) & 0xFF;
4104 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4105 pix = (u32Pal >> 8) & 0xFF;
4106 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4107 pix = u32Pal & 0xFF;
4108 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4109 *pu8TmpPtr++;
4110 break;
4111 }
4112
4113 case 24:
4114 *pu8TmpPtr++ = *pu8Src++ * iStep / LOGO_SHOW_STEPS;
4115 *pu8TmpPtr++ = *pu8Src++ * iStep / LOGO_SHOW_STEPS;
4116 *pu8TmpPtr++ = *pu8Src++ * iStep / LOGO_SHOW_STEPS;
4117 *pu8TmpPtr++;
4118 break;
4119 }
4120 }
4121
4122 pu8Dst -= cbLineDst;
4123 pu8Src += cbPadBytes;
4124 }
4125}
4126
4127
4128
4129
4130/**
4131 * Port I/O Handler for BIOS Logo OUT operations.
4132 *
4133 * @returns VBox status code.
4134 *
4135 * @param pDevIns The device instance.
4136 * @param pvUser User argument - ignored.
4137 * @param Port Port number used for the IN operation.
4138 * @param u32 The value to output.
4139 * @param cb The value size in bytes.
4140 */
4141PDMBOTHCBDECL(int) vbeIOPortWriteCMDLogo(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
4142{
4143 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4144 NOREF(pvUser);
4145 NOREF(Port);
4146
4147 Log(("vbeIOPortWriteCMDLogo: cb=%d u32=%#04x(%#04d) (byte)\n", cb, u32, u32));
4148
4149 if (cb == 2)
4150 {
4151 /* Get the logo command */
4152 switch (u32 & 0xFF00)
4153 {
4154 case LOGO_CMD_SET_OFFSET:
4155 pThis->offLogoData = u32 & 0xFF;
4156 break;
4157
4158 case LOGO_CMD_SHOW_BMP:
4159 {
4160 uint8_t iStep = u32 & 0xFF;
4161 const uint8_t *pu8Src = pThis->pu8LogoBitmap;
4162 uint8_t *pu8Dst;
4163 PLOGOHDR pLogoHdr = (PLOGOHDR)pThis->pu8Logo;
4164 uint32_t offDirty = 0;
4165 uint16_t xLogo = (LOGO_MAX_WIDTH - pThis->cxLogo) / 2;
4166 uint16_t yLogo = LOGO_MAX_HEIGHT - (LOGO_MAX_HEIGHT - pThis->cyLogo) / 2;
4167
4168 /* Check VRAM size */
4169 if (pThis->vram_size < LOGO_MAX_SIZE)
4170 break;
4171
4172 if (pThis->vram_size >= LOGO_MAX_SIZE * 2)
4173 pu8Dst = pThis->vram_ptrR3 + LOGO_MAX_SIZE;
4174 else
4175 pu8Dst = pThis->vram_ptrR3;
4176
4177 /* Clear screen - except on power on... */
4178 if (!pThis->fLogoClearScreen)
4179 {
4180 uint32_t *pu32TmpPtr = (uint32_t *)pu8Dst;
4181
4182 /* Clear vram */
4183 for (int i = 0; i < LOGO_MAX_WIDTH; i++)
4184 {
4185 for (int j = 0; j < LOGO_MAX_HEIGHT; j++)
4186 *pu32TmpPtr++ = 0;
4187 }
4188 pThis->fLogoClearScreen = true;
4189 }
4190
4191 /* Show the bitmap. */
4192 vbeShowBitmap(pThis->cLogoBits, xLogo, yLogo,
4193 pThis->cxLogo, pThis->cyLogo,
4194 iStep, &pThis->au32LogoPalette[0],
4195 pu8Src, pu8Dst);
4196
4197 /* Show the 'Press F12...' text. */
4198 if (pLogoHdr->fu8ShowBootMenu == 2)
4199 vbeShowBitmap(1, LOGO_F12TEXT_X, LOGO_F12TEXT_Y,
4200 LOGO_F12TEXT_WIDTH, LOGO_F12TEXT_HEIGHT,
4201 iStep, &pThis->au32LogoPalette[0],
4202 &g_abLogoF12BootText[0], pu8Dst);
4203
4204 /* Blit the offscreen buffer. */
4205 if (pThis->vram_size >= LOGO_MAX_SIZE * 2)
4206 {
4207 uint32_t *pu32TmpDst = (uint32_t *)pThis->vram_ptrR3;
4208 uint32_t *pu32TmpSrc = (uint32_t *)(pThis->vram_ptrR3 + LOGO_MAX_SIZE);
4209 for (int i = 0; i < LOGO_MAX_WIDTH; i++)
4210 {
4211 for (int j = 0; j < LOGO_MAX_HEIGHT; j++)
4212 *pu32TmpDst++ = *pu32TmpSrc++;
4213 }
4214 }
4215
4216 /* Set the dirty flags. */
4217 while (offDirty <= LOGO_MAX_SIZE)
4218 {
4219 vga_set_dirty(pThis, offDirty);
4220 offDirty += PAGE_SIZE;
4221 }
4222 break;
4223 }
4224
4225 default:
4226 Log(("vbeIOPortWriteCMDLogo: invalid command %d\n", u32));
4227 pThis->LogoCommand = LOGO_CMD_NOP;
4228 break;
4229 }
4230
4231 return VINF_SUCCESS;
4232 }
4233
4234 Log(("vbeIOPortWriteCMDLogo: Ignoring invalid cb=%d writes to the VBE Extra port!!!\n", cb));
4235 return VINF_SUCCESS;
4236}
4237
4238
4239/**
4240 * Port I/O Handler for BIOS Logo IN operations.
4241 *
4242 * @returns VBox status code.
4243 *
4244 * @param pDevIns The device instance.
4245 * @param pvUser User argument - ignored.
4246 * @param Port Port number used for the IN operation.
4247 * @param pu32 Where to store the result.
4248 * @param cb Number of bytes read.
4249 */
4250PDMBOTHCBDECL(int) vbeIOPortReadCMDLogo(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
4251{
4252 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4253 NOREF(pvUser);
4254 NOREF(Port);
4255
4256 PRTUINT64U p;
4257
4258 if (pThis->offLogoData + cb > pThis->cbLogo)
4259 {
4260 Log(("vbeIOPortReadCMDLogo: Requested address is out of Logo data!!! offLogoData=%#x(%d) cbLogo=%#x(%d)\n",
4261 pThis->offLogoData, pThis->offLogoData, pThis->cbLogo, pThis->cbLogo));
4262 return VINF_SUCCESS;
4263 }
4264 p = (PRTUINT64U)&pThis->pu8Logo[pThis->offLogoData];
4265
4266 switch (cb)
4267 {
4268 case 1: *pu32 = p->au8[0]; break;
4269 case 2: *pu32 = p->au16[0]; break;
4270 case 4: *pu32 = p->au32[0]; break;
4271 //case 8: *pu32 = p->au64[0]; break;
4272 default: AssertFailed(); break;
4273 }
4274 Log(("vbeIOPortReadCMDLogo: LogoOffset=%#x(%d) cb=%#x %.*Rhxs\n", pThis->offLogoData, pThis->offLogoData, cb, cb, pu32));
4275
4276 pThis->LogoCommand = LOGO_CMD_NOP;
4277 pThis->offLogoData += cb;
4278
4279 return VINF_SUCCESS;
4280}
4281
4282/**
4283 * Info handler, device version. Dumps VGA memory formatted as
4284 * ASCII text, no attributes. Only looks at the first page.
4285 *
4286 * @param pDevIns Device instance which registered the info.
4287 * @param pHlp Callback functions for doing output.
4288 * @param pszArgs Argument string. Optional and specific to the handler.
4289 */
4290static DECLCALLBACK(void) vgaInfoText(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4291{
4292 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4293 uint8_t *src;
4294 unsigned row, col;
4295 unsigned num_rows = 25, num_cols = 80;
4296
4297 /* Pure paranoia... */
4298 Assert(num_rows * num_cols * 8 <= pThis->vram_size);
4299
4300 src = pThis->vram_ptrR3;
4301 if (src) {
4302 for (col = 0; col < num_cols; ++col) pHlp->pfnPrintf(pHlp, "-"); pHlp->pfnPrintf(pHlp, "\n");
4303 for (row = 0; row < num_rows; ++row)
4304 {
4305 for (col = 0; col < num_cols; ++col)
4306 {
4307 pHlp->pfnPrintf(pHlp, "%c", *src);
4308 src += 8; /* chars are spaced 8 bytes apart */
4309 }
4310 pHlp->pfnPrintf(pHlp, "\n");
4311 }
4312 for (col = 0; col < num_cols; ++col) pHlp->pfnPrintf(pHlp, "-"); pHlp->pfnPrintf(pHlp, "\n");
4313 }
4314 else
4315 {
4316 pHlp->pfnPrintf(pHlp, "VGA memory not available!\n");
4317 }
4318}
4319
4320/**
4321 * Info handler, device version. Dumps VGA Sequencer registers.
4322 *
4323 * @param pDevIns Device instance which registered the info.
4324 * @param pHlp Callback functions for doing output.
4325 * @param pszArgs Argument string. Optional and specific to the handler.
4326 */
4327static DECLCALLBACK(void) vgaInfoSR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4328{
4329 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4330 unsigned i;
4331
4332 pHlp->pfnPrintf(pHlp, "VGA Sequencer (3C5): SR index 3C4:%02X\n", s->sr_index);
4333 Assert(sizeof(s->sr) >= 8);
4334 for (i = 0; i < 5; ++i)
4335 {
4336 pHlp->pfnPrintf(pHlp, " SR%02X:%02X", i, s->sr[i]);
4337 }
4338 pHlp->pfnPrintf(pHlp, "\n");
4339}
4340
4341/**
4342 * Info handler, device version. Dumps VGA CRTC registers.
4343 *
4344 * @param pDevIns Device instance which registered the info.
4345 * @param pHlp Callback functions for doing output.
4346 * @param pszArgs Argument string. Optional and specific to the handler.
4347 */
4348static DECLCALLBACK(void) vgaInfoCR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4349{
4350 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4351 unsigned i;
4352
4353 pHlp->pfnPrintf(pHlp, "VGA CRTC (3D5): CRTC index 3D4:%02X\n", s->cr_index);
4354 Assert(sizeof(s->cr) >= 24);
4355 for (i = 0; i < 10; ++i)
4356 {
4357 pHlp->pfnPrintf(pHlp, " CR%02X:%02X", i, s->cr[i]);
4358 }
4359 pHlp->pfnPrintf(pHlp, "\n");
4360 for (i = 10; i < 20; ++i)
4361 {
4362 pHlp->pfnPrintf(pHlp, " CR%02X:%02X", i, s->cr[i]);
4363 }
4364 pHlp->pfnPrintf(pHlp, "\n");
4365 for (i = 20; i < 25; ++i)
4366 {
4367 pHlp->pfnPrintf(pHlp, " CR%02X:%02X", i, s->cr[i]);
4368 }
4369 pHlp->pfnPrintf(pHlp, "\n");
4370}
4371
4372/**
4373 * Info handler, device version. Dumps VGA Sequencer registers.
4374 *
4375 * @param pDevIns Device instance which registered the info.
4376 * @param pHlp Callback functions for doing output.
4377 * @param pszArgs Argument string. Optional and specific to the handler.
4378 */
4379static DECLCALLBACK(void) vgaInfoAR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4380{
4381 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4382 unsigned i;
4383
4384 pHlp->pfnPrintf(pHlp, "VGA Attribute Controller (3C0): index reg %02X, flip-flop: %d (%s)\n",
4385 s->ar_index, s->ar_flip_flop, s->ar_flip_flop ? "data" : "index" );
4386 Assert(sizeof(s->ar) >= 0x14);
4387 pHlp->pfnPrintf(pHlp, " Palette:");
4388 for (i = 0; i < 0x10; ++i)
4389 {
4390 pHlp->pfnPrintf(pHlp, " %02X", i, s->ar[i]);
4391 }
4392 pHlp->pfnPrintf(pHlp, "\n");
4393 for (i = 0x10; i <= 0x14; ++i)
4394 {
4395 pHlp->pfnPrintf(pHlp, " AR%02X:%02X", i, s->ar[i]);
4396 }
4397 pHlp->pfnPrintf(pHlp, "\n");
4398}
4399
4400/**
4401 * Info handler, device version. Dumps VGA DAC registers.
4402 *
4403 * @param pDevIns Device instance which registered the info.
4404 * @param pHlp Callback functions for doing output.
4405 * @param pszArgs Argument string. Optional and specific to the handler.
4406 */
4407static DECLCALLBACK(void) vgaInfoDAC(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4408{
4409 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4410 unsigned i;
4411
4412 pHlp->pfnPrintf(pHlp, "VGA DAC contents:\n");
4413 for (i = 0; i < 0x100; ++i)
4414 {
4415 pHlp->pfnPrintf(pHlp, " %02X: %02X %02X %02X\n",
4416 i, s->palette[i*3+0], s->palette[i*3+1], s->palette[i*3+2]);
4417 }
4418}
4419
4420
4421/* -=-=-=-=-=- Ring 3: IBase -=-=-=-=-=- */
4422
4423/**
4424 * Queries an interface to the driver.
4425 *
4426 * @returns Pointer to interface.
4427 * @returns NULL if the interface was not supported by the driver.
4428 * @param pInterface Pointer to this interface structure.
4429 * @param enmInterface The requested interface identification.
4430 * @thread Any thread.
4431 */
4432static DECLCALLBACK(void *) vgaPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
4433{
4434 PVGASTATE pThis = (PVGASTATE)((uintptr_t)pInterface - RT_OFFSETOF(VGASTATE, Base));
4435 switch (enmInterface)
4436 {
4437 case PDMINTERFACE_BASE:
4438 return &pThis->Base;
4439 case PDMINTERFACE_DISPLAY_PORT:
4440 return &pThis->Port;
4441 default:
4442 return NULL;
4443 }
4444}
4445
4446
4447/* -=-=-=-=-=- Ring 3: Dummy IDisplayConnector -=-=-=-=-=- */
4448
4449/**
4450 * Resize the display.
4451 * This is called when the resolution changes. This usually happens on
4452 * request from the guest os, but may also happen as the result of a reset.
4453 *
4454 * @param pInterface Pointer to this interface.
4455 * @param cx New display width.
4456 * @param cy New display height
4457 * @thread The emulation thread.
4458 */
4459static DECLCALLBACK(int) vgaDummyResize(PPDMIDISPLAYCONNECTOR pInterface, uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
4460{
4461 return VINF_SUCCESS;
4462}
4463
4464
4465/**
4466 * Update a rectangle of the display.
4467 * PDMIDISPLAYPORT::pfnUpdateDisplay is the caller.
4468 *
4469 * @param pInterface Pointer to this interface.
4470 * @param x The upper left corner x coordinate of the rectangle.
4471 * @param y The upper left corner y coordinate of the rectangle.
4472 * @param cx The width of the rectangle.
4473 * @param cy The height of the rectangle.
4474 * @thread The emulation thread.
4475 */
4476static DECLCALLBACK(void) vgaDummyUpdateRect(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
4477{
4478}
4479
4480
4481/**
4482 * Refresh the display.
4483 *
4484 * The interval between these calls is set by
4485 * PDMIDISPLAYPORT::pfnSetRefreshRate(). The driver should call
4486 * PDMIDISPLAYPORT::pfnUpdateDisplay() if it wishes to refresh the
4487 * display. PDMIDISPLAYPORT::pfnUpdateDisplay calls pfnUpdateRect with
4488 * the changed rectangles.
4489 *
4490 * @param pInterface Pointer to this interface.
4491 * @thread The emulation thread.
4492 */
4493static DECLCALLBACK(void) vgaDummyRefresh(PPDMIDISPLAYCONNECTOR pInterface)
4494{
4495}
4496
4497
4498/* -=-=-=-=-=- Ring 3: IDisplayPort -=-=-=-=-=- */
4499
4500/** Converts a display port interface pointer to a vga state pointer. */
4501#define IDISPLAYPORT_2_VGASTATE(pInterface) ( (PVGASTATE)((uintptr_t)pInterface - RT_OFFSETOF(VGASTATE, Port)) )
4502
4503
4504/**
4505 * Update the display with any changed regions.
4506 *
4507 * @param pInterface Pointer to this interface.
4508 * @see PDMIKEYBOARDPORT::pfnUpdateDisplay() for details.
4509 */
4510static DECLCALLBACK(int) vgaPortUpdateDisplay(PPDMIDISPLAYPORT pInterface)
4511{
4512 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4513 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4514 PPDMDEVINS pDevIns = pThis->CTX_SUFF(pDevIns);
4515
4516 /* This should be called only in non VBVA mode. */
4517
4518 int rc = vga_update_display(pThis);
4519 if (rc != VINF_SUCCESS)
4520 return rc;
4521
4522 if (pThis->fHasDirtyBits && pThis->GCPhysVRAM && pThis->GCPhysVRAM != NIL_RTGCPHYS32)
4523 {
4524 PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
4525 pThis->fHasDirtyBits = false;
4526 }
4527 if (pThis->fRemappedVGA)
4528 {
4529 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000);
4530 pThis->fRemappedVGA = false;
4531 }
4532
4533 return VINF_SUCCESS;
4534}
4535
4536
4537/**
4538 * Update the entire display.
4539 *
4540 * @param pInterface Pointer to this interface.
4541 * @see PDMIKEYBOARDPORT::pfnUpdateDisplayAll() for details.
4542 */
4543static DECLCALLBACK(int) vgaPortUpdateDisplayAll(PPDMIDISPLAYPORT pInterface)
4544{
4545 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4546 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4547 PPDMDEVINS pDevIns = pThis->CTX_SUFF(pDevIns);
4548
4549 /* This is called both in VBVA mode and normal modes. */
4550
4551#ifdef DEBUG_sunlover
4552 LogFlow(("vgaPortUpdateDisplayAll\n"));
4553#endif /* DEBUG_sunlover */
4554
4555 pThis->graphic_mode = -1; /* force full update */
4556
4557 int rc = vga_update_display(pThis);
4558
4559 /* The dirty bits array has been just cleared, reset handlers as well. */
4560 if (pThis->GCPhysVRAM && pThis->GCPhysVRAM != NIL_RTGCPHYS32)
4561 {
4562 PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
4563 }
4564 if (pThis->fRemappedVGA)
4565 {
4566 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000);
4567 pThis->fRemappedVGA = false;
4568 }
4569
4570 return rc;
4571}
4572
4573
4574/**
4575 * Sets the refresh rate and restart the timer.
4576 *
4577 * @returns VBox status code.
4578 * @param pInterface Pointer to this interface.
4579 * @param cMilliesInterval Number of millies between two refreshes.
4580 * @see PDMIKEYBOARDPORT::pfnSetRefreshRate() for details.
4581 */
4582static DECLCALLBACK(int) vgaPortSetRefreshRate(PPDMIDISPLAYPORT pInterface, uint32_t cMilliesInterval)
4583{
4584 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4585
4586 pThis->cMilliesRefreshInterval = cMilliesInterval;
4587 if (cMilliesInterval)
4588 return TMTimerSetMillies(pThis->RefreshTimer, cMilliesInterval);
4589 return TMTimerStop(pThis->RefreshTimer);
4590}
4591
4592
4593/** @copydoc PDMIDISPLAYPORT::pfnQueryColorDepth */
4594static DECLCALLBACK(int) vgaPortQueryColorDepth(PPDMIDISPLAYPORT pInterface, uint32_t *pcBits)
4595{
4596 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4597
4598 if (!pcBits)
4599 return VERR_INVALID_PARAMETER;
4600 *pcBits = vga_get_bpp(pThis);
4601 return VINF_SUCCESS;
4602}
4603
4604/**
4605 * Create a 32-bbp snapshot of the display.
4606 *
4607 * @param pInterface Pointer to this interface.
4608 * @param pvData Pointer the buffer to copy the bits to.
4609 * @param cbData Size of the buffer.
4610 * @param pcx Where to store the width of the bitmap. (optional)
4611 * @param pcy Where to store the height of the bitmap. (optional)
4612 * @param pcbData Where to store the actual size of the bitmap. (optional)
4613 * @see PDMIKEYBOARDPORT::pfnSnapshot() for details.
4614 */
4615static DECLCALLBACK(int) vgaPortSnapshot(PPDMIDISPLAYPORT pInterface, void *pvData, size_t cbData, uint32_t *pcx, uint32_t *pcy, size_t *pcbData)
4616{
4617 /* @todo r=sunlover: replace the method with a direct VRAM rendering like in vgaPortUpdateDisplayRect. */
4618 PPDMIDISPLAYCONNECTOR pConnector;
4619 PDMIDISPLAYCONNECTOR Connector;
4620 int32_t graphic_mode;
4621 bool fRenderVRAM;
4622 size_t cbRequired;
4623 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4624 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4625 LogFlow(("vgaPortSnapshot: pvData=%p cbData=%d pcx=%p pcy=%p pcbData=%p\n", pvData, cbData, pcx, pcy, pcbData));
4626
4627 /*
4628 * Validate input.
4629 */
4630 if (!pvData)
4631 return VERR_INVALID_PARAMETER;
4632
4633 /*
4634 * Do a regular refresh first to resolve any pending resize issues.
4635 *
4636 * 20060317 It used to be pfnUpdateDisplay, but by VBVA design
4637 * only pfnUpdateDisplayAll is allowed to be called in VBVA mode.
4638 * Also since the goal here is to have updated display for screenshot,
4639 * the UpdateDisplayAll is even more logical to call. (sunlover)
4640 */
4641 pInterface->pfnUpdateDisplayAll(pInterface);
4642
4643 /*
4644 * Validate the buffer size.
4645 */
4646 cbRequired = RT_ALIGN_Z(pThis->last_scr_width, 4) * pThis->last_scr_height * 4;
4647 if (cbRequired > cbData)
4648 {
4649 Log(("vgaPortSnapshot: %d bytes are required, a buffer of %d bytes is profiled.\n", cbRequired, cbData));
4650 return VERR_BUFFER_OVERFLOW;
4651 }
4652
4653 /*
4654 * Temporarily replace the display connector interface with a fake one.
4655 */
4656 Connector.pu8Data = (uint8_t*)pvData;
4657 Connector.cBits = 32;
4658 Connector.cx = pThis->pDrv->cx;
4659 Connector.cy = pThis->pDrv->cy;
4660 Connector.cbScanline = RT_ALIGN_32(Connector.cx, 4) * 4;
4661 Connector.pfnRefresh = vgaDummyRefresh;
4662 Connector.pfnResize = vgaDummyResize;
4663 Connector.pfnUpdateRect = vgaDummyUpdateRect;
4664
4665 /* save & replace state data. */
4666 pConnector = pThis->pDrv;
4667 pThis->pDrv = &Connector;
4668 graphic_mode = pThis->graphic_mode;
4669 pThis->graphic_mode = -1; /* force a full refresh. */
4670 fRenderVRAM = pThis->fRenderVRAM;
4671 pThis->fRenderVRAM = 1; /* force the guest VRAM rendering to the given buffer. */
4672
4673 /* make the snapshot. */
4674 int rc = vga_update_display(pThis);
4675
4676 /* restore */
4677 pThis->pDrv = pConnector;
4678 pThis->graphic_mode = graphic_mode;
4679 pThis->fRenderVRAM = fRenderVRAM;
4680
4681 if (rc != VINF_SUCCESS)
4682 return rc;
4683
4684 /*
4685 * Return the result.
4686 */
4687 if (pcx)
4688 *pcx = Connector.cx;
4689 if (pcy)
4690 *pcy = Connector.cy;
4691 if (pcbData)
4692 *pcbData = cbRequired;
4693 LogFlow(("vgaPortSnapshot: returns VINF_SUCCESS (cx=%d cy=%d cbData=%d)\n", Connector.cx, Connector.cy, cbRequired));
4694 return VINF_SUCCESS;
4695}
4696
4697
4698/**
4699 * Copy bitmap to the display.
4700 *
4701 * @param pInterface Pointer to this interface.
4702 * @param pvData Pointer to the bitmap bits.
4703 * @param x The upper left corner x coordinate of the destination rectangle.
4704 * @param y The upper left corner y coordinate of the destination rectangle.
4705 * @param cx The width of the source and destination rectangles.
4706 * @param cy The height of the source and destination rectangles.
4707 * @see PDMIDISPLAYPORT::pfnDisplayBlt() for details.
4708 */
4709static DECLCALLBACK(int) vgaPortDisplayBlt(PPDMIDISPLAYPORT pInterface, const void *pvData, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
4710{
4711 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4712 int rc = VINF_SUCCESS;
4713 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4714 LogFlow(("vgaPortDisplayBlt: pvData=%p x=%d y=%d cx=%d cy=%d\n", pvData, x, y, cx, cy));
4715
4716 /*
4717 * Validate input.
4718 */
4719 if ( pvData
4720 && x < pThis->pDrv->cx
4721 && cx <= pThis->pDrv->cx
4722 && cx + x <= pThis->pDrv->cx
4723 && y < pThis->pDrv->cy
4724 && cy <= pThis->pDrv->cy
4725 && cy + y <= pThis->pDrv->cy)
4726 {
4727 /*
4728 * Determin bytes per pixel in the destination buffer.
4729 */
4730 size_t cbPixelDst = 0;
4731 switch (pThis->pDrv->cBits)
4732 {
4733 case 8:
4734 cbPixelDst = 1;
4735 break;
4736 case 15:
4737 case 16:
4738 cbPixelDst = 2;
4739 break;
4740 case 24:
4741 cbPixelDst = 3;
4742 break;
4743 case 32:
4744 cbPixelDst = 4;
4745 break;
4746 default:
4747 rc = VERR_INVALID_PARAMETER;
4748 break;
4749 }
4750 if (RT_SUCCESS(rc))
4751 {
4752 /*
4753 * The blitting loop.
4754 */
4755 size_t cbLineSrc = RT_ALIGN_Z(cx, 4) * 4;
4756 uint8_t *pu8Src = (uint8_t *)pvData;
4757 size_t cbLineDst = pThis->pDrv->cbScanline;
4758 uint8_t *pu8Dst = pThis->pDrv->pu8Data + y * cbLineDst + x * cbPixelDst;
4759 uint32_t cyLeft = cy;
4760 vga_draw_line_func *pfnVgaDrawLine = vga_draw_line_table[VGA_DRAW_LINE32 * 4 + get_depth_index(pThis->pDrv->cBits)];
4761 Assert(pfnVgaDrawLine);
4762 while (cyLeft-- > 0)
4763 {
4764 pfnVgaDrawLine(pThis, pu8Dst, pu8Src, cx);
4765 pu8Dst += cbLineDst;
4766 pu8Src += cbLineSrc;
4767 }
4768
4769 /*
4770 * Invalidate the area.
4771 */
4772 pThis->pDrv->pfnUpdateRect(pThis->pDrv, x, y, cx, cy);
4773 }
4774 }
4775 else
4776 rc = VERR_INVALID_PARAMETER;
4777
4778 LogFlow(("vgaPortDisplayBlt: returns %Rrc\n", rc));
4779 return rc;
4780}
4781
4782static DECLCALLBACK(void) vgaPortUpdateDisplayRect (PPDMIDISPLAYPORT pInterface, int32_t x, int32_t y, uint32_t w, uint32_t h)
4783{
4784 uint32_t v;
4785 vga_draw_line_func *vga_draw_line;
4786
4787 uint32_t cbPixelDst;
4788 uint32_t cbLineDst;
4789 uint8_t *pu8Dst;
4790
4791 uint32_t cbPixelSrc;
4792 uint32_t cbLineSrc;
4793 uint8_t *pu8Src;
4794
4795 uint32_t u32OffsetSrc, u32Dummy;
4796
4797 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
4798
4799#ifdef DEBUG_sunlover
4800 LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d\n", x, y, w, h));
4801#endif /* DEBUG_sunlover */
4802
4803 Assert(pInterface);
4804 Assert(s->pDrv);
4805 Assert(s->pDrv->pu8Data);
4806
4807 /* Check if there is something to do at all. */
4808 if (!s->fRenderVRAM)
4809 {
4810 /* The framebuffer uses the guest VRAM directly. */
4811#ifdef DEBUG_sunlover
4812 LogFlow(("vgaPortUpdateDisplayRect: nothing to do fRender is false.\n"));
4813#endif /* DEBUG_sunlover */
4814 return;
4815 }
4816
4817 /* Correct negative x and y coordinates. */
4818 if (x < 0)
4819 {
4820 x += w; /* Compute xRight which is also the new width. */
4821 w = (x < 0) ? 0 : x;
4822 x = 0;
4823 }
4824
4825 if (y < 0)
4826 {
4827 y += h; /* Compute yBottom, which is also the new height. */
4828 h = (y < 0) ? 0 : y;
4829 y = 0;
4830 }
4831
4832 /* Also check if coords are greater than the display resolution. */
4833 if (x + w > s->pDrv->cx)
4834 {
4835#ifndef VBOX
4836 w = s->pDrv->cx > x? s->pDrv->cx - x: 0;
4837#else
4838 // x < 0 is not possible here
4839 w = s->pDrv->cx > (uint32_t)x? s->pDrv->cx - x: 0;
4840#endif
4841 }
4842
4843 if (y + h > s->pDrv->cy)
4844 {
4845#ifndef VBOX
4846 h = s->pDrv->cy > y? s->pDrv->cy - y: 0;
4847#else
4848 // y < 0 is not possible here
4849 h = s->pDrv->cy > (uint32_t)y? s->pDrv->cy - y: 0;
4850#endif
4851 }
4852
4853#ifdef DEBUG_sunlover
4854 LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d (corrected coords)\n", x, y, w, h));
4855#endif /* DEBUG_sunlover */
4856
4857 /* Check if there is something to do at all. */
4858 if (w == 0 || h == 0)
4859 {
4860 /* Empty rectangle. */
4861#ifdef DEBUG_sunlover
4862 LogFlow(("vgaPortUpdateDisplayRect: nothing to do: %dx%d\n", w, h));
4863#endif /* DEBUG_sunlover */
4864 return;
4865 }
4866
4867 /** @todo This method should be made universal and not only for VBVA.
4868 * VGA_DRAW_LINE* must be selected and src/dst address calculation
4869 * changed.
4870 */
4871
4872 /* Choose the rendering function. */
4873 switch(s->get_bpp(s))
4874 {
4875 default:
4876 case 0:
4877 /* A LFB mode is already disabled, but the callback is still called
4878 * by Display because VBVA buffer is being flushed.
4879 * Nothing to do, just return.
4880 */
4881 return;
4882 case 8:
4883 v = VGA_DRAW_LINE8;
4884 break;
4885 case 15:
4886 v = VGA_DRAW_LINE15;
4887 break;
4888 case 16:
4889 v = VGA_DRAW_LINE16;
4890 break;
4891 case 24:
4892 v = VGA_DRAW_LINE24;
4893 break;
4894 case 32:
4895 v = VGA_DRAW_LINE32;
4896 break;
4897 }
4898
4899 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->pDrv->cBits)];
4900
4901 /* Compute source and destination addresses and pitches. */
4902 cbPixelDst = (s->pDrv->cBits + 7) / 8;
4903 cbLineDst = s->pDrv->cbScanline;
4904 pu8Dst = s->pDrv->pu8Data + y * cbLineDst + x * cbPixelDst;
4905
4906 cbPixelSrc = (s->get_bpp(s) + 7) / 8;
4907 s->get_offsets (s, &cbLineSrc, &u32OffsetSrc, &u32Dummy);
4908
4909 /* Assume that rendering is performed only on visible part of VRAM.
4910 * This is true because coordinates were verified.
4911 */
4912 pu8Src = s->vram_ptrR3;
4913 pu8Src += u32OffsetSrc + y * cbLineSrc + x * cbPixelSrc;
4914
4915 /* Render VRAM to framebuffer. */
4916
4917#ifdef DEBUG_sunlover
4918 LogFlow(("vgaPortUpdateDisplayRect: dst: %p, %d, %d. src: %p, %d, %d\n", pu8Dst, cbLineDst, cbPixelDst, pu8Src, cbLineSrc, cbPixelSrc));
4919#endif /* DEBUG_sunlover */
4920
4921 while (h-- > 0)
4922 {
4923 vga_draw_line (s, pu8Dst, pu8Src, w);
4924 pu8Dst += cbLineDst;
4925 pu8Src += cbLineSrc;
4926 }
4927
4928#ifdef DEBUG_sunlover
4929 LogFlow(("vgaPortUpdateDisplayRect: completed.\n"));
4930#endif /* DEBUG_sunlover */
4931}
4932
4933static DECLCALLBACK(void) vgaPortSetRenderVRAM(PPDMIDISPLAYPORT pInterface, bool fRender)
4934{
4935 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
4936
4937 LogFlow(("vgaPortSetRenderVRAM: fRender = %d\n", fRender));
4938
4939 s->fRenderVRAM = fRender;
4940}
4941
4942
4943static DECLCALLBACK(void) vgaTimerRefresh(PPDMDEVINS pDevIns, PTMTIMER pTimer)
4944{
4945 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4946 if (pThis->pDrv)
4947 pThis->pDrv->pfnRefresh(pThis->pDrv);
4948 if (pThis->cMilliesRefreshInterval)
4949 TMTimerSetMillies(pTimer, pThis->cMilliesRefreshInterval);
4950}
4951
4952
4953/* -=-=-=-=-=- Ring 3: PCI Device -=-=-=-=-=- */
4954
4955/**
4956 * Callback function for unmapping and/or mapping the VRAM MMIO2 region (called by the PCI bus).
4957 *
4958 * @return VBox status code.
4959 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
4960 * @param iRegion The region number.
4961 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
4962 * I/O port, else it's a physical address.
4963 * This address is *NOT* relative to pci_mem_base like earlier!
4964 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
4965 */
4966static DECLCALLBACK(int) vgaR3IORegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
4967{
4968 int rc;
4969 PPDMDEVINS pDevIns = pPciDev->pDevIns;
4970 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4971 LogFlow(("vgaR3IORegionMap: iRegion=%d GCPhysAddress=%RGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
4972 AssertReturn(iRegion == 0 && enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
4973
4974 if (GCPhysAddress != NIL_RTGCPHYS)
4975 {
4976 /*
4977 * Mapping the VRAM.
4978 */
4979 rc = PDMDevHlpMMIO2Map(pDevIns, iRegion, GCPhysAddress);
4980 AssertRC(rc);
4981 if (RT_SUCCESS(rc))
4982 {
4983 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
4984 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
4985 GCPhysAddress, GCPhysAddress + (pThis->vram_size - 1),
4986 vgaR3LFBAccessHandler, pThis,
4987 g_DeviceVga.szR0Mod, "vgaR0LFBAccessHandler", pDevIns->pvInstanceDataR0,
4988 g_DeviceVga.szRCMod, "vgaGCLFBAccessHandler", pDevIns->pvInstanceDataRC,
4989 "VGA LFB");
4990 AssertRC(rc);
4991 if (RT_SUCCESS(rc))
4992 pThis->GCPhysVRAM = GCPhysAddress;
4993 }
4994 }
4995 else
4996 {
4997 /*
4998 * Unmapping of the VRAM in progress.
4999 * Deregister the access handler so PGM doesn't get upset.
5000 */
5001 Assert(pThis->GCPhysVRAM);
5002 rc = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
5003 AssertRC(rc);
5004 pThis->GCPhysVRAM = 0;
5005 }
5006 return rc;
5007}
5008
5009
5010/* -=-=-=-=-=- Ring3: Misc Wrappers -=-=-=-=-=- */
5011
5012/**
5013 * Saves a state of the VGA device.
5014 *
5015 * @returns VBox status code.
5016 * @param pDevIns The device instance.
5017 * @param pSSMHandle The handle to save the state to.
5018 */
5019static DECLCALLBACK(int) vgaR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
5020{
5021 vga_save(pSSMHandle, PDMINS_2_DATA(pDevIns, PVGASTATE));
5022 return VINF_SUCCESS;
5023}
5024
5025
5026/**
5027 * Loads a saved VGA device state.
5028 *
5029 * @returns VBox status code.
5030 * @param pDevIns The device instance.
5031 * @param pSSMHandle The handle to the saved state.
5032 * @param u32Version The data unit version number.
5033 */
5034static DECLCALLBACK(int) vgaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
5035{
5036 if (vga_load(pSSMHandle, PDMINS_2_DATA(pDevIns, PVGASTATE), u32Version))
5037 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
5038 return VINF_SUCCESS;
5039}
5040
5041
5042/* -=-=-=-=-=- Ring 3: Device callbacks -=-=-=-=-=- */
5043
5044/**
5045 * Reset notification.
5046 *
5047 * @returns VBox status.
5048 * @param pDevIns The device instance data.
5049 */
5050static DECLCALLBACK(void) vgaR3Reset(PPDMDEVINS pDevIns)
5051{
5052 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5053 char *pchStart;
5054 char *pchEnd;
5055 LogFlow(("vgaReset\n"));
5056
5057 /* Clear the VRAM ourselves. */
5058 if (pThis->vram_ptrR3 && pThis->vram_size)
5059 {
5060#ifdef LOG_ENABLED /** @todo separate function. */
5061 /* First dump the textmode contents to the log; handy for capturing Windows blue screens. */
5062 uint8_t graphic_mode;
5063 VGAState *s = pThis;
5064
5065 if (!(s->ar_index & 0x20)) {
5066 graphic_mode = GMODE_BLANK;
5067 } else {
5068 graphic_mode = s->gr[6] & 1;
5069 }
5070 switch(graphic_mode)
5071 case GMODE_TEXT:
5072 {
5073 int cw, height, width, cheight, cx_min, cx_max, cy, cx;
5074 int x_incr;
5075 uint8_t *s1, *src, ch, cattr;
5076 int line_offset;
5077 uint16_t ch_attr;
5078
5079 line_offset = s->line_offset;
5080 s1 = s->CTX_SUFF(vram_ptr) + (s->start_addr * 4);
5081
5082 /* total width & height */
5083 cheight = (s->cr[9] & 0x1f) + 1;
5084 cw = 8;
5085 if (!(s->sr[1] & 0x01))
5086 cw = 9;
5087 if (s->sr[1] & 0x08)
5088 cw = 16; /* NOTE: no 18 pixel wide */
5089 x_incr = cw * ((s->pDrv->cBits + 7) >> 3);
5090 width = (s->cr[0x01] + 1);
5091 if (s->cr[0x06] == 100) {
5092 /* ugly hack for CGA 160x100x16 - explain me the logic */
5093 height = 100;
5094 } else {
5095 height = s->cr[0x12] |
5096 ((s->cr[0x07] & 0x02) << 7) |
5097 ((s->cr[0x07] & 0x40) << 3);
5098 height = (height + 1) / cheight;
5099 }
5100 if ((height * width) > CH_ATTR_SIZE) {
5101 /* better than nothing: exit if transient size is too big */
5102 break;
5103 }
5104 RTLogPrintf("VGA textmode BEGIN (%dx%d):\n\n", height, width);
5105 for(cy = 0; cy < height; cy++) {
5106 src = s1;
5107 cx_min = width;
5108 cx_max = -1;
5109 for(cx = 0; cx < width; cx++) {
5110 ch_attr = *(uint16_t *)src;
5111 if (cx < cx_min)
5112 cx_min = cx;
5113 if (cx > cx_max)
5114 cx_max = cx;
5115# ifdef WORDS_BIGENDIAN
5116 ch = ch_attr >> 8;
5117 cattr = ch_attr & 0xff;
5118# else
5119 ch = ch_attr & 0xff;
5120 cattr = ch_attr >> 8;
5121# endif
5122 RTLogPrintf("%c", ch);
5123
5124 src += 4;
5125 }
5126 if (cx_max != -1)
5127 RTLogPrintf("\n");
5128
5129 s1 += line_offset;
5130 }
5131 RTLogPrintf("VGA textmode END:\n\n");
5132 }
5133
5134#endif /* LOG_ENABLED */
5135 memset(pThis->vram_ptrR3, 0, pThis->vram_size);
5136 }
5137
5138 /*
5139 * Zero most of it.
5140 *
5141 * Unlike vga_reset we're leaving out a few members which we believe
5142 * must remain unchanged....
5143 */
5144 /* 1st part. */
5145 pchStart = (char *)&pThis->latch;
5146 pchEnd = (char *)&pThis->invalidated_y_table;
5147 memset(pchStart, 0, pchEnd - pchStart);
5148
5149 /* 2nd part. */
5150 pchStart = (char *)&pThis->last_palette;
5151 pchEnd = (char *)&pThis->u32Marker;
5152 memset(pchStart, 0, pchEnd - pchStart);
5153
5154
5155 /*
5156 * Restore and re-init some bits.
5157 */
5158 pThis->get_bpp = vga_get_bpp;
5159 pThis->get_offsets = vga_get_offsets;
5160 pThis->get_resolution = vga_get_resolution;
5161 pThis->graphic_mode = -1; /* Force full update. */
5162#ifdef CONFIG_BOCHS_VBE
5163 pThis->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
5164 pThis->vbe_regs[VBE_DISPI_INDEX_VBOX_VIDEO] = 0;
5165 pThis->vbe_bank_max = pThis->vram_size >> 16;
5166#endif /* CONFIG_BOCHS_VBE */
5167
5168 /*
5169 * Reset the LBF mapping.
5170 */
5171 pThis->fLFBUpdated = false;
5172 if ( ( pThis->fGCEnabled
5173 || pThis->fR0Enabled)
5174 && pThis->GCPhysVRAM
5175 && pThis->GCPhysVRAM != NIL_RTGCPHYS32)
5176 {
5177 int rc = PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
5178 AssertRC(rc);
5179 }
5180 if (pThis->fRemappedVGA)
5181 {
5182 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000);
5183 pThis->fRemappedVGA = false;
5184 }
5185
5186 /*
5187 * Reset the logo data.
5188 */
5189 pThis->LogoCommand = LOGO_CMD_NOP;
5190 pThis->offLogoData = 0;
5191
5192 /* notify port handler */
5193 if (pThis->pDrv)
5194 pThis->pDrv->pfnReset(pThis->pDrv);
5195}
5196
5197
5198/**
5199 * Device relocation callback.
5200 *
5201 * @param pDevIns Pointer to the device instance.
5202 * @param offDelta The relocation delta relative to the old location.
5203 *
5204 * @see FNPDMDEVRELOCATE for details.
5205 */
5206static DECLCALLBACK(void) vgaR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
5207{
5208 if (offDelta)
5209 {
5210 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5211 LogFlow(("vgaRelocate: offDelta = %08X\n", offDelta));
5212
5213 pThis->RCPtrLFBHandler += offDelta;
5214 pThis->vram_ptrRC += offDelta;
5215 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5216 }
5217}
5218
5219
5220/**
5221 * Attach command.
5222 *
5223 * This is called to let the device attach to a driver for a specified LUN
5224 * during runtime. This is not called during VM construction, the device
5225 * constructor have to attach to all the available drivers.
5226 *
5227 * This is like plugging in the monitor after turning on the PC.
5228 *
5229 * @returns VBox status code.
5230 * @param pDevIns The device instance.
5231 * @param iLUN The logical unit which is being detached.
5232 */
5233static DECLCALLBACK(int) vgaAttach(PPDMDEVINS pDevIns, unsigned iLUN)
5234{
5235 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5236 switch (iLUN)
5237 {
5238 /* LUN #0: Display port. */
5239 case 0:
5240 {
5241 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Base, &pThis->pDrvBase, "Display Port");
5242 if (RT_SUCCESS(rc))
5243 {
5244 pThis->pDrv = (PDMIDISPLAYCONNECTOR*)pThis->pDrvBase->pfnQueryInterface(pThis->pDrvBase, PDMINTERFACE_DISPLAY_CONNECTOR);
5245 if (pThis->pDrv)
5246 {
5247 /* pThis->pDrv->pu8Data can be NULL when there is no framebuffer. */
5248 if ( pThis->pDrv->pfnRefresh
5249 && pThis->pDrv->pfnResize
5250 && pThis->pDrv->pfnUpdateRect)
5251 rc = VINF_SUCCESS;
5252 else
5253 {
5254 Assert(pThis->pDrv->pfnRefresh);
5255 Assert(pThis->pDrv->pfnResize);
5256 Assert(pThis->pDrv->pfnUpdateRect);
5257 pThis->pDrv = NULL;
5258 pThis->pDrvBase = NULL;
5259 rc = VERR_INTERNAL_ERROR;
5260 }
5261 }
5262 else
5263 {
5264 AssertMsgFailed(("LUN #0 doesn't have a display connector interface! rc=%Rrc\n", rc));
5265 pThis->pDrvBase = NULL;
5266 rc = VERR_PDM_MISSING_INTERFACE;
5267 }
5268 }
5269 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5270 {
5271 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
5272 rc = VINF_SUCCESS;
5273 }
5274 else
5275 AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
5276 return rc;
5277 }
5278
5279 default:
5280 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
5281 return VERR_PDM_NO_SUCH_LUN;
5282 }
5283}
5284
5285
5286/**
5287 * Detach notification.
5288 *
5289 * This is called when a driver is detaching itself from a LUN of the device.
5290 * The device should adjust it's state to reflect this.
5291 *
5292 * This is like unplugging the monitor while the PC is still running.
5293 *
5294 * @param pDevIns The device instance.
5295 * @param iLUN The logical unit which is being detached.
5296 */
5297static DECLCALLBACK(void) vgaDetach(PPDMDEVINS pDevIns, unsigned iLUN)
5298{
5299 /*
5300 * Reset the interfaces and update the controller state.
5301 */
5302 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5303 switch (iLUN)
5304 {
5305 /* LUN #0: Display port. */
5306 case 0:
5307 pThis->pDrv = NULL;
5308 pThis->pDrvBase = NULL;
5309 break;
5310
5311 default:
5312 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
5313 break;
5314 }
5315}
5316
5317
5318
5319/**
5320 * Construct a VGA device instance for a VM.
5321 *
5322 * @returns VBox status.
5323 * @param pDevIns The device instance data.
5324 * If the registration structure is needed, pDevIns->pDevReg points to it.
5325 * @param iInstance Instance number. Use this to figure out which registers and such to use.
5326 * The device number is also found in pDevIns->iInstance, but since it's
5327 * likely to be freqently used PDM passes it as parameter.
5328 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
5329 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
5330 * iInstance it's expected to be used a bit in this function.
5331 */
5332static DECLCALLBACK(int) vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
5333{
5334 static bool s_fExpandDone = false;
5335 int rc;
5336 unsigned i;
5337 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5338 PVM pVM = PDMDevHlpGetVM(pDevIns);
5339#ifdef VBE_NEW_DYN_LIST
5340 uint32_t cCustomModes;
5341 uint32_t cyReduction;
5342 PVBEHEADER pVBEDataHdr;
5343 ModeInfoListItem *pCurMode;
5344 unsigned cb;
5345#endif
5346 Assert(iInstance == 0);
5347 Assert(pVM);
5348
5349 /*
5350 * Init static data.
5351 */
5352 if (!s_fExpandDone)
5353 {
5354 s_fExpandDone = true;
5355 vga_init_expand();
5356 }
5357
5358 /*
5359 * Validate configuration.
5360 */
5361 if (!CFGMR3AreValuesValid(pCfgHandle, "VRamSize\0"
5362 "GCEnabled\0"
5363 "R0Enabled\0"
5364 "FadeIn\0"
5365 "FadeOut\0"
5366 "LogoTime\0"
5367 "LogoFile\0"
5368 "ShowBootMenu\0"
5369 "CustomVideoModes\0"
5370 "HeightReduction\0"
5371 "CustomVideoMode1\0"
5372 "CustomVideoMode2\0"
5373 "CustomVideoMode3\0"
5374 "CustomVideoMode4\0"
5375 "CustomVideoMode5\0"
5376 "CustomVideoMode6\0"
5377 "CustomVideoMode7\0"
5378 "CustomVideoMode8\0"
5379 "CustomVideoMode9\0"
5380 "CustomVideoMode10\0"
5381 "CustomVideoMode11\0"
5382 "CustomVideoMode12\0"
5383 "CustomVideoMode13\0"
5384 "CustomVideoMode14\0"
5385 "CustomVideoMode15\0"
5386 "CustomVideoMode16\0"))
5387 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
5388 N_("Invalid configuration for vga device"));
5389
5390 /*
5391 * Init state data.
5392 */
5393 rc = CFGMR3QueryU32Def(pCfgHandle, "VRamSize", &pThis->vram_size, VGA_VRAM_DEFAULT);
5394 AssertLogRelRCReturn(rc, rc);
5395 if (pThis->vram_size > VGA_VRAM_MAX)
5396 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
5397 "VRamSize is too large, %#x, max %#x", pThis->vram_size, VGA_VRAM_MAX);
5398 if (pThis->vram_size < VGA_VRAM_MIN)
5399 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
5400 "VRamSize is too small, %#x, max %#x", pThis->vram_size, VGA_VRAM_MIN);
5401
5402 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &pThis->fGCEnabled, true);
5403 AssertLogRelRCReturn(rc, rc);
5404
5405 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &pThis->fR0Enabled, true);
5406 AssertLogRelRCReturn(rc, rc);
5407 Log(("VGA: VRamSize=%#x fGCenabled=%RTbool fR0Enabled=%RTbool\n", pThis->vram_size, pThis->fGCEnabled, pThis->fR0Enabled));
5408
5409 pThis->pDevInsR3 = pDevIns;
5410 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
5411 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5412
5413 vgaR3Reset(pDevIns);
5414
5415 /* The PCI devices configuration. */
5416 PCIDevSetVendorId( &pThis->Dev, 0x80ee); /* PCI vendor, just a free bogus value */
5417 PCIDevSetDeviceId( &pThis->Dev, 0xbeef);
5418 PCIDevSetClassSub( &pThis->Dev, 0x00); /* VGA controller */
5419 PCIDevSetClassBase( &pThis->Dev, 0x03);
5420 PCIDevSetHeaderType(&pThis->Dev, 0x00);
5421
5422 /* The LBF access handler - error handling is better here than in the map function. */
5423 rc = PDMR3LdrGetSymbolRCLazy(pVM, pDevIns->pDevReg->szRCMod, "vgaGCLFBAccessHandler", &pThis->RCPtrLFBHandler);
5424 if (RT_FAILURE(rc))
5425 {
5426 AssertReleaseMsgFailed(("PDMR3LdrGetSymbolRC(, %s, \"vgaGCLFBAccessHandler\",) -> %Rrc\n", pDevIns->pDevReg->szRCMod, rc));
5427 return rc;
5428 }
5429
5430 /* the interfaces. */
5431 pThis->Base.pfnQueryInterface = vgaPortQueryInterface;
5432
5433 pThis->Port.pfnUpdateDisplay = vgaPortUpdateDisplay;
5434 pThis->Port.pfnUpdateDisplayAll = vgaPortUpdateDisplayAll;
5435 pThis->Port.pfnQueryColorDepth = vgaPortQueryColorDepth;
5436 pThis->Port.pfnSetRefreshRate = vgaPortSetRefreshRate;
5437 pThis->Port.pfnSnapshot = vgaPortSnapshot;
5438 pThis->Port.pfnDisplayBlt = vgaPortDisplayBlt;
5439 pThis->Port.pfnUpdateDisplayRect = vgaPortUpdateDisplayRect;
5440 pThis->Port.pfnSetRenderVRAM = vgaPortSetRenderVRAM;
5441
5442
5443 /*
5444 * Allocate the VRAM and map the first 512KB of it into GC so we can speed up VGA support.
5445 */
5446 rc = PDMDevHlpMMIO2Register(pDevIns, 0 /* iRegion */, pThis->vram_size, 0, (void **)&pThis->vram_ptrR3, "VRam");
5447 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMIO2Register(%#x,) -> %Rrc\n", pThis->vram_size, rc), rc);
5448 pThis->vram_ptrR0 = (RTR0PTR)pThis->vram_ptrR3; /** @todo #1865 Map parts into R0 or just use PGM access (Mac only). */
5449
5450 if (pThis->fGCEnabled)
5451 {
5452 RTRCPTR pRCMapping = 0;
5453 rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, 0 /* iRegion */, 0 /* off */, VGA_MAPPING_SIZE, "VGA VRam", &pRCMapping);
5454 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMHyperMapMMIO2(%#x,) -> %Rrc\n", VGA_MAPPING_SIZE, rc), rc);
5455 pThis->vram_ptrRC = pRCMapping;
5456 }
5457
5458#if defined(VBOX_WITH_2X_4GB_ADDR_SPACE)
5459 if (pThis->fR0Enabled)
5460 {
5461 RTR0PTR pR0Mapping = 0;
5462 rc = PDMDevHlpMMIO2MapKernel(pDevIns, 0 /* iRegion */, 0 /* off */, VGA_MAPPING_SIZE, "VGA VRam", &pR0Mapping);
5463 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMapMMIO2IntoR0(%#x,) -> %Rrc\n", VGA_MAPPING_SIZE, rc), rc);
5464 pThis->vram_ptrR0 = pR0Mapping;
5465 }
5466#endif
5467
5468 /*
5469 * Register I/O ports, ROM and save state.
5470 */
5471 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3c0, 16, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3c0");
5472 if (RT_FAILURE(rc))
5473 return rc;
5474 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3b4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3b4");
5475 if (RT_FAILURE(rc))
5476 return rc;
5477 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3ba, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3ba");
5478 if (RT_FAILURE(rc))
5479 return rc;
5480 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3d4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3d4");
5481 if (RT_FAILURE(rc))
5482 return rc;
5483 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3da, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3da");
5484 if (RT_FAILURE(rc))
5485 return rc;
5486
5487#ifdef CONFIG_BOCHS_VBE
5488 rc = PDMDevHlpIOPortRegister(pDevIns, 0x1ce, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, NULL, NULL, "VGA/VBE - Index");
5489 if (RT_FAILURE(rc))
5490 return rc;
5491 rc = PDMDevHlpIOPortRegister(pDevIns, 0x1cf, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, NULL, NULL, "VGA/VBE - Data");
5492 if (RT_FAILURE(rc))
5493 return rc;
5494#if 0
5495 /* This now causes conflicts with Win2k & XP; it is not aware this range is taken
5496 and tries to map other devices there */
5497 /* Old Bochs. */
5498 rc = PDMDevHlpIOPortRegister(pDevIns, 0xff80, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, "VGA/VBE - Index Old");
5499 if (RT_FAILURE(rc))
5500 return rc;
5501 rc = PDMDevHlpIOPortRegister(pDevIns, 0xff81, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, "VGA/VBE - Data Old");
5502 if (RT_FAILURE(rc))
5503 return rc;
5504#endif
5505#endif /* CONFIG_BOCHS_VBE */
5506
5507 /* guest context extension */
5508 if (pThis->fGCEnabled)
5509 {
5510 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
5511 if (RT_FAILURE(rc))
5512 return rc;
5513 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
5514 if (RT_FAILURE(rc))
5515 return rc;
5516 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
5517 if (RT_FAILURE(rc))
5518 return rc;
5519 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
5520 if (RT_FAILURE(rc))
5521 return rc;
5522 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
5523 if (RT_FAILURE(rc))
5524 return rc;
5525#ifdef CONFIG_BOCHS_VBE
5526 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
5527 if (RT_FAILURE(rc))
5528 return rc;
5529 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
5530 if (RT_FAILURE(rc))
5531 return rc;
5532
5533#if 0
5534 /* This now causes conflicts with Win2k & XP; they are not aware this range is taken
5535 and try to map other devices there */
5536 /* Old Bochs. */
5537 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0xff80, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", "VGA/VBE - Index Old (GC)");
5538 if (RT_FAILURE(rc))
5539 return rc;
5540 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0xff81, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", "VGA/VBE - Index Old (GC)");
5541 if (RT_FAILURE(rc))
5542 return rc;
5543#endif
5544
5545#endif /* CONFIG_BOCHS_VBE */
5546 }
5547
5548 /* R0 context extension */
5549 if (pThis->fR0Enabled)
5550 {
5551 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
5552 if (RT_FAILURE(rc))
5553 return rc;
5554 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
5555 if (RT_FAILURE(rc))
5556 return rc;
5557 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
5558 if (RT_FAILURE(rc))
5559 return rc;
5560 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
5561 if (RT_FAILURE(rc))
5562 return rc;
5563 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
5564 if (RT_FAILURE(rc))
5565 return rc;
5566#ifdef CONFIG_BOCHS_VBE
5567 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
5568 if (RT_FAILURE(rc))
5569 return rc;
5570 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
5571 if (RT_FAILURE(rc))
5572 return rc;
5573
5574#if 0
5575 /* This now causes conflicts with Win2k & XP; they are not aware this range is taken
5576 and try to map other devices there */
5577 /* Old Bochs. */
5578 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0xff80, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", "VGA/VBE - Index Old (GC)");
5579 if (RT_FAILURE(rc))
5580 return rc;
5581 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0xff81, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", "VGA/VBE - Index Old (GC)");
5582 if (RT_FAILURE(rc))
5583 return rc;
5584#endif
5585
5586#endif /* CONFIG_BOCHS_VBE */
5587 }
5588
5589 /* vga mmio */
5590 rc = PDMDevHlpMMIORegister(pDevIns, 0x000a0000, 0x00020000, 0, vgaMMIOWrite, vgaMMIORead, vgaMMIOFill, "VGA - VGA Video Buffer");
5591 if (RT_FAILURE(rc))
5592 return rc;
5593 if (pThis->fGCEnabled)
5594 {
5595 rc = PDMDevHlpMMIORegisterGC(pDevIns, 0x000a0000, 0x00020000, 0, "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill");
5596 if (RT_FAILURE(rc))
5597 return rc;
5598 }
5599 if (pThis->fR0Enabled)
5600 {
5601 rc = PDMDevHlpMMIORegisterR0(pDevIns, 0x000a0000, 0x00020000, 0, "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill");
5602 if (RT_FAILURE(rc))
5603 return rc;
5604 }
5605
5606 /* vga bios */
5607 rc = PDMDevHlpIOPortRegister(pDevIns, VBE_PRINTF_PORT, 1, NULL, vgaIOPortWriteBIOS, vgaIOPortReadBIOS, NULL, NULL, "VGA BIOS debug/panic");
5608 if (RT_FAILURE(rc))
5609 return rc;
5610 if (pThis->fR0Enabled)
5611 {
5612 rc = PDMDevHlpIOPortRegisterR0(pDevIns, VBE_PRINTF_PORT, 1, 0, "vgaIOPortWriteBIOS", "vgaIOPortReadBIOS", NULL, NULL, "VGA BIOS debug/panic");
5613 if (RT_FAILURE(rc))
5614 return rc;
5615 }
5616
5617 AssertReleaseMsg(g_cbVgaBiosBinary <= _64K && g_cbVgaBiosBinary >= 32*_1K, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
5618 AssertReleaseMsg(RT_ALIGN_Z(g_cbVgaBiosBinary, PAGE_SIZE) == g_cbVgaBiosBinary, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
5619 rc = PDMDevHlpROMRegister(pDevIns, 0x000c0000, g_cbVgaBiosBinary, &g_abVgaBiosBinary[0],
5620 false /* fShadow */, "VGA BIOS");
5621 if (RT_FAILURE(rc))
5622 return rc;
5623
5624 /* save */
5625 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, VGA_SAVEDSTATE_VERSION,
5626 sizeof(*pThis), NULL, vgaR3SaveExec, NULL, NULL, vgaR3LoadExec, NULL);
5627 if (RT_FAILURE(rc))
5628 return rc;
5629
5630 /* PCI */
5631 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->Dev);
5632 if (RT_FAILURE(rc))
5633 return rc;
5634 /*AssertMsg(pThis->Dev.devfn == 16 || iInstance != 0, ("pThis->Dev.devfn=%d\n", pThis->Dev.devfn));*/
5635 if (pThis->Dev.devfn != 16 && iInstance == 0)
5636 Log(("!!WARNING!!: pThis->dev.devfn=%d (ignore if testcase or not started by Main)\n", pThis->Dev.devfn));
5637
5638 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0 /* iRegion */, pThis->vram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vgaR3IORegionMap);
5639 if (RT_FAILURE(rc))
5640 return rc;
5641
5642 /*
5643 * Create the refresh timer.
5644 */
5645 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, vgaTimerRefresh, "VGA Refresh Timer", &pThis->RefreshTimer);
5646 if (RT_FAILURE(rc))
5647 return rc;
5648
5649 /*
5650 * Attach to the display.
5651 */
5652 rc = vgaAttach(pDevIns, 0 /* display LUN # */);
5653 if (RT_FAILURE(rc))
5654 return rc;
5655
5656#ifdef VBE_NEW_DYN_LIST
5657 /*
5658 * Compute buffer size for the VBE BIOS Extra Data.
5659 */
5660 cb = sizeof(mode_info_list) + sizeof(ModeInfoListItem);
5661
5662 rc = CFGMR3QueryU32(pCfgHandle, "HeightReduction", &cyReduction);
5663 if (RT_SUCCESS(rc) && cyReduction)
5664 cb *= 2; /* Default mode list will be twice long */
5665 else
5666 cyReduction = 0;
5667
5668 rc = CFGMR3QueryU32(pCfgHandle, "CustomVideoModes", &cCustomModes);
5669 if (RT_SUCCESS(rc) && cCustomModes)
5670 cb += sizeof(ModeInfoListItem) * cCustomModes;
5671 else
5672 cCustomModes = 0;
5673
5674 /*
5675 * Allocate and initialize buffer for the VBE BIOS Extra Data.
5676 */
5677 pThis->cbVBEExtraData = sizeof(VBEHEADER) + cb;
5678 pThis->pu8VBEExtraData = (uint8_t *)PDMDevHlpMMHeapAllocZ(pDevIns, pThis->cbVBEExtraData);
5679 if (!pThis->pu8VBEExtraData)
5680 return VERR_NO_MEMORY;
5681
5682 pVBEDataHdr = (PVBEHEADER)pThis->pu8VBEExtraData;
5683 pVBEDataHdr->u16Signature = VBEHEADER_MAGIC;
5684 pVBEDataHdr->cbData = cb;
5685
5686# ifndef VRAM_SIZE_FIX
5687 pCurMode = memcpy(pVBEDataHdr + 1, &mode_info_list, sizeof(mode_info_list));
5688 pCurMode = (ModeInfoListItem *)((uintptr_t)pCurMode + sizeof(mode_info_list));
5689# else /* VRAM_SIZE_FIX defined */
5690 pCurMode = (ModeInfoListItem *)(pVBEDataHdr + 1);
5691 for (i = 0; i < MODE_INFO_SIZE; i++)
5692 {
5693 uint32_t pixelWidth, reqSize;
5694 if (mode_info_list[i].info.MemoryModel == VBE_MEMORYMODEL_TEXT_MODE)
5695 pixelWidth = 2;
5696 else
5697 pixelWidth = (mode_info_list[i].info.BitsPerPixel +7) / 8;
5698 reqSize = mode_info_list[i].info.XResolution
5699 * mode_info_list[i].info.YResolution
5700 * pixelWidth;
5701 if (reqSize >= pThis->vram_size)
5702 continue;
5703 *pCurMode = mode_info_list[i];
5704 pCurMode++;
5705 }
5706# endif /* VRAM_SIZE_FIX defined */
5707
5708 /*
5709 * Copy default modes with subtractred YResolution.
5710 */
5711 if (cyReduction)
5712 {
5713 ModeInfoListItem *pDefMode = mode_info_list;
5714 Log(("vgaR3Construct: cyReduction=%u\n", cyReduction));
5715# ifndef VRAM_SIZE_FIX
5716 for (i = 0; i < MODE_INFO_SIZE; i++, pCurMode++, pDefMode++)
5717 {
5718 *pCurMode = *pDefMode;
5719 pCurMode->mode += 0x30;
5720 pCurMode->info.YResolution -= cyReduction;
5721 }
5722# else /* VRAM_SIZE_FIX defined */
5723 for (i = 0; i < MODE_INFO_SIZE; i++, pDefMode++)
5724 {
5725 uint32_t pixelWidth, reqSize;
5726 if (pDefMode->info.MemoryModel == VBE_MEMORYMODEL_TEXT_MODE)
5727 pixelWidth = 2;
5728 else
5729 pixelWidth = (pDefMode->info.BitsPerPixel + 7) / 8;
5730 reqSize = pDefMode->info.XResolution * pDefMode->info.YResolution * pixelWidth;
5731 if (reqSize >= pThis->vram_size)
5732 continue;
5733 *pCurMode = *pDefMode;
5734 pCurMode->mode += 0x30;
5735 pCurMode->info.YResolution -= cyReduction;
5736 pCurMode++;
5737 }
5738# endif /* VRAM_SIZE_FIX defined */
5739 }
5740
5741
5742 /*
5743 * Add custom modes.
5744 */
5745 if (cCustomModes)
5746 {
5747 uint16_t u16CurMode = 0x160;
5748 for (i = 1; i <= cCustomModes; i++)
5749 {
5750 char szExtraDataKey[sizeof("CustomVideoModeXX")];
5751 char *pszExtraData = NULL;
5752
5753 /* query and decode the custom mode string. */
5754 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%d", i);
5755 rc = CFGMR3QueryStringAlloc(pCfgHandle, szExtraDataKey, &pszExtraData);
5756 if (RT_SUCCESS(rc))
5757 {
5758 ModeInfoListItem *pDefMode = mode_info_list;
5759 unsigned int cx, cy, cBits, cParams, j;
5760 uint16_t u16DefMode;
5761
5762 cParams = sscanf(pszExtraData, "%ux%ux%u", &cx, &cy, &cBits);
5763 if ( cParams != 3
5764 || (cBits != 16 && cBits != 24 && cBits != 32))
5765 {
5766 AssertMsgFailed(("Configuration error: Invalid mode data '%s' for '%s'! cBits=%d\n", pszExtraData, szExtraDataKey, cBits));
5767 return VERR_VGA_INVALID_CUSTOM_MODE;
5768 }
5769# ifdef VRAM_SIZE_FIX
5770 if (cx * cy * cBits / 8 >= pThis->vram_size)
5771 {
5772 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",
5773 cx, cy, cBits, pThis->vram_size / _1M));
5774 return VERR_VGA_INVALID_CUSTOM_MODE;
5775 }
5776# endif /* VRAM_SIZE_FIX defined */
5777 MMR3HeapFree(pszExtraData);
5778
5779 /* Use defaults from max@bpp mode. */
5780 switch (cBits)
5781 {
5782 case 16:
5783 u16DefMode = VBE_VESA_MODE_1024X768X565;
5784 break;
5785
5786 case 24:
5787 u16DefMode = VBE_VESA_MODE_1024X768X888;
5788 break;
5789
5790 case 32:
5791 u16DefMode = VBE_OWN_MODE_1024X768X8888;
5792 break;
5793
5794 default: /* gcc, shut up! */
5795 AssertMsgFailed(("gone postal!\n"));
5796 continue;
5797 }
5798
5799 /* mode_info_list is not terminated */
5800 for (j = 0; j < MODE_INFO_SIZE && pDefMode->mode != u16DefMode; j++)
5801 pDefMode++;
5802 Assert(j < MODE_INFO_SIZE);
5803
5804 *pCurMode = *pDefMode;
5805 pCurMode->mode = u16CurMode++;
5806
5807 /* adjust defaults */
5808 pCurMode->info.XResolution = cx;
5809 pCurMode->info.YResolution = cy;
5810
5811 switch (cBits)
5812 {
5813 case 16:
5814 pCurMode->info.BytesPerScanLine = cx * 2;
5815 pCurMode->info.LinBytesPerScanLine = cx * 2;
5816 break;
5817
5818 case 24:
5819 pCurMode->info.BytesPerScanLine = cx * 3;
5820 pCurMode->info.LinBytesPerScanLine = cx * 3;
5821 break;
5822
5823 case 32:
5824 pCurMode->info.BytesPerScanLine = cx * 4;
5825 pCurMode->info.LinBytesPerScanLine = cx * 4;
5826 break;
5827 }
5828
5829 /* commit it */
5830 pCurMode++;
5831 }
5832 else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
5833 {
5834 AssertMsgFailed(("CFGMR3QueryStringAlloc(,'%s',) -> %Rrc\n", szExtraDataKey, rc));
5835 return rc;
5836 }
5837 } /* foreach custom mode key */
5838 }
5839
5840 /*
5841 * Add the "End of list" mode.
5842 */
5843 memset(pCurMode, 0, sizeof(*pCurMode));
5844 pCurMode->mode = VBE_VESA_MODE_END_OF_LIST;
5845
5846 /*
5847 * Register I/O Port for the VBE BIOS Extra Data.
5848 */
5849 rc = PDMDevHlpIOPortRegister(pDevIns, VBE_EXTRA_PORT, 1, NULL, vbeIOPortWriteVBEExtra, vbeIOPortReadVBEExtra, NULL, NULL, "VBE BIOS Extra Data");
5850 if (RT_FAILURE(rc))
5851 return rc;
5852#endif /* VBE_NEW_DYN_LIST */
5853
5854 /*
5855 * Register I/O Port for the BIOS Logo.
5856 */
5857 rc = PDMDevHlpIOPortRegister(pDevIns, LOGO_IO_PORT, 1, NULL, vbeIOPortWriteCMDLogo, vbeIOPortReadCMDLogo, NULL, NULL, "BIOS Logo");
5858 if (RT_FAILURE(rc))
5859 return rc;
5860
5861 /*
5862 * Register debugger info callbacks.
5863 */
5864 PDMDevHlpDBGFInfoRegister(pDevIns, "vgatext", "Display VGA memory formatted as text.", vgaInfoText);
5865 PDMDevHlpDBGFInfoRegister(pDevIns, "vgacr", "Dump VGA CRTC registers.", vgaInfoCR);
5866 PDMDevHlpDBGFInfoRegister(pDevIns, "vgasr", "Dump VGA Sequencer registers.", vgaInfoSR);
5867 PDMDevHlpDBGFInfoRegister(pDevIns, "vgaar", "Dump VGA Attribute Controller registers.", vgaInfoAR);
5868 PDMDevHlpDBGFInfoRegister(pDevIns, "vgadac", "Dump VGA DAC registers.", vgaInfoDAC);
5869
5870 /*
5871 * Construct the logo header.
5872 */
5873 LOGOHDR LogoHdr = { LOGO_HDR_MAGIC, 0, 0, 0, 0, 0, 0 };
5874
5875 rc = CFGMR3QueryU8(pCfgHandle, "FadeIn", &LogoHdr.fu8FadeIn);
5876 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5877 LogoHdr.fu8FadeIn = 1;
5878 else if (RT_FAILURE(rc))
5879 return PDMDEV_SET_ERROR(pDevIns, rc,
5880 N_("Configuration error: Querying \"FadeIn\" as integer failed"));
5881
5882 rc = CFGMR3QueryU8(pCfgHandle, "FadeOut", &LogoHdr.fu8FadeOut);
5883 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5884 LogoHdr.fu8FadeOut = 1;
5885 else if (RT_FAILURE(rc))
5886 return PDMDEV_SET_ERROR(pDevIns, rc,
5887 N_("Configuration error: Querying \"FadeOut\" as integer failed"));
5888
5889 rc = CFGMR3QueryU16(pCfgHandle, "LogoTime", &LogoHdr.u16LogoMillies);
5890 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5891 LogoHdr.u16LogoMillies = 0;
5892 else if (RT_FAILURE(rc))
5893 return PDMDEV_SET_ERROR(pDevIns, rc,
5894 N_("Configuration error: Querying \"LogoTime\" as integer failed"));
5895
5896 /* Delay the logo a little bit */
5897 if (LogoHdr.fu8FadeIn && LogoHdr.fu8FadeOut && !LogoHdr.u16LogoMillies)
5898 LogoHdr.u16LogoMillies = RT_MAX(LogoHdr.u16LogoMillies, LOGO_DELAY_TIME);
5899
5900 rc = CFGMR3QueryU8(pCfgHandle, "ShowBootMenu", &LogoHdr.fu8ShowBootMenu);
5901 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5902 LogoHdr.fu8ShowBootMenu = 0;
5903 else if (RT_FAILURE(rc))
5904 return PDMDEV_SET_ERROR(pDevIns, rc,
5905 N_("Configuration error: Querying \"ShowBootMenu\" as integer failed"));
5906
5907 /*
5908 * Get the Logo file name.
5909 */
5910 rc = CFGMR3QueryStringAlloc(pCfgHandle, "LogoFile", &pThis->pszLogoFile);
5911 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5912 pThis->pszLogoFile = NULL;
5913 else if (RT_FAILURE(rc))
5914 return PDMDEV_SET_ERROR(pDevIns, rc,
5915 N_("Configuration error: Querying \"LogoFile\" as a string failed"));
5916 else if (!*pThis->pszLogoFile)
5917 {
5918 MMR3HeapFree(pThis->pszLogoFile);
5919 pThis->pszLogoFile = NULL;
5920 }
5921
5922 /*
5923 * Determine the logo size, open any specified logo file in the process.
5924 */
5925 LogoHdr.cbLogo = g_cbVgaDefBiosLogo;
5926 RTFILE FileLogo = NIL_RTFILE;
5927 if (pThis->pszLogoFile)
5928 {
5929 rc = RTFileOpen(&FileLogo, pThis->pszLogoFile,
5930 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
5931 if (RT_SUCCESS(rc))
5932 {
5933 uint64_t cbFile;
5934 rc = RTFileGetSize(FileLogo, &cbFile);
5935 if (RT_SUCCESS(rc))
5936 {
5937 if (cbFile > 0 && cbFile < 32*_1M)
5938 LogoHdr.cbLogo = (uint32_t)cbFile;
5939 else
5940 rc = VERR_TOO_MUCH_DATA;
5941 }
5942 }
5943 if (RT_FAILURE(rc))
5944 {
5945 /*
5946 * Ignore failure and fall back to the default logo.
5947 */
5948 LogRel(("vgaR3Construct: Failed to open logo file '%s', rc=%Rrc!\n", pThis->pszLogoFile, rc));
5949 if (FileLogo != NIL_RTFILE)
5950 RTFileClose(FileLogo);
5951 FileLogo = NIL_RTFILE;
5952 MMR3HeapFree(pThis->pszLogoFile);
5953 pThis->pszLogoFile = NULL;
5954 }
5955 }
5956
5957 /*
5958 * Disable graphic splash screen if it doesn't fit into VRAM.
5959 */
5960 if (pThis->vram_size < LOGO_MAX_SIZE)
5961 LogoHdr.fu8FadeIn = LogoHdr.fu8FadeOut = LogoHdr.u16LogoMillies = 0;
5962
5963 /*
5964 * Allocate buffer for the logo data.
5965 * RT_MAX() is applied to let us fall back to default logo on read failure.
5966 */
5967 pThis->cbLogo = sizeof(LogoHdr) + LogoHdr.cbLogo;
5968 pThis->pu8Logo = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, RT_MAX(pThis->cbLogo, g_cbVgaDefBiosLogo + sizeof(LogoHdr)));
5969 if (pThis->pu8Logo)
5970 {
5971 /*
5972 * Write the logo header.
5973 */
5974 PLOGOHDR pLogoHdr = (PLOGOHDR)pThis->pu8Logo;
5975 *pLogoHdr = LogoHdr;
5976
5977 /*
5978 * Write the logo bitmap.
5979 */
5980 if (pThis->pszLogoFile)
5981 {
5982 rc = RTFileRead(FileLogo, pLogoHdr + 1, LogoHdr.cbLogo, NULL);
5983 if (RT_FAILURE(rc))
5984 {
5985 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", LogoHdr.cbLogo, rc));
5986 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbVgaDefBiosLogo;
5987 memcpy(pLogoHdr + 1, g_abVgaDefBiosLogo, LogoHdr.cbLogo);
5988 }
5989 }
5990 else
5991 memcpy(pLogoHdr + 1, g_abVgaDefBiosLogo, LogoHdr.cbLogo);
5992
5993 rc = vbeParseBitmap(pThis);
5994 if (RT_FAILURE(rc))
5995 {
5996 AssertMsgFailed(("vbeParseBitmap() -> %Rrc\n", rc));
5997 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbVgaDefBiosLogo;
5998 memcpy(pLogoHdr + 1, g_abVgaDefBiosLogo, LogoHdr.cbLogo);
5999 }
6000
6001 rc = vbeParseBitmap(pThis);
6002 if (RT_FAILURE(rc))
6003 AssertReleaseMsgFailed(("Internal bitmap failed! vbeParseBitmap() -> %Rrc\n", rc));
6004
6005 rc = VINF_SUCCESS;
6006 }
6007 else
6008 rc = VERR_NO_MEMORY;
6009
6010 /*
6011 * Cleanup.
6012 */
6013 if (FileLogo != NIL_RTFILE)
6014 RTFileClose(FileLogo);
6015
6016 /*
6017 * Statistics.
6018 */
6019 STAM_REG(pVM, &pThis->StatRZMemoryRead, STAMTYPE_PROFILE, "/Devices/VGA/RZ/MMIO-Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryRead() body.");
6020 STAM_REG(pVM, &pThis->StatR3MemoryRead, STAMTYPE_PROFILE, "/Devices/VGA/R3/MMIO-Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryRead() body.");
6021 STAM_REG(pVM, &pThis->StatRZMemoryWrite, STAMTYPE_PROFILE, "/Devices/VGA/RZ/MMIO-Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryWrite() body.");
6022 STAM_REG(pVM, &pThis->StatR3MemoryWrite, STAMTYPE_PROFILE, "/Devices/VGA/R3/MMIO-Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryWrite() body.");
6023
6024 return rc;
6025}
6026
6027
6028/**
6029 * Destruct a device instance.
6030 *
6031 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
6032 * resources can be freed correctly.
6033 *
6034 * @param pDevIns The device instance data.
6035 */
6036static DECLCALLBACK(int) vgaR3Destruct(PPDMDEVINS pDevIns)
6037{
6038#ifdef VBE_NEW_DYN_LIST
6039 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
6040 LogFlow(("vgaR3Destruct:\n"));
6041
6042 /*
6043 * Free MM heap pointers.
6044 */
6045 if (pThis->pu8VBEExtraData)
6046 {
6047 MMR3HeapFree(pThis->pu8VBEExtraData);
6048 pThis->pu8VBEExtraData = NULL;
6049 }
6050#endif
6051
6052 return VINF_SUCCESS;
6053}
6054
6055
6056/**
6057 * The device registration structure.
6058 */
6059const PDMDEVREG g_DeviceVga =
6060{
6061 /* u32Version */
6062 PDM_DEVREG_VERSION,
6063 /* szDeviceName */
6064 "vga",
6065 /* szRCMod */
6066 "VBoxDDGC.gc",
6067 /* szR0Mod */
6068 "VBoxDDR0.r0",
6069 /* pszDescription */
6070 "VGA Adaptor with VESA extensions.",
6071 /* fFlags */
6072 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
6073 /* fClass */
6074 PDM_DEVREG_CLASS_GRAPHICS,
6075 /* cMaxInstances */
6076 1,
6077 /* cbInstance */
6078 sizeof(VGASTATE),
6079 /* pfnConstruct */
6080 vgaR3Construct,
6081 /* pfnDestruct */
6082 vgaR3Destruct,
6083 /* pfnRelocate */
6084 vgaR3Relocate,
6085 /* pfnIOCtl */
6086 NULL,
6087 /* pfnPowerOn */
6088 NULL,
6089 /* pfnReset */
6090 vgaR3Reset,
6091 /* pfnSuspend */
6092 NULL,
6093 /* pfnResume */
6094 NULL,
6095 /* pfnAttach */
6096 vgaAttach,
6097 /* pfnDetach */
6098 vgaDetach,
6099 /* pfnQueryInterface */
6100 NULL,
6101 /* pfnInitComplete */
6102 NULL,
6103 /* pfnPowerOff */
6104 NULL,
6105 /* pfnSoftReset */
6106 NULL,
6107 /* u32VersionEnd */
6108 PDM_DEVREG_VERSION
6109};
6110
6111#endif /* !IN_RING3 */
6112#endif /* VBOX */
6113#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
6114
6115/*
6116 * Local Variables:
6117 * nuke-trailing-whitespace-p:nil
6118 * End:
6119 */
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