VirtualBox

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

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

DevVGA: Made the ubuntu live cd boot screen fast on darwin. Fixed broken vram size restriction in the read byte mmio handler, would return a status code where the value goes and nobody would notice (rawmode + darwin/VT-x). Fixed a couple of vram boundrary checks, mostly for rawmode & darwin-VT-x, but some also applies to all modes.

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