VirtualBox

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

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

DevVGA: fixed off-by-one range check

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