VirtualBox

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

Last change on this file since 32619 was 32502, checked in by vboxsync, 14 years ago

vgaInfoText: Fixed div by zero error.

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