VirtualBox

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

Last change on this file since 43680 was 43526, checked in by vboxsync, 12 years ago

Stupid bug in debug output.

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