VirtualBox

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

最後變更 在這個檔案從39886是 39425,由 vboxsync 提交於 13 年 前

Also print display refresh interval in dbg info.

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

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