VirtualBox

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

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

Allow ring 0 logging from the VGA BIOS

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