* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/hw.h"
#include "vga.h"
#include "ui/console.h"
#include "hw/xen/xen.h"
#include "trace.h"
-//#define DEBUG_VGA
//#define DEBUG_VGA_MEM
//#define DEBUG_VGA_REG
-//#define DEBUG_BOCHS_VBE
-
/* 16 state changes per vertical frame @60 Hz */
#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGACommonState *s);
+
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
+static inline uint8_t sr(VGACommonState *s, int idx)
+{
+ return vbe_enabled(s) ? s->sr_vbe[idx] : s->sr[idx];
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
hwaddr base, offset, size;
s->has_chain4_alias = false;
s->plane_updated = 0xf;
}
- if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
- VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+ if ((sr(s, VGA_SEQ_PLANE_WRITE) & VGA_SR02_ALL_PLANES) ==
+ VGA_SR02_ALL_PLANES && sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
offset = 0;
switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
case 0:
size = 0x8000;
break;
}
+ assert(offset + size <= s->vram_size);
memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
memory_region_add_subregion_overlap(s->legacy_address_space, base,
((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
- clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
+ clocking_mode = (sr(s, VGA_SEQ_CLOCK_MODE) >> 3) & 1;
clock_sel = (s->msr >> 2) & 3;
dots = (s->msr & 1) ? 8 : 9;
r->total_chars = vtotal_lines * htotal_chars;
if (r->freq) {
- r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
+ r->ticks_per_char = NANOSECONDS_PER_SECOND / (r->total_chars * r->freq);
} else {
- r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
+ r->ticks_per_char = NANOSECONDS_PER_SECOND / chars_per_sec;
}
r->vstart = vretr_start_line;
"dots = %d\n"
"ticks/char = %" PRId64 "\n"
"\n",
- (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
+ (double) NANOSECONDS_PER_SECOND / (r->ticks_per_char * r->total_chars),
htotal_chars,
hretr_start_char,
hretr_skew_chars,
break;
}
}
-#if defined(DEBUG_VGA)
- printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
-#endif
+ trace_vga_std_read_io(addr, val);
return val;
}
if (vga_ioport_invalid(s, addr)) {
return;
}
-#ifdef DEBUG_VGA
- printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
-#endif
+ trace_vga_std_write_io(addr, val);
switch(addr) {
case VGA_ATT_W:
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr_vbe[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr_vbe[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr_vbe[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
- uint32_t val;
- val = s->vbe_index;
- return val;
+ return s->vbe_index;
}
uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
} else {
val = 0;
}
-#ifdef DEBUG_BOCHS_VBE
- printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
+ trace_vga_vbe_read(s->vbe_index, val);
return val;
}
VGACommonState *s = opaque;
if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
-#ifdef DEBUG_BOCHS_VBE
- printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
+ trace_vga_vbe_write(s->vbe_index, val);
switch(s->vbe_index) {
case VBE_DISPI_INDEX_ID:
if (val == VBE_DISPI_ID0 ||
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
s->bank_offset = 0;
}
break;
}
- if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+ if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
break;
}
- if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+ if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
plane = addr & 3;
mask = (1 << plane);
- if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ if (sr(s, VGA_SEQ_PLANE_WRITE) & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
mask = (1 << plane);
- if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ if (sr(s, VGA_SEQ_PLANE_WRITE) & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
do_write:
/* mask data according to sr[2] */
- mask = s->sr[VGA_SEQ_PLANE_WRITE];
+ mask = sr(s, VGA_SEQ_PLANE_WRITE);
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
/* total width & height */
cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
cwidth = 8;
- if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ if (!(sr(s, VGA_SEQ_CLOCK_MODE) & VGA_SR01_CHAR_CLK_8DOTS)) {
cwidth = 9;
}
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 0x08) {
cwidth = 16; /* NOTE: no 18 pixel wide */
}
width = (s->cr[VGA_CRTC_H_DISP] + 1);
int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
/* compute font data address (in plane 2) */
- v = s->sr[VGA_SEQ_CHARACTER_MAP];
+ v = sr(s, VGA_SEQ_CHARACTER_MAP);
offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
if (offset != s->font_offsets[0]) {
s->font_offsets[0] = offset;
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
}
}
+static bool vga_scanline_invalidated(VGACommonState *s, int y)
+{
+ if (y >= VGA_MAX_HEIGHT) {
+ return false;
+ }
+ return s->invalidated_y_table[y >> 5] & (1 << (y & 0x1f));
+}
+
void vga_sync_dirty_bitmap(VGACommonState *s)
{
memory_region_sync_dirty_bitmap(&s->vram);
DisplaySurface *surface = qemu_console_surface(s->con);
int y1, y, update, linesize, y_start, double_scan, mask, depth;
int width, height, shift_control, line_offset, bwidth, bits;
- ram_addr_t page0, page1, page_min, page_max;
+ ram_addr_t page0, page1;
+ DirtyBitmapSnapshot *snap = NULL;
int disp_width, multi_scan, multi_run;
uint8_t *d;
uint32_t v, addr1, addr;
full_update |= update_basic_params(s);
- if (!full_update)
- vga_sync_dirty_bitmap(s);
-
s->get_resolution(s, &width, &height);
disp_width = width;
}
if (shift_control == 0) {
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
disp_width <<= 1;
}
} else if (shift_control == 1) {
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
disp_width <<= 1;
}
}
height, format, s->line_offset,
s->vram_ptr + (s->start_addr * 4));
dpy_gfx_replace_surface(s->con, surface);
-#ifdef DEBUG_VGA
- printf("VGA: Using shared surface for depth=%d swap=%d\n",
- depth, byteswap);
-#endif
} else {
qemu_console_resize(s->con, disp_width, height);
surface = qemu_console_surface(s->con);
-#ifdef DEBUG_VGA
- printf("VGA: Using shadow surface for depth=%d swap=%d\n",
- depth, byteswap);
-#endif
}
s->last_scr_width = disp_width;
s->last_scr_height = height;
if (shift_control == 0) {
full_update |= update_palette16(s);
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
v = VGA_DRAW_LINE4D2;
} else {
v = VGA_DRAW_LINE4;
bits = 4;
} else if (shift_control == 1) {
full_update |= update_palette16(s);
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
v = VGA_DRAW_LINE2D2;
} else {
v = VGA_DRAW_LINE2;
#if 0
printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
- s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
+ s->line_compare, sr(s, VGA_SEQ_CLOCK_MODE));
#endif
addr1 = (s->start_addr * 4);
bwidth = (width * bits + 7) / 8;
y_start = -1;
- page_min = -1;
- page_max = 0;
d = surface_data(surface);
linesize = surface_stride(surface);
y1 = 0;
+
+ if (!full_update) {
+ vga_sync_dirty_bitmap(s);
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
+ bwidth * height,
+ DIRTY_MEMORY_VGA);
+ }
+
for(y = 0; y < height; y++) {
addr = addr1;
if (!(s->cr[VGA_CRTC_MODE] & 1)) {
update = full_update;
page0 = addr;
page1 = addr + bwidth - 1;
- update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
- DIRTY_MEMORY_VGA);
- /* explicit invalidation for the hardware cursor */
- update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
+ if (full_update) {
+ update = 1;
+ } else {
+ update = memory_region_snapshot_get_dirty(&s->vram, snap,
+ page0, page1 - page0);
+ }
+ /* explicit invalidation for the hardware cursor (cirrus only) */
+ update |= vga_scanline_invalidated(s, y);
if (update) {
if (y_start < 0)
y_start = y;
- if (page0 < page_min)
- page_min = page0;
- if (page1 > page_max)
- page_max = page1;
if (!(is_buffer_shared(surface))) {
vga_draw_line(s, d, s->vram_ptr + addr, width);
if (s->cursor_draw_line)
dpy_gfx_update(s->con, 0, y_start,
disp_width, y - y_start);
}
- /* reset modified pages */
- if (page_max >= page_min) {
- memory_region_reset_dirty(&s->vram,
- page_min,
- page_max - page_min,
- DIRTY_MEMORY_VGA);
- }
- memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+ g_free(snap);
+ memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
}
static void vga_draw_blank(VGACommonState *s, int full_update)
{
s->sr_index = 0;
memset(s->sr, '\0', sizeof(s->sr));
+ memset(s->sr_vbe, '\0', sizeof(s->sr_vbe));
s->gr_index = 0;
memset(s->gr, '\0', sizeof(s->gr));
s->ar_index = 0;
/* total width & height */
cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
cw = 8;
- if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ if (!(sr(s, VGA_SEQ_CLOCK_MODE) & VGA_SR01_CHAR_CLK_8DOTS)) {
cw = 9;
}
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 0x08) {
cw = 16; /* NOTE: no 18 pixel wide */
}
width = (s->cr[VGA_CRTC_H_DISP] + 1);
width = (s->last_width - size) / 2;
dst = chardata + s->last_width + width;
for (i = 0; i < size; i ++)
- console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
+ console_write_ch(dst ++, ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE,
+ QEMU_COLOR_BLACK, 1));
dpy_text_update(s->con, 0, 0, s->last_width, height);
}
/* force refresh */
s->graphic_mode = -1;
+ vbe_update_vgaregs(s);
return 0;
}
s->is_vbe_vmstate = 1;
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
- &error_abort);
+ &error_fatal);
vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
xen_register_framebuffer(&s->vram);
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);