VirtualBox

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

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

DevVGA: IOMMMIOModifyPage should be working with the new phys code now.

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