VirtualBox

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

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

VGA: fixed saved state

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

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