VirtualBox

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

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

Removed bank mask which assumed power of two VRAM size, replaced with max bank index.

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