VirtualBox

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

Last change on this file since 8088 was 8088, checked in by vboxsync, 17 years ago

Show the BIOS logo twice longer.

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