VirtualBox

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

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

dev/VGA: avoid extra resizes when HGSMI & VBVA is used (for now enabled only when Wddm driver is isnatalled in the guest)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 219.4 KB
Line 
1#ifdef VBOX
2/* $Id: DevVGA.cpp 28379 2010-04-15 17:14:16Z 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 int rc;
2129#ifdef VBOXVDMA
2130 /* do not do pfnResize in case VBVA is on since all mode changes are poerofmed over VBVA
2131 * we are checking for VDMA state here to ensure this code works only for WDDM driver,
2132 * although we should avoid calling pfnResize for XPDM as well, since pfnResize is actually an extra resize
2133 * event and generally only pfnVBVAxxx calls should be used with HGSMI + VBVA
2134 *
2135 * The reason for doing this for WDDM driver only now is to avoid regressions of the current code */
2136 PVBOXVDMAHOST pVdma = s->pVdma;
2137 if (pVdma && vboxVDMAIsEnabled(pVdma))
2138 rc = VINF_SUCCESS;
2139 else
2140#endif
2141 {
2142 /* Take into account the programmed start address (in DWORDs) of the visible screen. */
2143 rc = s->pDrv->pfnResize(s->pDrv, cBits, s->CTX_SUFF(vram_ptr) + s->start_addr * 4, s->line_offset, cx, cy);
2144 }
2145
2146 /* last stuff */
2147 s->last_bpp = cBits;
2148 s->last_scr_width = cx;
2149 s->last_scr_height = cy;
2150 s->last_width = cx;
2151 s->last_height = cy;
2152
2153 if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
2154 return rc;
2155 AssertRC(rc);
2156
2157 /* update palette */
2158 switch (s->pDrv->cBits)
2159 {
2160 case 32: s->rgb_to_pixel = rgb_to_pixel32_dup; break;
2161 case 16:
2162 default: s->rgb_to_pixel = rgb_to_pixel16_dup; break;
2163 case 15: s->rgb_to_pixel = rgb_to_pixel15_dup; break;
2164 case 8: s->rgb_to_pixel = rgb_to_pixel8_dup; break;
2165 }
2166 if (s->shift_control == 0)
2167 update_palette16(s);
2168 else if (s->shift_control == 1)
2169 update_palette16(s);
2170 return VINF_SUCCESS;
2171}
2172#endif /* VBOX */
2173
2174/*
2175 * graphic modes
2176 */
2177#ifndef VBOX
2178static void vga_draw_graphic(VGAState *s, int full_update)
2179#else
2180static int vga_draw_graphic(VGAState *s, int full_update)
2181#endif /* !VBOX */
2182{
2183 int y1, y2, y, update, page_min, page_max, linesize, y_start, double_scan;
2184 int width, height, shift_control, line_offset, page0, page1, bwidth;
2185 int disp_width, multi_run;
2186 uint8_t *d;
2187 uint32_t v, addr1, addr;
2188 vga_draw_line_func *vga_draw_line;
2189 int offsets_changed;
2190
2191 offsets_changed = update_basic_params(s);
2192
2193 full_update |= offsets_changed;
2194
2195 s->get_resolution(s, &width, &height);
2196 disp_width = width;
2197
2198 shift_control = (s->gr[0x05] >> 5) & 3;
2199 double_scan = (s->cr[0x09] >> 7);
2200 multi_run = double_scan;
2201 if (shift_control != s->shift_control ||
2202 double_scan != s->double_scan) {
2203 full_update = 1;
2204 s->shift_control = shift_control;
2205 s->double_scan = double_scan;
2206 }
2207
2208 if (shift_control == 0) {
2209 full_update |= update_palette16(s);
2210 if (s->sr[0x01] & 8) {
2211 v = VGA_DRAW_LINE4D2;
2212 disp_width <<= 1;
2213 } else {
2214 v = VGA_DRAW_LINE4;
2215 }
2216 } else if (shift_control == 1) {
2217 full_update |= update_palette16(s);
2218 if (s->sr[0x01] & 8) {
2219 v = VGA_DRAW_LINE2D2;
2220 disp_width <<= 1;
2221 } else {
2222 v = VGA_DRAW_LINE2;
2223 }
2224 } else {
2225 switch(s->get_bpp(s)) {
2226 default:
2227 case 0:
2228 full_update |= update_palette256(s);
2229 v = VGA_DRAW_LINE8D2;
2230 break;
2231 case 8:
2232 full_update |= update_palette256(s);
2233 v = VGA_DRAW_LINE8;
2234 break;
2235 case 15:
2236 v = VGA_DRAW_LINE15;
2237 break;
2238 case 16:
2239 v = VGA_DRAW_LINE16;
2240 break;
2241 case 24:
2242 v = VGA_DRAW_LINE24;
2243 break;
2244 case 32:
2245 v = VGA_DRAW_LINE32;
2246 break;
2247 }
2248 }
2249#ifndef VBOX
2250 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
2251
2252 if (disp_width != s->last_width ||
2253 height != s->last_height) {
2254 dpy_resize(s->ds, disp_width, height);
2255 s->last_scr_width = disp_width;
2256 s->last_scr_height = height;
2257 s->last_width = disp_width;
2258 s->last_height = height;
2259 full_update = 1;
2260 }
2261#else /* VBOX */
2262 if ( disp_width != (int)s->last_width
2263 || height != (int)s->last_height
2264 || s->get_bpp(s) != (int)s->last_bpp
2265 || offsets_changed)
2266 {
2267 int rc = vga_resize_graphic(s, disp_width, height, v);
2268 if (rc != VINF_SUCCESS) /* Return any rc, particularly VINF_VGA_RESIZE_IN_PROGRESS, to the caller. */
2269 return rc;
2270 full_update = 1;
2271 }
2272 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->pDrv->cBits)];
2273
2274#endif /* VBOX */
2275 if (s->cursor_invalidate)
2276 s->cursor_invalidate(s);
2277
2278 line_offset = s->line_offset;
2279#if 0
2280 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",
2281 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]));
2282#endif
2283 addr1 = (s->start_addr * 4);
2284#ifndef VBOX
2285 bwidth = width * 4;
2286#else /* VBOX */
2287 /* The width of VRAM scanline. */
2288 bwidth = s->line_offset;
2289 /* In some cases the variable is not yet set, probably due to incomplete
2290 * programming of the virtual hardware ports. Just return.
2291 */
2292 if (bwidth == 0) return VINF_SUCCESS;
2293#endif /* VBOX */
2294 y_start = -1;
2295 page_min = 0x7fffffff;
2296 page_max = -1;
2297#ifndef VBOX
2298 d = s->ds->data;
2299 linesize = s->ds->linesize;
2300#else /* VBOX */
2301 d = s->pDrv->pu8Data;
2302 linesize = s->pDrv->cbScanline;
2303#endif /* VBOX */
2304
2305 y1 = 0;
2306 y2 = s->cr[0x09] & 0x1F; /* starting row scan count */
2307 for(y = 0; y < height; y++) {
2308 addr = addr1;
2309 /* CGA/MDA compatibility. Note that these addresses are all
2310 * shifted left by two compared to VGA specs.
2311 */
2312 if (!(s->cr[0x17] & 1)) {
2313 addr = (addr & ~(1 << 15)) | ((y1 & 1) << 15);
2314 }
2315 if (!(s->cr[0x17] & 2)) {
2316 addr = (addr & ~(1 << 16)) | ((y1 & 2) << 15);
2317 }
2318#ifndef VBOX
2319 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
2320 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
2321 update = full_update |
2322 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
2323 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
2324 if ((page1 - page0) > TARGET_PAGE_SIZE) {
2325 /* if wide line, can use another page */
2326 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
2327 VGA_DIRTY_FLAG);
2328 }
2329#else /* VBOX */
2330 page0 = addr & TARGET_PAGE_MASK;
2331 page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
2332 update = full_update | vga_is_dirty(s, page0) | vga_is_dirty(s, page1);
2333 if (page1 - page0 > TARGET_PAGE_SIZE) {
2334 /* if wide line, can use another page */
2335 update |= vga_is_dirty(s, page0 + TARGET_PAGE_SIZE);
2336 }
2337#endif /* VBOX */
2338 /* explicit invalidation for the hardware cursor */
2339 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
2340 if (update) {
2341 if (y_start < 0)
2342 y_start = y;
2343 if (page0 < page_min)
2344 page_min = page0;
2345 if (page1 > page_max)
2346 page_max = page1;
2347#ifndef VBOX
2348 vga_draw_line(s, d, s->vram_ptr + addr, width);
2349#else /* VBOX */
2350 if (s->fRenderVRAM)
2351 vga_draw_line(s, d, s->CTX_SUFF(vram_ptr) + addr, width);
2352#endif /* VBOX */
2353 if (s->cursor_draw_line)
2354 s->cursor_draw_line(s, d, y);
2355 } else {
2356 if (y_start >= 0) {
2357 /* flush to display */
2358#ifndef VBOX
2359 dpy_update(s->ds, 0, y_start,
2360 disp_width, y - y_start);
2361#else /* VBOX */
2362 s->pDrv->pfnUpdateRect(s->pDrv, 0, y_start, disp_width, y - y_start);
2363#endif /* VBOX */
2364 y_start = -1;
2365 }
2366 }
2367 if (!multi_run) {
2368 y1++;
2369 multi_run = double_scan;
2370
2371 if (y2 == 0) {
2372 y2 = s->cr[0x09] & 0x1F;
2373 addr1 += line_offset;
2374 } else {
2375 --y2;
2376 }
2377 } else {
2378 multi_run--;
2379 }
2380 /* line compare acts on the displayed lines */
2381 if ((uint32_t)y == s->line_compare)
2382 addr1 = 0;
2383 d += linesize;
2384 }
2385 if (y_start >= 0) {
2386 /* flush to display */
2387#ifndef VBOX
2388 dpy_update(s->ds, 0, y_start,
2389 disp_width, y - y_start);
2390#else /* VBOX */
2391 s->pDrv->pfnUpdateRect(s->pDrv, 0, y_start, disp_width, y - y_start);
2392#endif /* VBOX */
2393 }
2394 /* reset modified pages */
2395 if (page_max != -1) {
2396#ifndef VBOX
2397 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
2398 VGA_DIRTY_FLAG);
2399#else /* VBOX */
2400 vga_reset_dirty(s, page_min, page_max + TARGET_PAGE_SIZE);
2401#endif /* VBOX */
2402 }
2403 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
2404#ifdef VBOX
2405 return VINF_SUCCESS;
2406#endif /* VBOX */
2407}
2408
2409static void vga_draw_blank(VGAState *s, int full_update)
2410{
2411#ifndef VBOX
2412 int i, w, val;
2413 uint8_t *d;
2414
2415 if (!full_update)
2416 return;
2417 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
2418 return;
2419 if (s->ds->depth == 8)
2420 val = s->rgb_to_pixel(0, 0, 0);
2421 else
2422 val = 0;
2423 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
2424 d = s->ds->data;
2425 for(i = 0; i < s->last_scr_height; i++) {
2426 memset(d, val, w);
2427 d += s->ds->linesize;
2428 }
2429 dpy_update(s->ds, 0, 0,
2430 s->last_scr_width, s->last_scr_height);
2431#else /* VBOX */
2432
2433 int i, w, val;
2434 uint8_t *d;
2435 uint32_t cbScanline = s->pDrv->cbScanline;
2436
2437 if (s->pDrv->pu8Data == s->vram_ptrR3) /* Do not clear the VRAM itself. */
2438 return;
2439 if (!full_update)
2440 return;
2441 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
2442 return;
2443 if (s->pDrv->cBits == 8)
2444 val = s->rgb_to_pixel(0, 0, 0);
2445 else
2446 val = 0;
2447 w = s->last_scr_width * ((s->pDrv->cBits + 7) >> 3);
2448 d = s->pDrv->pu8Data;
2449 for(i = 0; i < (int)s->last_scr_height; i++) {
2450 memset(d, val, w);
2451 d += cbScanline;
2452 }
2453 s->pDrv->pfnUpdateRect(s->pDrv, 0, 0, s->last_scr_width, s->last_scr_height);
2454#endif /* VBOX */
2455}
2456
2457#ifdef VBOX
2458static DECLCALLBACK(void) voidUpdateRect(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
2459{
2460}
2461#endif /* VBOX */
2462
2463
2464#define GMODE_TEXT 0
2465#define GMODE_GRAPH 1
2466#define GMODE_BLANK 2
2467
2468#ifndef VBOX
2469void vga_update_display(void)
2470{
2471 VGAState *s = vga_state;
2472#else /* VBOX */
2473static int vga_update_display(PVGASTATE s, bool fUpdateAll)
2474{
2475 int rc = VINF_SUCCESS;
2476#endif /* VBOX */
2477 int full_update, graphic_mode;
2478
2479#ifndef VBOX
2480 if (s->ds->depth == 0) {
2481#else /* VBOX */
2482 if (s->pDrv->cBits == 0) {
2483#endif /* VBOX */
2484 /* nothing to do */
2485 } else {
2486#ifndef VBOX
2487 switch(s->ds->depth) {
2488#else /* VBOX */
2489 switch(s->pDrv->cBits) {
2490#endif /* VBOX */
2491 case 8:
2492 s->rgb_to_pixel = rgb_to_pixel8_dup;
2493 break;
2494 case 15:
2495 s->rgb_to_pixel = rgb_to_pixel15_dup;
2496 break;
2497 default:
2498 case 16:
2499 s->rgb_to_pixel = rgb_to_pixel16_dup;
2500 break;
2501 case 32:
2502 s->rgb_to_pixel = rgb_to_pixel32_dup;
2503 break;
2504 }
2505
2506#ifdef VBOX
2507 if (fUpdateAll) {
2508 /* A full update is requested. Special processing for a "blank" mode is required. */
2509 typedef DECLCALLBACK(void) FNUPDATERECT(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy);
2510 typedef FNUPDATERECT *PFNUPDATERECT;
2511
2512 PFNUPDATERECT pfnUpdateRect = NULL;
2513
2514 /* Detect the "screen blank" conditions. */
2515 int fBlank = 0;
2516 if (!(s->ar_index & 0x20) || (s->sr[0x01] & 0x20)) {
2517 fBlank = 1;
2518 }
2519
2520 if (fBlank) {
2521 /* Provide a void pfnUpdateRect callback. */
2522 if (s->pDrv) {
2523 pfnUpdateRect = s->pDrv->pfnUpdateRect;
2524 s->pDrv->pfnUpdateRect = voidUpdateRect;
2525 }
2526 }
2527
2528 /* Do a complete redraw, which will pick up a new screen resolution. */
2529 if (s->gr[6] & 1) {
2530 s->graphic_mode = GMODE_GRAPH;
2531 rc = vga_draw_graphic(s, 1);
2532 } else {
2533 s->graphic_mode = GMODE_TEXT;
2534 rc = vga_draw_text(s, 1);
2535 }
2536
2537 if (fBlank) {
2538 /* Set the current mode and restore the callback. */
2539 s->graphic_mode = GMODE_BLANK;
2540 if (s->pDrv) {
2541 s->pDrv->pfnUpdateRect = pfnUpdateRect;
2542 }
2543 }
2544 return rc;
2545 }
2546#endif /* VBOX */
2547
2548 full_update = 0;
2549 if (!(s->ar_index & 0x20) || (s->sr[0x01] & 0x20)) {
2550 graphic_mode = GMODE_BLANK;
2551 } else {
2552 graphic_mode = s->gr[6] & 1;
2553 }
2554 if (graphic_mode != s->graphic_mode) {
2555 s->graphic_mode = graphic_mode;
2556 full_update = 1;
2557 }
2558 switch(graphic_mode) {
2559 case GMODE_TEXT:
2560#ifdef VBOX
2561 rc =
2562#endif /* VBOX */
2563 vga_draw_text(s, full_update);
2564 break;
2565 case GMODE_GRAPH:
2566#ifdef VBOX
2567 rc =
2568#endif /* VBOX */
2569 vga_draw_graphic(s, full_update);
2570 break;
2571 case GMODE_BLANK:
2572 default:
2573 vga_draw_blank(s, full_update);
2574 break;
2575 }
2576 }
2577#ifdef VBOX
2578 return rc;
2579#endif /* VBOX */
2580}
2581
2582/* force a full display refresh */
2583#ifndef VBOX
2584void vga_invalidate_display(void)
2585{
2586 VGAState *s = vga_state;
2587
2588 s->last_width = -1;
2589 s->last_height = -1;
2590}
2591#endif /* !VBOX */
2592
2593#ifndef VBOX /* see vgaR3Reset() */
2594static void vga_reset(VGAState *s)
2595{
2596 memset(s, 0, sizeof(VGAState));
2597 s->graphic_mode = -1; /* force full update */
2598}
2599#endif /* !VBOX */
2600
2601#ifndef VBOX
2602static CPUReadMemoryFunc *vga_mem_read[3] = {
2603 vga_mem_readb,
2604 vga_mem_readw,
2605 vga_mem_readl,
2606};
2607
2608static CPUWriteMemoryFunc *vga_mem_write[3] = {
2609 vga_mem_writeb,
2610 vga_mem_writew,
2611 vga_mem_writel,
2612};
2613#endif /* !VBOX */
2614
2615static void vga_save(QEMUFile *f, void *opaque)
2616{
2617 VGAState *s = (VGAState*)opaque;
2618 int i;
2619
2620 qemu_put_be32s(f, &s->latch);
2621 qemu_put_8s(f, &s->sr_index);
2622 qemu_put_buffer(f, s->sr, 8);
2623 qemu_put_8s(f, &s->gr_index);
2624 qemu_put_buffer(f, s->gr, 16);
2625 qemu_put_8s(f, &s->ar_index);
2626 qemu_put_buffer(f, s->ar, 21);
2627 qemu_put_be32s(f, &s->ar_flip_flop);
2628 qemu_put_8s(f, &s->cr_index);
2629 qemu_put_buffer(f, s->cr, 256);
2630 qemu_put_8s(f, &s->msr);
2631 qemu_put_8s(f, &s->fcr);
2632 qemu_put_8s(f, &s->st00);
2633 qemu_put_8s(f, &s->st01);
2634
2635 qemu_put_8s(f, &s->dac_state);
2636 qemu_put_8s(f, &s->dac_sub_index);
2637 qemu_put_8s(f, &s->dac_read_index);
2638 qemu_put_8s(f, &s->dac_write_index);
2639 qemu_put_buffer(f, s->dac_cache, 3);
2640 qemu_put_buffer(f, s->palette, 768);
2641
2642 qemu_put_be32s(f, &s->bank_offset);
2643#ifdef CONFIG_BOCHS_VBE
2644 qemu_put_byte(f, 1);
2645 qemu_put_be16s(f, &s->vbe_index);
2646 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2647 qemu_put_be16s(f, &s->vbe_regs[i]);
2648 qemu_put_be32s(f, &s->vbe_start_addr);
2649 qemu_put_be32s(f, &s->vbe_line_offset);
2650#else
2651 qemu_put_byte(f, 0);
2652#endif
2653}
2654
2655static int vga_load(QEMUFile *f, void *opaque, int version_id)
2656{
2657 VGAState *s = (VGAState*)opaque;
2658 int is_vbe, i;
2659 uint32_t u32Dummy;
2660
2661#ifndef VBOX /* checked by the caller. */
2662 if (version_id > VGA_SAVEDSTATE_VERSION)
2663 return -EINVAL;
2664#endif /* VBOX */
2665
2666 qemu_get_be32s(f, &s->latch);
2667 qemu_get_8s(f, &s->sr_index);
2668 qemu_get_buffer(f, s->sr, 8);
2669 qemu_get_8s(f, &s->gr_index);
2670 qemu_get_buffer(f, s->gr, 16);
2671 qemu_get_8s(f, &s->ar_index);
2672 qemu_get_buffer(f, s->ar, 21);
2673 qemu_get_be32s(f, (uint32_t *)&s->ar_flip_flop);
2674 qemu_get_8s(f, &s->cr_index);
2675 qemu_get_buffer(f, s->cr, 256);
2676 qemu_get_8s(f, &s->msr);
2677 qemu_get_8s(f, &s->fcr);
2678 qemu_get_8s(f, &s->st00);
2679 qemu_get_8s(f, &s->st01);
2680
2681 qemu_get_8s(f, &s->dac_state);
2682 qemu_get_8s(f, &s->dac_sub_index);
2683 qemu_get_8s(f, &s->dac_read_index);
2684 qemu_get_8s(f, &s->dac_write_index);
2685 qemu_get_buffer(f, s->dac_cache, 3);
2686 qemu_get_buffer(f, s->palette, 768);
2687
2688 qemu_get_be32s(f, (uint32_t *)&s->bank_offset);
2689 is_vbe = qemu_get_byte(f);
2690#ifdef CONFIG_BOCHS_VBE
2691 if (!is_vbe)
2692# ifndef VBOX
2693 return -EINVAL;
2694# else /* VBOX */
2695 {
2696 Log(("vga_load: !is_vbe !!\n"));
2697 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2698 }
2699# endif /* VBOX */
2700 qemu_get_be16s(f, &s->vbe_index);
2701 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2702 qemu_get_be16s(f, &s->vbe_regs[i]);
2703 qemu_get_be32s(f, &s->vbe_start_addr);
2704 qemu_get_be32s(f, &s->vbe_line_offset);
2705 if (version_id < 2)
2706 qemu_get_be32s(f, &u32Dummy);
2707 s->vbe_bank_max = s->vram_size >> 16;
2708#else
2709 if (is_vbe)
2710# ifndef VBOX
2711 return -EINVAL;
2712# else /* VBOX */
2713 {
2714 Log(("vga_load: is_vbe !!\n"));
2715 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2716 }
2717# endif /* VBOX */
2718#endif
2719
2720 /* force refresh */
2721 s->graphic_mode = -1;
2722 return 0;
2723}
2724
2725#ifndef VBOX /* see vgaR3IORegionMap */
2726static void vga_map(PCIDevice *pci_dev, int region_num,
2727 uint32_t addr, uint32_t size, int type)
2728{
2729 VGAState *s = vga_state;
2730
2731 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
2732}
2733#endif
2734
2735#ifndef VBOX /* see vgaR3Construct */
2736void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
2737 unsigned long vga_ram_offset, int vga_ram_size)
2738#else
2739static void vga_init_expand(void)
2740#endif
2741{
2742 int i, j, v, b;
2743
2744 for(i = 0;i < 256; i++) {
2745 v = 0;
2746 for(j = 0; j < 8; j++) {
2747 v |= ((i >> j) & 1) << (j * 4);
2748 }
2749 expand4[i] = v;
2750
2751 v = 0;
2752 for(j = 0; j < 4; j++) {
2753 v |= ((i >> (2 * j)) & 3) << (j * 4);
2754 }
2755 expand2[i] = v;
2756 }
2757 for(i = 0; i < 16; i++) {
2758 v = 0;
2759 for(j = 0; j < 4; j++) {
2760 b = ((i >> j) & 1);
2761 v |= b << (2 * j);
2762 v |= b << (2 * j + 1);
2763 }
2764 expand4to8[i] = v;
2765 }
2766#ifdef VBOX
2767}
2768#else /* !VBOX */
2769 vga_reset(s);
2770
2771 s->vram_ptr = vga_ram_base;
2772 s->vram_offset = vga_ram_offset;
2773 s->vram_size = vga_ram_size;
2774 s->ds = ds;
2775 s->get_bpp = vga_get_bpp;
2776 s->get_offsets = vga_get_offsets;
2777 s->get_resolution = vga_get_resolution;
2778 /* XXX: currently needed for display */
2779 vga_state = s;
2780}
2781
2782
2783int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
2784 unsigned long vga_ram_offset, int vga_ram_size)
2785{
2786 VGAState *s;
2787
2788 s = qemu_mallocz(sizeof(VGAState));
2789 if (!s)
2790 return -1;
2791
2792 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2793
2794 register_savevm("vga", 0, 1, vga_save, vga_load, s);
2795
2796 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2797
2798 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2799 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2800 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2801 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2802
2803 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2804
2805 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2806 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2807 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2808 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2809 s->bank_offset = 0;
2810
2811#ifdef CONFIG_BOCHS_VBE
2812 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
2813 s->vbe_bank_max = s->vram_size >> 16;
2814#if defined (TARGET_I386)
2815 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2816 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2817
2818 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2819 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2820
2821 /* old Bochs IO ports */
2822 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2823 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2824
2825 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2826 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2827#else
2828 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2829 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2830
2831 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2832 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2833#endif
2834#endif /* CONFIG_BOCHS_VBE */
2835
2836 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2837 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2838 vga_io_memory);
2839
2840 if (bus) {
2841 PCIDevice *d;
2842 uint8_t *pci_conf;
2843
2844 d = pci_register_device(bus, "VGA",
2845 sizeof(PCIDevice),
2846 -1, NULL, NULL);
2847 pci_conf = d->config;
2848 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2849 pci_conf[0x01] = 0x12;
2850 pci_conf[0x02] = 0x11;
2851 pci_conf[0x03] = 0x11;
2852 pci_conf[0x0a] = 0x00; // VGA controller
2853 pci_conf[0x0b] = 0x03;
2854 pci_conf[0x0e] = 0x00; // header_type
2855
2856 /* XXX: vga_ram_size must be a power of two */
2857 pci_register_io_region(d, 0, vga_ram_size,
2858 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2859 } else {
2860#ifdef CONFIG_BOCHS_VBE
2861 /* XXX: use optimized standard vga accesses */
2862 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2863 vga_ram_size, vga_ram_offset);
2864#endif
2865 }
2866 return 0;
2867}
2868#endif /* !VBOX */
2869
2870
2871#ifndef VBOX
2872/********************************************************/
2873/* vga screen dump */
2874
2875static int vga_save_w, vga_save_h;
2876
2877static void vga_save_dpy_update(DisplayState *s,
2878 int x, int y, int w, int h)
2879{
2880}
2881
2882static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2883{
2884 s->linesize = w * 4;
2885#ifndef VBOX
2886 s->data = qemu_malloc(h * s->linesize);
2887#else /* VBOX */
2888 if (!s->data)
2889 {
2890 PPDMDEVINS pDevIns = VGASTATE2DEVINS((PVGASTATE)s->pvVgaState);
2891 s->data = PDMDevHlpMMHeapAlloc(pDevIns, h * s->linesize);
2892 }
2893 else // (32-bpp buffer is allocated by the caller)
2894 s->linesize = ((w * 32 + 31) / 32) * 4;
2895#endif /* VBOX */
2896 vga_save_w = w;
2897 vga_save_h = h;
2898}
2899
2900static void vga_save_dpy_refresh(DisplayState *s)
2901{
2902}
2903
2904static int ppm_save(const char *filename, uint8_t *data,
2905 int w, int h, int linesize)
2906{
2907 FILE *f;
2908 uint8_t *d, *d1;
2909 unsigned int v;
2910 int y, x;
2911
2912 f = fopen(filename, "wb");
2913 if (!f)
2914 return -1;
2915 fprintf(f, "P6\n%d %d\n%d\n",
2916 w, h, 255);
2917 d1 = data;
2918 for(y = 0; y < h; y++) {
2919 d = d1;
2920 for(x = 0; x < w; x++) {
2921 v = *(uint32_t *)d;
2922 fputc((v >> 16) & 0xff, f);
2923 fputc((v >> 8) & 0xff, f);
2924 fputc((v) & 0xff, f);
2925 d += 4;
2926 }
2927 d1 += linesize;
2928 }
2929 fclose(f);
2930 return 0;
2931}
2932
2933/* save the vga display in a PPM image even if no display is
2934 available */
2935void vga_screen_dump(const char *filename)
2936{
2937 VGAState *s = vga_state;
2938 DisplayState *saved_ds, ds1, *ds = &ds1;
2939
2940 /* XXX: this is a little hackish */
2941 vga_invalidate_display();
2942 saved_ds = s->ds;
2943
2944 memset(ds, 0, sizeof(DisplayState));
2945 ds->dpy_update = vga_save_dpy_update;
2946 ds->dpy_resize = vga_save_dpy_resize;
2947 ds->dpy_refresh = vga_save_dpy_refresh;
2948 ds->depth = 32;
2949
2950 s->ds = ds;
2951 s->graphic_mode = -1;
2952 vga_update_display();
2953
2954 if (ds->data) {
2955 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
2956 s->ds->linesize);
2957 qemu_free(ds->data);
2958 }
2959 s->ds = saved_ds;
2960}
2961#endif /* !VBOX */
2962
2963
2964#if 0 //def VBOX
2965/* copy the vga display contents to the given buffer. the size of the buffer
2966 must be sufficient to store the screen copy (see below). the width and height
2967 parameters determine the required dimensions of the copy. If they differ
2968 from the actual screen dimensions, then the returned copy is shrinked or
2969 stretched accordingly. The copy is always a 32-bit image, so the size of
2970 the buffer supplied must be at least (((width * 32 + 31) / 32) * 4) * height,
2971 i.e. dword-aligned. returns zero if the operation was successfull and -1
2972 otherwise. */
2973
2974static int vga_copy_screen_to(PVGASTATE s, uint8_t *buf, int width, int height)
2975{
2976 DisplayState *saved_ds, ds1, *ds = &ds1;
2977 if (!buf || width <= 0 || height <= 0)
2978 return -1;
2979
2980 /* XXX: this is a little hackish */
2981 vga_invalidate_display(s);
2982 saved_ds = s->ds;
2983
2984 memset(ds, 0, sizeof(DisplayState));
2985 ds->dpy_update = vga_save_dpy_update;
2986 ds->dpy_resize = vga_save_dpy_resize;
2987 ds->dpy_refresh = vga_save_dpy_refresh;
2988 ds->depth = 32;
2989 ds->data = buf;
2990 ds->pvVgaState = s;
2991
2992 s->ds = ds;
2993 s->graphic_mode = -1;
2994 vga_update_display(s);
2995
2996//@@TODO (dmik): implement stretching/shrinking!
2997
2998 s->ds = saved_ds;
2999 return 0;
3000}
3001
3002/* copy the given buffer to the vga display. width and height define the
3003 dimensions of the image in the buffer. x and y define the point on the
3004 vga display to copy the image to. the buffer is assumed to contain a 32-bit
3005 image, so the size of one scanline must be ((width * 32 + 31) / 32) * 4),
3006 i.e. dword-aligned. returns zero if the operation was successfull and -1
3007 otherwise. */
3008static int vga_copy_screen_from(PVGASTATE s, uint8_t *buf, int x, int y, int width, int height)
3009{
3010 int bpl = ((width * 32 + 31) / 32) * 4;
3011 int linesize = s->ds->linesize;
3012 uint8_t *dst;
3013 uint8_t *src;
3014 int bpp;
3015 vga_draw_line_func *vga_draw_line;
3016
3017 if (!buf || x < 0 || y < 0 || width <= 0 || height <= 0
3018 || x + width > s->ds->width || y + height > s->ds->height)
3019 return -1;
3020
3021 vga_draw_line = vga_draw_line_table[VGA_DRAW_LINE32 * 4 + get_depth_index(s->ds->depth)];
3022 switch (s->ds->depth) {
3023 case 8: bpp = 1; break;
3024 case 15:
3025 case 16: bpp = 2; break;
3026 case 32: bpp = 4; break;
3027 default: return -1;
3028 }
3029
3030 dst = s->ds->data + y * linesize + x * bpp;
3031 src = buf;
3032 for (y = 0; y < height; y ++)
3033 {
3034 vga_draw_line(s, dst, src, width);
3035 dst += linesize;
3036 src += bpl;
3037 }
3038
3039 return 0;
3040}
3041#endif
3042
3043#endif /* !VBOX || !IN_RC || !IN_RING0 */
3044
3045
3046
3047#ifdef VBOX /* VirtualBox code start */
3048
3049
3050/* -=-=-=-=-=- all contexts -=-=-=-=-=- */
3051
3052/**
3053 * Port I/O Handler for VGA OUT operations.
3054 *
3055 * @returns VBox status code.
3056 *
3057 * @param pDevIns The device instance.
3058 * @param pvUser User argument - ignored.
3059 * @param Port Port number used for the IN operation.
3060 * @param u32 The value to output.
3061 * @param cb The value size in bytes.
3062 */
3063PDMBOTHCBDECL(int) vgaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3064{
3065 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3066
3067 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_HC_IOPORT_WRITE);
3068 if (rc != VINF_SUCCESS)
3069 return rc;
3070
3071 NOREF(pvUser);
3072 if (cb == 1)
3073 vga_ioport_write(s, Port, u32);
3074 else if (cb == 2)
3075 {
3076 vga_ioport_write(s, Port, u32 & 0xff);
3077 vga_ioport_write(s, Port + 1, u32 >> 8);
3078 }
3079 PDMCritSectLeave(&s->lock);
3080 return VINF_SUCCESS;
3081}
3082
3083
3084/**
3085 * Port I/O Handler for VGA IN operations.
3086 *
3087 * @returns VBox status code.
3088 *
3089 * @param pDevIns The device instance.
3090 * @param pvUser User argument - ignored.
3091 * @param Port Port number used for the IN operation.
3092 * @param pu32 Where to store the result.
3093 * @param cb Number of bytes read.
3094 */
3095PDMBOTHCBDECL(int) vgaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3096{
3097 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3098 NOREF(pvUser);
3099
3100 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_HC_IOPORT_READ);
3101 if (rc != VINF_SUCCESS)
3102 return rc;
3103
3104 rc = VERR_IOM_IOPORT_UNUSED;
3105 if (cb == 1)
3106 {
3107 *pu32 = vga_ioport_read(s, Port);
3108 rc = VINF_SUCCESS;
3109 }
3110 else if (cb == 2)
3111 {
3112 *pu32 = vga_ioport_read(s, Port)
3113 | (vga_ioport_read(s, Port + 1) << 8);
3114 rc = VINF_SUCCESS;
3115 }
3116 PDMCritSectLeave(&s->lock);
3117 return rc;
3118}
3119
3120
3121/**
3122 * Port I/O Handler for VBE OUT operations.
3123 *
3124 * @returns VBox status code.
3125 *
3126 * @param pDevIns The device instance.
3127 * @param pvUser User argument - ignored.
3128 * @param Port Port number used for the IN operation.
3129 * @param u32 The value to output.
3130 * @param cb The value size in bytes.
3131 */
3132PDMBOTHCBDECL(int) vgaIOPortWriteVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3133{
3134 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3135
3136 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_HC_IOPORT_WRITE);
3137 if (rc != VINF_SUCCESS)
3138 return rc;
3139
3140 NOREF(pvUser);
3141
3142#ifndef IN_RING3
3143 /*
3144 * This has to be done on the host in order to execute the connector callbacks.
3145 */
3146 if ( s->vbe_index == VBE_DISPI_INDEX_ENABLE
3147 || s->vbe_index == VBE_DISPI_INDEX_VBOX_VIDEO)
3148 {
3149 Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE - Switching to host...\n"));
3150 PDMCritSectLeave(&s->lock);
3151 return VINF_IOM_HC_IOPORT_WRITE;
3152 }
3153#endif
3154#ifdef VBE_BYTEWISE_IO
3155 if (cb == 1)
3156 {
3157 if (!s->fWriteVBEData)
3158 {
3159 if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
3160 && (u32 & VBE_DISPI_ENABLED))
3161 {
3162 s->fWriteVBEData = false;
3163 rc = vbe_ioport_write_data(s, Port, u32 & 0xFF);
3164 PDMCritSectLeave(&s->lock);
3165 return rc;
3166 }
3167 else
3168 {
3169 s->cbWriteVBEData = u32 & 0xFF;
3170 s->fWriteVBEData = true;
3171 PDMCritSectLeave(&s->lock);
3172 return VINF_SUCCESS;
3173 }
3174 }
3175 else
3176 {
3177 u32 = (s->cbWriteVBEData << 8) | (u32 & 0xFF);
3178 s->fWriteVBEData = false;
3179 cb = 2;
3180 }
3181 }
3182#endif
3183 if (cb == 2 || cb == 4)
3184 {
3185//#ifdef IN_RC
3186// /*
3187// * The VBE_DISPI_INDEX_ENABLE memsets the entire frame buffer.
3188// * Since we're not mapping the entire framebuffer any longer that
3189// * has to be done on the host.
3190// */
3191// if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
3192// && (u32 & VBE_DISPI_ENABLED))
3193// {
3194// Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE & VBE_DISPI_ENABLED - Switching to host...\n"));
3195// return VINF_IOM_HC_IOPORT_WRITE;
3196// }
3197//#endif
3198 rc = vbe_ioport_write_data(s, Port, u32);
3199 PDMCritSectLeave(&s->lock);
3200 return rc;
3201 }
3202 else
3203 AssertMsgFailed(("vgaIOPortWriteVBEData: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3204
3205 PDMCritSectLeave(&s->lock);
3206 return VINF_SUCCESS;
3207}
3208
3209
3210/**
3211 * Port I/O Handler for VBE OUT operations.
3212 *
3213 * @returns VBox status code.
3214 *
3215 * @param pDevIns The device instance.
3216 * @param pvUser User argument - ignored.
3217 * @param Port Port number used for the IN operation.
3218 * @param u32 The value to output.
3219 * @param cb The value size in bytes.
3220 */
3221PDMBOTHCBDECL(int) vgaIOPortWriteVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3222{
3223 NOREF(pvUser);
3224 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3225
3226 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_HC_IOPORT_WRITE);
3227 if (rc != VINF_SUCCESS)
3228 return rc;
3229
3230#ifdef VBE_BYTEWISE_IO
3231 if (cb == 1)
3232 {
3233 if (!s->fWriteVBEIndex)
3234 {
3235 s->cbWriteVBEIndex = u32 & 0x00FF;
3236 s->fWriteVBEIndex = true;
3237 PDMCritSectLeave(&s->lock);
3238 return VINF_SUCCESS;
3239 }
3240 else
3241 {
3242 s->fWriteVBEIndex = false;
3243 vbe_ioport_write_index(s, Port, (s->cbWriteVBEIndex << 8) | (u32 & 0x00FF));
3244 PDMCritSectLeave(&s->lock);
3245 return VINF_SUCCESS;
3246 }
3247 }
3248 else
3249#endif
3250 if (cb == 2)
3251 vbe_ioport_write_index(s, Port, u32);
3252 else
3253 AssertMsgFailed(("vgaIOPortWriteVBEIndex: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3254 PDMCritSectLeave(&s->lock);
3255 return VINF_SUCCESS;
3256}
3257
3258
3259/**
3260 * Port I/O Handler for VBE IN operations.
3261 *
3262 * @returns VBox status code.
3263 *
3264 * @param pDevIns The device instance.
3265 * @param pvUser User argument - ignored.
3266 * @param Port Port number used for the IN operation.
3267 * @param pu32 Where to store the result.
3268 * @param cb Number of bytes to read.
3269 */
3270PDMBOTHCBDECL(int) vgaIOPortReadVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3271{
3272 NOREF(pvUser);
3273 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3274
3275 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_HC_IOPORT_READ);
3276 if (rc != VINF_SUCCESS)
3277 return rc;
3278
3279#ifdef VBE_BYTEWISE_IO
3280 if (cb == 1)
3281 {
3282 if (!s->fReadVBEData)
3283 {
3284 *pu32 = (vbe_ioport_read_data(s, Port) >> 8) & 0xFF;
3285 s->fReadVBEData = true;
3286 PDMCritSectLeave(&s->lock);
3287 return VINF_SUCCESS;
3288 }
3289 else
3290 {
3291 *pu32 = vbe_ioport_read_data(s, Port) & 0xFF;
3292 s->fReadVBEData = false;
3293 PDMCritSectLeave(&s->lock);
3294 return VINF_SUCCESS;
3295 }
3296 }
3297 else
3298#endif
3299 if (cb == 2)
3300 {
3301 *pu32 = vbe_ioport_read_data(s, Port);
3302 PDMCritSectLeave(&s->lock);
3303 return VINF_SUCCESS;
3304 }
3305 else if (cb == 4)
3306 {
3307 /* Quick hack for getting the vram size. */
3308 *pu32 = s->vram_size;
3309 PDMCritSectLeave(&s->lock);
3310 return VINF_SUCCESS;
3311 }
3312 AssertMsgFailed(("vgaIOPortReadVBEData: Port=%#x cb=%d\n", Port, cb));
3313 PDMCritSectLeave(&s->lock);
3314 return VERR_IOM_IOPORT_UNUSED;
3315}
3316
3317
3318/**
3319 * Port I/O Handler for VBE IN operations.
3320 *
3321 * @returns VBox status code.
3322 *
3323 * @param pDevIns The device instance.
3324 * @param pvUser User argument - ignored.
3325 * @param Port Port number used for the IN operation.
3326 * @param pu32 Where to store the result.
3327 * @param cb Number of bytes to read.
3328 */
3329PDMBOTHCBDECL(int) vgaIOPortReadVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3330{
3331 NOREF(pvUser);
3332 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3333
3334 int rc = PDMCritSectEnter(&s->lock, VINF_IOM_HC_IOPORT_READ);
3335 if (rc != VINF_SUCCESS)
3336 return rc;
3337
3338#ifdef VBE_BYTEWISE_IO
3339 if (cb == 1)
3340 {
3341 if (!s->fReadVBEIndex)
3342 {
3343 *pu32 = (vbe_ioport_read_index(s, Port) >> 8) & 0xFF;
3344 s->fReadVBEIndex = true;
3345 PDMCritSectLeave(&s->lock);
3346 return VINF_SUCCESS;
3347 }
3348 else
3349 {
3350 *pu32 = vbe_ioport_read_index(s, Port) & 0xFF;
3351 s->fReadVBEIndex = false;
3352 PDMCritSectLeave(&s->lock);
3353 return VINF_SUCCESS;
3354 }
3355 }
3356 else
3357#endif
3358 if (cb == 2)
3359 {
3360 *pu32 = vbe_ioport_read_index(s, Port);
3361 PDMCritSectLeave(&s->lock);
3362 return VINF_SUCCESS;
3363 }
3364 PDMCritSectLeave(&s->lock);
3365 AssertMsgFailed(("vgaIOPortReadVBEIndex: Port=%#x cb=%d\n", Port, cb));
3366 return VERR_IOM_IOPORT_UNUSED;
3367}
3368
3369#ifdef VBOX_WITH_HGSMI
3370#ifdef IN_RING3
3371/**
3372 * Port I/O Handler for HGSMI OUT operations.
3373 *
3374 * @returns VBox status code.
3375 *
3376 * @param pDevIns The device instance.
3377 * @param pvUser User argument - ignored.
3378 * @param Port Port number used for the operation.
3379 * @param u32 The value to output.
3380 * @param cb The value size in bytes.
3381 */
3382static DECLCALLBACK(int) vgaR3IOPortHGSMIWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3383{
3384 LogFlowFunc(("Port 0x%x, u32 0x%x, cb %d\n", Port, u32, cb));
3385 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3386
3387 int rc = PDMCritSectEnter(&s->lock, VERR_SEM_BUSY);
3388 if (rc != VINF_SUCCESS)
3389 return rc;
3390
3391 NOREF(pvUser);
3392
3393 if (cb == 4)
3394 {
3395 switch (Port)
3396 {
3397 case 0x3b0: /* Host */
3398 {
3399#if defined(VBOX_WITH_VIDEOHWACCEL)
3400 if(u32 == HGSMIOFFSET_VOID)
3401 {
3402 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_LOW);
3403 HGSMIClearHostGuestFlags(s->pHGSMI, HGSMIHOSTFLAGS_IRQ);
3404 }
3405 else
3406#endif
3407 {
3408 HGSMIHostWrite(s->pHGSMI, u32);
3409 }
3410 } break;
3411
3412 case 0x3d0: /* Guest */
3413 {
3414 HGSMIGuestWrite(s->pHGSMI, u32);
3415 } break;
3416
3417 default:
3418 {
3419#ifdef DEBUG_sunlover
3420 AssertMsgFailed(("vgaR3IOPortHGSMIWrite: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3421#endif
3422 } break;
3423 }
3424 }
3425 else
3426 {
3427#ifdef DEBUG_sunlover
3428 AssertMsgFailed(("vgaR3IOPortHGSMIWrite: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3429#endif
3430 }
3431
3432 PDMCritSectLeave(&s->lock);
3433 return VINF_SUCCESS;
3434}
3435
3436/**
3437 * Port I/O Handler for HGSMI IN operations.
3438 *
3439 * @returns VBox status code.
3440 *
3441 * @param pDevIns The device instance.
3442 * @param pvUser User argument - ignored.
3443 * @param Port Port number used for the operation.
3444 * @param pu32 Where to store the result.
3445 * @param cb Number of bytes to read.
3446 */
3447static DECLCALLBACK(int) vgaR3IOPortHGSMIRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3448{
3449 LogFlowFunc(("Port 0x%x, cb %d\n", Port, cb));
3450 VGAState *s = PDMINS_2_DATA(pDevIns, PVGASTATE);
3451
3452 int rc = PDMCritSectEnter(&s->lock, VERR_SEM_BUSY);
3453 if (rc != VINF_SUCCESS)
3454 return rc;
3455
3456 NOREF(pvUser);
3457
3458 if (cb == 4)
3459 {
3460 switch (Port)
3461 {
3462 case 0x3b0: /* Host */
3463 {
3464 *pu32 = HGSMIHostRead(s->pHGSMI);
3465 } break;
3466 case 0x3d0: /* Guest */
3467 {
3468 *pu32 = HGSMIGuestRead(s->pHGSMI);
3469 } break;
3470 default:
3471 {
3472#ifdef DEBUG_sunlover
3473 AssertMsgFailed(("vgaR3IOPortHGSMIRead: Port=%#x cb=%d\n", Port, cb));
3474#endif
3475 rc = VERR_IOM_IOPORT_UNUSED;
3476 } break;
3477 }
3478 }
3479 else
3480 {
3481#ifdef DEBUG_sunlover
3482 AssertMsgFailed(("vgaR3IOPortHGSMIRead: Port=%#x cb=%d\n", Port, cb));
3483#endif
3484 rc = VERR_IOM_IOPORT_UNUSED;
3485 }
3486
3487 PDMCritSectLeave(&s->lock);
3488 return rc;
3489}
3490#endif /* IN_RING3 */
3491#endif /* VBOX_WITH_HGSMI */
3492
3493
3494
3495
3496/* -=-=-=-=-=- Guest Context -=-=-=-=-=- */
3497
3498/*
3499 * Internal. For use inside VGAGCMemoryFillWrite only.
3500 * Macro for apply logical operation and bit mask.
3501 */
3502#define APPLY_LOGICAL_AND_MASK(s, val, bit_mask) \
3503 /* apply logical operation */ \
3504 switch(s->gr[3] >> 3) \
3505 { \
3506 case 0: \
3507 default: \
3508 /* nothing to do */ \
3509 break; \
3510 case 1: \
3511 /* and */ \
3512 val &= s->latch; \
3513 break; \
3514 case 2: \
3515 /* or */ \
3516 val |= s->latch; \
3517 break; \
3518 case 3: \
3519 /* xor */ \
3520 val ^= s->latch; \
3521 break; \
3522 } \
3523 /* apply bit mask */ \
3524 val = (val & bit_mask) | (s->latch & ~bit_mask)
3525
3526/**
3527 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM and from the inside of VGADeviceGC.cpp.
3528 * This is the advanced version of vga_mem_writeb function.
3529 *
3530 * @returns VBox status code.
3531 * @param pThis VGA device structure
3532 * @param pvUser User argument - ignored.
3533 * @param GCPhysAddr Physical address of memory to write.
3534 * @param u32Item Data to write, up to 4 bytes.
3535 * @param cbItem Size of data Item, only 1/2/4 bytes is allowed for now.
3536 * @param cItems Number of data items to write.
3537 */
3538static int vgaInternalMMIOFill(PVGASTATE pThis, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems)
3539{
3540 uint32_t b;
3541 uint32_t write_mask, bit_mask, set_mask;
3542 uint32_t aVal[4];
3543 unsigned i;
3544 NOREF(pvUser);
3545
3546 for (i = 0; i < cbItem; i++)
3547 {
3548 aVal[i] = u32Item & 0xff;
3549 u32Item >>= 8;
3550 }
3551
3552 /* convert to VGA memory offset */
3553 /// @todo add check for the end of region
3554 GCPhysAddr &= 0x1ffff;
3555 switch((pThis->gr[6] >> 2) & 3) {
3556 case 0:
3557 break;
3558 case 1:
3559 if (GCPhysAddr >= 0x10000)
3560 return VINF_SUCCESS;
3561 GCPhysAddr += pThis->bank_offset;
3562 break;
3563 case 2:
3564 GCPhysAddr -= 0x10000;
3565 if (GCPhysAddr >= 0x8000)
3566 return VINF_SUCCESS;
3567 break;
3568 default:
3569 case 3:
3570 GCPhysAddr -= 0x18000;
3571 if (GCPhysAddr >= 0x8000)
3572 return VINF_SUCCESS;
3573 break;
3574 }
3575
3576 if (pThis->sr[4] & 0x08) {
3577 /* chain 4 mode : simplest access */
3578 VERIFY_VRAM_WRITE_OFF_RETURN(pThis, GCPhysAddr + cItems * cbItem - 1);
3579
3580 while (cItems-- > 0)
3581 for (i = 0; i < cbItem; i++)
3582 {
3583 if (pThis->sr[2] & (1 << (GCPhysAddr & 3)))
3584 {
3585 pThis->CTX_SUFF(vram_ptr)[GCPhysAddr] = aVal[i];
3586 vga_set_dirty(pThis, GCPhysAddr);
3587 }
3588 GCPhysAddr++;
3589 }
3590 } else if (pThis->gr[5] & 0x10) {
3591 /* odd/even mode (aka text mode mapping) */
3592 VERIFY_VRAM_WRITE_OFF_RETURN(pThis, GCPhysAddr * 2 + cItems * cbItem - 1);
3593 while (cItems-- > 0)
3594 for (i = 0; i < cbItem; i++)
3595 {
3596 unsigned plane = (pThis->gr[4] & 2) | (GCPhysAddr & 1);
3597 if (pThis->sr[2] & (1 << plane)) {
3598 RTGCPHYS PhysAddr2 = ((GCPhysAddr & ~1) << 2) | plane;
3599 pThis->CTX_SUFF(vram_ptr)[PhysAddr2] = aVal[i];
3600 vga_set_dirty(pThis, PhysAddr2);
3601 }
3602 GCPhysAddr++;
3603 }
3604 } else {
3605 /* standard VGA latched access */
3606 VERIFY_VRAM_WRITE_OFF_RETURN(pThis, GCPhysAddr + cItems * cbItem - 1);
3607
3608 switch(pThis->gr[5] & 3) {
3609 default:
3610 case 0:
3611 /* rotate */
3612 b = pThis->gr[3] & 7;
3613 bit_mask = pThis->gr[8];
3614 bit_mask |= bit_mask << 8;
3615 bit_mask |= bit_mask << 16;
3616 set_mask = mask16[pThis->gr[1]];
3617
3618 for (i = 0; i < cbItem; i++)
3619 {
3620 aVal[i] = ((aVal[i] >> b) | (aVal[i] << (8 - b))) & 0xff;
3621 aVal[i] |= aVal[i] << 8;
3622 aVal[i] |= aVal[i] << 16;
3623
3624 /* apply set/reset mask */
3625 aVal[i] = (aVal[i] & ~set_mask) | (mask16[pThis->gr[0]] & set_mask);
3626
3627 APPLY_LOGICAL_AND_MASK(pThis, aVal[i], bit_mask);
3628 }
3629 break;
3630 case 1:
3631 for (i = 0; i < cbItem; i++)
3632 aVal[i] = pThis->latch;
3633 break;
3634 case 2:
3635 bit_mask = pThis->gr[8];
3636 bit_mask |= bit_mask << 8;
3637 bit_mask |= bit_mask << 16;
3638 for (i = 0; i < cbItem; i++)
3639 {
3640 aVal[i] = mask16[aVal[i] & 0x0f];
3641
3642 APPLY_LOGICAL_AND_MASK(pThis, aVal[i], bit_mask);
3643 }
3644 break;
3645 case 3:
3646 /* rotate */
3647 b = pThis->gr[3] & 7;
3648
3649 for (i = 0; i < cbItem; i++)
3650 {
3651 aVal[i] = (aVal[i] >> b) | (aVal[i] << (8 - b));
3652 bit_mask = pThis->gr[8] & aVal[i];
3653 bit_mask |= bit_mask << 8;
3654 bit_mask |= bit_mask << 16;
3655 aVal[i] = mask16[pThis->gr[0]];
3656
3657 APPLY_LOGICAL_AND_MASK(pThis, aVal[i], bit_mask);
3658 }
3659 break;
3660 }
3661
3662 /* mask data according to sr[2] */
3663 write_mask = mask16[pThis->sr[2]];
3664
3665 /* actually write data */
3666 if (cbItem == 1)
3667 {
3668 /* The most frequently case is 1 byte I/O. */
3669 while (cItems-- > 0)
3670 {
3671 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
3672 vga_set_dirty(pThis, GCPhysAddr << 2);
3673 GCPhysAddr++;
3674 }
3675 }
3676 else if (cbItem == 2)
3677 {
3678 /* The second case is 2 bytes I/O. */
3679 while (cItems-- > 0)
3680 {
3681 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
3682 vga_set_dirty(pThis, GCPhysAddr << 2);
3683 GCPhysAddr++;
3684
3685 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[1] & write_mask);
3686 vga_set_dirty(pThis, GCPhysAddr << 2);
3687 GCPhysAddr++;
3688 }
3689 }
3690 else
3691 {
3692 /* And the rest is 4 bytes. */
3693 Assert(cbItem == 4);
3694 while (cItems-- > 0)
3695 for (i = 0; i < cbItem; i++)
3696 {
3697 ((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pThis->CTX_SUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[i] & write_mask);
3698 vga_set_dirty(pThis, GCPhysAddr << 2);
3699 GCPhysAddr++;
3700 }
3701 }
3702 }
3703 return VINF_SUCCESS;
3704}
3705
3706/**
3707 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM and from the inside of VGADeviceGC.cpp.
3708 * This is the advanced version of vga_mem_writeb function.
3709 *
3710 * @returns VBox status code.
3711 * @param pDevIns Pointer device instance.
3712 * @param pvUser User argument - ignored.
3713 * @param GCPhysAddr Physical address of memory to write.
3714 * @param u32Item Data to write, up to 4 bytes.
3715 * @param cbItem Size of data Item, only 1/2/4 bytes is allowed for now.
3716 * @param cItems Number of data items to write.
3717 */
3718PDMBOTHCBDECL(int) vgaMMIOFill(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems)
3719{
3720 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3721
3722 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_HC_MMIO_WRITE);
3723 if (rc != VINF_SUCCESS)
3724 return rc;
3725
3726 rc = vgaInternalMMIOFill(pThis, pvUser, GCPhysAddr, u32Item, cbItem, cItems);
3727 PDMCritSectLeave(&pThis->lock);
3728 return rc;
3729}
3730#undef APPLY_LOGICAL_AND_MASK
3731
3732
3733/**
3734 * Legacy VGA memory (0xa0000 - 0xbffff) read hook, to be called from IOM.
3735 *
3736 * @returns VBox status code.
3737 * @param pDevIns Pointer device instance.
3738 * @param pvUser User argument - ignored.
3739 * @param GCPhysAddr Physical address of memory to read.
3740 * @param pv Where to store readed data.
3741 * @param cb Bytes to read.
3742 */
3743PDMBOTHCBDECL(int) vgaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3744{
3745 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3746 STAM_PROFILE_START(&pThis->CTX_MID_Z(Stat,MemoryRead), a);
3747 NOREF(pvUser);
3748
3749 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_HC_MMIO_READ);
3750 if (rc != VINF_SUCCESS)
3751 return rc;
3752
3753 switch (cb)
3754 {
3755 case 1:
3756 *(uint8_t *)pv = vga_mem_readb(pThis, GCPhysAddr, &rc); break;
3757 case 2:
3758 *(uint16_t *)pv = vga_mem_readb(pThis, GCPhysAddr, &rc)
3759 | (vga_mem_readb(pThis, GCPhysAddr + 1, &rc) << 8);
3760 break;
3761 case 4:
3762 *(uint32_t *)pv = vga_mem_readb(pThis, GCPhysAddr, &rc)
3763 | (vga_mem_readb(pThis, GCPhysAddr + 1, &rc) << 8)
3764 | (vga_mem_readb(pThis, GCPhysAddr + 2, &rc) << 16)
3765 | (vga_mem_readb(pThis, GCPhysAddr + 3, &rc) << 24);
3766 break;
3767
3768 case 8:
3769 *(uint64_t *)pv = (uint64_t)vga_mem_readb(pThis, GCPhysAddr, &rc)
3770 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 1, &rc) << 8)
3771 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 2, &rc) << 16)
3772 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 3, &rc) << 24)
3773 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 4, &rc) << 32)
3774 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 5, &rc) << 40)
3775 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 6, &rc) << 48)
3776 | ((uint64_t)vga_mem_readb(pThis, GCPhysAddr + 7, &rc) << 56);
3777 break;
3778
3779 default:
3780 {
3781 uint8_t *pu8Data = (uint8_t *)pv;
3782 while (cb-- > 0)
3783 {
3784 *pu8Data++ = vga_mem_readb(pThis, GCPhysAddr++, &rc);
3785 if (RT_UNLIKELY(rc != VINF_SUCCESS))
3786 break;
3787 }
3788 }
3789 }
3790 STAM_PROFILE_STOP(&pThis->CTX_MID_Z(Stat,MemoryRead), a);
3791 PDMCritSectLeave(&pThis->lock);
3792 return rc;
3793}
3794
3795/**
3796 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM.
3797 *
3798 * @returns VBox status code.
3799 * @param pDevIns Pointer device instance.
3800 * @param pvUser User argument - ignored.
3801 * @param GCPhysAddr Physical address of memory to write.
3802 * @param pv Pointer to data.
3803 * @param cb Bytes to write.
3804 */
3805PDMBOTHCBDECL(int) vgaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3806{
3807 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
3808 uint8_t *pu8 = (uint8_t *)pv;
3809 STAM_PROFILE_START(&pThis->CTX_MID_Z(Stat,MemoryWrite), a);
3810
3811 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_HC_MMIO_WRITE);
3812 if (rc != VINF_SUCCESS)
3813 return rc;
3814
3815 switch (cb)
3816 {
3817 case 1:
3818 rc = vga_mem_writeb(pThis, GCPhysAddr, *pu8);
3819 break;
3820#if 1
3821 case 2:
3822 rc = vga_mem_writeb(pThis, GCPhysAddr + 0, pu8[0]);
3823 if (RT_LIKELY(rc == VINF_SUCCESS))
3824 rc = vga_mem_writeb(pThis, GCPhysAddr + 1, pu8[1]);
3825 break;
3826 case 4:
3827 rc = vga_mem_writeb(pThis, GCPhysAddr + 0, pu8[0]);
3828 if (RT_LIKELY(rc == VINF_SUCCESS))
3829 rc = vga_mem_writeb(pThis, GCPhysAddr + 1, pu8[1]);
3830 if (RT_LIKELY(rc == VINF_SUCCESS))
3831 rc = vga_mem_writeb(pThis, GCPhysAddr + 2, pu8[2]);
3832 if (RT_LIKELY(rc == VINF_SUCCESS))
3833 rc = vga_mem_writeb(pThis, GCPhysAddr + 3, pu8[3]);
3834 break;
3835 case 8:
3836 rc = vga_mem_writeb(pThis, GCPhysAddr + 0, pu8[0]);
3837 if (RT_LIKELY(rc == VINF_SUCCESS))
3838 rc = vga_mem_writeb(pThis, GCPhysAddr + 1, pu8[1]);
3839 if (RT_LIKELY(rc == VINF_SUCCESS))
3840 rc = vga_mem_writeb(pThis, GCPhysAddr + 2, pu8[2]);
3841 if (RT_LIKELY(rc == VINF_SUCCESS))
3842 rc = vga_mem_writeb(pThis, GCPhysAddr + 3, pu8[3]);
3843 if (RT_LIKELY(rc == VINF_SUCCESS))
3844 rc = vga_mem_writeb(pThis, GCPhysAddr + 4, pu8[4]);
3845 if (RT_LIKELY(rc == VINF_SUCCESS))
3846 rc = vga_mem_writeb(pThis, GCPhysAddr + 5, pu8[5]);
3847 if (RT_LIKELY(rc == VINF_SUCCESS))
3848 rc = vga_mem_writeb(pThis, GCPhysAddr + 6, pu8[6]);
3849 if (RT_LIKELY(rc == VINF_SUCCESS))
3850 rc = vga_mem_writeb(pThis, GCPhysAddr + 7, pu8[7]);
3851 break;
3852#else
3853 case 2:
3854 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint16_t *)pv, 2, 1);
3855 break;
3856 case 4:
3857 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint32_t *)pv, 4, 1);
3858 break;
3859 case 8:
3860 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint64_t *)pv, 8, 1);
3861 break;
3862#endif
3863 default:
3864 while (cb-- > 0 && rc == VINF_SUCCESS)
3865 rc = vga_mem_writeb(pThis, GCPhysAddr++, *pu8++);
3866 break;
3867
3868 }
3869 STAM_PROFILE_STOP(&pThis->CTX_MID_Z(Stat,MemoryWrite), a);
3870 PDMCritSectLeave(&pThis->lock);
3871 return rc;
3872}
3873
3874
3875/**
3876 * Handle LFB access.
3877 * @returns VBox status code.
3878 * @param pVM VM handle.
3879 * @param pThis VGA device instance data.
3880 * @param GCPhys The access physical address.
3881 * @param GCPtr The access virtual address (only GC).
3882 */
3883static int vgaLFBAccess(PVM pVM, PVGASTATE pThis, RTGCPHYS GCPhys, RTGCPTR GCPtr)
3884{
3885 int rc = PDMCritSectEnter(&pThis->lock, VINF_EM_RAW_EMULATE_INSTR);
3886 if (rc != VINF_SUCCESS)
3887 return rc;
3888
3889 /*
3890 * Set page dirty bit.
3891 */
3892 vga_set_dirty(pThis, GCPhys - pThis->GCPhysVRAM);
3893 pThis->fLFBUpdated = true;
3894
3895 /*
3896 * Turn of the write handler for this particular page and make it R/W.
3897 * Then return telling the caller to restart the guest instruction.
3898 * ASSUME: the guest always maps video memory RW.
3899 */
3900 rc = PGMHandlerPhysicalPageTempOff(pVM, pThis->GCPhysVRAM, GCPhys);
3901 if (RT_SUCCESS(rc))
3902 {
3903#ifndef IN_RING3
3904 rc = PGMShwModifyPage(PDMDevHlpGetVMCPU(pThis->CTX_SUFF(pDevIns)), GCPtr, 1, X86_PTE_RW, ~(uint64_t)X86_PTE_RW);
3905 PDMCritSectLeave(&pThis->lock);
3906 AssertMsgReturn( rc == VINF_SUCCESS
3907 /* In the SMP case the page table might be removed while we wait for the PGM lock in the trap handler. */
3908 || rc == VERR_PAGE_TABLE_NOT_PRESENT
3909 || rc == VERR_PAGE_NOT_PRESENT,
3910 ("PGMShwModifyPage -> GCPtr=%RGv rc=%d\n", GCPtr, rc),
3911 rc);
3912 return VINF_SUCCESS;
3913#else /* IN_RING3 : We don't have any virtual page address of the access here. */
3914 PDMCritSectLeave(&pThis->lock);
3915 Assert(GCPtr == 0);
3916 return VINF_SUCCESS;
3917#endif
3918 }
3919 else
3920 {
3921 PDMCritSectLeave(&pThis->lock);
3922 AssertMsgFailed(("PGMHandlerPhysicalPageTempOff -> rc=%d\n", rc));
3923 }
3924 return rc;
3925}
3926
3927
3928#ifdef IN_RC
3929/**
3930 * #PF Handler for VBE LFB access.
3931 *
3932 * @returns VBox status code (appropriate for GC return).
3933 * @param pVM VM Handle.
3934 * @param uErrorCode CPU Error code.
3935 * @param pRegFrame Trap register frame.
3936 * @param pvFault The fault address (cr2).
3937 * @param GCPhysFault The GC physical address corresponding to pvFault.
3938 * @param pvUser User argument, ignored.
3939 */
3940PDMBOTHCBDECL(int) vgaGCLFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
3941{
3942 PVGASTATE pThis = (PVGASTATE)pvUser;
3943 Assert(pThis);
3944 Assert(GCPhysFault >= pThis->GCPhysVRAM);
3945 AssertMsg(uErrorCode & X86_TRAP_PF_RW, ("uErrorCode=%#x\n", uErrorCode));
3946
3947 return vgaLFBAccess(pVM, pThis, GCPhysFault, pvFault);
3948}
3949
3950#elif IN_RING0
3951
3952/**
3953 * #PF Handler for VBE LFB access.
3954 *
3955 * @returns VBox status code (appropriate for GC return).
3956 * @param pVM VM Handle.
3957 * @param uErrorCode CPU Error code.
3958 * @param pRegFrame Trap register frame.
3959 * @param pvFault The fault address (cr2).
3960 * @param GCPhysFault The GC physical address corresponding to pvFault.
3961 * @param pvUser User argument, ignored.
3962 */
3963PDMBOTHCBDECL(int) vgaR0LFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
3964{
3965 PVGASTATE pThis = (PVGASTATE)pvUser;
3966 Assert(pThis);
3967 Assert(GCPhysFault >= pThis->GCPhysVRAM);
3968 AssertMsg(uErrorCode & X86_TRAP_PF_RW, ("uErrorCode=%#x\n", uErrorCode));
3969
3970 return vgaLFBAccess(pVM, pThis, GCPhysFault, pvFault);
3971}
3972
3973#else /* IN_RING3 */
3974
3975/**
3976 * HC access handler for the LFB.
3977 *
3978 * @returns VINF_SUCCESS if the handler have carried out the operation.
3979 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
3980 * @param pVM VM Handle.
3981 * @param GCPhys The physical address the guest is writing to.
3982 * @param pvPhys The HC mapping of that address.
3983 * @param pvBuf What the guest is reading/writing.
3984 * @param cbBuf How much it's reading/writing.
3985 * @param enmAccessType The access type.
3986 * @param pvUser User argument.
3987 */
3988static DECLCALLBACK(int) vgaR3LFBAccessHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
3989{
3990 PVGASTATE pThis = (PVGASTATE)pvUser;
3991 int rc;
3992 Assert(pThis);
3993 Assert(GCPhys >= pThis->GCPhysVRAM);
3994 rc = vgaLFBAccess(pVM, pThis, GCPhys, 0);
3995 if (RT_SUCCESS(rc))
3996 return VINF_PGM_HANDLER_DO_DEFAULT;
3997 AssertMsg(rc <= VINF_SUCCESS, ("rc=%Rrc\n", rc));
3998 return rc;
3999}
4000#endif /* IN_RING3 */
4001
4002/* -=-=-=-=-=- All rings: VGA BIOS I/Os -=-=-=-=-=- */
4003
4004/**
4005 * Port I/O Handler for VGA BIOS IN operations.
4006 *
4007 * @returns VBox status code.
4008 *
4009 * @param pDevIns The device instance.
4010 * @param pvUser User argument - ignored.
4011 * @param Port Port number used for the IN operation.
4012 * @param pu32 Where to store the result.
4013 * @param cb Number of bytes read.
4014 */
4015PDMBOTHCBDECL(int) vgaIOPortReadBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
4016{
4017 NOREF(pDevIns);
4018 NOREF(pvUser);
4019 NOREF(Port);
4020 NOREF(pu32);
4021 NOREF(cb);
4022 return VERR_IOM_IOPORT_UNUSED;
4023}
4024
4025/**
4026 * Port I/O Handler for VGA BIOS OUT operations.
4027 *
4028 * @returns VBox status code.
4029 *
4030 * @param pDevIns The device instance.
4031 * @param pvUser User argument - ignored.
4032 * @param Port Port number used for the IN operation.
4033 * @param u32 The value to output.
4034 * @param cb The value size in bytes.
4035 */
4036PDMBOTHCBDECL(int) vgaIOPortWriteBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
4037{
4038 static int lastWasNotNewline = 0; /* We are only called in a single-threaded way */
4039 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4040
4041 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_HC_IOPORT_WRITE);
4042 if (rc != VINF_SUCCESS)
4043 return rc;
4044
4045 /*
4046 * VGA BIOS char printing.
4047 */
4048 if ( cb == 1
4049 && Port == VBE_PRINTF_PORT)
4050 {
4051#if 0
4052 switch (u32)
4053 {
4054 case '\r': Log(("vgabios: <return>\n")); break;
4055 case '\n': Log(("vgabios: <newline>\n")); break;
4056 case '\t': Log(("vgabios: <tab>\n")); break;
4057 default:
4058 Log(("vgabios: %c\n", u32));
4059 }
4060#else
4061 if (lastWasNotNewline == 0)
4062 Log(("vgabios: "));
4063 if (u32 != '\r') /* return - is only sent in conjunction with '\n' */
4064 Log(("%c", u32));
4065 if (u32 == '\n')
4066 lastWasNotNewline = 0;
4067 else
4068 lastWasNotNewline = 1;
4069#endif
4070 PDMCritSectLeave(&pThis->lock);
4071 return VINF_SUCCESS;
4072 }
4073
4074 PDMCritSectLeave(&pThis->lock);
4075 /* not in use. */
4076 return VERR_IOM_IOPORT_UNUSED;
4077}
4078
4079
4080/* -=-=-=-=-=- Ring 3 -=-=-=-=-=- */
4081
4082#ifdef IN_RING3
4083
4084# ifdef VBE_NEW_DYN_LIST
4085/**
4086 * Port I/O Handler for VBE Extra OUT operations.
4087 *
4088 * @returns VBox status code.
4089 *
4090 * @param pDevIns The device instance.
4091 * @param pvUser User argument - ignored.
4092 * @param Port Port number used for the IN operation.
4093 * @param u32 The value to output.
4094 * @param cb The value size in bytes.
4095 */
4096PDMBOTHCBDECL(int) vbeIOPortWriteVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
4097{
4098 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4099 NOREF(pvUser);
4100 NOREF(Port);
4101
4102 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_HC_IOPORT_WRITE);
4103 if (rc != VINF_SUCCESS)
4104 return rc;
4105
4106 if (cb == 2)
4107 {
4108 Log(("vbeIOPortWriteVBEExtra: addr=%#RX32\n", u32));
4109 pThis->u16VBEExtraAddress = u32;
4110 }
4111 else
4112 Log(("vbeIOPortWriteVBEExtra: Ignoring invalid cb=%d writes to the VBE Extra port!!!\n", cb));
4113 PDMCritSectLeave(&pThis->lock);
4114
4115 return VINF_SUCCESS;
4116}
4117
4118
4119/**
4120 * Port I/O Handler for VBE Extra IN operations.
4121 *
4122 * @returns VBox status code.
4123 *
4124 * @param pDevIns The device instance.
4125 * @param pvUser User argument - ignored.
4126 * @param Port Port number used for the IN operation.
4127 * @param pu32 Where to store the result.
4128 * @param cb Number of bytes read.
4129 */
4130PDMBOTHCBDECL(int) vbeIOPortReadVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
4131{
4132 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4133 NOREF(pvUser);
4134 NOREF(Port);
4135
4136 int rc = PDMCritSectEnter(&pThis->lock, VINF_IOM_HC_IOPORT_READ);
4137 if (rc != VINF_SUCCESS)
4138 return rc;
4139
4140 if (pThis->u16VBEExtraAddress == 0xffff)
4141 {
4142 Log(("vbeIOPortReadVBEExtra: Requested number of 64k video banks\n"));
4143 *pu32 = pThis->vram_size / _64K;
4144 rc = VINF_SUCCESS;
4145 }
4146 else
4147 if ( pThis->u16VBEExtraAddress >= pThis->cbVBEExtraData
4148 || pThis->u16VBEExtraAddress + cb > pThis->cbVBEExtraData)
4149 {
4150 *pu32 = 0;
4151 Log(("vbeIOPortReadVBEExtra: Requested address is out of VBE data!!! Address=%#x(%d) cbVBEExtraData=%#x(%d)\n",
4152 pThis->u16VBEExtraAddress, pThis->u16VBEExtraAddress, pThis->cbVBEExtraData, pThis->cbVBEExtraData));
4153 rc = VINF_SUCCESS;
4154 }
4155 else
4156 if (cb == 1)
4157 {
4158 *pu32 = pThis->pu8VBEExtraData[pThis->u16VBEExtraAddress] & 0xFF;
4159
4160 Log(("vbeIOPortReadVBEExtra: cb=%#x %.*Rhxs\n", cb, cb, pu32));
4161 rc = VINF_SUCCESS;
4162 }
4163 else
4164 if (cb == 2)
4165 {
4166 *pu32 = pThis->pu8VBEExtraData[pThis->u16VBEExtraAddress]
4167 | pThis->pu8VBEExtraData[pThis->u16VBEExtraAddress + 1] << 8;
4168
4169 Log(("vbeIOPortReadVBEExtra: cb=%#x %.*Rhxs\n", cb, cb, pu32));
4170 rc = VINF_SUCCESS;
4171 }
4172 else
4173 {
4174 Log(("vbeIOPortReadVBEExtra: Invalid cb=%d read from the VBE Extra port!!!\n", cb));
4175 rc = VERR_IOM_IOPORT_UNUSED;
4176 }
4177
4178 PDMCritSectLeave(&pThis->lock);
4179 return rc;
4180}
4181# endif /* VBE_NEW_DYN_LIST */
4182
4183
4184/**
4185 * Parse the logo bitmap data at init time.
4186 *
4187 * @returns VBox status code.
4188 *
4189 * @param pThis The VGA instance data.
4190 */
4191static int vbeParseBitmap(PVGASTATE pThis)
4192{
4193 uint16_t i;
4194 PBMPINFO bmpInfo;
4195 POS2HDR pOs2Hdr;
4196 POS22HDR pOs22Hdr;
4197 PWINHDR pWinHdr;
4198
4199 /*
4200 * Get bitmap header data
4201 */
4202 bmpInfo = (PBMPINFO)(pThis->pu8Logo + sizeof(LOGOHDR));
4203 pWinHdr = (PWINHDR)(pThis->pu8Logo + sizeof(LOGOHDR) + sizeof(BMPINFO));
4204
4205 if (bmpInfo->Type == BMP_ID)
4206 {
4207 switch (pWinHdr->Size)
4208 {
4209 case BMP_HEADER_OS21:
4210 pOs2Hdr = (POS2HDR)pWinHdr;
4211 pThis->cxLogo = pOs2Hdr->Width;
4212 pThis->cyLogo = pOs2Hdr->Height;
4213 pThis->cLogoPlanes = pOs2Hdr->Planes;
4214 pThis->cLogoBits = pOs2Hdr->BitCount;
4215 pThis->LogoCompression = BMP_COMPRESS_NONE;
4216 pThis->cLogoUsedColors = 0;
4217 break;
4218
4219 case BMP_HEADER_OS22:
4220 pOs22Hdr = (POS22HDR)pWinHdr;
4221 pThis->cxLogo = pOs22Hdr->Width;
4222 pThis->cyLogo = pOs22Hdr->Height;
4223 pThis->cLogoPlanes = pOs22Hdr->Planes;
4224 pThis->cLogoBits = pOs22Hdr->BitCount;
4225 pThis->LogoCompression = pOs22Hdr->Compression;
4226 pThis->cLogoUsedColors = pOs22Hdr->ClrUsed;
4227 break;
4228
4229 case BMP_HEADER_WIN3:
4230 pThis->cxLogo = pWinHdr->Width;
4231 pThis->cyLogo = pWinHdr->Height;
4232 pThis->cLogoPlanes = pWinHdr->Planes;
4233 pThis->cLogoBits = pWinHdr->BitCount;
4234 pThis->LogoCompression = pWinHdr->Compression;
4235 pThis->cLogoUsedColors = pWinHdr->ClrUsed;
4236 break;
4237
4238 default:
4239 AssertMsgFailed(("Unsupported bitmap header.\n"));
4240 break;
4241 }
4242
4243 if (pThis->cxLogo > LOGO_MAX_WIDTH || pThis->cyLogo > LOGO_MAX_HEIGHT)
4244 {
4245 AssertMsgFailed(("Bitmap %ux%u is too big.\n", pThis->cxLogo, pThis->cyLogo));
4246 return VERR_INVALID_PARAMETER;
4247 }
4248
4249 if (pThis->cLogoPlanes != 1)
4250 {
4251 AssertMsgFailed(("Bitmap planes %u != 1.\n", pThis->cLogoPlanes));
4252 return VERR_INVALID_PARAMETER;
4253 }
4254
4255 if (pThis->cLogoBits != 4 && pThis->cLogoBits != 8 && pThis->cLogoBits != 24)
4256 {
4257 AssertMsgFailed(("Unsupported %u depth.\n", pThis->cLogoBits));
4258 return VERR_INVALID_PARAMETER;
4259 }
4260
4261 if (pThis->cLogoUsedColors > 256)
4262 {
4263 AssertMsgFailed(("Unsupported %u colors.\n", pThis->cLogoUsedColors));
4264 return VERR_INVALID_PARAMETER;
4265 }
4266
4267 if (pThis->LogoCompression != BMP_COMPRESS_NONE)
4268 {
4269 AssertMsgFailed(("Unsupported %u compression.\n", pThis->LogoCompression));
4270 return VERR_INVALID_PARAMETER;
4271 }
4272
4273 /*
4274 * Read bitmap palette
4275 */
4276 if (!pThis->cLogoUsedColors)
4277 pThis->cLogoPalEntries = 1 << (pThis->cLogoPlanes * pThis->cLogoBits);
4278 else
4279 pThis->cLogoPalEntries = pThis->cLogoUsedColors;
4280
4281 if (pThis->cLogoPalEntries)
4282 {
4283 const uint8_t *pu8Pal = pThis->pu8Logo + sizeof(LOGOHDR) + sizeof(BMPINFO) + pWinHdr->Size; /* ASSUMES Size location (safe) */
4284
4285 for (i = 0; i < pThis->cLogoPalEntries; i++)
4286 {
4287 uint16_t j;
4288 uint32_t u32Pal = 0;
4289
4290 for (j = 0; j < 3; j++)
4291 {
4292 uint8_t b = *pu8Pal++;
4293 u32Pal <<= 8;
4294 u32Pal |= b;
4295 }
4296
4297 pu8Pal++; /* skip unused byte */
4298 pThis->au32LogoPalette[i] = u32Pal;
4299 }
4300 }
4301
4302 /*
4303 * Bitmap data offset
4304 */
4305 pThis->pu8LogoBitmap = pThis->pu8Logo + sizeof(LOGOHDR) + bmpInfo->Offset;
4306 }
4307
4308 return VINF_SUCCESS;
4309}
4310
4311
4312/**
4313 * Show logo bitmap data.
4314 *
4315 * @returns VBox status code.
4316 *
4317 * @param cbDepth Logo depth.
4318 * @param xLogo Logo X position.
4319 * @param yLogo Logo Y position.
4320 * @param cxLogo Logo width.
4321 * @param cyLogo Logo height.
4322 * @param iStep Fade in/fade out step.
4323 * @param pu32Palette Palette data.
4324 * @param pu8Src Source buffer.
4325 * @param pu8Dst Destination buffer.
4326 */
4327static void vbeShowBitmap(uint16_t cBits, uint16_t xLogo, uint16_t yLogo, uint16_t cxLogo, uint16_t cyLogo, uint8_t iStep,
4328 const uint32_t *pu32Palette, const uint8_t *pu8Src, uint8_t *pu8Dst)
4329{
4330 uint16_t i;
4331 size_t cbPadBytes = 0;
4332 size_t cbLineDst = LOGO_MAX_WIDTH * 4;
4333 uint16_t cyLeft = cyLogo;
4334
4335 pu8Dst += xLogo * 4 + yLogo * cbLineDst;
4336
4337 switch (cBits)
4338 {
4339 case 1:
4340 pu8Dst += cyLogo * cbLineDst;
4341 cbPadBytes = 0;
4342 break;
4343
4344 case 4:
4345 if (((cxLogo % 8) == 0) || ((cxLogo % 8) > 6))
4346 cbPadBytes = 0;
4347 else if ((cxLogo % 8) <= 2)
4348 cbPadBytes = 3;
4349 else if ((cxLogo % 8) <= 4)
4350 cbPadBytes = 2;
4351 else
4352 cbPadBytes = 1;
4353 break;
4354
4355 case 8:
4356 cbPadBytes = ((cxLogo % 4) == 0) ? 0 : (4 - (cxLogo % 4));
4357 break;
4358
4359 case 24:
4360 cbPadBytes = cxLogo % 4;
4361 break;
4362 }
4363
4364 uint8_t j = 0, c = 0;
4365
4366 while (cyLeft-- > 0)
4367 {
4368 uint8_t *pu8TmpPtr = pu8Dst;
4369
4370 if (cBits != 1)
4371 j = 0;
4372
4373 for (i = 0; i < cxLogo; i++)
4374 {
4375 uint8_t pix;
4376
4377 switch (cBits)
4378 {
4379 case 1:
4380 {
4381 if (!j)
4382 c = *pu8Src++;
4383
4384 pix = (c & 1) ? 0xFF : 0;
4385 c >>= 1;
4386
4387 if (pix)
4388 {
4389 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4390 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4391 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4392 *pu8TmpPtr++;
4393 }
4394 else
4395 {
4396 pu8TmpPtr += 4;
4397 }
4398
4399 j = (j + 1) % 8;
4400 break;
4401 }
4402
4403 case 4:
4404 {
4405 if (!j)
4406 c = *pu8Src++;
4407
4408 pix = (c >> 4) & 0xF;
4409 c <<= 4;
4410
4411 uint32_t u32Pal = pu32Palette[pix];
4412
4413 pix = (u32Pal >> 16) & 0xFF;
4414 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4415 pix = (u32Pal >> 8) & 0xFF;
4416 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4417 pix = u32Pal & 0xFF;
4418 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4419 *pu8TmpPtr++;
4420
4421 j = (j + 1) % 2;
4422 break;
4423 }
4424
4425 case 8:
4426 {
4427 uint32_t u32Pal = pu32Palette[*pu8Src++];
4428
4429 pix = (u32Pal >> 16) & 0xFF;
4430 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4431 pix = (u32Pal >> 8) & 0xFF;
4432 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4433 pix = u32Pal & 0xFF;
4434 *pu8TmpPtr++ = pix * iStep / LOGO_SHOW_STEPS;
4435 *pu8TmpPtr++;
4436 break;
4437 }
4438
4439 case 24:
4440 *pu8TmpPtr++ = *pu8Src++ * iStep / LOGO_SHOW_STEPS;
4441 *pu8TmpPtr++ = *pu8Src++ * iStep / LOGO_SHOW_STEPS;
4442 *pu8TmpPtr++ = *pu8Src++ * iStep / LOGO_SHOW_STEPS;
4443 *pu8TmpPtr++;
4444 break;
4445 }
4446 }
4447
4448 pu8Dst -= cbLineDst;
4449 pu8Src += cbPadBytes;
4450 }
4451}
4452
4453
4454
4455
4456/**
4457 * Port I/O Handler for BIOS Logo OUT operations.
4458 *
4459 * @returns VBox status code.
4460 *
4461 * @param pDevIns The device instance.
4462 * @param pvUser User argument - ignored.
4463 * @param Port Port number used for the IN operation.
4464 * @param u32 The value to output.
4465 * @param cb The value size in bytes.
4466 */
4467PDMBOTHCBDECL(int) vbeIOPortWriteCMDLogo(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
4468{
4469 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4470 NOREF(pvUser);
4471 NOREF(Port);
4472
4473 Log(("vbeIOPortWriteCMDLogo: cb=%d u32=%#04x(%#04d) (byte)\n", cb, u32, u32));
4474
4475 if (cb == 2)
4476 {
4477 /* Get the logo command */
4478 switch (u32 & 0xFF00)
4479 {
4480 case LOGO_CMD_SET_OFFSET:
4481 pThis->offLogoData = u32 & 0xFF;
4482 break;
4483
4484 case LOGO_CMD_SHOW_BMP:
4485 {
4486 uint8_t iStep = u32 & 0xFF;
4487 const uint8_t *pu8Src = pThis->pu8LogoBitmap;
4488 uint8_t *pu8Dst;
4489 PLOGOHDR pLogoHdr = (PLOGOHDR)pThis->pu8Logo;
4490 uint32_t offDirty = 0;
4491 uint16_t xLogo = (LOGO_MAX_WIDTH - pThis->cxLogo) / 2;
4492 uint16_t yLogo = LOGO_MAX_HEIGHT - (LOGO_MAX_HEIGHT - pThis->cyLogo) / 2;
4493
4494 /* Check VRAM size */
4495 if (pThis->vram_size < LOGO_MAX_SIZE)
4496 break;
4497
4498 if (pThis->vram_size >= LOGO_MAX_SIZE * 2)
4499 pu8Dst = pThis->vram_ptrR3 + LOGO_MAX_SIZE;
4500 else
4501 pu8Dst = pThis->vram_ptrR3;
4502
4503 /* Clear screen - except on power on... */
4504 if (!pThis->fLogoClearScreen)
4505 {
4506 uint32_t *pu32TmpPtr = (uint32_t *)pu8Dst;
4507
4508 /* Clear vram */
4509 for (int i = 0; i < LOGO_MAX_WIDTH; i++)
4510 {
4511 for (int j = 0; j < LOGO_MAX_HEIGHT; j++)
4512 *pu32TmpPtr++ = 0;
4513 }
4514 pThis->fLogoClearScreen = true;
4515 }
4516
4517 /* Show the bitmap. */
4518 vbeShowBitmap(pThis->cLogoBits, xLogo, yLogo,
4519 pThis->cxLogo, pThis->cyLogo,
4520 iStep, &pThis->au32LogoPalette[0],
4521 pu8Src, pu8Dst);
4522
4523 /* Show the 'Press F12...' text. */
4524 if (pLogoHdr->fu8ShowBootMenu == 2)
4525 vbeShowBitmap(1, LOGO_F12TEXT_X, LOGO_F12TEXT_Y,
4526 LOGO_F12TEXT_WIDTH, LOGO_F12TEXT_HEIGHT,
4527 iStep, &pThis->au32LogoPalette[0],
4528 &g_abLogoF12BootText[0], pu8Dst);
4529
4530 /* Blit the offscreen buffer. */
4531 if (pThis->vram_size >= LOGO_MAX_SIZE * 2)
4532 {
4533 uint32_t *pu32TmpDst = (uint32_t *)pThis->vram_ptrR3;
4534 uint32_t *pu32TmpSrc = (uint32_t *)(pThis->vram_ptrR3 + LOGO_MAX_SIZE);
4535 for (int i = 0; i < LOGO_MAX_WIDTH; i++)
4536 {
4537 for (int j = 0; j < LOGO_MAX_HEIGHT; j++)
4538 *pu32TmpDst++ = *pu32TmpSrc++;
4539 }
4540 }
4541
4542 /* Set the dirty flags. */
4543 while (offDirty <= LOGO_MAX_SIZE)
4544 {
4545 vga_set_dirty(pThis, offDirty);
4546 offDirty += PAGE_SIZE;
4547 }
4548 break;
4549 }
4550
4551 default:
4552 Log(("vbeIOPortWriteCMDLogo: invalid command %d\n", u32));
4553 pThis->LogoCommand = LOGO_CMD_NOP;
4554 break;
4555 }
4556
4557 return VINF_SUCCESS;
4558 }
4559
4560 Log(("vbeIOPortWriteCMDLogo: Ignoring invalid cb=%d writes to the VBE Extra port!!!\n", cb));
4561 return VINF_SUCCESS;
4562}
4563
4564
4565/**
4566 * Port I/O Handler for BIOS Logo IN operations.
4567 *
4568 * @returns VBox status code.
4569 *
4570 * @param pDevIns The device instance.
4571 * @param pvUser User argument - ignored.
4572 * @param Port Port number used for the IN operation.
4573 * @param pu32 Where to store the result.
4574 * @param cb Number of bytes read.
4575 */
4576PDMBOTHCBDECL(int) vbeIOPortReadCMDLogo(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
4577{
4578 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4579 NOREF(pvUser);
4580 NOREF(Port);
4581
4582 PRTUINT64U p;
4583
4584 if (pThis->offLogoData + cb > pThis->cbLogo)
4585 {
4586 Log(("vbeIOPortReadCMDLogo: Requested address is out of Logo data!!! offLogoData=%#x(%d) cbLogo=%#x(%d)\n",
4587 pThis->offLogoData, pThis->offLogoData, pThis->cbLogo, pThis->cbLogo));
4588 return VINF_SUCCESS;
4589 }
4590 p = (PRTUINT64U)&pThis->pu8Logo[pThis->offLogoData];
4591
4592 switch (cb)
4593 {
4594 case 1: *pu32 = p->au8[0]; break;
4595 case 2: *pu32 = p->au16[0]; break;
4596 case 4: *pu32 = p->au32[0]; break;
4597 //case 8: *pu32 = p->au64[0]; break;
4598 default: AssertFailed(); break;
4599 }
4600 Log(("vbeIOPortReadCMDLogo: LogoOffset=%#x(%d) cb=%#x %.*Rhxs\n", pThis->offLogoData, pThis->offLogoData, cb, cb, pu32));
4601
4602 pThis->LogoCommand = LOGO_CMD_NOP;
4603 pThis->offLogoData += cb;
4604
4605 return VINF_SUCCESS;
4606}
4607
4608/**
4609 * Info handler, device version. Dumps VGA memory formatted as
4610 * ASCII text, no attributes. Only looks at the first page.
4611 *
4612 * @param pDevIns Device instance which registered the info.
4613 * @param pHlp Callback functions for doing output.
4614 * @param pszArgs Argument string. Optional and specific to the handler.
4615 */
4616static DECLCALLBACK(void) vgaInfoText(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4617{
4618 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
4619 uint8_t *src;
4620 unsigned row, col;
4621 unsigned num_rows = 25, num_cols = 80;
4622
4623 /* Pure paranoia... */
4624 Assert(num_rows * num_cols * 8 <= pThis->vram_size);
4625
4626 src = pThis->vram_ptrR3;
4627 if (src)
4628 {
4629 for (col = 0; col < num_cols; ++col)
4630 pHlp->pfnPrintf(pHlp, "-");
4631 pHlp->pfnPrintf(pHlp, "\n");
4632 for (row = 0; row < num_rows; ++row)
4633 {
4634 for (col = 0; col < num_cols; ++col)
4635 {
4636 pHlp->pfnPrintf(pHlp, "%c", *src);
4637 src += 8; /* chars are spaced 8 bytes apart */
4638 }
4639 pHlp->pfnPrintf(pHlp, "\n");
4640 }
4641 for (col = 0; col < num_cols; ++col)
4642 pHlp->pfnPrintf(pHlp, "-");
4643 pHlp->pfnPrintf(pHlp, "\n");
4644 }
4645 else
4646 {
4647 pHlp->pfnPrintf(pHlp, "VGA memory not available!\n");
4648 }
4649}
4650
4651/**
4652 * Info handler, device version. Dumps VGA Sequencer registers.
4653 *
4654 * @param pDevIns Device instance which registered the info.
4655 * @param pHlp Callback functions for doing output.
4656 * @param pszArgs Argument string. Optional and specific to the handler.
4657 */
4658static DECLCALLBACK(void) vgaInfoSR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4659{
4660 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4661 unsigned i;
4662
4663 pHlp->pfnPrintf(pHlp, "VGA Sequencer (3C5): SR index 3C4:%02X\n", s->sr_index);
4664 Assert(sizeof(s->sr) >= 8);
4665 for (i = 0; i < 5; ++i)
4666 {
4667 pHlp->pfnPrintf(pHlp, " SR%02X:%02X", i, s->sr[i]);
4668 }
4669 pHlp->pfnPrintf(pHlp, "\n");
4670}
4671
4672/**
4673 * Info handler, device version. Dumps VGA CRTC registers.
4674 *
4675 * @param pDevIns Device instance which registered the info.
4676 * @param pHlp Callback functions for doing output.
4677 * @param pszArgs Argument string. Optional and specific to the handler.
4678 */
4679static DECLCALLBACK(void) vgaInfoCR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4680{
4681 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4682 unsigned i;
4683
4684 pHlp->pfnPrintf(pHlp, "VGA CRTC (3D5): CRTC index 3D4:%02X\n", s->cr_index);
4685 Assert(sizeof(s->cr) >= 24);
4686 for (i = 0; i < 10; ++i)
4687 {
4688 pHlp->pfnPrintf(pHlp, " CR%02X:%02X", i, s->cr[i]);
4689 }
4690 pHlp->pfnPrintf(pHlp, "\n");
4691 for (i = 10; i < 20; ++i)
4692 {
4693 pHlp->pfnPrintf(pHlp, " CR%02X:%02X", i, s->cr[i]);
4694 }
4695 pHlp->pfnPrintf(pHlp, "\n");
4696 for (i = 20; i < 25; ++i)
4697 {
4698 pHlp->pfnPrintf(pHlp, " CR%02X:%02X", i, s->cr[i]);
4699 }
4700 pHlp->pfnPrintf(pHlp, "\n");
4701}
4702
4703/**
4704 * Info handler, device version. Dumps VGA Sequencer registers.
4705 *
4706 * @param pDevIns Device instance which registered the info.
4707 * @param pHlp Callback functions for doing output.
4708 * @param pszArgs Argument string. Optional and specific to the handler.
4709 */
4710static DECLCALLBACK(void) vgaInfoAR(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4711{
4712 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4713 unsigned i;
4714
4715 pHlp->pfnPrintf(pHlp, "VGA Attribute Controller (3C0): index reg %02X, flip-flop: %d (%s)\n",
4716 s->ar_index, s->ar_flip_flop, s->ar_flip_flop ? "data" : "index" );
4717 Assert(sizeof(s->ar) >= 0x14);
4718 pHlp->pfnPrintf(pHlp, " Palette:");
4719 for (i = 0; i < 0x10; ++i)
4720 {
4721 pHlp->pfnPrintf(pHlp, " %02X", i, s->ar[i]);
4722 }
4723 pHlp->pfnPrintf(pHlp, "\n");
4724 for (i = 0x10; i <= 0x14; ++i)
4725 {
4726 pHlp->pfnPrintf(pHlp, " AR%02X:%02X", i, s->ar[i]);
4727 }
4728 pHlp->pfnPrintf(pHlp, "\n");
4729}
4730
4731/**
4732 * Info handler, device version. Dumps VGA DAC registers.
4733 *
4734 * @param pDevIns Device instance which registered the info.
4735 * @param pHlp Callback functions for doing output.
4736 * @param pszArgs Argument string. Optional and specific to the handler.
4737 */
4738static DECLCALLBACK(void) vgaInfoDAC(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4739{
4740 PVGASTATE s = PDMINS_2_DATA(pDevIns, PVGASTATE);
4741 unsigned i;
4742
4743 pHlp->pfnPrintf(pHlp, "VGA DAC contents:\n");
4744 for (i = 0; i < 0x100; ++i)
4745 {
4746 pHlp->pfnPrintf(pHlp, " %02X: %02X %02X %02X\n",
4747 i, s->palette[i*3+0], s->palette[i*3+1], s->palette[i*3+2]);
4748 }
4749}
4750
4751
4752/* -=-=-=-=-=- Ring 3: IBase -=-=-=-=-=- */
4753
4754/**
4755 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4756 */
4757static DECLCALLBACK(void *) vgaPortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4758{
4759 PVGASTATE pThis = RT_FROM_MEMBER(pInterface, VGASTATE, IBase);
4760 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
4761 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYPORT, &pThis->IPort);
4762#if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL)
4763 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYVBVACALLBACKS, &pThis->IVBVACallbacks);
4764#endif
4765 return NULL;
4766}
4767
4768
4769/* -=-=-=-=-=- Ring 3: Dummy IDisplayConnector -=-=-=-=-=- */
4770
4771/**
4772 * Resize the display.
4773 * This is called when the resolution changes. This usually happens on
4774 * request from the guest os, but may also happen as the result of a reset.
4775 *
4776 * @param pInterface Pointer to this interface.
4777 * @param cx New display width.
4778 * @param cy New display height
4779 * @thread The emulation thread.
4780 */
4781static DECLCALLBACK(int) vgaDummyResize(PPDMIDISPLAYCONNECTOR pInterface, uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
4782{
4783 return VINF_SUCCESS;
4784}
4785
4786
4787/**
4788 * Update a rectangle of the display.
4789 * PDMIDISPLAYPORT::pfnUpdateDisplay is the caller.
4790 *
4791 * @param pInterface Pointer to this interface.
4792 * @param x The upper left corner x coordinate of the rectangle.
4793 * @param y The upper left corner y coordinate of the rectangle.
4794 * @param cx The width of the rectangle.
4795 * @param cy The height of the rectangle.
4796 * @thread The emulation thread.
4797 */
4798static DECLCALLBACK(void) vgaDummyUpdateRect(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
4799{
4800}
4801
4802
4803/**
4804 * Refresh the display.
4805 *
4806 * The interval between these calls is set by
4807 * PDMIDISPLAYPORT::pfnSetRefreshRate(). The driver should call
4808 * PDMIDISPLAYPORT::pfnUpdateDisplay() if it wishes to refresh the
4809 * display. PDMIDISPLAYPORT::pfnUpdateDisplay calls pfnUpdateRect with
4810 * the changed rectangles.
4811 *
4812 * @param pInterface Pointer to this interface.
4813 * @thread The emulation thread.
4814 */
4815static DECLCALLBACK(void) vgaDummyRefresh(PPDMIDISPLAYCONNECTOR pInterface)
4816{
4817}
4818
4819
4820/* -=-=-=-=-=- Ring 3: IDisplayPort -=-=-=-=-=- */
4821
4822/** Converts a display port interface pointer to a vga state pointer. */
4823#define IDISPLAYPORT_2_VGASTATE(pInterface) ( (PVGASTATE)((uintptr_t)pInterface - RT_OFFSETOF(VGASTATE, IPort)) )
4824
4825
4826/**
4827 * Update the display with any changed regions.
4828 *
4829 * @param pInterface Pointer to this interface.
4830 * @see PDMIKEYBOARDPORT::pfnUpdateDisplay() for details.
4831 */
4832static DECLCALLBACK(int) vgaPortUpdateDisplay(PPDMIDISPLAYPORT pInterface)
4833{
4834 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4835 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4836 PPDMDEVINS pDevIns = pThis->CTX_SUFF(pDevIns);
4837
4838 int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
4839 AssertRC(rc);
4840
4841#ifndef VBOX_WITH_HGSMI
4842 /* This should be called only in non VBVA mode. */
4843#else
4844 if (VBVAUpdateDisplay (pThis) == VINF_SUCCESS)
4845 {
4846 PDMCritSectLeave(&pThis->lock);
4847 return VINF_SUCCESS;
4848 }
4849#endif /* VBOX_WITH_HGSMI */
4850
4851 if (pThis->fHasDirtyBits && pThis->GCPhysVRAM && pThis->GCPhysVRAM != NIL_RTGCPHYS32)
4852 {
4853 PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
4854 pThis->fHasDirtyBits = false;
4855 }
4856 if (pThis->fRemappedVGA)
4857 {
4858 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000);
4859 pThis->fRemappedVGA = false;
4860 }
4861
4862 rc = vga_update_display(pThis, false);
4863 if (rc != VINF_SUCCESS)
4864 {
4865 PDMCritSectLeave(&pThis->lock);
4866 return rc;
4867 }
4868 PDMCritSectLeave(&pThis->lock);
4869 return VINF_SUCCESS;
4870}
4871
4872/* Internal worker called under pThis->lock. */
4873static int updateDisplayAll(PVGASTATE pThis)
4874{
4875 PPDMDEVINS pDevIns = pThis->CTX_SUFF(pDevIns);
4876
4877 /* The dirty bits array has been just cleared, reset handlers as well. */
4878 if (pThis->GCPhysVRAM && pThis->GCPhysVRAM != NIL_RTGCPHYS32)
4879 {
4880 PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
4881 }
4882 if (pThis->fRemappedVGA)
4883 {
4884 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000);
4885 pThis->fRemappedVGA = false;
4886 }
4887
4888 pThis->graphic_mode = -1; /* force full update */
4889
4890 return vga_update_display(pThis, true);
4891}
4892
4893
4894/**
4895 * Update the entire display.
4896 *
4897 * @param pInterface Pointer to this interface.
4898 * @see PDMIKEYBOARDPORT::pfnUpdateDisplayAll() for details.
4899 */
4900static DECLCALLBACK(int) vgaPortUpdateDisplayAll(PPDMIDISPLAYPORT pInterface)
4901{
4902 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4903 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4904 PPDMDEVINS pDevIns = pThis->CTX_SUFF(pDevIns);
4905
4906 /* This is called both in VBVA mode and normal modes. */
4907
4908#ifdef DEBUG_sunlover
4909 LogFlow(("vgaPortUpdateDisplayAll\n"));
4910#endif /* DEBUG_sunlover */
4911
4912 int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
4913 AssertRC(rc);
4914
4915 rc = updateDisplayAll(pThis);
4916
4917 PDMCritSectLeave(&pThis->lock);
4918 return rc;
4919}
4920
4921
4922/**
4923 * Sets the refresh rate and restart the timer.
4924 *
4925 * @returns VBox status code.
4926 * @param pInterface Pointer to this interface.
4927 * @param cMilliesInterval Number of millies between two refreshes.
4928 * @see PDMIKEYBOARDPORT::pfnSetRefreshRate() for details.
4929 */
4930static DECLCALLBACK(int) vgaPortSetRefreshRate(PPDMIDISPLAYPORT pInterface, uint32_t cMilliesInterval)
4931{
4932 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4933
4934 pThis->cMilliesRefreshInterval = cMilliesInterval;
4935 if (cMilliesInterval)
4936 return TMTimerSetMillies(pThis->RefreshTimer, cMilliesInterval);
4937 return TMTimerStop(pThis->RefreshTimer);
4938}
4939
4940
4941/** @copydoc PDMIDISPLAYPORT::pfnQueryColorDepth */
4942static DECLCALLBACK(int) vgaPortQueryColorDepth(PPDMIDISPLAYPORT pInterface, uint32_t *pcBits)
4943{
4944 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4945
4946 if (!pcBits)
4947 return VERR_INVALID_PARAMETER;
4948 *pcBits = vga_get_bpp(pThis);
4949 return VINF_SUCCESS;
4950}
4951
4952/**
4953 * Create a 32-bbp screenshot of the display. Size of the bitmap scanline in bytes is 4*width.
4954 *
4955 * @param pInterface Pointer to this interface.
4956 * @param ppu8Data Where to store the pointer to the allocated buffer.
4957 * @param pcbData Where to store the actual size of the bitmap.
4958 * @param pcx Where to store the width of the bitmap.
4959 * @param pcy Where to store the height of the bitmap.
4960 * @see PDMIDISPLAYPORT::pfnTakeScreenshot() for details.
4961 */
4962static DECLCALLBACK(int) vgaPortTakeScreenshot(PPDMIDISPLAYPORT pInterface, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pcx, uint32_t *pcy)
4963{
4964 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
4965 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
4966
4967 LogFlow(("vgaPortTakeScreenshot: ppu8Data=%p pcbData=%p pcx=%p pcy=%p\n", ppu8Data, pcbData, pcx, pcy));
4968
4969 /*
4970 * Validate input.
4971 */
4972 if (!RT_VALID_PTR(ppu8Data) || !RT_VALID_PTR(pcbData) || !RT_VALID_PTR(pcx) || !RT_VALID_PTR(pcy))
4973 return VERR_INVALID_PARAMETER;
4974
4975 int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
4976 AssertRCReturn(rc, rc);
4977
4978 /*
4979 * Do a complete screen update first to resolve any pending resize issues.
4980 */
4981 updateDisplayAll(pThis);
4982
4983 /*
4984 * The display connector interface is temporarily replaced with the fake one.
4985 */
4986 PDMIDISPLAYCONNECTOR Connector;
4987 memset(&Connector, 0, sizeof (PDMIDISPLAYCONNECTOR));
4988
4989 /*
4990 * Allocate the buffer for 32 bits per pixel bitmap.
4991 */
4992 size_t cbRequired = pThis->last_scr_width * 4 * pThis->last_scr_height;
4993
4994 if (cbRequired)
4995 {
4996 uint8_t *pu8Data = (uint8_t *)RTMemAlloc(cbRequired);
4997
4998 if (pu8Data == NULL)
4999 {
5000 rc = VERR_NO_MEMORY;
5001 }
5002 else
5003 {
5004 /*
5005 * Only 3 methods, assigned below, will be called during the screenshot update.
5006 * All other are already set to NULL.
5007 */
5008
5009 Connector.pu8Data = pu8Data;
5010 Connector.cBits = 32;
5011 Connector.cx = pThis->last_scr_width;
5012 Connector.cy = pThis->last_scr_height;
5013 Connector.cbScanline = Connector.cx * 4;
5014 Connector.pfnRefresh = vgaDummyRefresh;
5015 Connector.pfnResize = vgaDummyResize;
5016 Connector.pfnUpdateRect = vgaDummyUpdateRect;
5017
5018 /* Save & replace state data. */
5019 PPDMIDISPLAYCONNECTOR pConnectorSaved = pThis->pDrv;
5020 int32_t graphic_mode_saved = pThis->graphic_mode;
5021 bool fRenderVRAMSaved = pThis->fRenderVRAM;
5022
5023 pThis->pDrv = &Connector;
5024 pThis->graphic_mode = -1; /* force a full refresh. */
5025 pThis->fRenderVRAM = 1; /* force the guest VRAM rendering to the given buffer. */
5026
5027 /* Make the screenshot.
5028 *
5029 * The second parameter is 'false' because the current display state, already updated by the
5030 * pfnUpdateDisplayAll call above, is being rendered to an external buffer using a fake connector.
5031 * That is if display is blanked, we expect a black screen in the external buffer.
5032 */
5033 rc = vga_update_display(pThis, false);
5034
5035 /* Restore. */
5036 pThis->pDrv = pConnectorSaved;
5037 pThis->graphic_mode = graphic_mode_saved;
5038 pThis->fRenderVRAM = fRenderVRAMSaved;
5039
5040 if (rc == VINF_SUCCESS)
5041 {
5042 /*
5043 * Return the result.
5044 */
5045 *ppu8Data = pu8Data;
5046 *pcbData = cbRequired;
5047 *pcx = Connector.cx;
5048 *pcy = Connector.cy;
5049 }
5050 }
5051 }
5052
5053 PDMCritSectLeave(&pThis->lock);
5054
5055 LogFlow(("vgaPortTakeScreenshot: returns %Rrc (cbData=%d cx=%d cy=%d)\n", rc, cbRequired, Connector.cx, Connector.cy));
5056 return rc;
5057}
5058
5059/**
5060 * Free a screenshot buffer allocated in vgaPortTakeScreenshot.
5061 *
5062 * @param pInterface Pointer to this interface.
5063 * @param pu8Data Pointer returned by vgaPortTakeScreenshot.
5064 * @see PDMIDISPLAYPORT::pfnFreeScreenshot() for details.
5065 */
5066static DECLCALLBACK(void) vgaPortFreeScreenshot(PPDMIDISPLAYPORT pInterface, uint8_t *pu8Data)
5067{
5068 NOREF(pInterface);
5069
5070 LogFlow(("vgaPortFreeScreenshot: pu8Data=%p\n", pu8Data));
5071
5072 RTMemFree(pu8Data);
5073}
5074
5075/**
5076 * Copy bitmap to the display.
5077 *
5078 * @param pInterface Pointer to this interface.
5079 * @param pvData Pointer to the bitmap bits.
5080 * @param x The upper left corner x coordinate of the destination rectangle.
5081 * @param y The upper left corner y coordinate of the destination rectangle.
5082 * @param cx The width of the source and destination rectangles.
5083 * @param cy The height of the source and destination rectangles.
5084 * @see PDMIDISPLAYPORT::pfnDisplayBlt() for details.
5085 */
5086static DECLCALLBACK(int) vgaPortDisplayBlt(PPDMIDISPLAYPORT pInterface, const void *pvData, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
5087{
5088 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
5089 int rc = VINF_SUCCESS;
5090 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis));
5091 LogFlow(("vgaPortDisplayBlt: pvData=%p x=%d y=%d cx=%d cy=%d\n", pvData, x, y, cx, cy));
5092
5093 rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
5094 AssertRC(rc);
5095
5096 /*
5097 * Validate input.
5098 */
5099 if ( pvData
5100 && x < pThis->pDrv->cx
5101 && cx <= pThis->pDrv->cx
5102 && cx + x <= pThis->pDrv->cx
5103 && y < pThis->pDrv->cy
5104 && cy <= pThis->pDrv->cy
5105 && cy + y <= pThis->pDrv->cy)
5106 {
5107 /*
5108 * Determin bytes per pixel in the destination buffer.
5109 */
5110 size_t cbPixelDst = 0;
5111 switch (pThis->pDrv->cBits)
5112 {
5113 case 8:
5114 cbPixelDst = 1;
5115 break;
5116 case 15:
5117 case 16:
5118 cbPixelDst = 2;
5119 break;
5120 case 24:
5121 cbPixelDst = 3;
5122 break;
5123 case 32:
5124 cbPixelDst = 4;
5125 break;
5126 default:
5127 rc = VERR_INVALID_PARAMETER;
5128 break;
5129 }
5130 if (RT_SUCCESS(rc))
5131 {
5132 /*
5133 * The blitting loop.
5134 */
5135 size_t cbLineSrc = cx * 4; /* 32 bits per pixel. */
5136 uint8_t *pu8Src = (uint8_t *)pvData;
5137 size_t cbLineDst = pThis->pDrv->cbScanline;
5138 uint8_t *pu8Dst = pThis->pDrv->pu8Data + y * cbLineDst + x * cbPixelDst;
5139 uint32_t cyLeft = cy;
5140 vga_draw_line_func *pfnVgaDrawLine = vga_draw_line_table[VGA_DRAW_LINE32 * 4 + get_depth_index(pThis->pDrv->cBits)];
5141 Assert(pfnVgaDrawLine);
5142 while (cyLeft-- > 0)
5143 {
5144 pfnVgaDrawLine(pThis, pu8Dst, pu8Src, cx);
5145 pu8Dst += cbLineDst;
5146 pu8Src += cbLineSrc;
5147 }
5148
5149 /*
5150 * Invalidate the area.
5151 */
5152 pThis->pDrv->pfnUpdateRect(pThis->pDrv, x, y, cx, cy);
5153 }
5154 }
5155 else
5156 rc = VERR_INVALID_PARAMETER;
5157
5158 PDMCritSectLeave(&pThis->lock);
5159
5160 LogFlow(("vgaPortDisplayBlt: returns %Rrc\n", rc));
5161 return rc;
5162}
5163
5164static DECLCALLBACK(void) vgaPortUpdateDisplayRect (PPDMIDISPLAYPORT pInterface, int32_t x, int32_t y, uint32_t w, uint32_t h)
5165{
5166 uint32_t v;
5167 vga_draw_line_func *vga_draw_line;
5168
5169 uint32_t cbPixelDst;
5170 uint32_t cbLineDst;
5171 uint8_t *pu8Dst;
5172
5173 uint32_t cbPixelSrc;
5174 uint32_t cbLineSrc;
5175 uint8_t *pu8Src;
5176
5177 uint32_t u32OffsetSrc, u32Dummy;
5178
5179 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
5180
5181#ifdef DEBUG_sunlover
5182 LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d\n", x, y, w, h));
5183#endif /* DEBUG_sunlover */
5184
5185 Assert(pInterface);
5186 Assert(s->pDrv);
5187 Assert(s->pDrv->pu8Data);
5188
5189 /* Check if there is something to do at all. */
5190 if (!s->fRenderVRAM)
5191 {
5192 /* The framebuffer uses the guest VRAM directly. */
5193#ifdef DEBUG_sunlover
5194 LogFlow(("vgaPortUpdateDisplayRect: nothing to do fRender is false.\n"));
5195#endif /* DEBUG_sunlover */
5196 return;
5197 }
5198
5199 int rc = PDMCritSectEnter(&s->lock, VERR_SEM_BUSY);
5200 AssertRC(rc);
5201
5202 /* Correct negative x and y coordinates. */
5203 if (x < 0)
5204 {
5205 x += w; /* Compute xRight which is also the new width. */
5206 w = (x < 0) ? 0 : x;
5207 x = 0;
5208 }
5209
5210 if (y < 0)
5211 {
5212 y += h; /* Compute yBottom, which is also the new height. */
5213 h = (y < 0) ? 0 : y;
5214 y = 0;
5215 }
5216
5217 /* Also check if coords are greater than the display resolution. */
5218 if (x + w > s->pDrv->cx)
5219 {
5220#ifndef VBOX
5221 w = s->pDrv->cx > x? s->pDrv->cx - x: 0;
5222#else
5223 // x < 0 is not possible here
5224 w = s->pDrv->cx > (uint32_t)x? s->pDrv->cx - x: 0;
5225#endif
5226 }
5227
5228 if (y + h > s->pDrv->cy)
5229 {
5230#ifndef VBOX
5231 h = s->pDrv->cy > y? s->pDrv->cy - y: 0;
5232#else
5233 // y < 0 is not possible here
5234 h = s->pDrv->cy > (uint32_t)y? s->pDrv->cy - y: 0;
5235#endif
5236 }
5237
5238#ifdef DEBUG_sunlover
5239 LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d (corrected coords)\n", x, y, w, h));
5240#endif /* DEBUG_sunlover */
5241
5242 /* Check if there is something to do at all. */
5243 if (w == 0 || h == 0)
5244 {
5245 /* Empty rectangle. */
5246#ifdef DEBUG_sunlover
5247 LogFlow(("vgaPortUpdateDisplayRect: nothing to do: %dx%d\n", w, h));
5248#endif /* DEBUG_sunlover */
5249 PDMCritSectLeave(&s->lock);
5250 return;
5251 }
5252
5253 /** @todo This method should be made universal and not only for VBVA.
5254 * VGA_DRAW_LINE* must be selected and src/dst address calculation
5255 * changed.
5256 */
5257
5258 /* Choose the rendering function. */
5259 switch(s->get_bpp(s))
5260 {
5261 default:
5262 case 0:
5263 /* A LFB mode is already disabled, but the callback is still called
5264 * by Display because VBVA buffer is being flushed.
5265 * Nothing to do, just return.
5266 */
5267 PDMCritSectLeave(&s->lock);
5268 return;
5269 case 8:
5270 v = VGA_DRAW_LINE8;
5271 break;
5272 case 15:
5273 v = VGA_DRAW_LINE15;
5274 break;
5275 case 16:
5276 v = VGA_DRAW_LINE16;
5277 break;
5278 case 24:
5279 v = VGA_DRAW_LINE24;
5280 break;
5281 case 32:
5282 v = VGA_DRAW_LINE32;
5283 break;
5284 }
5285
5286 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->pDrv->cBits)];
5287
5288 /* Compute source and destination addresses and pitches. */
5289 cbPixelDst = (s->pDrv->cBits + 7) / 8;
5290 cbLineDst = s->pDrv->cbScanline;
5291 pu8Dst = s->pDrv->pu8Data + y * cbLineDst + x * cbPixelDst;
5292
5293 cbPixelSrc = (s->get_bpp(s) + 7) / 8;
5294 s->get_offsets (s, &cbLineSrc, &u32OffsetSrc, &u32Dummy);
5295
5296 /* Assume that rendering is performed only on visible part of VRAM.
5297 * This is true because coordinates were verified.
5298 */
5299 pu8Src = s->vram_ptrR3;
5300 pu8Src += u32OffsetSrc + y * cbLineSrc + x * cbPixelSrc;
5301
5302 /* Render VRAM to framebuffer. */
5303
5304#ifdef DEBUG_sunlover
5305 LogFlow(("vgaPortUpdateDisplayRect: dst: %p, %d, %d. src: %p, %d, %d\n", pu8Dst, cbLineDst, cbPixelDst, pu8Src, cbLineSrc, cbPixelSrc));
5306#endif /* DEBUG_sunlover */
5307
5308 while (h-- > 0)
5309 {
5310 vga_draw_line (s, pu8Dst, pu8Src, w);
5311 pu8Dst += cbLineDst;
5312 pu8Src += cbLineSrc;
5313 }
5314 PDMCritSectLeave(&s->lock);
5315
5316#ifdef DEBUG_sunlover
5317 LogFlow(("vgaPortUpdateDisplayRect: completed.\n"));
5318#endif /* DEBUG_sunlover */
5319}
5320
5321static DECLCALLBACK(int) vgaPortCopyRect (PPDMIDISPLAYPORT pInterface,
5322 uint32_t w,
5323 uint32_t h,
5324 const uint8_t *pu8Src,
5325 int32_t xSrc,
5326 int32_t ySrc,
5327 uint32_t u32SrcWidth,
5328 uint32_t u32SrcHeight,
5329 uint32_t u32SrcLineSize,
5330 uint32_t u32SrcBitsPerPixel,
5331 uint8_t *pu8Dst,
5332 int32_t xDst,
5333 int32_t yDst,
5334 uint32_t u32DstWidth,
5335 uint32_t u32DstHeight,
5336 uint32_t u32DstLineSize,
5337 uint32_t u32DstBitsPerPixel)
5338{
5339 uint32_t v;
5340 vga_draw_line_func *vga_draw_line;
5341
5342 uint32_t cbPixelDst;
5343 uint32_t cbLineDst;
5344 uint8_t *pu8DstPtr;
5345
5346 uint32_t cbPixelSrc;
5347 uint32_t cbLineSrc;
5348 const uint8_t *pu8SrcPtr;
5349
5350#ifdef DEBUG_sunlover
5351 LogFlow(("vgaPortCopyRect: %d,%d %dx%d -> %d,%d\n", xSrc, ySrc, w, h, xDst, yDst));
5352#endif /* DEBUG_sunlover */
5353
5354 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
5355
5356 Assert(pInterface);
5357 Assert(s->pDrv);
5358
5359 int32_t xSrcCorrected = xSrc;
5360 int32_t ySrcCorrected = ySrc;
5361 uint32_t wCorrected = w;
5362 uint32_t hCorrected = h;
5363
5364 /* Correct source coordinates to be within the source bitmap. */
5365 if (xSrcCorrected < 0)
5366 {
5367 xSrcCorrected += wCorrected; /* Compute xRight which is also the new width. */
5368 wCorrected = (xSrcCorrected < 0) ? 0 : xSrcCorrected;
5369 xSrcCorrected = 0;
5370 }
5371
5372 if (ySrcCorrected < 0)
5373 {
5374 ySrcCorrected += hCorrected; /* Compute yBottom, which is also the new height. */
5375 hCorrected = (ySrcCorrected < 0) ? 0 : ySrcCorrected;
5376 ySrcCorrected = 0;
5377 }
5378
5379 /* Also check if coords are greater than the display resolution. */
5380 if (xSrcCorrected + wCorrected > u32SrcWidth)
5381 {
5382 /* xSrcCorrected < 0 is not possible here */
5383 wCorrected = u32SrcWidth > (uint32_t)xSrcCorrected? u32SrcWidth - xSrcCorrected: 0;
5384 }
5385
5386 if (ySrcCorrected + hCorrected > u32SrcHeight)
5387 {
5388 /* y < 0 is not possible here */
5389 hCorrected = u32SrcHeight > (uint32_t)ySrcCorrected? u32SrcHeight - ySrcCorrected: 0;
5390 }
5391
5392#ifdef DEBUG_sunlover
5393 LogFlow(("vgaPortCopyRect: %d,%d %dx%d (corrected coords)\n", xSrcCorrected, ySrcCorrected, wCorrected, hCorrected));
5394#endif /* DEBUG_sunlover */
5395
5396 /* Check if there is something to do at all. */
5397 if (wCorrected == 0 || hCorrected == 0)
5398 {
5399 /* Empty rectangle. */
5400#ifdef DEBUG_sunlover
5401 LogFlow(("vgaPortUpdateDisplayRectEx: nothing to do: %dx%d\n", wCorrected, hCorrected));
5402#endif /* DEBUG_sunlover */
5403 return VINF_SUCCESS;
5404 }
5405
5406 /* Check that the corrected source rectangle is within the destination.
5407 * Note: source rectangle is adjusted, but the target must be large enough.
5408 */
5409 if ( xDst < 0
5410 || yDst < 0
5411 || xDst + wCorrected > u32DstWidth
5412 || yDst + hCorrected > u32DstHeight)
5413 {
5414 return VERR_INVALID_PARAMETER;
5415 }
5416
5417 /* Choose the rendering function. */
5418 switch(u32SrcBitsPerPixel)
5419 {
5420 default:
5421 case 0:
5422 /* Nothing to do, just return. */
5423 return VINF_SUCCESS;
5424 case 8:
5425 v = VGA_DRAW_LINE8;
5426 break;
5427 case 15:
5428 v = VGA_DRAW_LINE15;
5429 break;
5430 case 16:
5431 v = VGA_DRAW_LINE16;
5432 break;
5433 case 24:
5434 v = VGA_DRAW_LINE24;
5435 break;
5436 case 32:
5437 v = VGA_DRAW_LINE32;
5438 break;
5439 }
5440
5441 int rc = PDMCritSectEnter(&s->lock, VERR_SEM_BUSY);
5442 AssertRC(rc);
5443
5444 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(u32DstBitsPerPixel)];
5445
5446 /* Compute source and destination addresses and pitches. */
5447 cbPixelDst = (u32DstBitsPerPixel + 7) / 8;
5448 cbLineDst = u32DstLineSize;
5449 pu8DstPtr = pu8Dst + yDst * cbLineDst + xDst * cbPixelDst;
5450
5451 cbPixelSrc = (u32SrcBitsPerPixel + 7) / 8;
5452 cbLineSrc = u32SrcLineSize;
5453 pu8SrcPtr = pu8Src + ySrcCorrected * cbLineSrc + xSrcCorrected * cbPixelSrc;
5454
5455#ifdef DEBUG_sunlover
5456 LogFlow(("vgaPortCopyRect: dst: %p, %d, %d. src: %p, %d, %d\n", pu8DstPtr, cbLineDst, cbPixelDst, pu8SrcPtr, cbLineSrc, cbPixelSrc));
5457#endif /* DEBUG_sunlover */
5458
5459 while (hCorrected-- > 0)
5460 {
5461 vga_draw_line (s, pu8DstPtr, pu8SrcPtr, wCorrected);
5462 pu8DstPtr += cbLineDst;
5463 pu8SrcPtr += cbLineSrc;
5464 }
5465 PDMCritSectLeave(&s->lock);
5466
5467#ifdef DEBUG_sunlover
5468 LogFlow(("vgaPortCopyRect: completed.\n"));
5469#endif /* DEBUG_sunlover */
5470
5471 return VINF_SUCCESS;
5472}
5473
5474static DECLCALLBACK(void) vgaPortSetRenderVRAM(PPDMIDISPLAYPORT pInterface, bool fRender)
5475{
5476 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
5477
5478 LogFlow(("vgaPortSetRenderVRAM: fRender = %d\n", fRender));
5479
5480 s->fRenderVRAM = fRender;
5481}
5482
5483
5484static DECLCALLBACK(void) vgaTimerRefresh(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
5485{
5486 PVGASTATE pThis = (PVGASTATE)pvUser;
5487
5488 if (pThis->pDrv)
5489 pThis->pDrv->pfnRefresh(pThis->pDrv);
5490
5491 if (pThis->cMilliesRefreshInterval)
5492 TMTimerSetMillies(pTimer, pThis->cMilliesRefreshInterval);
5493}
5494
5495
5496/* -=-=-=-=-=- Ring 3: PCI Device -=-=-=-=-=- */
5497
5498/**
5499 * Callback function for unmapping and/or mapping the VRAM MMIO2 region (called by the PCI bus).
5500 *
5501 * @return VBox status code.
5502 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
5503 * @param iRegion The region number.
5504 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
5505 * I/O port, else it's a physical address.
5506 * This address is *NOT* relative to pci_mem_base like earlier!
5507 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
5508 */
5509static DECLCALLBACK(int) vgaR3IORegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
5510{
5511 int rc;
5512 PPDMDEVINS pDevIns = pPciDev->pDevIns;
5513 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5514 LogFlow(("vgaR3IORegionMap: iRegion=%d GCPhysAddress=%RGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
5515 AssertReturn(iRegion == 0 && enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
5516
5517 if (GCPhysAddress != NIL_RTGCPHYS)
5518 {
5519 /*
5520 * Mapping the VRAM.
5521 */
5522 rc = PDMDevHlpMMIO2Map(pDevIns, iRegion, GCPhysAddress);
5523 AssertRC(rc);
5524 if (RT_SUCCESS(rc))
5525 {
5526 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
5527 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
5528 GCPhysAddress, GCPhysAddress + (pThis->vram_size - 1),
5529 vgaR3LFBAccessHandler, pThis,
5530 g_DeviceVga.szR0Mod, "vgaR0LFBAccessHandler", pDevIns->pvInstanceDataR0,
5531 g_DeviceVga.szRCMod, "vgaGCLFBAccessHandler", pDevIns->pvInstanceDataRC,
5532 "VGA LFB");
5533 AssertRC(rc);
5534 if (RT_SUCCESS(rc))
5535 pThis->GCPhysVRAM = GCPhysAddress;
5536 }
5537 }
5538 else
5539 {
5540 /*
5541 * Unmapping of the VRAM in progress.
5542 * Deregister the access handler so PGM doesn't get upset.
5543 */
5544 Assert(pThis->GCPhysVRAM);
5545 rc = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
5546 AssertRC(rc);
5547 pThis->GCPhysVRAM = 0;
5548 }
5549 return rc;
5550}
5551
5552
5553/* -=-=-=-=-=- Ring3: Misc Wrappers & Sidekicks -=-=-=-=-=- */
5554
5555/**
5556 * Saves a important bits of the VGA device config.
5557 *
5558 * @param pThis The VGA instance data.
5559 * @param pSSM The saved state handle.
5560 */
5561static void vgaR3SaveConfig(PVGASTATE pThis, PSSMHANDLE pSSM)
5562{
5563 SSMR3PutU32(pSSM, pThis->vram_size);
5564 SSMR3PutU32(pSSM, pThis->cMonitors);
5565}
5566
5567
5568/**
5569 * @copydoc FNSSMDEVLIVEEXEC
5570 */
5571static DECLCALLBACK(int) vgaR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
5572{
5573 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5574 Assert(uPass == 0); NOREF(uPass);
5575 vgaR3SaveConfig(pThis, pSSM);
5576 return VINF_SSM_DONT_CALL_AGAIN;
5577}
5578
5579
5580/**
5581 * @copydoc FNSSMDEVSAVEPREP
5582 */
5583static DECLCALLBACK(int) vgaR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5584{
5585#ifdef VBOX_WITH_VIDEOHWACCEL
5586 return vboxVBVASaveStatePrep(pDevIns, pSSM);
5587#else
5588 return VINF_SUCCESS;
5589#endif
5590}
5591
5592
5593/**
5594 * @copydoc FNSSMDEVSAVEEXEC
5595 */
5596static DECLCALLBACK(int) vgaR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5597{
5598 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5599 vgaR3SaveConfig(pThis, pSSM);
5600 vga_save(pSSM, PDMINS_2_DATA(pDevIns, PVGASTATE));
5601#ifdef VBOX_WITH_HGSMI
5602 SSMR3PutBool(pSSM, true);
5603 return vboxVBVASaveStateExec(pDevIns, pSSM);
5604#else
5605 SSMR3PutBool(pSSM, false);
5606 return VINF_SUCCESS;
5607#endif
5608}
5609
5610
5611/**
5612 * @copydoc FNSSMDEVSAVEEXEC
5613 */
5614static DECLCALLBACK(int) vgaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
5615{
5616 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5617 int rc;
5618
5619 if ( uVersion != VGA_SAVEDSTATE_VERSION
5620 && uVersion != VGA_SAVEDSTATE_VERSION_HOST_HEAP
5621 && uVersion != VGA_SAVEDSTATE_VERSION_WITH_CONFIG
5622 && uVersion != VGA_SAVEDSTATE_VERSION_HGSMI
5623 && uVersion != VGA_SAVEDSTATE_VERSION_PRE_HGSMI
5624 && uVersion != VGA_SAVEDSTATE_VERSION_ANCIENT)
5625 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
5626
5627 if (uVersion > VGA_SAVEDSTATE_VERSION_HGSMI)
5628 {
5629 /* Check the config */
5630 uint32_t cbVRam;
5631 rc = SSMR3GetU32(pSSM, &cbVRam);
5632 AssertRCReturn(rc, rc);
5633 if (pThis->vram_size != cbVRam)
5634 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("VRAM size changed: config=%#x state=%#x"), pThis->vram_size, cbVRam);
5635
5636 uint32_t cMonitors;
5637 rc = SSMR3GetU32(pSSM, &cMonitors);
5638 AssertRCReturn(rc, rc);
5639 if (pThis->cMonitors != cMonitors)
5640 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Monitor count changed: config=%u state=%u"), pThis->cMonitors, cMonitors);
5641 }
5642
5643 if (uPass == SSM_PASS_FINAL)
5644 {
5645 rc = vga_load(pSSM, pThis, uVersion);
5646 if (RT_FAILURE(rc))
5647 return rc;
5648 bool fWithHgsmi = uVersion == VGA_SAVEDSTATE_VERSION_HGSMI;
5649 if (uVersion > VGA_SAVEDSTATE_VERSION_HGSMI)
5650 {
5651 rc = SSMR3GetBool(pSSM, &fWithHgsmi);
5652 AssertRCReturn(rc, rc);
5653 }
5654 if (fWithHgsmi)
5655 {
5656#ifdef VBOX_WITH_HGSMI
5657 rc = vboxVBVALoadStateExec(pDevIns, pSSM, uVersion);
5658 AssertRCReturn(rc, rc);
5659#else
5660 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("HGSMI is not compiled in, but it is present in the saved state"));
5661#endif
5662 }
5663 }
5664 return VINF_SUCCESS;
5665}
5666
5667
5668/**
5669 * @copydoc FNSSMDEVLOADDONE
5670 */
5671static DECLCALLBACK(int) vgaR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5672{
5673#ifdef VBOX_WITH_HGSMI
5674 return vboxVBVALoadStateDone(pDevIns, pSSM);
5675#else
5676 return VINF_SUCCESS;
5677#endif
5678}
5679
5680
5681/* -=-=-=-=-=- Ring 3: Device callbacks -=-=-=-=-=- */
5682
5683/**
5684 * Reset notification.
5685 *
5686 * @returns VBox status.
5687 * @param pDevIns The device instance data.
5688 */
5689static DECLCALLBACK(void) vgaR3Reset(PPDMDEVINS pDevIns)
5690{
5691 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5692 char *pchStart;
5693 char *pchEnd;
5694 LogFlow(("vgaReset\n"));
5695
5696#ifdef VBOX_WITH_HGSMI
5697 VBVAReset(pThis);
5698#endif /* VBOX_WITH_HGSMI */
5699
5700
5701 /* Clear the VRAM ourselves. */
5702 if (pThis->vram_ptrR3 && pThis->vram_size)
5703 {
5704#ifdef LOG_ENABLED /** @todo separate function. */
5705 /* First dump the textmode contents to the log; handy for capturing Windows blue screens. */
5706 uint8_t graphic_mode;
5707 VGAState *s = pThis;
5708
5709 if (!(s->ar_index & 0x20)) {
5710 graphic_mode = GMODE_BLANK;
5711 } else {
5712 graphic_mode = s->gr[6] & 1;
5713 }
5714 switch(graphic_mode)
5715 case GMODE_TEXT:
5716 {
5717 int cw, height, width, cheight, cx_min, cx_max, cy, cx;
5718 int x_incr;
5719 uint8_t *s1, *src, ch, cattr;
5720 int line_offset;
5721 uint16_t ch_attr;
5722
5723 line_offset = s->line_offset;
5724 s1 = s->CTX_SUFF(vram_ptr) + (s->start_addr * 4);
5725
5726 /* total width & height */
5727 cheight = (s->cr[9] & 0x1f) + 1;
5728 cw = 8;
5729 if (!(s->sr[1] & 0x01))
5730 cw = 9;
5731 if (s->sr[1] & 0x08)
5732 cw = 16; /* NOTE: no 18 pixel wide */
5733 x_incr = cw * ((s->pDrv->cBits + 7) >> 3);
5734 width = (s->cr[0x01] + 1);
5735 if (s->cr[0x06] == 100) {
5736 /* ugly hack for CGA 160x100x16 - explain me the logic */
5737 height = 100;
5738 } else {
5739 height = s->cr[0x12] |
5740 ((s->cr[0x07] & 0x02) << 7) |
5741 ((s->cr[0x07] & 0x40) << 3);
5742 height = (height + 1) / cheight;
5743 }
5744 if ((height * width) > CH_ATTR_SIZE) {
5745 /* better than nothing: exit if transient size is too big */
5746 break;
5747 }
5748 RTLogPrintf("VGA textmode BEGIN (%dx%d):\n\n", height, width);
5749 for(cy = 0; cy < height; cy++) {
5750 src = s1;
5751 cx_min = width;
5752 cx_max = -1;
5753 for(cx = 0; cx < width; cx++) {
5754 ch_attr = *(uint16_t *)src;
5755 if (cx < cx_min)
5756 cx_min = cx;
5757 if (cx > cx_max)
5758 cx_max = cx;
5759# ifdef WORDS_BIGENDIAN
5760 ch = ch_attr >> 8;
5761 cattr = ch_attr & 0xff;
5762# else
5763 ch = ch_attr & 0xff;
5764 cattr = ch_attr >> 8;
5765# endif
5766 RTLogPrintf("%c", ch);
5767
5768#ifndef VBOX
5769 src += 4;
5770#else
5771 src += 8; /* Every second byte of a plane is used in text mode. */
5772#endif
5773 }
5774 if (cx_max != -1)
5775 RTLogPrintf("\n");
5776
5777 s1 += line_offset;
5778 }
5779 RTLogPrintf("VGA textmode END:\n\n");
5780 }
5781
5782#endif /* LOG_ENABLED */
5783 memset(pThis->vram_ptrR3, 0, pThis->vram_size);
5784 }
5785
5786 /*
5787 * Zero most of it.
5788 *
5789 * Unlike vga_reset we're leaving out a few members which we believe
5790 * must remain unchanged....
5791 */
5792 /* 1st part. */
5793 pchStart = (char *)&pThis->latch;
5794 pchEnd = (char *)&pThis->invalidated_y_table;
5795 memset(pchStart, 0, pchEnd - pchStart);
5796
5797 /* 2nd part. */
5798 pchStart = (char *)&pThis->last_palette;
5799 pchEnd = (char *)&pThis->u32Marker;
5800 memset(pchStart, 0, pchEnd - pchStart);
5801
5802
5803 /*
5804 * Restore and re-init some bits.
5805 */
5806 pThis->get_bpp = vga_get_bpp;
5807 pThis->get_offsets = vga_get_offsets;
5808 pThis->get_resolution = vga_get_resolution;
5809 pThis->graphic_mode = -1; /* Force full update. */
5810#ifdef CONFIG_BOCHS_VBE
5811 pThis->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
5812 pThis->vbe_regs[VBE_DISPI_INDEX_VBOX_VIDEO] = 0;
5813 pThis->vbe_bank_max = pThis->vram_size >> 16;
5814#endif /* CONFIG_BOCHS_VBE */
5815
5816 /*
5817 * Reset the LBF mapping.
5818 */
5819 pThis->fLFBUpdated = false;
5820 if ( ( pThis->fGCEnabled
5821 || pThis->fR0Enabled)
5822 && pThis->GCPhysVRAM
5823 && pThis->GCPhysVRAM != NIL_RTGCPHYS32)
5824 {
5825 int rc = PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM);
5826 AssertRC(rc);
5827 }
5828 if (pThis->fRemappedVGA)
5829 {
5830 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000);
5831 pThis->fRemappedVGA = false;
5832 }
5833
5834 /*
5835 * Reset the logo data.
5836 */
5837 pThis->LogoCommand = LOGO_CMD_NOP;
5838 pThis->offLogoData = 0;
5839
5840 /* notify port handler */
5841 if (pThis->pDrv)
5842 pThis->pDrv->pfnReset(pThis->pDrv);
5843
5844 /* Reset latched access mask. */
5845 pThis->uMaskLatchAccess = 0x3ff;
5846 pThis->cLatchAccesses = 0;
5847 pThis->u64LastLatchedAccess = 0;
5848 pThis->iMask = 0;
5849}
5850
5851
5852/**
5853 * Device relocation callback.
5854 *
5855 * @param pDevIns Pointer to the device instance.
5856 * @param offDelta The relocation delta relative to the old location.
5857 *
5858 * @see FNPDMDEVRELOCATE for details.
5859 */
5860static DECLCALLBACK(void) vgaR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
5861{
5862 if (offDelta)
5863 {
5864 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5865 LogFlow(("vgaRelocate: offDelta = %08X\n", offDelta));
5866
5867 pThis->RCPtrLFBHandler += offDelta;
5868 pThis->vram_ptrRC += offDelta;
5869 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5870 }
5871}
5872
5873
5874/**
5875 * Attach command.
5876 *
5877 * This is called to let the device attach to a driver for a specified LUN
5878 * during runtime. This is not called during VM construction, the device
5879 * constructor have to attach to all the available drivers.
5880 *
5881 * This is like plugging in the monitor after turning on the PC.
5882 *
5883 * @returns VBox status code.
5884 * @param pDevIns The device instance.
5885 * @param iLUN The logical unit which is being detached.
5886 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
5887 */
5888static DECLCALLBACK(int) vgaAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5889{
5890 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5891
5892 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
5893 ("VGA device does not support hotplugging\n"),
5894 VERR_INVALID_PARAMETER);
5895
5896 switch (iLUN)
5897 {
5898 /* LUN #0: Display port. */
5899 case 0:
5900 {
5901 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &pThis->pDrvBase, "Display Port");
5902 if (RT_SUCCESS(rc))
5903 {
5904 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIDISPLAYCONNECTOR);
5905 if (pThis->pDrv)
5906 {
5907 /* pThis->pDrv->pu8Data can be NULL when there is no framebuffer. */
5908 if ( pThis->pDrv->pfnRefresh
5909 && pThis->pDrv->pfnResize
5910 && pThis->pDrv->pfnUpdateRect)
5911 rc = VINF_SUCCESS;
5912 else
5913 {
5914 Assert(pThis->pDrv->pfnRefresh);
5915 Assert(pThis->pDrv->pfnResize);
5916 Assert(pThis->pDrv->pfnUpdateRect);
5917 pThis->pDrv = NULL;
5918 pThis->pDrvBase = NULL;
5919 rc = VERR_INTERNAL_ERROR;
5920 }
5921#ifdef VBOX_WITH_VIDEOHWACCEL
5922 if(rc == VINF_SUCCESS)
5923 {
5924 rc = vbvaVHWAConstruct(pThis);
5925 if (rc != VERR_NOT_IMPLEMENTED)
5926 AssertRC(rc);
5927 }
5928#endif
5929 }
5930 else
5931 {
5932 AssertMsgFailed(("LUN #0 doesn't have a display connector interface! rc=%Rrc\n", rc));
5933 pThis->pDrvBase = NULL;
5934 rc = VERR_PDM_MISSING_INTERFACE;
5935 }
5936 }
5937 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5938 {
5939 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
5940 rc = VINF_SUCCESS;
5941 }
5942 else
5943 AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
5944 return rc;
5945 }
5946
5947 default:
5948 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
5949 return VERR_PDM_NO_SUCH_LUN;
5950 }
5951}
5952
5953
5954/**
5955 * Detach notification.
5956 *
5957 * This is called when a driver is detaching itself from a LUN of the device.
5958 * The device should adjust it's state to reflect this.
5959 *
5960 * This is like unplugging the monitor while the PC is still running.
5961 *
5962 * @param pDevIns The device instance.
5963 * @param iLUN The logical unit which is being detached.
5964 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
5965 */
5966static DECLCALLBACK(void) vgaDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5967{
5968 /*
5969 * Reset the interfaces and update the controller state.
5970 */
5971 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
5972
5973 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
5974 ("VGA device does not support hotplugging\n"));
5975
5976 switch (iLUN)
5977 {
5978 /* LUN #0: Display port. */
5979 case 0:
5980 pThis->pDrv = NULL;
5981 pThis->pDrvBase = NULL;
5982 break;
5983
5984 default:
5985 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
5986 break;
5987 }
5988}
5989
5990
5991/**
5992 * Destruct a device instance.
5993 *
5994 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
5995 * resources can be freed correctly.
5996 *
5997 * @param pDevIns The device instance data.
5998 */
5999static DECLCALLBACK(int) vgaR3Destruct(PPDMDEVINS pDevIns)
6000{
6001 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
6002
6003#ifdef VBE_NEW_DYN_LIST
6004 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
6005 LogFlow(("vgaR3Destruct:\n"));
6006
6007 /*
6008 * Free MM heap pointers.
6009 */
6010 if (pThis->pu8VBEExtraData)
6011 {
6012 MMR3HeapFree(pThis->pu8VBEExtraData);
6013 pThis->pu8VBEExtraData = NULL;
6014 }
6015#endif
6016
6017 PDMR3CritSectDelete(&pThis->lock);
6018 return VINF_SUCCESS;
6019}
6020
6021
6022/**
6023 * @interface_method_impl{PDMDEVREG,pfnConstruct}
6024 */
6025static DECLCALLBACK(int) vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
6026{
6027
6028 static bool s_fExpandDone = false;
6029 int rc;
6030 unsigned i;
6031#ifdef VBE_NEW_DYN_LIST
6032 uint32_t cCustomModes;
6033 uint32_t cyReduction;
6034 PVBEHEADER pVBEDataHdr;
6035 ModeInfoListItem *pCurMode;
6036 unsigned cb;
6037#endif
6038 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
6039 PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
6040 PVM pVM = PDMDevHlpGetVM(pDevIns);
6041
6042 Assert(iInstance == 0);
6043 Assert(pVM);
6044
6045 /*
6046 * Init static data.
6047 */
6048 if (!s_fExpandDone)
6049 {
6050 s_fExpandDone = true;
6051 vga_init_expand();
6052 }
6053
6054 /*
6055 * Validate configuration.
6056 */
6057 if (!CFGMR3AreValuesValid(pCfg, "VRamSize\0"
6058 "MonitorCount\0"
6059 "GCEnabled\0"
6060 "R0Enabled\0"
6061 "FadeIn\0"
6062 "FadeOut\0"
6063 "LogoTime\0"
6064 "LogoFile\0"
6065 "ShowBootMenu\0"
6066 "CustomVideoModes\0"
6067 "HeightReduction\0"
6068 "CustomVideoMode1\0"
6069 "CustomVideoMode2\0"
6070 "CustomVideoMode3\0"
6071 "CustomVideoMode4\0"
6072 "CustomVideoMode5\0"
6073 "CustomVideoMode6\0"
6074 "CustomVideoMode7\0"
6075 "CustomVideoMode8\0"
6076 "CustomVideoMode9\0"
6077 "CustomVideoMode10\0"
6078 "CustomVideoMode11\0"
6079 "CustomVideoMode12\0"
6080 "CustomVideoMode13\0"
6081 "CustomVideoMode14\0"
6082 "CustomVideoMode15\0"
6083 "CustomVideoMode16\0"))
6084 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
6085 N_("Invalid configuration for vga device"));
6086
6087 /*
6088 * Init state data.
6089 */
6090 rc = CFGMR3QueryU32Def(pCfg, "VRamSize", &pThis->vram_size, VGA_VRAM_DEFAULT);
6091 AssertLogRelRCReturn(rc, rc);
6092 if (pThis->vram_size > VGA_VRAM_MAX)
6093 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
6094 "VRamSize is too large, %#x, max %#x", pThis->vram_size, VGA_VRAM_MAX);
6095 if (pThis->vram_size < VGA_VRAM_MIN)
6096 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
6097 "VRamSize is too small, %#x, max %#x", pThis->vram_size, VGA_VRAM_MIN);
6098
6099 rc = CFGMR3QueryU32Def(pCfg, "MonitorCount", &pThis->cMonitors, 1);
6100 AssertLogRelRCReturn(rc, rc);
6101
6102 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
6103 AssertLogRelRCReturn(rc, rc);
6104
6105 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
6106 AssertLogRelRCReturn(rc, rc);
6107 Log(("VGA: VRamSize=%#x fGCenabled=%RTbool fR0Enabled=%RTbool\n", pThis->vram_size, pThis->fGCEnabled, pThis->fR0Enabled));
6108
6109 pThis->pDevInsR3 = pDevIns;
6110 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
6111 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
6112
6113 vgaR3Reset(pDevIns);
6114
6115 /* The PCI devices configuration. */
6116 PCIDevSetVendorId( &pThis->Dev, 0x80ee); /* PCI vendor, just a free bogus value */
6117 PCIDevSetDeviceId( &pThis->Dev, 0xbeef);
6118 PCIDevSetClassSub( &pThis->Dev, 0x00); /* VGA controller */
6119 PCIDevSetClassBase( &pThis->Dev, 0x03);
6120 PCIDevSetHeaderType(&pThis->Dev, 0x00);
6121#if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL)
6122 PCIDevSetInterruptPin(&pThis->Dev, 1);
6123#endif
6124
6125 /* The LBF access handler - error handling is better here than in the map function. */
6126 rc = PDMR3LdrGetSymbolRCLazy(pVM, pDevIns->pReg->szRCMod, "vgaGCLFBAccessHandler", &pThis->RCPtrLFBHandler);
6127 if (RT_FAILURE(rc))
6128 {
6129 AssertReleaseMsgFailed(("PDMR3LdrGetSymbolRC(, %s, \"vgaGCLFBAccessHandler\",) -> %Rrc\n", pDevIns->pReg->szRCMod, rc));
6130 return rc;
6131 }
6132
6133 /* the interfaces. */
6134 pThis->IBase.pfnQueryInterface = vgaPortQueryInterface;
6135
6136 pThis->IPort.pfnUpdateDisplay = vgaPortUpdateDisplay;
6137 pThis->IPort.pfnUpdateDisplayAll = vgaPortUpdateDisplayAll;
6138 pThis->IPort.pfnQueryColorDepth = vgaPortQueryColorDepth;
6139 pThis->IPort.pfnSetRefreshRate = vgaPortSetRefreshRate;
6140 pThis->IPort.pfnTakeScreenshot = vgaPortTakeScreenshot;
6141 pThis->IPort.pfnFreeScreenshot = vgaPortFreeScreenshot;
6142 pThis->IPort.pfnDisplayBlt = vgaPortDisplayBlt;
6143 pThis->IPort.pfnUpdateDisplayRect = vgaPortUpdateDisplayRect;
6144 pThis->IPort.pfnCopyRect = vgaPortCopyRect;
6145 pThis->IPort.pfnSetRenderVRAM = vgaPortSetRenderVRAM;
6146
6147#if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL)
6148 pThis->IVBVACallbacks.pfnVHWACommandCompleteAsynch = vbvaVHWACommandCompleteAsynch;
6149#endif
6150
6151 /*
6152 * Allocate the VRAM and map the first 512KB of it into GC so we can speed up VGA support.
6153 */
6154 rc = PDMDevHlpMMIO2Register(pDevIns, 0 /* iRegion */, pThis->vram_size, 0, (void **)&pThis->vram_ptrR3, "VRam");
6155 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMIO2Register(%#x,) -> %Rrc\n", pThis->vram_size, rc), rc);
6156 pThis->vram_ptrR0 = (RTR0PTR)pThis->vram_ptrR3; /** @todo #1865 Map parts into R0 or just use PGM access (Mac only). */
6157
6158 if (pThis->fGCEnabled)
6159 {
6160 RTRCPTR pRCMapping = 0;
6161 rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, 0 /* iRegion */, 0 /* off */, VGA_MAPPING_SIZE, "VGA VRam", &pRCMapping);
6162 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMHyperMapMMIO2(%#x,) -> %Rrc\n", VGA_MAPPING_SIZE, rc), rc);
6163 pThis->vram_ptrRC = pRCMapping;
6164 }
6165
6166#if defined(VBOX_WITH_2X_4GB_ADDR_SPACE)
6167 if (pThis->fR0Enabled)
6168 {
6169 RTR0PTR pR0Mapping = 0;
6170 rc = PDMDevHlpMMIO2MapKernel(pDevIns, 0 /* iRegion */, 0 /* off */, VGA_MAPPING_SIZE, "VGA VRam", &pR0Mapping);
6171 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMapMMIO2IntoR0(%#x,) -> %Rrc\n", VGA_MAPPING_SIZE, rc), rc);
6172 pThis->vram_ptrR0 = pR0Mapping;
6173 }
6174#endif
6175
6176 /*
6177 * Register I/O ports, ROM and save state.
6178 */
6179 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3c0, 16, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3c0");
6180 if (RT_FAILURE(rc))
6181 return rc;
6182 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3b4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3b4");
6183 if (RT_FAILURE(rc))
6184 return rc;
6185 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3ba, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3ba");
6186 if (RT_FAILURE(rc))
6187 return rc;
6188 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3d4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3d4");
6189 if (RT_FAILURE(rc))
6190 return rc;
6191 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3da, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3da");
6192 if (RT_FAILURE(rc))
6193 return rc;
6194#ifdef VBOX_WITH_HGSMI
6195 /* Use reserved VGA IO ports for HGSMI. */
6196 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3b0, 4, NULL, vgaR3IOPortHGSMIWrite, vgaR3IOPortHGSMIRead, NULL, NULL, "VGA - 3b0 (HGSMI host)");
6197 if (RT_FAILURE(rc))
6198 return rc;
6199 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3d0, 4, NULL, vgaR3IOPortHGSMIWrite, vgaR3IOPortHGSMIRead, NULL, NULL, "VGA - 3d0 (HGSMI guest)");
6200 if (RT_FAILURE(rc))
6201 return rc;
6202#endif /* VBOX_WITH_HGSMI */
6203
6204#ifdef CONFIG_BOCHS_VBE
6205 rc = PDMDevHlpIOPortRegister(pDevIns, 0x1ce, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, NULL, NULL, "VGA/VBE - Index");
6206 if (RT_FAILURE(rc))
6207 return rc;
6208 rc = PDMDevHlpIOPortRegister(pDevIns, 0x1cf, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, NULL, NULL, "VGA/VBE - Data");
6209 if (RT_FAILURE(rc))
6210 return rc;
6211#if 0
6212 /* This now causes conflicts with Win2k & XP; it is not aware this range is taken
6213 and tries to map other devices there */
6214 /* Old Bochs. */
6215 rc = PDMDevHlpIOPortRegister(pDevIns, 0xff80, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, "VGA/VBE - Index Old");
6216 if (RT_FAILURE(rc))
6217 return rc;
6218 rc = PDMDevHlpIOPortRegister(pDevIns, 0xff81, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, "VGA/VBE - Data Old");
6219 if (RT_FAILURE(rc))
6220 return rc;
6221#endif
6222#endif /* CONFIG_BOCHS_VBE */
6223
6224 /* guest context extension */
6225 if (pThis->fGCEnabled)
6226 {
6227 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
6228 if (RT_FAILURE(rc))
6229 return rc;
6230 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
6231 if (RT_FAILURE(rc))
6232 return rc;
6233 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
6234 if (RT_FAILURE(rc))
6235 return rc;
6236 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
6237 if (RT_FAILURE(rc))
6238 return rc;
6239 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
6240 if (RT_FAILURE(rc))
6241 return rc;
6242#ifdef CONFIG_BOCHS_VBE
6243 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
6244 if (RT_FAILURE(rc))
6245 return rc;
6246 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
6247 if (RT_FAILURE(rc))
6248 return rc;
6249
6250#if 0
6251 /* This now causes conflicts with Win2k & XP; they are not aware this range is taken
6252 and try to map other devices there */
6253 /* Old Bochs. */
6254 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0xff80, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", "VGA/VBE - Index Old (GC)");
6255 if (RT_FAILURE(rc))
6256 return rc;
6257 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0xff81, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", "VGA/VBE - Index Old (GC)");
6258 if (RT_FAILURE(rc))
6259 return rc;
6260#endif
6261
6262#endif /* CONFIG_BOCHS_VBE */
6263 }
6264
6265 /* R0 context extension */
6266 if (pThis->fR0Enabled)
6267 {
6268 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
6269 if (RT_FAILURE(rc))
6270 return rc;
6271 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
6272 if (RT_FAILURE(rc))
6273 return rc;
6274 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
6275 if (RT_FAILURE(rc))
6276 return rc;
6277 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
6278 if (RT_FAILURE(rc))
6279 return rc;
6280 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
6281 if (RT_FAILURE(rc))
6282 return rc;
6283#ifdef CONFIG_BOCHS_VBE
6284 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
6285 if (RT_FAILURE(rc))
6286 return rc;
6287 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
6288 if (RT_FAILURE(rc))
6289 return rc;
6290
6291#if 0
6292 /* This now causes conflicts with Win2k & XP; they are not aware this range is taken
6293 and try to map other devices there */
6294 /* Old Bochs. */
6295 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0xff80, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", "VGA/VBE - Index Old (GC)");
6296 if (RT_FAILURE(rc))
6297 return rc;
6298 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0xff81, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", "VGA/VBE - Index Old (GC)");
6299 if (RT_FAILURE(rc))
6300 return rc;
6301#endif
6302
6303#endif /* CONFIG_BOCHS_VBE */
6304 }
6305
6306 /* vga mmio */
6307 rc = PDMDevHlpMMIORegister(pDevIns, 0x000a0000, 0x00020000, 0, vgaMMIOWrite, vgaMMIORead, vgaMMIOFill, "VGA - VGA Video Buffer");
6308 if (RT_FAILURE(rc))
6309 return rc;
6310 if (pThis->fGCEnabled)
6311 {
6312 rc = PDMDevHlpMMIORegisterRC(pDevIns, 0x000a0000, 0x00020000, 0, "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill");
6313 if (RT_FAILURE(rc))
6314 return rc;
6315 }
6316 if (pThis->fR0Enabled)
6317 {
6318 rc = PDMDevHlpMMIORegisterR0(pDevIns, 0x000a0000, 0x00020000, 0, "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill");
6319 if (RT_FAILURE(rc))
6320 return rc;
6321 }
6322
6323 /* vga bios */
6324 rc = PDMDevHlpIOPortRegister(pDevIns, VBE_PRINTF_PORT, 1, NULL, vgaIOPortWriteBIOS, vgaIOPortReadBIOS, NULL, NULL, "VGA BIOS debug/panic");
6325 if (RT_FAILURE(rc))
6326 return rc;
6327 if (pThis->fR0Enabled)
6328 {
6329 rc = PDMDevHlpIOPortRegisterR0(pDevIns, VBE_PRINTF_PORT, 1, 0, "vgaIOPortWriteBIOS", "vgaIOPortReadBIOS", NULL, NULL, "VGA BIOS debug/panic");
6330 if (RT_FAILURE(rc))
6331 return rc;
6332 }
6333
6334 AssertReleaseMsg(g_cbVgaBiosBinary <= _64K && g_cbVgaBiosBinary >= 32*_1K, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
6335 AssertReleaseMsg(RT_ALIGN_Z(g_cbVgaBiosBinary, PAGE_SIZE) == g_cbVgaBiosBinary, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
6336 rc = PDMDevHlpROMRegister(pDevIns, 0x000c0000, g_cbVgaBiosBinary, &g_abVgaBiosBinary[0],
6337 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "VGA BIOS");
6338 if (RT_FAILURE(rc))
6339 return rc;
6340
6341 /* save */
6342 rc = PDMDevHlpSSMRegisterEx(pDevIns, VGA_SAVEDSTATE_VERSION, sizeof(*pThis), NULL,
6343 NULL, vgaR3LiveExec, NULL,
6344 vgaR3SavePrep, vgaR3SaveExec, NULL,
6345 NULL, vgaR3LoadExec, vgaR3LoadDone);
6346 if (RT_FAILURE(rc))
6347 return rc;
6348
6349 /* PCI */
6350 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->Dev);
6351 if (RT_FAILURE(rc))
6352 return rc;
6353 /*AssertMsg(pThis->Dev.devfn == 16 || iInstance != 0, ("pThis->Dev.devfn=%d\n", pThis->Dev.devfn));*/
6354 if (pThis->Dev.devfn != 16 && iInstance == 0)
6355 Log(("!!WARNING!!: pThis->dev.devfn=%d (ignore if testcase or not started by Main)\n", pThis->Dev.devfn));
6356
6357 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0 /* iRegion */, pThis->vram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vgaR3IORegionMap);
6358 if (RT_FAILURE(rc))
6359 return rc;
6360
6361 /* Initialize the PDM lock. */
6362 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "VGA");
6363 if (RT_FAILURE(rc))
6364 {
6365 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
6366 return rc;
6367 }
6368
6369 /*
6370 * Create the refresh timer.
6371 */
6372 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, vgaTimerRefresh,
6373 pThis, TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo This needs to be fixed! We cannot take the I/O lock at this point! */
6374 "VGA Refresh Timer", &pThis->RefreshTimer);
6375 if (RT_FAILURE(rc))
6376 return rc;
6377
6378 /*
6379 * Attach to the display.
6380 */
6381 rc = vgaAttach(pDevIns, 0 /* display LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
6382 if (RT_FAILURE(rc))
6383 return rc;
6384
6385#ifdef VBE_NEW_DYN_LIST
6386 /*
6387 * Compute buffer size for the VBE BIOS Extra Data.
6388 */
6389 cb = sizeof(mode_info_list) + sizeof(ModeInfoListItem);
6390
6391 rc = CFGMR3QueryU32(pCfg, "HeightReduction", &cyReduction);
6392 if (RT_SUCCESS(rc) && cyReduction)
6393 cb *= 2; /* Default mode list will be twice long */
6394 else
6395 cyReduction = 0;
6396
6397 rc = CFGMR3QueryU32(pCfg, "CustomVideoModes", &cCustomModes);
6398 if (RT_SUCCESS(rc) && cCustomModes)
6399 cb += sizeof(ModeInfoListItem) * cCustomModes;
6400 else
6401 cCustomModes = 0;
6402
6403 /*
6404 * Allocate and initialize buffer for the VBE BIOS Extra Data.
6405 */
6406 AssertRelease(sizeof(VBEHEADER) + cb < 65536);
6407 pThis->cbVBEExtraData = (uint16_t)(sizeof(VBEHEADER) + cb);
6408 pThis->pu8VBEExtraData = (uint8_t *)PDMDevHlpMMHeapAllocZ(pDevIns, pThis->cbVBEExtraData);
6409 if (!pThis->pu8VBEExtraData)
6410 return VERR_NO_MEMORY;
6411
6412 pVBEDataHdr = (PVBEHEADER)pThis->pu8VBEExtraData;
6413 pVBEDataHdr->u16Signature = VBEHEADER_MAGIC;
6414 pVBEDataHdr->cbData = cb;
6415
6416# ifndef VRAM_SIZE_FIX
6417 pCurMode = memcpy(pVBEDataHdr + 1, &mode_info_list, sizeof(mode_info_list));
6418 pCurMode = (ModeInfoListItem *)((uintptr_t)pCurMode + sizeof(mode_info_list));
6419# else /* VRAM_SIZE_FIX defined */
6420 pCurMode = (ModeInfoListItem *)(pVBEDataHdr + 1);
6421 for (i = 0; i < MODE_INFO_SIZE; i++)
6422 {
6423 uint32_t pixelWidth, reqSize;
6424 if (mode_info_list[i].info.MemoryModel == VBE_MEMORYMODEL_TEXT_MODE)
6425 pixelWidth = 2;
6426 else
6427 pixelWidth = (mode_info_list[i].info.BitsPerPixel +7) / 8;
6428 reqSize = mode_info_list[i].info.XResolution
6429 * mode_info_list[i].info.YResolution
6430 * pixelWidth;
6431 if (reqSize >= pThis->vram_size)
6432 continue;
6433 *pCurMode = mode_info_list[i];
6434 pCurMode++;
6435 }
6436# endif /* VRAM_SIZE_FIX defined */
6437
6438 /*
6439 * Copy default modes with subtractred YResolution.
6440 */
6441 if (cyReduction)
6442 {
6443 ModeInfoListItem *pDefMode = mode_info_list;
6444 Log(("vgaR3Construct: cyReduction=%u\n", cyReduction));
6445# ifndef VRAM_SIZE_FIX
6446 for (i = 0; i < MODE_INFO_SIZE; i++, pCurMode++, pDefMode++)
6447 {
6448 *pCurMode = *pDefMode;
6449 pCurMode->mode += 0x30;
6450 pCurMode->info.YResolution -= cyReduction;
6451 }
6452# else /* VRAM_SIZE_FIX defined */
6453 for (i = 0; i < MODE_INFO_SIZE; i++, pDefMode++)
6454 {
6455 uint32_t pixelWidth, reqSize;
6456 if (pDefMode->info.MemoryModel == VBE_MEMORYMODEL_TEXT_MODE)
6457 pixelWidth = 2;
6458 else
6459 pixelWidth = (pDefMode->info.BitsPerPixel + 7) / 8;
6460 reqSize = pDefMode->info.XResolution * pDefMode->info.YResolution * pixelWidth;
6461 if (reqSize >= pThis->vram_size)
6462 continue;
6463 *pCurMode = *pDefMode;
6464 pCurMode->mode += 0x30;
6465 pCurMode->info.YResolution -= cyReduction;
6466 pCurMode++;
6467 }
6468# endif /* VRAM_SIZE_FIX defined */
6469 }
6470
6471
6472 /*
6473 * Add custom modes.
6474 */
6475 if (cCustomModes)
6476 {
6477 uint16_t u16CurMode = 0x160;
6478 for (i = 1; i <= cCustomModes; i++)
6479 {
6480 char szExtraDataKey[sizeof("CustomVideoModeXX")];
6481 char *pszExtraData = NULL;
6482
6483 /* query and decode the custom mode string. */
6484 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%d", i);
6485 rc = CFGMR3QueryStringAlloc(pCfg, szExtraDataKey, &pszExtraData);
6486 if (RT_SUCCESS(rc))
6487 {
6488 ModeInfoListItem *pDefMode = mode_info_list;
6489 unsigned int cx, cy, cBits, cParams, j;
6490 uint16_t u16DefMode;
6491
6492 cParams = sscanf(pszExtraData, "%ux%ux%u", &cx, &cy, &cBits);
6493 if ( cParams != 3
6494 || (cBits != 16 && cBits != 24 && cBits != 32))
6495 {
6496 AssertMsgFailed(("Configuration error: Invalid mode data '%s' for '%s'! cBits=%d\n", pszExtraData, szExtraDataKey, cBits));
6497 return VERR_VGA_INVALID_CUSTOM_MODE;
6498 }
6499 /* Round up the X resolution to a multiple of eight. */
6500 cx = (cx + 7) & ~7;
6501# ifdef VRAM_SIZE_FIX
6502 if (cx * cy * cBits / 8 >= pThis->vram_size)
6503 {
6504 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",
6505 cx, cy, cBits, pThis->vram_size / _1M));
6506 return VERR_VGA_INVALID_CUSTOM_MODE;
6507 }
6508# endif /* VRAM_SIZE_FIX defined */
6509 MMR3HeapFree(pszExtraData);
6510
6511 /* Use defaults from max@bpp mode. */
6512 switch (cBits)
6513 {
6514 case 16:
6515 u16DefMode = VBE_VESA_MODE_1024X768X565;
6516 break;
6517
6518 case 24:
6519 u16DefMode = VBE_VESA_MODE_1024X768X888;
6520 break;
6521
6522 case 32:
6523 u16DefMode = VBE_OWN_MODE_1024X768X8888;
6524 break;
6525
6526 default: /* gcc, shut up! */
6527 AssertMsgFailed(("gone postal!\n"));
6528 continue;
6529 }
6530
6531 /* mode_info_list is not terminated */
6532 for (j = 0; j < MODE_INFO_SIZE && pDefMode->mode != u16DefMode; j++)
6533 pDefMode++;
6534 Assert(j < MODE_INFO_SIZE);
6535
6536 *pCurMode = *pDefMode;
6537 pCurMode->mode = u16CurMode++;
6538
6539 /* adjust defaults */
6540 pCurMode->info.XResolution = cx;
6541 pCurMode->info.YResolution = cy;
6542
6543 switch (cBits)
6544 {
6545 case 16:
6546 pCurMode->info.BytesPerScanLine = cx * 2;
6547 pCurMode->info.LinBytesPerScanLine = cx * 2;
6548 break;
6549
6550 case 24:
6551 pCurMode->info.BytesPerScanLine = cx * 3;
6552 pCurMode->info.LinBytesPerScanLine = cx * 3;
6553 break;
6554
6555 case 32:
6556 pCurMode->info.BytesPerScanLine = cx * 4;
6557 pCurMode->info.LinBytesPerScanLine = cx * 4;
6558 break;
6559 }
6560
6561 /* commit it */
6562 pCurMode++;
6563 }
6564 else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
6565 {
6566 AssertMsgFailed(("CFGMR3QueryStringAlloc(,'%s',) -> %Rrc\n", szExtraDataKey, rc));
6567 return rc;
6568 }
6569 } /* foreach custom mode key */
6570 }
6571
6572 /*
6573 * Add the "End of list" mode.
6574 */
6575 memset(pCurMode, 0, sizeof(*pCurMode));
6576 pCurMode->mode = VBE_VESA_MODE_END_OF_LIST;
6577
6578 /*
6579 * Register I/O Port for the VBE BIOS Extra Data.
6580 */
6581 rc = PDMDevHlpIOPortRegister(pDevIns, VBE_EXTRA_PORT, 1, NULL, vbeIOPortWriteVBEExtra, vbeIOPortReadVBEExtra, NULL, NULL, "VBE BIOS Extra Data");
6582 if (RT_FAILURE(rc))
6583 return rc;
6584#endif /* VBE_NEW_DYN_LIST */
6585
6586 /*
6587 * Register I/O Port for the BIOS Logo.
6588 */
6589 rc = PDMDevHlpIOPortRegister(pDevIns, LOGO_IO_PORT, 1, NULL, vbeIOPortWriteCMDLogo, vbeIOPortReadCMDLogo, NULL, NULL, "BIOS Logo");
6590 if (RT_FAILURE(rc))
6591 return rc;
6592
6593 /*
6594 * Register debugger info callbacks.
6595 */
6596 PDMDevHlpDBGFInfoRegister(pDevIns, "vgatext", "Display VGA memory formatted as text.", vgaInfoText);
6597 PDMDevHlpDBGFInfoRegister(pDevIns, "vgacr", "Dump VGA CRTC registers.", vgaInfoCR);
6598 PDMDevHlpDBGFInfoRegister(pDevIns, "vgasr", "Dump VGA Sequencer registers.", vgaInfoSR);
6599 PDMDevHlpDBGFInfoRegister(pDevIns, "vgaar", "Dump VGA Attribute Controller registers.", vgaInfoAR);
6600 PDMDevHlpDBGFInfoRegister(pDevIns, "vgadac", "Dump VGA DAC registers.", vgaInfoDAC);
6601
6602 /*
6603 * Construct the logo header.
6604 */
6605 LOGOHDR LogoHdr = { LOGO_HDR_MAGIC, 0, 0, 0, 0, 0, 0 };
6606
6607 rc = CFGMR3QueryU8(pCfg, "FadeIn", &LogoHdr.fu8FadeIn);
6608 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6609 LogoHdr.fu8FadeIn = 1;
6610 else if (RT_FAILURE(rc))
6611 return PDMDEV_SET_ERROR(pDevIns, rc,
6612 N_("Configuration error: Querying \"FadeIn\" as integer failed"));
6613
6614 rc = CFGMR3QueryU8(pCfg, "FadeOut", &LogoHdr.fu8FadeOut);
6615 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6616 LogoHdr.fu8FadeOut = 1;
6617 else if (RT_FAILURE(rc))
6618 return PDMDEV_SET_ERROR(pDevIns, rc,
6619 N_("Configuration error: Querying \"FadeOut\" as integer failed"));
6620
6621 rc = CFGMR3QueryU16(pCfg, "LogoTime", &LogoHdr.u16LogoMillies);
6622 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6623 LogoHdr.u16LogoMillies = 0;
6624 else if (RT_FAILURE(rc))
6625 return PDMDEV_SET_ERROR(pDevIns, rc,
6626 N_("Configuration error: Querying \"LogoTime\" as integer failed"));
6627
6628 /* Delay the logo a little bit */
6629 if (LogoHdr.fu8FadeIn && LogoHdr.fu8FadeOut && !LogoHdr.u16LogoMillies)
6630 LogoHdr.u16LogoMillies = RT_MAX(LogoHdr.u16LogoMillies, LOGO_DELAY_TIME);
6631
6632 rc = CFGMR3QueryU8(pCfg, "ShowBootMenu", &LogoHdr.fu8ShowBootMenu);
6633 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6634 LogoHdr.fu8ShowBootMenu = 0;
6635 else if (RT_FAILURE(rc))
6636 return PDMDEV_SET_ERROR(pDevIns, rc,
6637 N_("Configuration error: Querying \"ShowBootMenu\" as integer failed"));
6638
6639 /*
6640 * Get the Logo file name.
6641 */
6642 rc = CFGMR3QueryStringAlloc(pCfg, "LogoFile", &pThis->pszLogoFile);
6643 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
6644 pThis->pszLogoFile = NULL;
6645 else if (RT_FAILURE(rc))
6646 return PDMDEV_SET_ERROR(pDevIns, rc,
6647 N_("Configuration error: Querying \"LogoFile\" as a string failed"));
6648 else if (!*pThis->pszLogoFile)
6649 {
6650 MMR3HeapFree(pThis->pszLogoFile);
6651 pThis->pszLogoFile = NULL;
6652 }
6653
6654 /*
6655 * Determine the logo size, open any specified logo file in the process.
6656 */
6657 LogoHdr.cbLogo = g_cbVgaDefBiosLogo;
6658 RTFILE FileLogo = NIL_RTFILE;
6659 if (pThis->pszLogoFile)
6660 {
6661 rc = RTFileOpen(&FileLogo, pThis->pszLogoFile,
6662 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
6663 if (RT_SUCCESS(rc))
6664 {
6665 uint64_t cbFile;
6666 rc = RTFileGetSize(FileLogo, &cbFile);
6667 if (RT_SUCCESS(rc))
6668 {
6669 if (cbFile > 0 && cbFile < 32*_1M)
6670 LogoHdr.cbLogo = (uint32_t)cbFile;
6671 else
6672 rc = VERR_TOO_MUCH_DATA;
6673 }
6674 }
6675 if (RT_FAILURE(rc))
6676 {
6677 /*
6678 * Ignore failure and fall back to the default logo.
6679 */
6680 LogRel(("vgaR3Construct: Failed to open logo file '%s', rc=%Rrc!\n", pThis->pszLogoFile, rc));
6681 if (FileLogo != NIL_RTFILE)
6682 RTFileClose(FileLogo);
6683 FileLogo = NIL_RTFILE;
6684 MMR3HeapFree(pThis->pszLogoFile);
6685 pThis->pszLogoFile = NULL;
6686 }
6687 }
6688
6689 /*
6690 * Disable graphic splash screen if it doesn't fit into VRAM.
6691 */
6692 if (pThis->vram_size < LOGO_MAX_SIZE)
6693 LogoHdr.fu8FadeIn = LogoHdr.fu8FadeOut = LogoHdr.u16LogoMillies = 0;
6694
6695 /*
6696 * Allocate buffer for the logo data.
6697 * RT_MAX() is applied to let us fall back to default logo on read failure.
6698 */
6699 pThis->cbLogo = sizeof(LogoHdr) + LogoHdr.cbLogo;
6700 pThis->pu8Logo = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, RT_MAX(pThis->cbLogo, g_cbVgaDefBiosLogo + sizeof(LogoHdr)));
6701 if (pThis->pu8Logo)
6702 {
6703 /*
6704 * Write the logo header.
6705 */
6706 PLOGOHDR pLogoHdr = (PLOGOHDR)pThis->pu8Logo;
6707 *pLogoHdr = LogoHdr;
6708
6709 /*
6710 * Write the logo bitmap.
6711 */
6712 if (pThis->pszLogoFile)
6713 {
6714 rc = RTFileRead(FileLogo, pLogoHdr + 1, LogoHdr.cbLogo, NULL);
6715 if (RT_FAILURE(rc))
6716 {
6717 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", LogoHdr.cbLogo, rc));
6718 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbVgaDefBiosLogo;
6719 memcpy(pLogoHdr + 1, g_abVgaDefBiosLogo, LogoHdr.cbLogo);
6720 }
6721 }
6722 else
6723 memcpy(pLogoHdr + 1, g_abVgaDefBiosLogo, LogoHdr.cbLogo);
6724
6725 rc = vbeParseBitmap(pThis);
6726 if (RT_FAILURE(rc))
6727 {
6728 AssertMsgFailed(("vbeParseBitmap() -> %Rrc\n", rc));
6729 pLogoHdr->cbLogo = LogoHdr.cbLogo = g_cbVgaDefBiosLogo;
6730 memcpy(pLogoHdr + 1, g_abVgaDefBiosLogo, LogoHdr.cbLogo);
6731 }
6732
6733 rc = vbeParseBitmap(pThis);
6734 if (RT_FAILURE(rc))
6735 AssertReleaseMsgFailed(("Internal bitmap failed! vbeParseBitmap() -> %Rrc\n", rc));
6736
6737 rc = VINF_SUCCESS;
6738 }
6739 else
6740 rc = VERR_NO_MEMORY;
6741
6742 /*
6743 * Cleanup.
6744 */
6745 if (FileLogo != NIL_RTFILE)
6746 RTFileClose(FileLogo);
6747
6748#ifdef VBOX_WITH_HGSMI
6749 VBVAInit (pThis);
6750#endif /* VBOX_WITH_HGSMI */
6751
6752#ifdef VBOXVDMA
6753 if(rc == VINF_SUCCESS)
6754 {
6755 /* @todo: perhaps this should be done from some guest->host callback,
6756 * that would as well specify the cmd pool size */
6757 rc = vboxVDMAConstruct(pThis, &pThis->pVdma, 1024);
6758 AssertRC(rc);
6759 }
6760#endif
6761 /*
6762 * Statistics.
6763 */
6764 STAM_REG(pVM, &pThis->StatRZMemoryRead, STAMTYPE_PROFILE, "/Devices/VGA/RZ/MMIO-Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryRead() body.");
6765 STAM_REG(pVM, &pThis->StatR3MemoryRead, STAMTYPE_PROFILE, "/Devices/VGA/R3/MMIO-Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryRead() body.");
6766 STAM_REG(pVM, &pThis->StatRZMemoryWrite, STAMTYPE_PROFILE, "/Devices/VGA/RZ/MMIO-Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryWrite() body.");
6767 STAM_REG(pVM, &pThis->StatR3MemoryWrite, STAMTYPE_PROFILE, "/Devices/VGA/R3/MMIO-Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryWrite() body.");
6768 STAM_REG(pVM, &pThis->StatMapPage, STAMTYPE_COUNTER, "/Devices/VGA/MapPageCalls", STAMUNIT_OCCURENCES, "Calls to IOMMMIOMapMMIO2Page.");
6769
6770 /* Init latched access mask. */
6771 pThis->uMaskLatchAccess = 0x3ff;
6772 return rc;
6773}
6774
6775
6776/**
6777 * The device registration structure.
6778 */
6779const PDMDEVREG g_DeviceVga =
6780{
6781 /* u32Version */
6782 PDM_DEVREG_VERSION,
6783 /* szName */
6784 "vga",
6785 /* szRCMod */
6786 "VBoxDDGC.gc",
6787 /* szR0Mod */
6788 "VBoxDDR0.r0",
6789 /* pszDescription */
6790 "VGA Adaptor with VESA extensions.",
6791 /* fFlags */
6792 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
6793 /* fClass */
6794 PDM_DEVREG_CLASS_GRAPHICS,
6795 /* cMaxInstances */
6796 1,
6797 /* cbInstance */
6798 sizeof(VGASTATE),
6799 /* pfnConstruct */
6800 vgaR3Construct,
6801 /* pfnDestruct */
6802 vgaR3Destruct,
6803 /* pfnRelocate */
6804 vgaR3Relocate,
6805 /* pfnIOCtl */
6806 NULL,
6807 /* pfnPowerOn */
6808 NULL,
6809 /* pfnReset */
6810 vgaR3Reset,
6811 /* pfnSuspend */
6812 NULL,
6813 /* pfnResume */
6814 NULL,
6815 /* pfnAttach */
6816 vgaAttach,
6817 /* pfnDetach */
6818 vgaDetach,
6819 /* pfnQueryInterface */
6820 NULL,
6821 /* pfnInitComplete */
6822 NULL,
6823 /* pfnPowerOff */
6824 NULL,
6825 /* pfnSoftReset */
6826 NULL,
6827 /* u32VersionEnd */
6828 PDM_DEVREG_VERSION
6829};
6830
6831#endif /* !IN_RING3 */
6832#endif /* VBOX */
6833#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
6834
6835/*
6836 * Local Variables:
6837 * nuke-trailing-whitespace-p:nil
6838 * End:
6839 */
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