VirtualBox

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

Last change on this file since 28129 was 28129, checked in by vboxsync, 15 years ago

Devices/VGA: two forgotten "PDMCritSectLeave"s

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

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