VirtualBox

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

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

Use GMODE_BLANK also when Screen Off bit in SR01 is set. Fixes garbage on X11 startup.

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

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