DevVGA.cpp revision 53d856ff201cb36f6403a2dfc9ee7db1e885a18a
#ifdef VBOX
/** @file
*
*/
/*
* Copyright (C) 2006 InnoTek Systemberatung GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License as published by the Free Software Foundation,
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
* distribution. VirtualBox OSE is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY of any kind.
*
* If you received this file as part of a commercial VirtualBox
* distribution, then only the terms of your commercial VirtualBox
* license agreement apply instead of the previous paragraph.
*
* --------------------------------------------------------------------
*
* This code is based on:
*
* QEMU VGA Emulator.
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The default amount of VRAM. */
#define VGA_VRAM_DEFAULT (_4M)
/** The maximum amount of VRAM. */
/** The minimum amount of VRAM. */
#define VGA_VRAM_MIN (_1M)
/** The maximum number of monitors. */
#define VGA_MONITORS_MAX 64
/** The size of the VGA GC mapping.
* This is supposed to be all the VGA memory accessible to the guest.
* The initial value was 256KB but NTAllInOne.iso appears to access more
* thus the limit was upped to 512KB.
*
* @todo Someone with some VGA knowhow should make a better guess at this value.
*/
#define VGA_MAPPING_SIZE _512K
/** Converts a vga adaptor state pointer to a device instance pointer. */
/** Use VBE bytewise I/O */
#define VBE_BYTEWISE_IO
/** Use VBE new dynamic mode list.
* If this is not defined, no checks are carried out to see if the modes all
* fit into the framebuffer! See the VRAM_SIZE_FIX define. */
#define VBE_NEW_DYN_LIST
/** Check that the video modes fit into virtual video memory.
* Only works when VBE_NEW_DYN_LIST is defined! */
#define VRAM_SIZE_FIX
/** Some fixes to ensure that logical scan-line lengths are not overwritten. */
#define KEEP_SCAN_LINE_LENGTH
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_VGA
#include <VBox/VBoxGuest.h>
# include "DevVGAModes.h"
# include <stdio.h> /* sscan */
#endif
#include "vl_vbox.h"
#include "DevVGA.h"
#include "Builtins.h"
#include "Builtins2.h"
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
PDMBOTHCBDECL(int) vgaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
PDMBOTHCBDECL(int) vgaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
PDMBOTHCBDECL(int) vgaIOPortWriteVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
PDMBOTHCBDECL(int) vgaIOPortWriteVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
PDMBOTHCBDECL(int) vgaIOPortReadVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
PDMBOTHCBDECL(int) vgaIOPortReadVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
PDMBOTHCBDECL(int) vgaMMIOFill(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems);
PDMBOTHCBDECL(int) vgaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
PDMBOTHCBDECL(int) vgaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
#ifdef IN_GC
PDMBOTHCBDECL(int) vgaGCLFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
#endif
#ifdef IN_RING0
PDMBOTHCBDECL(int) vgaR0LFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
#endif
#ifdef IN_RING3
# ifdef VBE_NEW_DYN_LIST
PDMBOTHCBDECL(int) vbeIOPortReadVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
PDMBOTHCBDECL(int) vbeIOPortWriteVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
# endif
#endif /* IN_RING3 */
/**
* Set a VRAM page dirty.
*
* @param pData VGA instance data.
* @param offVRAM The VRAM offset of the page to set.
*/
{
AssertMsg(offVRAM < pData->vram_size, ("offVRAM = %p, pData->vram_size = %p\n", offVRAM, pData->vram_size));
pData->fHaveDirtyBits = true;
}
/**
* Tests if a VRAM page is dirty.
*
* @returns true if dirty.
* @returns false if clean.
* @param pData VGA instance data.
* @param offVRAM The VRAM offset of the page to check.
*/
{
AssertMsg(offVRAM < pData->vram_size, ("offVRAM = %p, pData->vram_size = %p\n", offVRAM, pData->vram_size));
}
/**
* Reset dirty flags in a give range.
*
* @param pData VGA instance data.
* @param offVRAMStart Offset into the VRAM buffer of the first page.
* @param offVRAMEnd Offset into the VRAM buffer of the last page - exclusive.
*/
{
}
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
#endif /* VBOX */
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
#ifndef VBOX
#include "vl.h"
#include "vga_int.h"
#endif /* !VBOX */
#ifdef LOG_ENABLED
//#define DEBUG_VGA
//#define DEBUG_VGA_MEM
//#define DEBUG_VGA_REG
#define DEBUG_BOCHS_VBE
#endif
/* force some bits to zero */
#ifdef VBOX
static
#endif /* VBOX */
(uint8_t)~0xfc,
(uint8_t)~0xc2,
(uint8_t)~0xf0,
(uint8_t)~0xc0,
(uint8_t)~0xf1,
(uint8_t)~0xff,
(uint8_t)~0xff,
(uint8_t)~0x00,
};
#ifdef VBOX
static
#endif /* VBOX */
};
((uint32_t)( \
#ifdef WORDS_BIGENDIAN
#else
#define PAT(x) (x)
#endif
#ifdef WORDS_BIGENDIAN
#define BIG 1
#else
#define BIG 0
#endif
#ifdef WORDS_BIGENDIAN
#else
#endif
PAT(0x00000000),
PAT(0x000000ff),
PAT(0x0000ff00),
PAT(0x0000ffff),
PAT(0x00ff0000),
PAT(0x00ff00ff),
PAT(0x00ffff00),
PAT(0x00ffffff),
PAT(0xff000000),
PAT(0xff0000ff),
PAT(0xff00ff00),
PAT(0xff00ffff),
PAT(0xffff0000),
PAT(0xffff00ff),
PAT(0xffffff00),
PAT(0xffffffff),
};
#ifdef WORDS_BIGENDIAN
#define PAT(x) (x)
#else
#endif
PAT(0x00000000),
PAT(0x000000ff),
PAT(0x0000ff00),
PAT(0x0000ffff),
PAT(0x00ff0000),
PAT(0x00ff00ff),
PAT(0x00ffff00),
PAT(0x00ffffff),
PAT(0xff000000),
PAT(0xff0000ff),
PAT(0xff00ff00),
PAT(0xff00ffff),
PAT(0xffff0000),
PAT(0xffff00ff),
PAT(0xffffff00),
PAT(0xffffffff),
};
PAT(0x00000000),
PAT(0x0000ffff),
PAT(0xffff0000),
PAT(0xffffffff),
};
#endif /* VBOX && IN_RING3 */
#ifndef VBOX
int vga_io_memory;
#endif /* !VBOX */
{
/* check port range access depending on color/monochrome mode */
val = 0xff;
} else {
switch(addr) {
case 0x3c0:
if (s->ar_flip_flop == 0) {
} else {
val = 0;
}
break;
case 0x3c1:
if (index < 21)
else
val = 0;
break;
case 0x3c2:
break;
case 0x3c4:
break;
case 0x3c5:
#ifdef DEBUG_VGA_REG
#endif
break;
case 0x3c7:
break;
case 0x3c8:
val = s->dac_write_index;
break;
case 0x3c9:
if (++s->dac_sub_index == 3) {
s->dac_sub_index = 0;
s->dac_read_index++;
}
break;
case 0x3ca:
break;
case 0x3cc:
break;
case 0x3ce:
break;
case 0x3cf:
#ifdef DEBUG_VGA_REG
#endif
break;
case 0x3b4:
case 0x3d4:
break;
case 0x3b5:
case 0x3d5:
#ifdef DEBUG_VGA_REG
#endif
break;
case 0x3ba:
case 0x3da:
/* just toggle to fool polling */
s->ar_flip_flop = 0;
break;
default:
val = 0x00;
break;
}
}
#if defined(DEBUG_VGA)
#endif
return val;
}
{
int index;
/* check port range access depending on color/monochrome mode */
return;
#ifdef DEBUG_VGA
#endif
switch(addr) {
case 0x3c0:
if (s->ar_flip_flop == 0) {
val &= 0x3f;
} else {
switch(index) {
#ifndef VBOX
case 0x00 ... 0x0f:
#else /* VBOX */
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
#endif /* VBOX */
break;
case 0x10:
break;
case 0x11:
break;
case 0x12:
break;
case 0x13:
break;
case 0x14:
break;
default:
break;
}
}
s->ar_flip_flop ^= 1;
break;
case 0x3c2:
break;
case 0x3c4:
break;
case 0x3c5:
#ifdef DEBUG_VGA_REG
#endif
break;
case 0x3c7:
s->dac_read_index = val;
s->dac_sub_index = 0;
s->dac_state = 3;
break;
case 0x3c8:
s->dac_write_index = val;
s->dac_sub_index = 0;
s->dac_state = 0;
break;
case 0x3c9:
if (++s->dac_sub_index == 3) {
s->dac_sub_index = 0;
s->dac_write_index++;
}
break;
case 0x3ce:
break;
case 0x3cf:
#ifdef DEBUG_VGA_REG
#endif
break;
case 0x3b4:
case 0x3d4:
break;
case 0x3b5:
case 0x3d5:
#ifdef DEBUG_VGA_REG
#endif
/* handle CR0-7 protection */
/* can always write bit 4 of CR7 */
if (s->cr_index == 7)
return;
}
switch(s->cr_index) {
case 0x01: /* horizontal display end */
case 0x07:
case 0x09:
case 0x0c:
case 0x0d:
case 0x12: /* veritcal display end */
break;
default:
break;
}
break;
case 0x3ba:
case 0x3da:
break;
}
}
#ifdef CONFIG_BOCHS_VBE
{
return val;
}
{
if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
switch(s->vbe_index) {
/* XXX: do not hardcode ? */
case VBE_DISPI_INDEX_XRES:
break;
case VBE_DISPI_INDEX_YRES:
break;
case VBE_DISPI_INDEX_BPP:
break;
default:
break;
}
} else if (s->vbe_index == VBE_DISPI_INDEX_CMONITORS) {
val = s->monitor_count;
} else {
}
} else {
val = 0;
}
#ifdef DEBUG_BOCHS_VBE
#endif
return val;
}
{
}
{
if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
#ifdef DEBUG_BOCHS_VBE
#endif
switch(s->vbe_index) {
case VBE_DISPI_INDEX_ID:
if (val == VBE_DISPI_ID0 ||
val == VBE_DISPI_ID1 ||
val == VBE_DISPI_ID2) {
}
break;
case VBE_DISPI_INDEX_XRES:
#ifdef KEEP_SCAN_LINE_LENGTH
else
/* XXX: support weird bochs semantics ? */
s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
s->vbe_start_addr = 0;
#endif /* KEEP_SCAN_LINE_LENGTH defined */
}
break;
case VBE_DISPI_INDEX_YRES:
if (val <= VBE_DISPI_MAX_YRES) {
#ifdef KEEP_SCAN_LINE_LENGTH
s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
s->vbe_start_addr = 0;
#endif /* KEEP_SCAN_LINE_LENGTH defined */
}
break;
case VBE_DISPI_INDEX_BPP:
if (val == 0)
val = 8;
#ifdef KEEP_SCAN_LINE_LENGTH
if (val == 4)
else
/* XXX: support weird bochs semantics ? */
s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
s->vbe_start_addr = 0;
#endif /* KEEP_SCAN_LINE_LENGTH defined */
}
break;
case VBE_DISPI_INDEX_BANK:
} else {
val &= s->vbe_bank_mask;
}
val &= s->vbe_bank_mask;
break;
case VBE_DISPI_INDEX_ENABLE:
if (val & VBE_DISPI_ENABLED) {
int h, shift_control;
#ifdef VBOX
/* Check the values before we screw up with a resolution which is too big or small. */
else
#ifndef KEEP_SCAN_LINE_LENGTH
if ( !s->vbe_regs[VBE_DISPI_INDEX_XRES]
|| !s->vbe_regs[VBE_DISPI_INDEX_YRES]
{
AssertMsgFailed(("XRES=%d YRES=%d cb=%d vram_size=%d\n",
return;
}
#else /* KEEP_SCAN_LINE_LENGTH defined */
if ( !s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH]
|| !s->vbe_regs[VBE_DISPI_INDEX_YRES]
{
AssertMsgFailed(("VIRT WIDTH=%d YRES=%d cb=%d vram_size=%d\n",
return;
}
#endif /* KEEP_SCAN_LINE_LENGTH defined */
#endif /* VBOX */
#ifndef KEEP_SCAN_LINE_LENGTH
s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
else
s->vbe_start_addr = 0;
#endif /* KEEP_SCAN_LINE_LENGTH not defined */
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
}
/* we initialize the VGA graphic mode (should be done
in BIOS) */
/* width */
/* height (only meaningful if < 1024) */
s->cr[0x12] = h;
((h >> 7) & 0x02) | ((h >> 3) & 0x40);
/* line compare to 1023 */
shift_control = 0;
} else {
shift_control = 2;
}
} else {
/* XXX: the bios should do that */
#ifdef VBOX
/* sunlover 21.12.2006
* Here is probably more to reset. When this was executed in GC
* then the *update* functions could not detect a mode change.
* Or may be these update function should take the s->vbe_regs[s->vbe_index]
* into account when detecting a mode change.
*
* The 'mode reset not detected' problem is now fixed by executing the
* VBE_DISPI_INDEX_ENABLE case always in RING3 in order to call the
* LFBChange callback.
*/
#endif /* VBOX */
s->bank_offset = 0;
}
#ifdef VBOX
#ifdef IN_RING3
/*
* LFB video mode is either disabled or changed. This notification
* is used by the display to disable VBVA.
*/
#endif /* IN_RING3 */
#endif /* VBOX */
break;
{
int w, h, line_offset;
return;
w = val;
line_offset = w >> 1;
else
h = s->vram_size / line_offset;
/* XXX: support weird bochs semantics ? */
if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
return;
s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
s->vbe_line_offset = line_offset;
}
break;
case VBE_DISPI_INDEX_X_OFFSET:
case VBE_DISPI_INDEX_Y_OFFSET:
{
int x;
x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
s->vbe_start_addr += x >> 1;
else
s->vbe_start_addr >>= 2;
}
break;
default:
break;
}
}
}
#endif
/* called for accesses between 0xa0000 and 0xc0000 */
#ifdef VBOX
static
#endif /* VBOX */
{
int memory_map_mode, plane;
/* convert to VGA memory offset */
addr &= 0x1ffff;
switch(memory_map_mode) {
case 0:
break;
case 1:
if (addr >= 0x10000)
return 0xff;
addr += s->bank_offset;
break;
case 2:
addr -= 0x10000;
if (addr >= 0x8000)
return 0xff;
break;
default:
case 3:
addr -= 0x18000;
if (addr >= 0x8000)
return 0xff;
break;
}
#ifdef IN_GC
if (addr >= VGA_MAPPING_SIZE)
return VINF_IOM_HC_MMIO_WRITE;
#endif
/* chain 4 mode : simplest access */
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
} else {
/* standard VGA latched access */
#ifndef VBOX
#else /* VBOX && IN_GC */
#endif /* VBOX && IN_GC */
/* read mode 0 */
} else {
/* read mode 1 */
}
}
return ret;
}
#ifndef VBOX
{
uint32_t v;
#ifdef TARGET_WORDS_BIGENDIAN
#else
#endif
return v;
}
{
uint32_t v;
#ifdef TARGET_WORDS_BIGENDIAN
#else
#endif
return v;
}
#endif /* !VBOX */
/* called for accesses between 0xa0000 and 0xc0000 */
#ifdef VBOX
static
#endif /* VBOX */
{
#ifdef DEBUG_VGA_MEM
#endif
/* convert to VGA memory offset */
addr &= 0x1ffff;
switch(memory_map_mode) {
case 0:
break;
case 1:
if (addr >= 0x10000)
return VINF_SUCCESS;
addr += s->bank_offset;
break;
case 2:
addr -= 0x10000;
if (addr >= 0x8000)
return VINF_SUCCESS;
break;
default:
case 3:
addr -= 0x18000;
if (addr >= 0x8000)
return VINF_SUCCESS;
break;
}
/* chain 4 mode : simplest access */
#ifndef VBOX
#else /* VBOX */
#ifdef IN_GC
if (addr >= VGA_MAPPING_SIZE)
return VINF_IOM_HC_MMIO_WRITE;
#else
{
AssertMsgFailed(("addr=%VGp - this needs to be done in HC! bank_offset=%08x memory_map_mode=%d\n",
return VINF_SUCCESS;
}
#endif
#endif /* VBOX */
#ifdef DEBUG_VGA_MEM
#endif
#ifndef VBOX
#else /* VBOX */
vga_set_dirty(s, addr);
#endif /* VBOX */
}
#ifndef VBOX
#else /* VBOX */
#ifdef IN_GC
if (addr >= VGA_MAPPING_SIZE)
return VINF_IOM_HC_MMIO_WRITE;
#else
{
AssertMsgFailed(("addr=%VGp - this needs to be done in HC! bank_offset=%08x memory_map_mode=%d\n",
return VINF_SUCCESS;
}
#endif
#endif /* VBOX */
#ifdef DEBUG_VGA_MEM
#endif
#ifndef VBOX
#else /* VBOX */
vga_set_dirty(s, addr);
#endif /* VBOX */
}
} else {
#ifdef IN_GC
return VINF_IOM_HC_MMIO_WRITE;
#else
{
AssertMsgFailed(("addr=%VGp - this needs to be done in HC! bank_offset=%08x memory_map_mode=%d\n",
return VINF_SUCCESS;
}
#endif
/* standard VGA latched access */
switch(write_mode) {
default:
case 0:
/* rotate */
break;
case 1:
goto do_write;
case 2:
break;
case 3:
/* rotate */
break;
}
/* apply logical operation */
switch(func_select) {
case 0:
default:
/* nothing to do */
break;
case 1:
/* and */
break;
case 2:
/* or */
break;
case 3:
/* xor */
break;
}
/* apply bit mask */
/* mask data according to sr[2] */
#ifndef VBOX
(val & write_mask);
#else /* VBOX */
(val & write_mask);
#endif /* VBOX */
#ifdef DEBUG_VGA_MEM
Log(("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
#endif
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
}
return VINF_SUCCESS;
}
#ifndef VBOX
{
#ifdef TARGET_WORDS_BIGENDIAN
#else
#endif
}
{
#ifdef TARGET_WORDS_BIGENDIAN
#else
#endif
}
#endif /* !VBOX */
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
{
return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
}
static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
{
return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
}
static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
{
return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
}
static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
{
return (r << 16) | (g << 8) | b;
}
#define DEPTH 8
#include "DevVGATmpl.h"
#define DEPTH 15
#include "DevVGATmpl.h"
#define DEPTH 16
#include "DevVGATmpl.h"
#define DEPTH 32
#include "DevVGATmpl.h"
static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
{
unsigned int col;
col = rgb_to_pixel8(r, g, b);
return col;
}
static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
{
unsigned int col;
col = rgb_to_pixel15(r, g, b);
return col;
}
static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
{
unsigned int col;
col = rgb_to_pixel16(r, g, b);
return col;
}
static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
{
unsigned int col;
col = rgb_to_pixel32(r, g, b);
return col;
}
/* return true if the palette was modified */
static int update_palette16(VGAState *s)
{
int full_update, i;
full_update = 0;
palette = s->last_palette;
for(i = 0; i < 16; i++) {
v = s->ar[i];
else
v = v * 3;
full_update = 1;
}
}
return full_update;
}
/* return true if the palette was modified */
static int update_palette256(VGAState *s)
{
int full_update, i;
full_update = 0;
palette = s->last_palette;
v = 0;
for(i = 0; i < 256; i++) {
full_update = 1;
}
v += 3;
}
return full_update;
}
static void vga_get_offsets(VGAState *s,
{
#ifdef CONFIG_BOCHS_VBE
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
} else
#endif
{
/* compute line_offset in bytes */
line_offset <<= 3;
/* starting address */
/* line compare */
}
}
/* update start_addr and line_offset. Return TRUE if modified */
static int update_basic_params(VGAState *s)
{
int full_update;
full_update = 0;
if (line_offset != s->line_offset ||
start_addr != s->start_addr ||
line_compare != s->line_compare) {
s->line_offset = line_offset;
s->start_addr = start_addr;
s->line_compare = line_compare;
full_update = 1;
}
return full_update;
}
static inline int get_depth_index(int depth)
{
switch(depth) {
default:
case 8:
return 0;
case 15:
return 1;
case 16:
return 2;
case 32:
return 3;
}
}
};
};
};
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
/*
* Text mode update
* Missing:
* - double scan
* - double width
* - underline
* - flashing
*/
#ifndef VBOX
#else
#endif /* !VBOX */
{
full_update |= update_palette16(s);
palette = s->last_palette;
/* compute font data address (in plane 2) */
v = s->sr[3];
if (offset != s->font_offsets[0]) {
s->font_offsets[0] = offset;
full_update = 1;
}
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
full_update = 1;
}
/* if the plane 2 was modified since the last display, it
indicates the font may have been modified */
s->plane_updated = 0;
full_update = 1;
}
full_update |= update_basic_params(s);
line_offset = s->line_offset;
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
/* total width & height */
cw = 8;
cw = 9;
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
/* ugly hack for CGA 160x100x16 - explain me the logic */
height = 100;
} else {
}
/* better than nothing: exit if transient size is too big */
#ifndef VBOX
return;
#else
return VINF_SUCCESS;
#endif /* VBOX */
}
#ifndef VBOX
s->last_width = width;
s->last_height = height;
full_update = 1;
#else /* VBOX */
/* For text modes the direct use of guest VRAM is not implemented, so bpp and cbLine are 0 here. */
s->last_width = width;
s->last_height = height;
full_update = 1;
if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
return rc;
#endif /* VBOX */
}
if (cursor_offset != s->cursor_offset ||
/* if the cursor position changed, we update the old and new
chars */
if (s->cursor_offset < CH_ATTR_SIZE)
s->last_ch_attr[s->cursor_offset] = ~0;
if (cursor_offset < CH_ATTR_SIZE)
s->last_ch_attr[cursor_offset] = ~0;
s->cursor_offset = cursor_offset;
}
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
if (cw == 16)
else
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
ch_attr_ptr = s->last_ch_attr;
cx_max = -1;
*ch_attr_ptr = ch_attr;
#ifdef WORDS_BIGENDIAN
#else
#endif
if (cw != 9) {
} else {
dup9 = 0;
dup9 = 1;
}
if (src == cursor_ptr &&
int line_start, line_last, h;
/* draw the cursor */
/* XXX: check that */
if (cw != 9) {
} else {
}
}
}
}
src += 4;
ch_attr_ptr++;
}
#ifndef VBOX
if (cx_max != -1) {
}
#else
if (cx_max != -1)
#endif
s1 += line_offset;
}
#ifdef VBOX
return VINF_SUCCESS;
#endif /* VBOX */
}
enum {
};
};
static int vga_get_bpp(VGAState *s)
{
int ret;
#ifdef CONFIG_BOCHS_VBE
} else
#endif
{
ret = 0;
}
return ret;
}
{
#ifdef CONFIG_BOCHS_VBE
} else
#endif
{
}
}
#ifndef VBOX
{
int y;
if (y1 >= VGA_MAX_HEIGHT)
return;
if (y2 >= VGA_MAX_HEIGHT)
y2 = VGA_MAX_HEIGHT;
}
}
#endif /* !VBOX*/
#ifdef VBOX
/**
* Performs the display driver resizing when in graphics mode.
*
* This will recalc / update any status data depending on the driver
* properties (bit depth mostly).
*
* @returns VINF_SUCCESS on success.
* @returns VINF_VGA_RESIZE_IN_PROGRESS if the operation wasn't complete.
* @param s Pointer to the vga status.
* @param cx The width.
* @param cy The height.
*/
{
/** @todo r=sunlover: If the guest changes VBE_DISPI_INDEX_X_OFFSET, VBE_DISPI_INDEX_Y_OFFSET
* registers, then the third parameter of the following call should be
* probably 's->CTXSUFF(vram_ptr) + s->vbe_start_addr'.
*/
/* last stuff */
s->last_scr_width = cx;
s->last_scr_height = cy;
s->last_width = cx;
s->last_height = cy;
if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
return rc;
/* update palette */
{
case 16:
default: s->rgb_to_pixel = rgb_to_pixel16_dup; break;
}
if (s->shift_control == 0)
update_palette16(s);
else if (s->shift_control == 1)
update_palette16(s);
return VINF_SUCCESS;
}
#endif /* VBOX */
/*
* graphic modes
*/
#ifndef VBOX
#else
#endif /* !VBOX */
{
uint8_t *d;
bool offsets_changed;
disp_width = width;
if (shift_control != 1) {
} else {
/* in CGA modes, multi_scan is ignored */
/* XXX: is it correct ? */
}
if (shift_control != s->shift_control ||
double_scan != s->double_scan) {
full_update = 1;
s->shift_control = shift_control;
s->double_scan = double_scan;
}
if (shift_control == 0) {
full_update |= update_palette16(s);
v = VGA_DRAW_LINE4D2;
disp_width <<= 1;
} else {
v = VGA_DRAW_LINE4;
}
} else if (shift_control == 1) {
full_update |= update_palette16(s);
v = VGA_DRAW_LINE2D2;
disp_width <<= 1;
} else {
v = VGA_DRAW_LINE2;
}
} else {
switch(s->get_bpp(s)) {
default:
case 0:
full_update |= update_palette256(s);
v = VGA_DRAW_LINE8D2;
break;
case 8:
full_update |= update_palette256(s);
v = VGA_DRAW_LINE8;
break;
case 15:
v = VGA_DRAW_LINE15;
break;
case 16:
v = VGA_DRAW_LINE16;
break;
case 24:
v = VGA_DRAW_LINE24;
break;
case 32:
v = VGA_DRAW_LINE32;
break;
}
}
#ifndef VBOX
if (disp_width != s->last_width ||
height != s->last_height) {
s->last_scr_width = disp_width;
s->last_scr_height = height;
s->last_width = disp_width;
s->last_height = height;
full_update = 1;
}
#else /* VBOX */
if ( disp_width != (int)s->last_width
|| height != (int)s->last_height
|| offsets_changed)
{
if (rc != VINF_SUCCESS) /* Return any rc, particularly VINF_VGA_RESIZE_IN_PROGRESS, to the caller. */
return rc;
full_update = 1;
}
#endif /* VBOX */
if (s->cursor_invalidate)
s->cursor_invalidate(s);
line_offset = s->line_offset;
#if 0
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",
#endif
#ifndef VBOX
#else /* VBOX */
/* The width of VRAM scanline. */
bwidth = s->line_offset;
/* In some cases the variable is not yet set, probably due to incomplete
* programming of the virtual hardware ports. Just return.
*/
if (bwidth == 0) return VINF_SUCCESS;
#endif /* VBOX */
y_start = -1;
page_min = 0x7fffffff;
page_max = -1;
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
y1 = 0;
for(y = 0; y < height; y++) {
int shift;
/* CGA compatibility handling */
}
}
#ifndef VBOX
update = full_update |
/* if wide line, can use another page */
}
#else /* VBOX */
/* if wide line, can use another page */
}
#endif /* VBOX */
/* explicit invalidation for the hardware cursor */
if (update) {
if (y_start < 0)
y_start = y;
#ifndef VBOX
#else /* VBOX */
if (s->fRenderVRAM)
#endif /* VBOX */
if (s->cursor_draw_line)
s->cursor_draw_line(s, d, y);
} else {
if (y_start >= 0) {
/* flush to display */
#ifndef VBOX
disp_width, y - y_start);
#else /* VBOX */
#endif /* VBOX */
y_start = -1;
}
}
if (!multi_run) {
addr1 += line_offset;
y1++;
} else {
multi_run--;
}
/* line compare acts on the displayed lines */
if ((uint32_t)y == s->line_compare)
addr1 = 0;
d += linesize;
}
if (y_start >= 0) {
/* flush to display */
#ifndef VBOX
disp_width, y - y_start);
#else /* VBOX */
#endif /* VBOX */
}
/* reset modified pages */
if (page_max != -1) {
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
}
#ifdef VBOX
return VINF_SUCCESS;
#endif /* VBOX */
}
{
#ifndef VBOX
int i, w, val;
uint8_t *d;
if (!full_update)
return;
if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
return;
val = s->rgb_to_pixel(0, 0, 0);
else
val = 0;
for(i = 0; i < s->last_scr_height; i++) {
}
dpy_update(s->ds, 0, 0,
s->last_scr_width, s->last_scr_height);
#else /* VBOX */
int i, w, val;
uint8_t *d;
if (!full_update)
return;
if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
return;
val = s->rgb_to_pixel(0, 0, 0);
else
val = 0;
for(i = 0; i < (int)s->last_scr_height; i++) {
d += cbScanline;
}
#endif /* VBOX */
}
#define GMODE_TEXT 0
#define GMODE_GRAPH 1
#define GMODE_BLANK 2
#ifndef VBOX
void vga_update_display(void)
{
#else /* VBOX */
static int vga_update_display(PVGASTATE s)
{
int rc = VINF_SUCCESS;
#endif /* VBOX */
int full_update, graphic_mode;
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
/* nothing to do */
} else {
#ifndef VBOX
#else /* VBOX */
#endif /* VBOX */
case 8:
break;
case 15:
break;
default:
case 16:
break;
case 32:
break;
}
full_update = 0;
if (!(s->ar_index & 0x20)) {
} else {
}
if (graphic_mode != s->graphic_mode) {
s->graphic_mode = graphic_mode;
full_update = 1;
}
switch(graphic_mode) {
case GMODE_TEXT:
#ifdef VBOX
rc =
#endif /* VBOX */
vga_draw_text(s, full_update);
break;
case GMODE_GRAPH:
#ifdef VBOX
rc =
#endif /* VBOX */
break;
case GMODE_BLANK:
default:
break;
}
}
#ifdef VBOX
return rc;
#endif /* VBOX */
}
/* force a full display refresh */
#ifndef VBOX
void vga_invalidate_display(void)
{
s->last_width = -1;
s->last_height = -1;
}
#endif /* !VBOX */
#ifndef VBOX /* see vgaR3Reset() */
{
}
#endif /* !VBOX */
#ifndef VBOX
};
};
#endif /* !VBOX */
{
int i;
qemu_put_be32s(f, &s->latch);
qemu_put_8s(f, &s->sr_index);
qemu_put_8s(f, &s->gr_index);
qemu_put_8s(f, &s->ar_index);
qemu_put_be32s(f, &s->ar_flip_flop);
qemu_put_8s(f, &s->cr_index);
qemu_put_8s(f, &s->msr);
qemu_put_8s(f, &s->fcr);
qemu_put_8s(f, &s->st00);
qemu_put_8s(f, &s->st01);
qemu_put_8s(f, &s->dac_state);
qemu_put_8s(f, &s->dac_sub_index);
qemu_put_8s(f, &s->dac_read_index);
qemu_put_8s(f, &s->dac_write_index);
qemu_put_be32s(f, &s->bank_offset);
#ifdef CONFIG_BOCHS_VBE
qemu_put_byte(f, 1);
qemu_put_be16s(f, &s->vbe_index);
for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
qemu_put_be16s(f, &s->vbe_regs[i]);
qemu_put_be32s(f, &s->vbe_start_addr);
qemu_put_be32s(f, &s->vbe_line_offset);
qemu_put_be32s(f, &s->vbe_bank_mask);
#else
qemu_put_byte(f, 0);
#endif
}
{
int is_vbe, i;
if (version_id != 1)
#ifndef VBOX
return -EINVAL;
#else /* VBOX */
{
}
#endif /* VBOX */
qemu_get_be32s(f, &s->latch);
qemu_get_8s(f, &s->sr_index);
qemu_get_8s(f, &s->gr_index);
qemu_get_8s(f, &s->ar_index);
qemu_get_8s(f, &s->cr_index);
qemu_get_8s(f, &s->msr);
qemu_get_8s(f, &s->fcr);
qemu_get_8s(f, &s->st00);
qemu_get_8s(f, &s->st01);
qemu_get_8s(f, &s->dac_state);
qemu_get_8s(f, &s->dac_sub_index);
qemu_get_8s(f, &s->dac_read_index);
qemu_get_8s(f, &s->dac_write_index);
is_vbe = qemu_get_byte(f);
#ifdef CONFIG_BOCHS_VBE
if (!is_vbe)
#ifndef VBOX
return -EINVAL;
#else /* VBOX */
{
Log(("vga_load: !is_vbe !!\n"));
}
#endif /* VBOX */
qemu_get_be16s(f, &s->vbe_index);
for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
qemu_get_be16s(f, &s->vbe_regs[i]);
qemu_get_be32s(f, &s->vbe_start_addr);
qemu_get_be32s(f, &s->vbe_line_offset);
qemu_get_be32s(f, &s->vbe_bank_mask);
#else
if (is_vbe)
#ifndef VBOX
return -EINVAL;
#else /* VBOX */
{
Log(("vga_load: is_vbe !!\n"));
}
#endif /* VBOX */
#endif
/* force refresh */
s->graphic_mode = -1;
return 0;
}
#ifndef VBOX /* see vgaR3IORegionMap */
{
}
#endif
#ifndef VBOX /* see vgaR3Construct */
unsigned long vga_ram_offset, int vga_ram_size)
#else
static void vga_init_expand(void)
#endif
{
int i, j, v, b;
for(i = 0;i < 256; i++) {
v = 0;
for(j = 0; j < 8; j++) {
v |= ((i >> j) & 1) << (j * 4);
}
expand4[i] = v;
v = 0;
for(j = 0; j < 4; j++) {
v |= ((i >> (2 * j)) & 3) << (j * 4);
}
expand2[i] = v;
}
for(i = 0; i < 16; i++) {
v = 0;
for(j = 0; j < 4; j++) {
b = ((i >> j) & 1);
v |= b << (2 * j);
v |= b << (2 * j + 1);
}
expand4to8[i] = v;
}
#ifdef VBOX
}
#else /* !VBOX */
vga_reset(s);
s->vram_ptr = vga_ram_base;
s->vram_offset = vga_ram_offset;
s->vram_size = vga_ram_size;
s->get_bpp = vga_get_bpp;
s->get_offsets = vga_get_offsets;
/* XXX: currently needed for display */
vga_state = s;
}
unsigned long vga_ram_offset, int vga_ram_size)
{
VGAState *s;
s = qemu_mallocz(sizeof(VGAState));
if (!s)
return -1;
s->bank_offset = 0;
#ifdef CONFIG_BOCHS_VBE
#if defined (TARGET_I386)
/* old Bochs IO ports */
#else
#endif
#endif /* CONFIG_BOCHS_VBE */
if (bus) {
PCIDevice *d;
sizeof(PCIDevice),
/* XXX: vga_ram_size must be a power of two */
} else {
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */
#endif
}
return 0;
}
#endif /* !VBOX */
#ifndef VBOX
/********************************************************/
/* vga screen dump */
static int vga_save_w, vga_save_h;
static void vga_save_dpy_update(DisplayState *s,
int x, int y, int w, int h)
{
}
static void vga_save_dpy_resize(DisplayState *s, int w, int h)
{
s->linesize = w * 4;
#ifndef VBOX
#else /* VBOX */
if (!s->data)
{
}
else // (32-bpp buffer is allocated by the caller)
#endif /* VBOX */
vga_save_w = w;
vga_save_h = h;
}
static void vga_save_dpy_refresh(DisplayState *s)
{
}
int w, int h, int linesize)
{
FILE *f;
unsigned int v;
int y, x;
if (!f)
return -1;
fprintf(f, "P6\n%d %d\n%d\n",
w, h, 255);
for(y = 0; y < h; y++) {
d = d1;
for(x = 0; x < w; x++) {
v = *(uint32_t *)d;
fputc((v) & 0xff, f);
d += 4;
}
}
fclose(f);
return 0;
}
/* save the vga display in a PPM image even if no display is
available */
void vga_screen_dump(const char *filename)
{
/* XXX: this is a little hackish */
s->graphic_mode = -1;
}
}
#endif /* !VBOX */
#if 0 //def VBOX
/* copy the vga display contents to the given buffer. the size of the buffer
must be sufficient to store the screen copy (see below). the width and height
parameters determine the required dimensions of the copy. If they differ
from the actual screen dimensions, then the returned copy is shrinked or
stretched accordingly. The copy is always a 32-bit image, so the size of
the buffer supplied must be at least (((width * 32 + 31) / 32) * 4) * height,
i.e. dword-aligned. returns zero if the operation was successfull and -1
otherwise. */
{
return -1;
/* XXX: this is a little hackish */
ds->pvVgaState = s;
s->graphic_mode = -1;
//@@TODO (dmik): implement stretching/shrinking!
return 0;
}
/* copy the given buffer to the vga display. width and height define the
dimensions of the image in the buffer. x and y define the point on the
vga display to copy the image to. the buffer is assumed to contain a 32-bit
image, so the size of one scanline must be ((width * 32 + 31) / 32) * 4),
i.e. dword-aligned. returns zero if the operation was successfull and -1
otherwise. */
{
int bpp;
return -1;
case 15:
default: return -1;
}
for (y = 0; y < height; y ++)
{
}
return 0;
}
#endif
#endif /* !VBOX || !IN_GC || !IN_RING0 */
#ifdef VBOX /* InnoTek code start */
/* -=-=-=-=-=- all contexts -=-=-=-=-=- */
/**
* Port I/O Handler for VGA OUT operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
PDMBOTHCBDECL(int) vgaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
if (cb == 1)
else if (cb == 2)
{
}
return VINF_SUCCESS;
}
/**
* Port I/O Handler for VGA IN operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes read.
*/
PDMBOTHCBDECL(int) vgaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
if (cb == 1)
{
return VINF_SUCCESS;
}
else if (cb == 2)
{
return VINF_SUCCESS;
}
return VERR_IOM_IOPORT_UNUSED;
}
/**
* Port I/O Handler for VBE OUT operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
PDMBOTHCBDECL(int) vgaIOPortWriteVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
#ifdef IN_GC
/*
* The VBE_DISPI_INDEX_ENABLE has to be done on the host in order to call pfnLFBModeChange callback.
*/
if (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
{
Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE - Switching to host...\n"));
return VINF_IOM_HC_IOPORT_WRITE;
}
#endif
#ifdef VBE_BYTEWISE_IO
if (cb == 1)
{
if (!s->fWriteVBEData)
{
if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
&& (u32 & VBE_DISPI_ENABLED))
{
s->fWriteVBEData = false;
return VINF_SUCCESS;
}
else
{
s->fWriteVBEData = true;
return VINF_SUCCESS;
}
}
else
{
s->fWriteVBEData = false;
cb = 2;
}
}
#endif
if (cb == 2)
{
//#ifdef IN_GC
// /*
// * The VBE_DISPI_INDEX_ENABLE memsets the entire frame buffer.
// * Since we're not mapping the entire framebuffer any longer that
// * has to be done on the host.
// */
// if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
// && (u32 & VBE_DISPI_ENABLED))
// {
// Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE & VBE_DISPI_ENABLED - Switching to host...\n"));
// return VINF_IOM_HC_IOPORT_WRITE;
// }
//#endif
}
else
return VINF_SUCCESS;
}
/**
* Port I/O Handler for VBE OUT operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
PDMBOTHCBDECL(int) vgaIOPortWriteVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
#ifdef VBE_BYTEWISE_IO
if (cb == 1)
{
if (!s->fWriteVBEIndex)
{
s->fWriteVBEIndex = true;
return VINF_SUCCESS;
}
else
{
s->fWriteVBEIndex = false;
return VINF_SUCCESS;
}
}
else
#endif
if (cb == 2)
else
return VINF_SUCCESS;
}
/**
* Port I/O Handler for VBE IN operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes to read.
*/
PDMBOTHCBDECL(int) vgaIOPortReadVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
#ifdef VBE_BYTEWISE_IO
if (cb == 1)
{
if (!s->fReadVBEData)
{
s->fReadVBEData = true;
return VINF_SUCCESS;
}
else
{
s->fReadVBEData = false;
return VINF_SUCCESS;
}
}
else
#endif
if (cb == 2)
{
return VINF_SUCCESS;
}
else if (cb == 4)
{
/* Quick hack for getting the vram size. */
return VINF_SUCCESS;
}
return VERR_IOM_IOPORT_UNUSED;
}
/**
* Port I/O Handler for VBE IN operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes to read.
*/
PDMBOTHCBDECL(int) vgaIOPortReadVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
#ifdef VBE_BYTEWISE_IO
if (cb == 1)
{
if (!s->fReadVBEIndex)
{
s->fReadVBEIndex = true;
return VINF_SUCCESS;
}
else
{
s->fReadVBEIndex = false;
return VINF_SUCCESS;
}
}
else
#endif
if (cb == 2)
{
return VINF_SUCCESS;
}
return VERR_IOM_IOPORT_UNUSED;
}
/* -=-=-=-=-=- Guest Context -=-=-=-=-=- */
/*
* Internal. For use inside VGAGCMemoryFillWrite only.
* Macro for apply logical operation and bit mask.
*/
/* apply logical operation */ \
{ \
case 0: \
default: \
/* nothing to do */ \
break; \
case 1: \
/* and */ \
break; \
case 2: \
/* or */ \
break; \
case 3: \
/* xor */ \
break; \
} \
/* apply bit mask */ \
/**
* Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM and from the inside of VGADeviceGC.cpp.
* This is the advanced version of vga_mem_writeb function.
*
* @returns VBox status code.
* @param pDevIns Pointer device instance.
* @param pvUser User argument - ignored.
* @param GCPhysAddr Physical address of memory to write.
* @param u32Item Data to write, up to 4 bytes.
* @param cbItem Size of data Item, only 1/2/4 bytes is allowed for now.
* @param cItems Number of data items to write.
*/
PDMBOTHCBDECL(int) vgaMMIOFill(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems)
{
uint32_t b;
unsigned i;
for (i = 0; i < cbItem; i++)
{
u32Item >>= 8;
}
/* convert to VGA memory offset */
/// @todo add check for the end of region
GCPhysAddr &= 0x1ffff;
case 0:
break;
case 1:
if (GCPhysAddr >= 0x10000)
return VINF_SUCCESS;
break;
case 2:
GCPhysAddr -= 0x10000;
if (GCPhysAddr >= 0x8000)
return VINF_SUCCESS;
break;
default:
case 3:
GCPhysAddr -= 0x18000;
if (GCPhysAddr >= 0x8000)
return VINF_SUCCESS;
break;
}
/* chain 4 mode : simplest access */
#ifdef IN_GC
return VINF_IOM_HC_MMIO_WRITE;
#else
{
return VINF_SUCCESS;
}
#endif
while (cItems-- > 0)
for (i = 0; i < cbItem; i++)
{
{
}
GCPhysAddr++;
}
#ifdef IN_GC
return VINF_IOM_HC_MMIO_WRITE;
#else
{
return VINF_SUCCESS;
}
#endif
while (cItems-- > 0)
for (i = 0; i < cbItem; i++)
{
}
GCPhysAddr++;
}
} else {
#ifdef IN_GC
return VINF_IOM_HC_MMIO_WRITE;
#else
{
return VINF_SUCCESS;
}
#endif
/* standard VGA latched access */
default:
case 0:
/* rotate */
for (i = 0; i < cbItem; i++)
{
}
break;
case 1:
for (i = 0; i < cbItem; i++)
break;
case 2:
for (i = 0; i < cbItem; i++)
{
}
break;
case 3:
/* rotate */
for (i = 0; i < cbItem; i++)
{
}
break;
}
/* mask data according to sr[2] */
/* actually write data */
if (cbItem == 1)
{
/* The most frequently case is 1 byte I/O. */
while (cItems-- > 0)
{
((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
GCPhysAddr++;
}
}
else if (cbItem == 2)
{
/* The second case is 2 bytes I/O. */
while (cItems-- > 0)
{
((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
GCPhysAddr++;
((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[1] & write_mask);
GCPhysAddr++;
}
}
else
{
/* And the rest is 4 bytes. */
while (cItems-- > 0)
for (i = 0; i < cbItem; i++)
{
((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[i] & write_mask);
GCPhysAddr++;
}
}
}
return VINF_SUCCESS;
}
/**
* Legacy VGA memory (0xa0000 - 0xbffff) read hook, to be called from IOM.
*
* @returns VBox status code.
* @param pDevIns Pointer device instance.
* @param pvUser User argument - ignored.
* @param GCPhysAddr Physical address of memory to read.
* @param pv Where to store readed data.
* @param cb Bytes to read.
*/
PDMBOTHCBDECL(int) vgaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
{
switch (cb)
{
case 1:
case 2:
break;
case 4:
break;
default:
{
while (cb-- > 0)
}
}
return VINF_SUCCESS;
}
/**
* Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM.
*
* @returns VBox status code.
* @param pDevIns Pointer device instance.
* @param pvUser User argument - ignored.
* @param GCPhysAddr Physical address of memory to write.
* @param pv Pointer to data.
* @param cb Bytes to write.
*/
PDMBOTHCBDECL(int) vgaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
{
int rc = VINF_SUCCESS;
switch (cb)
{
case 1:
break;
#if 1
case 2:
break;
case 4:
break;
#else
case 2:
break;
case 4:
break;
#endif
default:
break;
}
return rc;
}
/**
* Handle LFB access.
* @returns VBox status code.
* @param pVM VM handle.
* @param pData VGA device instance data.
* @param GCPhys The access physical address.
* @param GCPtr The access virtual address (only GC).
*/
{
int rc;
/*
* Set page dirty bit.
*/
pData->fLFBUpdated = true;
/*
* Turn of the write handler for this particular page and make it R/W.
* Then return telling the caller to restart the guest instruction.
* ASSUME: the guest always maps video memory RW.
*/
if (VBOX_SUCCESS(rc))
{
#ifndef IN_RING3
if (VBOX_SUCCESS(rc))
return VINF_SUCCESS;
else
#else /* IN_RING3 : We don't have any virtual page address of the access here. */
return VINF_SUCCESS;
#endif
}
else
return rc;
}
#ifdef IN_GC
/**
* #PF Handler for VBE LFB access.
*
* @returns VBox status code (appropriate for GC return).
* @param pVM VM Handle.
* @param uErrorCode CPU Error code.
* @param pRegFrame Trap register frame.
* @param pvFault The fault address (cr2).
* @param GCPhysFault The GC physical address corresponding to pvFault.
* @param pvUser User argument, ignored.
*/
PDMBOTHCBDECL(int) vgaGCLFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
{
}
/**
* #PF Handler for VBE LFB access.
*
* @returns VBox status code (appropriate for GC return).
* @param pVM VM Handle.
* @param uErrorCode CPU Error code.
* @param pRegFrame Trap register frame.
* @param pvFault The fault address (cr2).
* @param GCPhysFault The GC physical address corresponding to pvFault.
* @param pvUser User argument, ignored.
*/
PDMBOTHCBDECL(int) vgaR0LFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
{
}
#else /* IN_RING3 */
/**
* HC access handler for the LFB.
*
* @returns VINF_SUCCESS if the handler have carried out the operation.
* @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
* @param pVM VM Handle.
* @param GCPhys The physical address the guest is writing to.
* @param pvPhys The HC mapping of that address.
* @param enmAccessType The access type.
* @param pvUser User argument.
*/
static DECLCALLBACK(int) vgaR3LFBAccessHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
{
int rc;
if (VBOX_SUCCESS(rc))
return VINF_PGM_HANDLER_DO_DEFAULT;
return rc;
}
#endif /* IN_RING3 */
/* -=-=-=-=-=- Ring 3 -=-=-=-=-=- */
#ifdef IN_RING3
# ifdef VBE_NEW_DYN_LIST
/**
* Port I/O Handler for VBE Extra OUT operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
PDMBOTHCBDECL(int) vbeIOPortWriteVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
if (cb == 2)
{
return VINF_SUCCESS;
}
return VINF_SUCCESS;
}
/**
* Port I/O Handler for VBE Extra IN operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes read.
*/
PDMBOTHCBDECL(int) vbeIOPortReadVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
{
Log(("vbeIOPortReadVBEExtra: Requested number of 64k video banks\n"));
return VINF_SUCCESS;
}
{
*pu32 = 0;
Log(("vbeIOPortReadVBEExtra: Requested address is out of VBE data!!! Address=%#x(%d) cbVBEExtraData=%#x(%d)\n",
pData->u16VBEExtraAddress, pData->u16VBEExtraAddress, pData->cbVBEExtraData, pData->cbVBEExtraData));
return VINF_SUCCESS;
}
if (cb == 1)
{
return VINF_SUCCESS;
}
if (cb == 2)
{
return VINF_SUCCESS;
}
return VERR_IOM_IOPORT_UNUSED;
}
# endif /* VBE_NEW_DYN_LIST */
/**
* Port I/O Handler for VGA BIOS IN operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes read.
*/
static DECLCALLBACK(int) vgaIOPortReadBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
return VERR_IOM_IOPORT_UNUSED;
}
/**
* Port I/O Handler for VGA BIOS OUT operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
static DECLCALLBACK(int) vgaIOPortWriteBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
static int lastWasNotNewline = 0; /* We are only called in a single-threaded way */
/*
* VGA BIOS char printing.
*/
if ( cb == 1
&& Port == VBE_PRINTF_PORT)
{
#if 0
switch (u32)
{
default:
}
#else
if (lastWasNotNewline == 0)
Log(("vgabios: "));
if (u32 == '\n')
lastWasNotNewline = 0;
else
lastWasNotNewline = 1;
#endif
return VINF_SUCCESS;
}
/* not in use. */
return VINF_SUCCESS;
}
/* -=-=-=-=-=- Ring 3: IBase -=-=-=-=-=- */
/**
* Queries an interface to the driver.
*
* @returns Pointer to interface.
* @returns NULL if the interface was not supported by the driver.
* @param pInterface Pointer to this interface structure.
* @param enmInterface The requested interface identification.
* @thread Any thread.
*/
{
switch (enmInterface)
{
case PDMINTERFACE_BASE:
default:
return NULL;
}
}
/* -=-=-=-=-=- Ring 3: Dummy IDisplayConnector -=-=-=-=-=- */
/**
* Resize the display.
* This is called when the resolution changes. This usually happens on
* request from the guest os, but may also happen as the result of a reset.
*
* @param pInterface Pointer to this interface.
* @param cx New display width.
* @param cy New display height
* @thread The emulation thread.
*/
static DECLCALLBACK(int) vgaDummyResize(PPDMIDISPLAYCONNECTOR pInterface, uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
{
return VINF_SUCCESS;
}
/**
* Update a rectangle of the display.
* PDMIDISPLAYPORT::pfnUpdateDisplay is the caller.
*
* @param pInterface Pointer to this interface.
* @param x The upper left corner x coordinate of the rectangle.
* @param y The upper left corner y coordinate of the rectangle.
* @param cx The width of the rectangle.
* @param cy The height of the rectangle.
* @thread The emulation thread.
*/
static DECLCALLBACK(void) vgaDummyUpdateRect(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
{
}
/**
* Refresh the display.
*
* The interval between these calls is set by
* PDMIDISPLAYPORT::pfnSetRefreshRate(). The driver should call
* PDMIDISPLAYPORT::pfnUpdateDisplay() if it wishes to refresh the
* display. PDMIDISPLAYPORT::pfnUpdateDisplay calls pfnUpdateRect with
* the changed rectangles.
*
* @param pInterface Pointer to this interface.
* @thread The emulation thread.
*/
{
}
/* -=-=-=-=-=- Ring 3: IDisplayPort -=-=-=-=-=- */
/** Converts a display port interface pointer to a vga state pointer. */
#define IDISPLAYPORT_2_VGASTATE(pInterface) ( (PVGASTATE)((uintptr_t)pInterface - RT_OFFSETOF(VGASTATE, Port)) )
/**
* Update the display with any changed regions.
*
* @param pInterface Pointer to this interface.
* @see PDMIKEYBOARDPORT::pfnUpdateDisplay() for details.
*/
{
#ifdef DEBUG_sunlover
LogFlow(("vgaPortUpdateDisplay\n"));
#endif /* DEBUG_sunlover */
/* This should be called only in non VBVA mode. */
if (rc != VINF_SUCCESS)
return rc;
if (pData->fHaveDirtyBits)
{
pData->fHaveDirtyBits = false;
}
return VINF_SUCCESS;
}
/**
* Update the entire display.
*
* @param pInterface Pointer to this interface.
* @see PDMIKEYBOARDPORT::pfnUpdateDisplayAll() for details.
*/
{
/* This is called both in VBVA mode and normal modes. */
#ifdef DEBUG_sunlover
LogFlow(("vgaPortUpdateDisplayAll\n"));
#endif /* DEBUG_sunlover */
return vga_update_display(pData);
}
/**
* Sets the refresh rate and restart the timer.
*
* @returns VBox status code.
* @param pInterface Pointer to this interface.
* @param cMilliesInterval Number of millies between two refreshes.
* @see PDMIKEYBOARDPORT::pfnSetRefreshRate() for details.
*/
static DECLCALLBACK(int) vgaPortSetRefreshRate(PPDMIDISPLAYPORT pInterface, uint32_t cMilliesInterval)
{
if (cMilliesInterval)
}
/** @copydoc PDMIDISPLAYPORT::pfnQueryColorDepth */
{
if (!pcBits)
return VERR_INVALID_PARAMETER;
return VINF_SUCCESS;
}
/**
* Create a 32-bbp snapshot of the display.
*
* @param pInterface Pointer to this interface.
* @param pvData Pointer the buffer to copy the bits to.
* @param cbData Size of the buffer.
* @param pcx Where to store the width of the bitmap. (optional)
* @param pcy Where to store the height of the bitmap. (optional)
* @param pcbData Where to store the actual size of the bitmap. (optional)
* @see PDMIKEYBOARDPORT::pfnSnapshot() for details.
*/
static DECLCALLBACK(int) vgaPortSnapshot(PPDMIDISPLAYPORT pInterface, void *pvData, size_t cbData, uint32_t *pcx, uint32_t *pcy, size_t *pcbData)
{
/* @todo r=sunlover: replace the method with a direct VRAM rendering like in vgaPortUpdateDisplayRect. */
LogFlow(("vgaPortSnapshot: pvData=%p cbData=%d pcx=%p pcy=%p pcbData=%p\n", pvData, cbData, pcx, pcy, pcbData));
/*
* Validate input.
*/
if (!pvData)
return VERR_INVALID_PARAMETER;
/*
* Do a regular refresh first to resolve any pending resize issues.
*
* 20060317 It used to be pfnUpdateDisplay, but by VBVA design
* only pfnUpdateDisplayAll is allowed to be called in VBVA mode.
* Also since the goal here is to have updated display for screenshot,
* the UpdateDisplayAll is even more logical to call. (sunlover)
*/
/*
* Validate the buffer size.
*/
if (cbRequired > cbData)
{
Log(("vgaPortSnapshot: %d bytes are required, a buffer of %d bytes is profiled.\n", cbRequired, cbData));
return VERR_BUFFER_OVERFLOW;
}
/*
* Temporarily replace the display connector interface with a fake one.
*/
/* save & replace state data. */
/* make the snapshot. */
/* restore */
if (rc != VINF_SUCCESS)
return rc;
/*
* Return the result.
*/
if (pcx)
if (pcy)
if (pcbData)
*pcbData = cbRequired;
LogFlow(("vgaPortSnapshot: returns VINF_SUCCESS (cx=%d cy=%d cbData=%d)\n", Connector.cx, Connector.cy, cbRequired));
return VINF_SUCCESS;
}
/**
* Copy bitmap to the display.
*
* @param pInterface Pointer to this interface.
* @param pvData Pointer to the bitmap bits.
* @param x The upper left corner x coordinate of the destination rectangle.
* @param y The upper left corner y coordinate of the destination rectangle.
* @param cx The width of the source and destination rectangles.
* @param cy The height of the source and destination rectangles.
* @see PDMIDISPLAYPORT::pfnDisplayBlt() for details.
*/
static DECLCALLBACK(int) vgaPortDisplayBlt(PPDMIDISPLAYPORT pInterface, const void *pvData, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
{
int rc = VINF_SUCCESS;
/*
* Validate input.
*/
if ( pvData
{
/*
* Determin bytes per pixel in the destination buffer.
*/
size_t cbPixelDst = 0;
{
case 8:
cbPixelDst = 1;
break;
case 15:
case 16:
cbPixelDst = 2;
break;
case 24:
cbPixelDst = 3;
break;
case 32:
cbPixelDst = 4;
break;
default:
break;
}
if (VBOX_SUCCESS(rc))
{
/*
* The blitting loop.
*/
vga_draw_line_func *pfnVgaDrawLine = vga_draw_line_table[VGA_DRAW_LINE32 * 4 + get_depth_index(pData->pDrv->cBits)];
while (cyLeft-- > 0)
{
}
/*
* Invalidate the area.
*/
}
}
else
return rc;
}
static DECLCALLBACK(void) vgaPortUpdateDisplayRect (PPDMIDISPLAYPORT pInterface, int32_t x, int32_t y, uint32_t w, uint32_t h)
{
uint32_t v;
#ifdef DEBUG_sunlover
LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d\n", x, y, w, h));
#endif /* DEBUG_sunlover */
/* Check if there is something to do at all. */
if (!s->fRenderVRAM)
{
/* The framebuffer uses the guest VRAM directly. */
#ifdef DEBUG_sunlover
LogFlow(("vgaPortUpdateDisplayRect: nothing to do fRender is false.\n"));
#endif /* DEBUG_sunlover */
return;
}
/* Correct negative x and y coordinates. */
if (x < 0)
{
x += w; /* Compute xRight which is also the new width. */
w = (x < 0) ? 0 : x;
x = 0;
}
if (y < 0)
{
y += h; /* Compute yBottom, which is also the new height. */
h = (y < 0) ? 0 : y;
y = 0;
}
/* Also check if coords are greater than the display resolution. */
{
#ifndef VBOX
#else
// x < 0 is not possible here
#endif
}
{
#ifndef VBOX
#else
// y < 0 is not possible here
#endif
}
#ifdef DEBUG_sunlover
LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d (corrected coords)\n", x, y, w, h));
#endif /* DEBUG_sunlover */
/* Check if there is something to do at all. */
if (w == 0 || h == 0)
{
/* Empty rectangle. */
#ifdef DEBUG_sunlover
LogFlow(("vgaPortUpdateDisplayRect: nothing to do: %dx%d\n", w, h));
#endif /* DEBUG_sunlover */
return;
}
/** @todo This method should be made universal and not only for VBVA.
* changed.
*/
/* Choose the rendering function. */
switch(s->get_bpp(s))
{
default:
case 0:
return;
case 8:
v = VGA_DRAW_LINE8;
break;
case 15:
v = VGA_DRAW_LINE15;
break;
case 16:
v = VGA_DRAW_LINE16;
break;
case 24:
v = VGA_DRAW_LINE24;
break;
case 32:
v = VGA_DRAW_LINE32;
break;
}
/* Compute source and destination addresses and pitches. */
/* Assume that rendering is performed only on visible part of VRAM.
* This is true because coordinates were verified.
*/
pu8Src = s->vram_ptrHC;
/* Render VRAM to framebuffer. */
#ifdef DEBUG_sunlover
LogFlow(("vgaPortUpdateDisplayRect: dst: %p, %d, %d. src: %p, %d, %d\n", pu8Dst, cbLineDst, cbPixelDst, pu8Src, cbLineSrc, cbPixelSrc));
#endif /* DEBUG_sunlover */
while (h-- > 0)
{
}
#ifdef DEBUG_sunlover
LogFlow(("vgaPortUpdateDisplayRect: completed.\n"));
#endif /* DEBUG_sunlover */
}
{
s->fRenderVRAM = fRender;
}
{
if (pData->cMilliesRefreshInterval)
}
/* -=-=-=-=-=- Ring 3: PCI Device -=-=-=-=-=- */
/**
* Callback function for mapping an PCI I/O region.
*
* @return VBox status code.
* @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
* @param iRegion The region number.
* @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
* I/O port, else it's a physical address.
* This address is *NOT* relative to pci_mem_base like earlier!
* @param enmType One of the PCI_ADDRESS_SPACE_* values.
*/
static DECLCALLBACK(int) vgaR3IORegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
{
int rc;
LogFlow(("vgaR3IORegionMap: iRegion=%d GCPhysAddress=%VGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
/*
* VRam mapping.
*/
{
/*
* Register and lock the VRAM.
*
* Windows usually re-initializes the PCI devices, so we have to check whether the memory was
* already registered before trying to do that all over again.
*/
if (pData->GCPhysVRAM)
{
("The Guest OS relocated our LFB! old GCPhysVRAM=%VGp new GCPhysAddress=%VGp\n",
rc = VINF_SUCCESS;
}
else
{
/*
* Register and lock the VRAM.
*/
rc = MMR3PhysRegister(pVM, pData->vram_ptrHC, GCPhysAddress, pData->vram_size, MM_RAM_FLAGS_MMIO2, "VRam");
if (VBOX_SUCCESS(rc))
{
if (!pData->GCPhysVRAM)
"VGA LFB");
if (VBOX_SUCCESS(rc))
{
/*
* Map the first 256KB of the VRAM into GC for GC VGA support.
*/
if (VBOX_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
else
}
else
}
return rc;
}
else
return VERR_INTERNAL_ERROR;
}
/* -=-=-=-=-=- Ring3: Misc Wrappers -=-=-=-=-=- */
/**
* Saves a state of the VGA device.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSMHandle The handle to save the state to.
*/
{
return VINF_SUCCESS;
}
/**
* Loads a saved VGA device state.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSMHandle The handle to the saved state.
* @param u32Version The data unit version number.
*/
static DECLCALLBACK(int) vgaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
{
return VINF_SUCCESS;
}
/* -=-=-=-=-=- Ring 3: Device callbacks -=-=-=-=-=- */
/**
* Reset notification.
*
* @returns VBox status.
* @param pDevIns The device instance data.
*/
{
char *pchStart;
char *pchEnd;
LogFlow(("vgaReset\n"));
/* Clear the VRAM ourselves. */
{
#ifdef LOG_ENABLED /** @todo separate function. */
/* First dump the textmode contents to the log; handy for capturing Windows blue screens. */
if (!(s->ar_index & 0x20)) {
} else {
}
switch(graphic_mode)
case GMODE_TEXT:
{
int x_incr;
int line_offset;
line_offset = s->line_offset;
/* total width & height */
cw = 8;
cw = 9;
/* ugly hack for CGA 160x100x16 - explain me the logic */
height = 100;
} else {
}
/* better than nothing: exit if transient size is too big */
break;
}
cx_max = -1;
# ifdef WORDS_BIGENDIAN
# else
# endif
src += 4;
}
if (cx_max != -1)
RTLogPrintf("\n");
s1 += line_offset;
}
RTLogPrintf("VGA textmode END:\n\n");
}
#endif
}
/*
* Zero most of it.
*
* Unlike vga_reset we're leaving out a few members which believe must
* remain unchanged....
*/
/* 1st part. */
/* 2nd part. */
/*
* Restore and re-init some bits.
*/
#ifdef CONFIG_BOCHS_VBE
#endif /* CONFIG_BOCHS_VBE */
/*
* Reset the LBF mapping.
*/
pData->fLFBUpdated = false;
if ( ( pData->fGCEnabled
|| pData->fR0Enabled)
&& pData->GCPhysVRAM)
{
}
/* notify port handler */
}
/**
* Device relocation callback.
*
* @param pDevIns Pointer to the device instance.
* @param offDelta The relocation delta relative to the old location.
*
* @see FNPDMDEVRELOCATE for details.
*/
{
if (offDelta)
{
}
}
/**
* Attach command.
*
* This is called to let the device attach to a driver for a specified LUN
* during runtime. This is not called during VM construction, the device
* constructor have to attach to all the available drivers.
*
* This is like plugging in the monitor after turning on the PC.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being detached.
*/
{
switch (iLUN)
{
/* LUN #0: Display port. */
case 0:
{
if (VBOX_SUCCESS(rc))
{
pData->pDrv = (PDMIDISPLAYCONNECTOR*)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_DISPLAY_CONNECTOR);
{
rc = VINF_SUCCESS;
else
{
}
}
else
{
}
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
{
Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
rc = VINF_SUCCESS;
}
else
return rc;
}
default:
return VERR_PDM_NO_SUCH_LUN;
}
}
/**
* Detach notification.
*
* This is called when a driver is detaching itself from a LUN of the device.
* The device should adjust it's state to reflect this.
*
* This is like unplugging the monitor while the PC is still running.
*
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being detached.
*/
{
/*
* Reset the interfaces and update the controller state.
*/
switch (iLUN)
{
/* LUN #0: Display port. */
case 0:
break;
default:
break;
}
}
/**
* Construct a VGA device instance for a VM.
*
* @returns VBox status.
* @param pDevIns The device instance data.
* If the registration structure is needed, pDevIns->pDevReg points to it.
* @param iInstance Instance number. Use this to figure out which registers and such to use.
* The device number is also found in pDevIns->iInstance, but since it's
* likely to be freqently used PDM passes it as parameter.
* @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
* of the device instance. It's also found in pDevIns->pCfgHandle, but like
* iInstance it's expected to be used a bit in this function.
*/
{
static bool fExpandDone = false;
bool f;
int rc;
unsigned i;
#ifdef VBE_NEW_DYN_LIST
unsigned cb;
#endif
/*
* Init static data.
*/
if (!fExpandDone)
{
fExpandDone = true;
}
/*
* Validate configuration.
*/
"MonitorCount\0"
"GCEnabled\0"
"R0Enabled\0"
"CustomVideoModes\0"
"HeightReduction\0"
"CustomVideoMode1\0"
"CustomVideoMode2\0"
"CustomVideoMode3\0"
"CustomVideoMode4\0"
"CustomVideoMode5\0"
"CustomVideoMode6\0"
"CustomVideoMode7\0"
"CustomVideoMode8\0"
"CustomVideoMode9\0"
"CustomVideoMode10\0"
"CustomVideoMode11\0"
"CustomVideoMode12\0"
"CustomVideoMode13\0"
"CustomVideoMode14\0"
"CustomVideoMode15\0"
"CustomVideoMode16"))
N_("Invalid configuration for vga device"));
/*
* Init state data.
*/
{
}
{
}
{
}
pData->fGCEnabled = true;
if (VBOX_SUCCESS(rc) && !f)
pData->fGCEnabled = false;
pData->fR0Enabled = true;
if (VBOX_SUCCESS(rc) && !f)
pData->fR0Enabled = false;
/* The PCI devices configuration. */
/* The LBF access handler - error handling is better here than in the map function. */
rc = PDMR3GetSymbolGCLazy(pVM, pDevIns->pDevReg->szGCMod, "vgaGCLFBAccessHandler", &pData->GCPtrLFBHandler);
if (VBOX_FAILURE(rc))
{
AssertReleaseMsgFailed(("PDMR3GetSymbolGC(, %s, \"vgaGCLFBAccessHandler\",) -> %Vrc\n", pDevIns->pDevReg->szGCMod, rc));
return rc;
}
/* the interfaces. */
/*
* Register I/O ports, ROM and save state.
*/
rc = PDMDevHlpIOPortRegister(pDevIns, 0x3c0, 16, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3c0");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0x3b4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3b4");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0x3ba, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3ba");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0x3d4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3d4");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0x3da, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3da");
if (VBOX_FAILURE(rc))
return rc;
#ifdef CONFIG_BOCHS_VBE
rc = PDMDevHlpIOPortRegister(pDevIns, 0x1ce, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, NULL, NULL, "VGA/VBE - Index");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0x1cf, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, NULL, NULL, "VGA/VBE - Data");
if (VBOX_FAILURE(rc))
return rc;
#if 0
/* This now causes conflicts with Win2k & XP; it is not aware this range is taken
and tries to map other devices there */
/* Old Bochs. */
rc = PDMDevHlpIOPortRegister(pDevIns, 0xff80, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, "VGA/VBE - Index Old");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0xff81, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, "VGA/VBE - Data Old");
if (VBOX_FAILURE(rc))
return rc;
#endif
#endif /* CONFIG_BOCHS_VBE */
/* guest context extension */
if (pData->fGCEnabled)
{
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
if (VBOX_FAILURE(rc))
return rc;
#ifdef CONFIG_BOCHS_VBE
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
if (VBOX_FAILURE(rc))
return rc;
#if 0
/* This now causes conflicts with Win2k & XP; it is not aware this range is taken
and tries to map other devices there */
/* Old Bochs. */
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0xff80, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", "VGA/VBE - Index Old (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0xff81, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", "VGA/VBE - Index Old (GC)");
if (VBOX_FAILURE(rc))
return rc;
#endif
#endif /* CONFIG_BOCHS_VBE */
}
/* R0 context extension */
if (pData->fR0Enabled)
{
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
if (VBOX_FAILURE(rc))
return rc;
#ifdef CONFIG_BOCHS_VBE
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
if (VBOX_FAILURE(rc))
return rc;
#if 0
/* This now causes conflicts with Win2k & XP; it is not aware this range is taken
and tries to map other devices there */
/* Old Bochs. */
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0xff80, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", "VGA/VBE - Index Old (GC)");
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0xff81, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", "VGA/VBE - Index Old (GC)");
if (VBOX_FAILURE(rc))
return rc;
#endif
#endif /* CONFIG_BOCHS_VBE */
}
/* vga mmio */
rc = PDMDevHlpMMIORegister(pDevIns, 0x000a0000, 0x00020000, 0, vgaMMIOWrite, vgaMMIORead, vgaMMIOFill, "VGA - VGA Video Buffer");
if (VBOX_FAILURE(rc))
return rc;
if (pData->fGCEnabled)
{
rc = PDMDevHlpMMIORegisterGC(pDevIns, 0x000a0000, 0x00020000, 0, "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill", "VGA - VGA Video Buffer");
if (VBOX_FAILURE(rc))
return rc;
}
if (pData->fR0Enabled)
{
rc = PDMDevHlpMMIORegisterR0(pDevIns, 0x000a0000, 0x00020000, 0, "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill", "VGA - VGA Video Buffer");
if (VBOX_FAILURE(rc))
return rc;
}
/* vga bios */
rc = PDMDevHlpIOPortRegister(pDevIns, VBE_PRINTF_PORT, 1, NULL, vgaIOPortWriteBIOS, vgaIOPortReadBIOS, NULL, NULL, "VGA BIOS debug/panic");
if (VBOX_FAILURE(rc))
return rc;
AssertReleaseMsg(g_cbVgaBiosBinary <= _64K && g_cbVgaBiosBinary >= 32*_1K, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
AssertReleaseMsg(RT_ALIGN_Z(g_cbVgaBiosBinary, PAGE_SIZE) == g_cbVgaBiosBinary, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
rc = PDMDevHlpROMRegister(pDevIns, 0x000c0000, g_cbVgaBiosBinary, &g_abVgaBiosBinary[0], "VGA BIOS");
if (VBOX_FAILURE(rc))
return rc;
/* save */
rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, 1 /* version */, sizeof(*pData),
if (VBOX_FAILURE(rc))
return rc;
/* PCI */
if (VBOX_FAILURE(rc))
return rc;
/*AssertMsg(pData->Dev.devfn == 16 || iInstance != 0, ("pData->Dev.devfn=%d\n", pData->Dev.devfn));*/
Log(("!!WARNING!!: pData->dev.devfn=%d (ignore if testcase or no started by Main)\n", pData->Dev.devfn));
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, pData->vram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vgaR3IORegionMap);
if (VBOX_FAILURE(rc))
return rc;
/*
* Create the refresh timer.
*/
rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, vgaTimerRefresh, "VGA Refresh Timer", &pData->RefreshTimer);
if (VBOX_FAILURE(rc))
return rc;
/*
* Attach to the display.
*/
if (VBOX_FAILURE(rc))
return rc;
/*
* Allocate the VRAM.
*/
if (VBOX_FAILURE(rc))
{
return rc;
}
#ifdef VBE_NEW_DYN_LIST
/*
* Compute buffer size for the VBE BIOS Extra Data.
*/
else
cyReduction = 0;
else
cCustomModes = 0;
/*
* Allocate and initialize buffer for the VBE BIOS Extra Data.
*/
if (!pData->pu8VBEExtraData)
return VERR_NO_MEMORY;
#ifndef VRAM_SIZE_FIX
#else /* VRAM_SIZE_FIX defined */
for (i = 0; i < MODE_INFO_SIZE; i++)
{
pixelWidth = 2;
else
* pixelWidth;
continue;
*pCurMode = mode_info_list[i];
pCurMode++;
}
#endif /* VRAM_SIZE_FIX defined */
/*
* Copy default modes with subtractred YResolution.
*/
if (cyReduction)
{
#ifndef VRAM_SIZE_FIX
{
}
#else /* VRAM_SIZE_FIX defined */
for (i = 0; i < MODE_INFO_SIZE; i++, pDefMode++)
{
pixelWidth = 2;
else
continue;
pCurMode++;
}
#endif /* VRAM_SIZE_FIX defined */
}
/*
* Add custom modes.
*/
if (cCustomModes)
{
for (i = 1; i <= cCustomModes; i++)
{
char szExtraDataKey[sizeof("CustomVideoModeXX")];
char *pszExtraData = NULL;
/* query and decode the custom mode string. */
if (VBOX_SUCCESS(rc))
{
if ( cParams != 3
{
AssertMsgFailed(("Configuration error: Invalid mode data '%s' for '%s'! cBits=%d\n", pszExtraData, szExtraDataKey, cBits));
return VERR_VGA_INVALID_CUSTOM_MODE;
}
#ifdef VRAM_SIZE_FIX
{
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",
return VERR_VGA_INVALID_CUSTOM_MODE;
}
#endif /* VRAM_SIZE_FIX defined */
/* Use defaults from max@bpp mode. */
switch (cBits)
{
case 16:
break;
case 24:
break;
case 32:
break;
default: /* gcc, shut up! */
AssertMsgFailed(("gone postal!\n"));
continue;
}
pDefMode++;
/* adjust defaults */
switch (cBits)
{
case 16:
break;
case 24:
break;
case 32:
break;
}
/* commit it */
pCurMode++;
}
else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
{
return rc;
}
} /* foreach custom mode key */
}
/*
* Add the "End of list" mode.
*/
/*
* Register I/O Port for the VBE BIOS Extra Data.
*/
rc = PDMDevHlpIOPortRegister(pDevIns, VBE_EXTRA_PORT, 1, NULL, vbeIOPortWriteVBEExtra, vbeIOPortReadVBEExtra, NULL, NULL, "VBE BIOS Extra Data");
if (VBOX_FAILURE(rc))
return rc;
#endif
/*
* Statistics.
*/
STAM_REG(pVM, &pData->StatGCMemoryRead, STAMTYPE_PROFILE, "/Devices/VGA/GC/Memory/Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryRead() body.");
STAM_REG(pVM, &pData->StatGCMemoryWrite, STAMTYPE_PROFILE, "/Devices/VGA/GC/Memory/Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryWrite() body.");
STAM_REG(pVM, &pData->StatGCIOPortRead, STAMTYPE_PROFILE, "/Devices/VGA/GC/IOPort/Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCIOPortRead() body.");
STAM_REG(pVM, &pData->StatGCIOPortWrite, STAMTYPE_PROFILE, "/Devices/VGA/GC/IOPort/Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCIOPortWrite() body.");
return VINF_SUCCESS;
}
/**
* Destruct a device instance.
*
* Most VM resources are freed by the VM. This callback is provided so that any non-VM
* resources can be freed correctly.
*
* @param pDevIns The device instance data.
*/
{
#ifdef VBE_NEW_DYN_LIST
LogFlow(("vgaR3Destruct:\n"));
/*
* Free MM heap pointers.
*/
if (pData->pu8VBEExtraData)
{
}
#endif
#if 0 /** @todo r=bird: We can't free the buffer here because it's still locked.
* (That's the reason why we didn't do it earlier.) */
/*
* Free the VRAM.
*/
if (VBOX_FAILURE(rc))
{
return rc;
}
#endif
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceVga =
{
/* u32Version */
/* szDeviceName */
"vga",
/* szGCMod */
"VBoxDDGC.gc",
/* szR0Mod */
"VBoxDDR0.r0",
/* pszDescription */
"VGA Adaptor with VESA extensions.",
/* fFlags */
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
/* fClass */
/* cMaxInstances */
1,
/* cbInstance */
sizeof(VGASTATE),
/* pfnConstruct */
/* pfnDestruct */
/* pfnRelocate */
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
/* pfnDetach */
/* pfnQueryInterface */
NULL,
/* pfnInitComplete */
};
#endif /* !IN_RING3 */
#endif /* VBOX */
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
/*
* Local Variables:
* nuke-trailing-whitespace-p:nil
* End:
*/