1bf21cd93STycho Nightingale /*- 24c87aefeSPatrick Mooney * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 34c87aefeSPatrick Mooney * 4bf21cd93STycho Nightingale * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 5bf21cd93STycho Nightingale * All rights reserved. 6bf21cd93STycho Nightingale * 7bf21cd93STycho Nightingale * Redistribution and use in source and binary forms, with or without 8bf21cd93STycho Nightingale * modification, are permitted provided that the following conditions 9bf21cd93STycho Nightingale * are met: 10bf21cd93STycho Nightingale * 1. Redistributions of source code must retain the above copyright 11bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer. 12bf21cd93STycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright 13bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer in the 14bf21cd93STycho Nightingale * documentation and/or other materials provided with the distribution. 15bf21cd93STycho Nightingale * 16bf21cd93STycho Nightingale * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 17bf21cd93STycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18bf21cd93STycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19bf21cd93STycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20bf21cd93STycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21bf21cd93STycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22bf21cd93STycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23bf21cd93STycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24bf21cd93STycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25bf21cd93STycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26bf21cd93STycho Nightingale * SUCH DAMAGE. 27bf21cd93STycho Nightingale */ 28bf21cd93STycho Nightingale 294c87aefeSPatrick Mooney /* 304c87aefeSPatrick Mooney * Copyright 2018 Joyent, Inc. 314c87aefeSPatrick Mooney */ 324c87aefeSPatrick Mooney 33bf21cd93STycho Nightingale #include <sys/cdefs.h> 34bf21cd93STycho Nightingale __FBSDID("$FreeBSD$"); 35bf21cd93STycho Nightingale 36bf21cd93STycho Nightingale #include <sys/param.h> 37bf21cd93STycho Nightingale 38bf21cd93STycho Nightingale #include <assert.h> 39bf21cd93STycho Nightingale #include <pthread.h> 40bf21cd93STycho Nightingale #include <stdbool.h> 41bf21cd93STycho Nightingale #include <stdio.h> 42bf21cd93STycho Nightingale #include <stdlib.h> 43bf21cd93STycho Nightingale #include <string.h> 44bf21cd93STycho Nightingale 45bf21cd93STycho Nightingale #include <machine/vmm.h> 46bf21cd93STycho Nightingale 47bf21cd93STycho Nightingale #include "bhyvegc.h" 48bf21cd93STycho Nightingale #include "console.h" 49bf21cd93STycho Nightingale #include "inout.h" 50bf21cd93STycho Nightingale #include "mem.h" 51bf21cd93STycho Nightingale #include "vga.h" 52bf21cd93STycho Nightingale 53bf21cd93STycho Nightingale #define KB (1024UL) 54bf21cd93STycho Nightingale #define MB (1024 * 1024UL) 55bf21cd93STycho Nightingale 56bf21cd93STycho Nightingale struct vga_softc { 57bf21cd93STycho Nightingale struct mem_range mr; 58bf21cd93STycho Nightingale 59bf21cd93STycho Nightingale struct bhyvegc *gc; 60bf21cd93STycho Nightingale int gc_width; 61bf21cd93STycho Nightingale int gc_height; 62bf21cd93STycho Nightingale struct bhyvegc_image *gc_image; 63bf21cd93STycho Nightingale 64bf21cd93STycho Nightingale uint8_t *vga_ram; 65bf21cd93STycho Nightingale 66bf21cd93STycho Nightingale /* 67bf21cd93STycho Nightingale * General registers 68bf21cd93STycho Nightingale */ 69bf21cd93STycho Nightingale uint8_t vga_misc; 70bf21cd93STycho Nightingale uint8_t vga_sts1; 71bf21cd93STycho Nightingale 72bf21cd93STycho Nightingale /* 73bf21cd93STycho Nightingale * Sequencer 74bf21cd93STycho Nightingale */ 75bf21cd93STycho Nightingale struct { 76bf21cd93STycho Nightingale int seq_index; 77bf21cd93STycho Nightingale uint8_t seq_reset; 78bf21cd93STycho Nightingale uint8_t seq_clock_mode; 79bf21cd93STycho Nightingale int seq_cm_dots; 80bf21cd93STycho Nightingale uint8_t seq_map_mask; 81bf21cd93STycho Nightingale uint8_t seq_cmap_sel; 82bf21cd93STycho Nightingale int seq_cmap_pri_off; 83bf21cd93STycho Nightingale int seq_cmap_sec_off; 84bf21cd93STycho Nightingale uint8_t seq_mm; 85bf21cd93STycho Nightingale } vga_seq; 86bf21cd93STycho Nightingale 87bf21cd93STycho Nightingale /* 88bf21cd93STycho Nightingale * CRT Controller 89bf21cd93STycho Nightingale */ 90bf21cd93STycho Nightingale struct { 91bf21cd93STycho Nightingale int crtc_index; 92bf21cd93STycho Nightingale uint8_t crtc_mode_ctrl; 93bf21cd93STycho Nightingale uint8_t crtc_horiz_total; 94bf21cd93STycho Nightingale uint8_t crtc_horiz_disp_end; 95bf21cd93STycho Nightingale uint8_t crtc_start_horiz_blank; 96bf21cd93STycho Nightingale uint8_t crtc_end_horiz_blank; 97bf21cd93STycho Nightingale uint8_t crtc_start_horiz_retrace; 98bf21cd93STycho Nightingale uint8_t crtc_end_horiz_retrace; 99bf21cd93STycho Nightingale uint8_t crtc_vert_total; 100bf21cd93STycho Nightingale uint8_t crtc_overflow; 101bf21cd93STycho Nightingale uint8_t crtc_present_row_scan; 102bf21cd93STycho Nightingale uint8_t crtc_max_scan_line; 103bf21cd93STycho Nightingale uint8_t crtc_cursor_start; 104bf21cd93STycho Nightingale uint8_t crtc_cursor_on; 105bf21cd93STycho Nightingale uint8_t crtc_cursor_end; 106bf21cd93STycho Nightingale uint8_t crtc_start_addr_high; 107bf21cd93STycho Nightingale uint8_t crtc_start_addr_low; 108bf21cd93STycho Nightingale uint16_t crtc_start_addr; 109bf21cd93STycho Nightingale uint8_t crtc_cursor_loc_low; 110bf21cd93STycho Nightingale uint8_t crtc_cursor_loc_high; 111bf21cd93STycho Nightingale uint16_t crtc_cursor_loc; 112bf21cd93STycho Nightingale uint8_t crtc_vert_retrace_start; 113bf21cd93STycho Nightingale uint8_t crtc_vert_retrace_end; 114bf21cd93STycho Nightingale uint8_t crtc_vert_disp_end; 115bf21cd93STycho Nightingale uint8_t crtc_offset; 116bf21cd93STycho Nightingale uint8_t crtc_underline_loc; 117bf21cd93STycho Nightingale uint8_t crtc_start_vert_blank; 118bf21cd93STycho Nightingale uint8_t crtc_end_vert_blank; 119bf21cd93STycho Nightingale uint8_t crtc_line_compare; 120bf21cd93STycho Nightingale } vga_crtc; 121bf21cd93STycho Nightingale 122bf21cd93STycho Nightingale /* 123bf21cd93STycho Nightingale * Graphics Controller 124bf21cd93STycho Nightingale */ 125bf21cd93STycho Nightingale struct { 126bf21cd93STycho Nightingale int gc_index; 127bf21cd93STycho Nightingale uint8_t gc_set_reset; 128bf21cd93STycho Nightingale uint8_t gc_enb_set_reset; 129bf21cd93STycho Nightingale uint8_t gc_color_compare; 130bf21cd93STycho Nightingale uint8_t gc_rotate; 131bf21cd93STycho Nightingale uint8_t gc_op; 132bf21cd93STycho Nightingale uint8_t gc_read_map_sel; 133bf21cd93STycho Nightingale uint8_t gc_mode; 134bf21cd93STycho Nightingale bool gc_mode_c4; /* chain 4 */ 135bf21cd93STycho Nightingale bool gc_mode_oe; /* odd/even */ 136bf21cd93STycho Nightingale uint8_t gc_mode_rm; /* read mode */ 137bf21cd93STycho Nightingale uint8_t gc_mode_wm; /* write mode */ 138bf21cd93STycho Nightingale uint8_t gc_misc; 139bf21cd93STycho Nightingale uint8_t gc_misc_gm; /* graphics mode */ 140bf21cd93STycho Nightingale uint8_t gc_misc_mm; /* memory map */ 141bf21cd93STycho Nightingale uint8_t gc_color_dont_care; 142bf21cd93STycho Nightingale uint8_t gc_bit_mask; 143bf21cd93STycho Nightingale uint8_t gc_latch0; 144bf21cd93STycho Nightingale uint8_t gc_latch1; 145bf21cd93STycho Nightingale uint8_t gc_latch2; 146bf21cd93STycho Nightingale uint8_t gc_latch3; 147bf21cd93STycho Nightingale } vga_gc; 148bf21cd93STycho Nightingale 149bf21cd93STycho Nightingale /* 150bf21cd93STycho Nightingale * Attribute Controller 151bf21cd93STycho Nightingale */ 152bf21cd93STycho Nightingale struct { 153bf21cd93STycho Nightingale int atc_flipflop; 154bf21cd93STycho Nightingale int atc_index; 155bf21cd93STycho Nightingale uint8_t atc_palette[16]; 156bf21cd93STycho Nightingale uint8_t atc_mode; 157bf21cd93STycho Nightingale uint8_t atc_overscan_color; 158bf21cd93STycho Nightingale uint8_t atc_color_plane_enb; 159bf21cd93STycho Nightingale uint8_t atc_horiz_pixel_panning; 160bf21cd93STycho Nightingale uint8_t atc_color_select; 161bf21cd93STycho Nightingale uint8_t atc_color_select_45; 162bf21cd93STycho Nightingale uint8_t atc_color_select_67; 163bf21cd93STycho Nightingale } vga_atc; 164bf21cd93STycho Nightingale 165bf21cd93STycho Nightingale /* 166bf21cd93STycho Nightingale * DAC 167bf21cd93STycho Nightingale */ 168bf21cd93STycho Nightingale struct { 169bf21cd93STycho Nightingale uint8_t dac_state; 1704c87aefeSPatrick Mooney uint8_t dac_rd_index; 1714c87aefeSPatrick Mooney uint8_t dac_rd_subindex; 1724c87aefeSPatrick Mooney uint8_t dac_wr_index; 1734c87aefeSPatrick Mooney uint8_t dac_wr_subindex; 174bf21cd93STycho Nightingale uint8_t dac_palette[3 * 256]; 175bf21cd93STycho Nightingale uint32_t dac_palette_rgb[256]; 176bf21cd93STycho Nightingale } vga_dac; 177bf21cd93STycho Nightingale }; 178bf21cd93STycho Nightingale 179bf21cd93STycho Nightingale static bool 180bf21cd93STycho Nightingale vga_in_reset(struct vga_softc *sc) 181bf21cd93STycho Nightingale { 182bf21cd93STycho Nightingale return (((sc->vga_seq.seq_clock_mode & SEQ_CM_SO) != 0) || 183bf21cd93STycho Nightingale ((sc->vga_seq.seq_reset & SEQ_RESET_ASYNC) == 0) || 184bf21cd93STycho Nightingale ((sc->vga_seq.seq_reset & SEQ_RESET_SYNC) == 0) || 185bf21cd93STycho Nightingale ((sc->vga_crtc.crtc_mode_ctrl & CRTC_MC_TE) == 0)); 186bf21cd93STycho Nightingale } 187bf21cd93STycho Nightingale 188bf21cd93STycho Nightingale static void 189bf21cd93STycho Nightingale vga_check_size(struct bhyvegc *gc, struct vga_softc *sc) 190bf21cd93STycho Nightingale { 191bf21cd93STycho Nightingale int old_width, old_height; 192bf21cd93STycho Nightingale 193bf21cd93STycho Nightingale if (vga_in_reset(sc)) 194bf21cd93STycho Nightingale return; 195bf21cd93STycho Nightingale 1964c87aefeSPatrick Mooney //old_width = sc->gc_width; 1974c87aefeSPatrick Mooney //old_height = sc->gc_height; 1984c87aefeSPatrick Mooney old_width = sc->gc_image->width; 1994c87aefeSPatrick Mooney old_height = sc->gc_image->height; 200bf21cd93STycho Nightingale 201bf21cd93STycho Nightingale /* 202bf21cd93STycho Nightingale * Horizontal Display End: For text modes this is the number 203bf21cd93STycho Nightingale * of characters. For graphics modes this is the number of 204bf21cd93STycho Nightingale * pixels per scanlines divided by the number of pixels per 205bf21cd93STycho Nightingale * character clock. 206bf21cd93STycho Nightingale */ 207bf21cd93STycho Nightingale sc->gc_width = (sc->vga_crtc.crtc_horiz_disp_end + 1) * 208bf21cd93STycho Nightingale sc->vga_seq.seq_cm_dots; 209bf21cd93STycho Nightingale 210bf21cd93STycho Nightingale sc->gc_height = (sc->vga_crtc.crtc_vert_disp_end | 211bf21cd93STycho Nightingale (((sc->vga_crtc.crtc_overflow & CRTC_OF_VDE8) >> CRTC_OF_VDE8_SHIFT) << 8) | 212bf21cd93STycho Nightingale (((sc->vga_crtc.crtc_overflow & CRTC_OF_VDE9) >> CRTC_OF_VDE9_SHIFT) << 9)) + 1; 213bf21cd93STycho Nightingale 214bf21cd93STycho Nightingale if (old_width != sc->gc_width || old_height != sc->gc_height) 215bf21cd93STycho Nightingale bhyvegc_resize(gc, sc->gc_width, sc->gc_height); 216bf21cd93STycho Nightingale } 217bf21cd93STycho Nightingale 218bf21cd93STycho Nightingale static uint32_t 219bf21cd93STycho Nightingale vga_get_pixel(struct vga_softc *sc, int x, int y) 220bf21cd93STycho Nightingale { 221bf21cd93STycho Nightingale int offset; 222bf21cd93STycho Nightingale int bit; 223bf21cd93STycho Nightingale uint8_t data; 224bf21cd93STycho Nightingale uint8_t idx; 225bf21cd93STycho Nightingale 226bf21cd93STycho Nightingale offset = (y * sc->gc_width / 8) + (x / 8); 227bf21cd93STycho Nightingale bit = 7 - (x % 8); 228bf21cd93STycho Nightingale 229bf21cd93STycho Nightingale data = (((sc->vga_ram[offset + 0 * 64*KB] >> bit) & 0x1) << 0) | 230bf21cd93STycho Nightingale (((sc->vga_ram[offset + 1 * 64*KB] >> bit) & 0x1) << 1) | 231bf21cd93STycho Nightingale (((sc->vga_ram[offset + 2 * 64*KB] >> bit) & 0x1) << 2) | 232bf21cd93STycho Nightingale (((sc->vga_ram[offset + 3 * 64*KB] >> bit) & 0x1) << 3); 233bf21cd93STycho Nightingale 234bf21cd93STycho Nightingale data &= sc->vga_atc.atc_color_plane_enb; 235bf21cd93STycho Nightingale 236bf21cd93STycho Nightingale if (sc->vga_atc.atc_mode & ATC_MC_IPS) { 237bf21cd93STycho Nightingale idx = sc->vga_atc.atc_palette[data] & 0x0f; 238bf21cd93STycho Nightingale idx |= sc->vga_atc.atc_color_select_45; 239bf21cd93STycho Nightingale } else { 240bf21cd93STycho Nightingale idx = sc->vga_atc.atc_palette[data]; 241bf21cd93STycho Nightingale } 242bf21cd93STycho Nightingale idx |= sc->vga_atc.atc_color_select_67; 243bf21cd93STycho Nightingale 244bf21cd93STycho Nightingale return (sc->vga_dac.dac_palette_rgb[idx]); 245bf21cd93STycho Nightingale } 246bf21cd93STycho Nightingale 247bf21cd93STycho Nightingale static void 248bf21cd93STycho Nightingale vga_render_graphics(struct vga_softc *sc) 249bf21cd93STycho Nightingale { 250bf21cd93STycho Nightingale int x, y; 251bf21cd93STycho Nightingale 252bf21cd93STycho Nightingale for (y = 0; y < sc->gc_height; y++) { 253bf21cd93STycho Nightingale for (x = 0; x < sc->gc_width; x++) { 254bf21cd93STycho Nightingale int offset; 255bf21cd93STycho Nightingale 256bf21cd93STycho Nightingale offset = y * sc->gc_width + x; 257bf21cd93STycho Nightingale sc->gc_image->data[offset] = vga_get_pixel(sc, x, y); 258bf21cd93STycho Nightingale } 259bf21cd93STycho Nightingale } 260bf21cd93STycho Nightingale } 261bf21cd93STycho Nightingale 262bf21cd93STycho Nightingale static uint32_t 263bf21cd93STycho Nightingale vga_get_text_pixel(struct vga_softc *sc, int x, int y) 264bf21cd93STycho Nightingale { 265bf21cd93STycho Nightingale int dots, offset, bit, font_offset; 266bf21cd93STycho Nightingale uint8_t ch, attr, font; 267bf21cd93STycho Nightingale uint8_t idx; 268bf21cd93STycho Nightingale 269bf21cd93STycho Nightingale dots = sc->vga_seq.seq_cm_dots; 270bf21cd93STycho Nightingale 271bf21cd93STycho Nightingale offset = 2 * sc->vga_crtc.crtc_start_addr; 272bf21cd93STycho Nightingale offset += (y / 16 * sc->gc_width / dots) * 2 + (x / dots) * 2; 273bf21cd93STycho Nightingale 2744c87aefeSPatrick Mooney bit = 7 - (x % dots > 7 ? 7 : x % dots); 275bf21cd93STycho Nightingale 276bf21cd93STycho Nightingale ch = sc->vga_ram[offset + 0 * 64*KB]; 277bf21cd93STycho Nightingale attr = sc->vga_ram[offset + 1 * 64*KB]; 278bf21cd93STycho Nightingale 279bf21cd93STycho Nightingale if (sc->vga_crtc.crtc_cursor_on && 280bf21cd93STycho Nightingale (offset == (sc->vga_crtc.crtc_cursor_loc * 2)) && 281bf21cd93STycho Nightingale ((y % 16) >= (sc->vga_crtc.crtc_cursor_start & CRTC_CS_CS)) && 282bf21cd93STycho Nightingale ((y % 16) <= (sc->vga_crtc.crtc_cursor_end & CRTC_CE_CE))) { 283bf21cd93STycho Nightingale idx = sc->vga_atc.atc_palette[attr & 0xf]; 284bf21cd93STycho Nightingale return (sc->vga_dac.dac_palette_rgb[idx]); 285bf21cd93STycho Nightingale } 286bf21cd93STycho Nightingale 287bf21cd93STycho Nightingale if ((sc->vga_seq.seq_mm & SEQ_MM_EM) && 288bf21cd93STycho Nightingale sc->vga_seq.seq_cmap_pri_off != sc->vga_seq.seq_cmap_sec_off) { 289bf21cd93STycho Nightingale if (attr & 0x8) 290bf21cd93STycho Nightingale font_offset = sc->vga_seq.seq_cmap_pri_off + 291bf21cd93STycho Nightingale (ch << 5) + y % 16; 292bf21cd93STycho Nightingale else 293bf21cd93STycho Nightingale font_offset = sc->vga_seq.seq_cmap_sec_off + 294bf21cd93STycho Nightingale (ch << 5) + y % 16; 295bf21cd93STycho Nightingale attr &= ~0x8; 296bf21cd93STycho Nightingale } else { 297bf21cd93STycho Nightingale font_offset = (ch << 5) + y % 16; 298bf21cd93STycho Nightingale } 299bf21cd93STycho Nightingale 300bf21cd93STycho Nightingale font = sc->vga_ram[font_offset + 2 * 64*KB]; 301bf21cd93STycho Nightingale 3024c87aefeSPatrick Mooney if (font & (1 << bit)) 303bf21cd93STycho Nightingale idx = sc->vga_atc.atc_palette[attr & 0xf]; 304bf21cd93STycho Nightingale else 305bf21cd93STycho Nightingale idx = sc->vga_atc.atc_palette[attr >> 4]; 306bf21cd93STycho Nightingale 307bf21cd93STycho Nightingale return (sc->vga_dac.dac_palette_rgb[idx]); 308bf21cd93STycho Nightingale } 309bf21cd93STycho Nightingale 310bf21cd93STycho Nightingale static void 311bf21cd93STycho Nightingale vga_render_text(struct vga_softc *sc) 312bf21cd93STycho Nightingale { 313bf21cd93STycho Nightingale int x, y; 314bf21cd93STycho Nightingale 315bf21cd93STycho Nightingale for (y = 0; y < sc->gc_height; y++) { 316bf21cd93STycho Nightingale for (x = 0; x < sc->gc_width; x++) { 317bf21cd93STycho Nightingale int offset; 318bf21cd93STycho Nightingale 319bf21cd93STycho Nightingale offset = y * sc->gc_width + x; 320bf21cd93STycho Nightingale sc->gc_image->data[offset] = vga_get_text_pixel(sc, x, y); 321bf21cd93STycho Nightingale } 322bf21cd93STycho Nightingale } 323bf21cd93STycho Nightingale } 324bf21cd93STycho Nightingale 3254c87aefeSPatrick Mooney void 326bf21cd93STycho Nightingale vga_render(struct bhyvegc *gc, void *arg) 327bf21cd93STycho Nightingale { 328bf21cd93STycho Nightingale struct vga_softc *sc = arg; 329bf21cd93STycho Nightingale 330bf21cd93STycho Nightingale vga_check_size(gc, sc); 331bf21cd93STycho Nightingale 332bf21cd93STycho Nightingale if (vga_in_reset(sc)) { 333bf21cd93STycho Nightingale memset(sc->gc_image->data, 0, 334bf21cd93STycho Nightingale sc->gc_image->width * sc->gc_image->height * 335bf21cd93STycho Nightingale sizeof (uint32_t)); 336bf21cd93STycho Nightingale return; 337bf21cd93STycho Nightingale } 338bf21cd93STycho Nightingale 339bf21cd93STycho Nightingale if (sc->vga_gc.gc_misc_gm && (sc->vga_atc.atc_mode & ATC_MC_GA)) 340bf21cd93STycho Nightingale vga_render_graphics(sc); 341bf21cd93STycho Nightingale else 342bf21cd93STycho Nightingale vga_render_text(sc); 343bf21cd93STycho Nightingale } 344bf21cd93STycho Nightingale 345bf21cd93STycho Nightingale static uint64_t 346bf21cd93STycho Nightingale vga_mem_rd_handler(struct vmctx *ctx, uint64_t addr, void *arg1) 347bf21cd93STycho Nightingale { 348bf21cd93STycho Nightingale struct vga_softc *sc = arg1; 349bf21cd93STycho Nightingale uint8_t map_sel; 350bf21cd93STycho Nightingale int offset; 351bf21cd93STycho Nightingale 352bf21cd93STycho Nightingale offset = addr; 353bf21cd93STycho Nightingale switch (sc->vga_gc.gc_misc_mm) { 354bf21cd93STycho Nightingale case 0x0: 355bf21cd93STycho Nightingale /* 356bf21cd93STycho Nightingale * extended mode: base 0xa0000 size 128k 357bf21cd93STycho Nightingale */ 358bf21cd93STycho Nightingale offset -=0xa0000; 359bf21cd93STycho Nightingale offset &= (128 * KB - 1); 360bf21cd93STycho Nightingale break; 361bf21cd93STycho Nightingale case 0x1: 362bf21cd93STycho Nightingale /* 363bf21cd93STycho Nightingale * EGA/VGA mode: base 0xa0000 size 64k 364bf21cd93STycho Nightingale */ 365bf21cd93STycho Nightingale offset -=0xa0000; 366bf21cd93STycho Nightingale offset &= (64 * KB - 1); 367bf21cd93STycho Nightingale break; 368bf21cd93STycho Nightingale case 0x2: 369bf21cd93STycho Nightingale /* 370bf21cd93STycho Nightingale * monochrome text mode: base 0xb0000 size 32kb 371bf21cd93STycho Nightingale */ 3724c87aefeSPatrick Mooney #ifdef __FreeBSD__ 373bf21cd93STycho Nightingale assert(0); 3744c87aefeSPatrick Mooney #else 3754c87aefeSPatrick Mooney abort(); 3764c87aefeSPatrick Mooney #endif 377bf21cd93STycho Nightingale case 0x3: 378bf21cd93STycho Nightingale /* 379bf21cd93STycho Nightingale * color text mode and CGA: base 0xb8000 size 32kb 380bf21cd93STycho Nightingale */ 381bf21cd93STycho Nightingale offset -=0xb8000; 382bf21cd93STycho Nightingale offset &= (32 * KB - 1); 383bf21cd93STycho Nightingale break; 384bf21cd93STycho Nightingale } 385bf21cd93STycho Nightingale 386bf21cd93STycho Nightingale /* Fill latches. */ 387bf21cd93STycho Nightingale sc->vga_gc.gc_latch0 = sc->vga_ram[offset + 0*64*KB]; 388bf21cd93STycho Nightingale sc->vga_gc.gc_latch1 = sc->vga_ram[offset + 1*64*KB]; 389bf21cd93STycho Nightingale sc->vga_gc.gc_latch2 = sc->vga_ram[offset + 2*64*KB]; 390bf21cd93STycho Nightingale sc->vga_gc.gc_latch3 = sc->vga_ram[offset + 3*64*KB]; 391bf21cd93STycho Nightingale 392bf21cd93STycho Nightingale if (sc->vga_gc.gc_mode_rm) { 393bf21cd93STycho Nightingale /* read mode 1 */ 394bf21cd93STycho Nightingale assert(0); 395bf21cd93STycho Nightingale } 396bf21cd93STycho Nightingale 397bf21cd93STycho Nightingale map_sel = sc->vga_gc.gc_read_map_sel; 398bf21cd93STycho Nightingale if (sc->vga_gc.gc_mode_oe) { 399bf21cd93STycho Nightingale map_sel |= (offset & 1); 400bf21cd93STycho Nightingale offset &= ~1; 401bf21cd93STycho Nightingale } 402bf21cd93STycho Nightingale 403bf21cd93STycho Nightingale /* read mode 0: return the byte from the selected plane. */ 404bf21cd93STycho Nightingale offset += map_sel * 64*KB; 405bf21cd93STycho Nightingale 406bf21cd93STycho Nightingale return (sc->vga_ram[offset]); 407bf21cd93STycho Nightingale } 408bf21cd93STycho Nightingale 409bf21cd93STycho Nightingale static void 410bf21cd93STycho Nightingale vga_mem_wr_handler(struct vmctx *ctx, uint64_t addr, uint8_t val, void *arg1) 411bf21cd93STycho Nightingale { 412bf21cd93STycho Nightingale struct vga_softc *sc = arg1; 413bf21cd93STycho Nightingale uint8_t c0, c1, c2, c3; 414bf21cd93STycho Nightingale uint8_t m0, m1, m2, m3; 415bf21cd93STycho Nightingale uint8_t set_reset; 416bf21cd93STycho Nightingale uint8_t enb_set_reset; 417bf21cd93STycho Nightingale uint8_t mask; 418bf21cd93STycho Nightingale int offset; 419bf21cd93STycho Nightingale 420bf21cd93STycho Nightingale offset = addr; 421bf21cd93STycho Nightingale switch (sc->vga_gc.gc_misc_mm) { 422bf21cd93STycho Nightingale case 0x0: 423bf21cd93STycho Nightingale /* 424bf21cd93STycho Nightingale * extended mode: base 0xa0000 size 128kb 425bf21cd93STycho Nightingale */ 426bf21cd93STycho Nightingale offset -=0xa0000; 427bf21cd93STycho Nightingale offset &= (128 * KB - 1); 428bf21cd93STycho Nightingale break; 429bf21cd93STycho Nightingale case 0x1: 430bf21cd93STycho Nightingale /* 431bf21cd93STycho Nightingale * EGA/VGA mode: base 0xa0000 size 64kb 432bf21cd93STycho Nightingale */ 433bf21cd93STycho Nightingale offset -=0xa0000; 434bf21cd93STycho Nightingale offset &= (64 * KB - 1); 435bf21cd93STycho Nightingale break; 436bf21cd93STycho Nightingale case 0x2: 437bf21cd93STycho Nightingale /* 438bf21cd93STycho Nightingale * monochrome text mode: base 0xb0000 size 32kb 439bf21cd93STycho Nightingale */ 4404c87aefeSPatrick Mooney #ifdef __FreeBSD__ 441bf21cd93STycho Nightingale assert(0); 4424c87aefeSPatrick Mooney #else 4434c87aefeSPatrick Mooney abort(); 4444c87aefeSPatrick Mooney #endif 445bf21cd93STycho Nightingale case 0x3: 446bf21cd93STycho Nightingale /* 447bf21cd93STycho Nightingale * color text mode and CGA: base 0xb8000 size 32kb 448bf21cd93STycho Nightingale */ 449bf21cd93STycho Nightingale offset -=0xb8000; 450bf21cd93STycho Nightingale offset &= (32 * KB - 1); 451bf21cd93STycho Nightingale break; 452bf21cd93STycho Nightingale } 453bf21cd93STycho Nightingale 454bf21cd93STycho Nightingale set_reset = sc->vga_gc.gc_set_reset; 455bf21cd93STycho Nightingale enb_set_reset = sc->vga_gc.gc_enb_set_reset; 456bf21cd93STycho Nightingale 457bf21cd93STycho Nightingale c0 = sc->vga_gc.gc_latch0; 458bf21cd93STycho Nightingale c1 = sc->vga_gc.gc_latch1; 459bf21cd93STycho Nightingale c2 = sc->vga_gc.gc_latch2; 460bf21cd93STycho Nightingale c3 = sc->vga_gc.gc_latch3; 461bf21cd93STycho Nightingale 462bf21cd93STycho Nightingale switch (sc->vga_gc.gc_mode_wm) { 463bf21cd93STycho Nightingale case 0: 464bf21cd93STycho Nightingale /* write mode 0 */ 465bf21cd93STycho Nightingale mask = sc->vga_gc.gc_bit_mask; 466bf21cd93STycho Nightingale 467bf21cd93STycho Nightingale val = (val >> sc->vga_gc.gc_rotate) | 468bf21cd93STycho Nightingale (val << (8 - sc->vga_gc.gc_rotate)); 469bf21cd93STycho Nightingale 470bf21cd93STycho Nightingale switch (sc->vga_gc.gc_op) { 471bf21cd93STycho Nightingale case 0x00: /* replace */ 472bf21cd93STycho Nightingale m0 = (set_reset & 1) ? mask : 0x00; 473bf21cd93STycho Nightingale m1 = (set_reset & 2) ? mask : 0x00; 474bf21cd93STycho Nightingale m2 = (set_reset & 4) ? mask : 0x00; 475bf21cd93STycho Nightingale m3 = (set_reset & 8) ? mask : 0x00; 476bf21cd93STycho Nightingale 477bf21cd93STycho Nightingale c0 = (enb_set_reset & 1) ? (c0 & ~mask) : (val & mask); 478bf21cd93STycho Nightingale c1 = (enb_set_reset & 2) ? (c1 & ~mask) : (val & mask); 479bf21cd93STycho Nightingale c2 = (enb_set_reset & 4) ? (c2 & ~mask) : (val & mask); 480bf21cd93STycho Nightingale c3 = (enb_set_reset & 8) ? (c3 & ~mask) : (val & mask); 481bf21cd93STycho Nightingale 482bf21cd93STycho Nightingale c0 |= m0; 483bf21cd93STycho Nightingale c1 |= m1; 484bf21cd93STycho Nightingale c2 |= m2; 485bf21cd93STycho Nightingale c3 |= m3; 486bf21cd93STycho Nightingale break; 487bf21cd93STycho Nightingale case 0x08: /* AND */ 488bf21cd93STycho Nightingale m0 = set_reset & 1 ? 0xff : ~mask; 489bf21cd93STycho Nightingale m1 = set_reset & 2 ? 0xff : ~mask; 490bf21cd93STycho Nightingale m2 = set_reset & 4 ? 0xff : ~mask; 491bf21cd93STycho Nightingale m3 = set_reset & 8 ? 0xff : ~mask; 492bf21cd93STycho Nightingale 493bf21cd93STycho Nightingale c0 = enb_set_reset & 1 ? c0 & m0 : val & m0; 494bf21cd93STycho Nightingale c1 = enb_set_reset & 2 ? c1 & m1 : val & m1; 495bf21cd93STycho Nightingale c2 = enb_set_reset & 4 ? c2 & m2 : val & m2; 496bf21cd93STycho Nightingale c3 = enb_set_reset & 8 ? c3 & m3 : val & m3; 497bf21cd93STycho Nightingale break; 498bf21cd93STycho Nightingale case 0x10: /* OR */ 499bf21cd93STycho Nightingale m0 = set_reset & 1 ? mask : 0x00; 500bf21cd93STycho Nightingale m1 = set_reset & 2 ? mask : 0x00; 501bf21cd93STycho Nightingale m2 = set_reset & 4 ? mask : 0x00; 502bf21cd93STycho Nightingale m3 = set_reset & 8 ? mask : 0x00; 503bf21cd93STycho Nightingale 504bf21cd93STycho Nightingale c0 = enb_set_reset & 1 ? c0 | m0 : val | m0; 505bf21cd93STycho Nightingale c1 = enb_set_reset & 2 ? c1 | m1 : val | m1; 506bf21cd93STycho Nightingale c2 = enb_set_reset & 4 ? c2 | m2 : val | m2; 507bf21cd93STycho Nightingale c3 = enb_set_reset & 8 ? c3 | m3 : val | m3; 508bf21cd93STycho Nightingale break; 509bf21cd93STycho Nightingale case 0x18: /* XOR */ 510bf21cd93STycho Nightingale m0 = set_reset & 1 ? mask : 0x00; 511bf21cd93STycho Nightingale m1 = set_reset & 2 ? mask : 0x00; 512bf21cd93STycho Nightingale m2 = set_reset & 4 ? mask : 0x00; 513bf21cd93STycho Nightingale m3 = set_reset & 8 ? mask : 0x00; 514bf21cd93STycho Nightingale 515bf21cd93STycho Nightingale c0 = enb_set_reset & 1 ? c0 ^ m0 : val ^ m0; 516bf21cd93STycho Nightingale c1 = enb_set_reset & 2 ? c1 ^ m1 : val ^ m1; 517bf21cd93STycho Nightingale c2 = enb_set_reset & 4 ? c2 ^ m2 : val ^ m2; 518bf21cd93STycho Nightingale c3 = enb_set_reset & 8 ? c3 ^ m3 : val ^ m3; 519bf21cd93STycho Nightingale break; 520bf21cd93STycho Nightingale } 521bf21cd93STycho Nightingale break; 522bf21cd93STycho Nightingale case 1: 523bf21cd93STycho Nightingale /* write mode 1 */ 524bf21cd93STycho Nightingale break; 525bf21cd93STycho Nightingale case 2: 526bf21cd93STycho Nightingale /* write mode 2 */ 527bf21cd93STycho Nightingale mask = sc->vga_gc.gc_bit_mask; 528bf21cd93STycho Nightingale 529bf21cd93STycho Nightingale switch (sc->vga_gc.gc_op) { 530bf21cd93STycho Nightingale case 0x00: /* replace */ 531bf21cd93STycho Nightingale m0 = (val & 1 ? 0xff : 0x00) & mask; 532bf21cd93STycho Nightingale m1 = (val & 2 ? 0xff : 0x00) & mask; 533bf21cd93STycho Nightingale m2 = (val & 4 ? 0xff : 0x00) & mask; 534bf21cd93STycho Nightingale m3 = (val & 8 ? 0xff : 0x00) & mask; 535bf21cd93STycho Nightingale 536bf21cd93STycho Nightingale c0 &= ~mask; 537bf21cd93STycho Nightingale c1 &= ~mask; 538bf21cd93STycho Nightingale c2 &= ~mask; 539bf21cd93STycho Nightingale c3 &= ~mask; 540bf21cd93STycho Nightingale 541bf21cd93STycho Nightingale c0 |= m0; 542bf21cd93STycho Nightingale c1 |= m1; 543bf21cd93STycho Nightingale c2 |= m2; 544bf21cd93STycho Nightingale c3 |= m3; 545bf21cd93STycho Nightingale break; 546bf21cd93STycho Nightingale case 0x08: /* AND */ 547bf21cd93STycho Nightingale m0 = (val & 1 ? 0xff : 0x00) | ~mask; 548bf21cd93STycho Nightingale m1 = (val & 2 ? 0xff : 0x00) | ~mask; 549bf21cd93STycho Nightingale m2 = (val & 4 ? 0xff : 0x00) | ~mask; 550bf21cd93STycho Nightingale m3 = (val & 8 ? 0xff : 0x00) | ~mask; 551bf21cd93STycho Nightingale 552bf21cd93STycho Nightingale c0 &= m0; 553bf21cd93STycho Nightingale c1 &= m1; 554bf21cd93STycho Nightingale c2 &= m2; 555bf21cd93STycho Nightingale c3 &= m3; 556bf21cd93STycho Nightingale break; 557bf21cd93STycho Nightingale case 0x10: /* OR */ 558bf21cd93STycho Nightingale m0 = (val & 1 ? 0xff : 0x00) & mask; 559bf21cd93STycho Nightingale m1 = (val & 2 ? 0xff : 0x00) & mask; 560bf21cd93STycho Nightingale m2 = (val & 4 ? 0xff : 0x00) & mask; 561bf21cd93STycho Nightingale m3 = (val & 8 ? 0xff : 0x00) & mask; 562bf21cd93STycho Nightingale 563bf21cd93STycho Nightingale c0 |= m0; 564bf21cd93STycho Nightingale c1 |= m1; 565bf21cd93STycho Nightingale c2 |= m2; 566bf21cd93STycho Nightingale c3 |= m3; 567bf21cd93STycho Nightingale break; 568bf21cd93STycho Nightingale case 0x18: /* XOR */ 569bf21cd93STycho Nightingale m0 = (val & 1 ? 0xff : 0x00) & mask; 570bf21cd93STycho Nightingale m1 = (val & 2 ? 0xff : 0x00) & mask; 571bf21cd93STycho Nightingale m2 = (val & 4 ? 0xff : 0x00) & mask; 572bf21cd93STycho Nightingale m3 = (val & 8 ? 0xff : 0x00) & mask; 573bf21cd93STycho Nightingale 574bf21cd93STycho Nightingale c0 ^= m0; 575bf21cd93STycho Nightingale c1 ^= m1; 576bf21cd93STycho Nightingale c2 ^= m2; 577bf21cd93STycho Nightingale c3 ^= m3; 578bf21cd93STycho Nightingale break; 579bf21cd93STycho Nightingale } 580bf21cd93STycho Nightingale break; 581bf21cd93STycho Nightingale case 3: 582bf21cd93STycho Nightingale /* write mode 3 */ 583bf21cd93STycho Nightingale mask = sc->vga_gc.gc_bit_mask & val; 584bf21cd93STycho Nightingale 585bf21cd93STycho Nightingale val = (val >> sc->vga_gc.gc_rotate) | 586bf21cd93STycho Nightingale (val << (8 - sc->vga_gc.gc_rotate)); 587bf21cd93STycho Nightingale 588bf21cd93STycho Nightingale switch (sc->vga_gc.gc_op) { 589bf21cd93STycho Nightingale case 0x00: /* replace */ 590bf21cd93STycho Nightingale m0 = (set_reset & 1 ? 0xff : 0x00) & mask; 591bf21cd93STycho Nightingale m1 = (set_reset & 2 ? 0xff : 0x00) & mask; 592bf21cd93STycho Nightingale m2 = (set_reset & 4 ? 0xff : 0x00) & mask; 593bf21cd93STycho Nightingale m3 = (set_reset & 8 ? 0xff : 0x00) & mask; 594bf21cd93STycho Nightingale 595bf21cd93STycho Nightingale c0 &= ~mask; 596bf21cd93STycho Nightingale c1 &= ~mask; 597bf21cd93STycho Nightingale c2 &= ~mask; 598bf21cd93STycho Nightingale c3 &= ~mask; 599bf21cd93STycho Nightingale 600bf21cd93STycho Nightingale c0 |= m0; 601bf21cd93STycho Nightingale c1 |= m1; 602bf21cd93STycho Nightingale c2 |= m2; 603bf21cd93STycho Nightingale c3 |= m3; 604bf21cd93STycho Nightingale break; 605bf21cd93STycho Nightingale case 0x08: /* AND */ 606bf21cd93STycho Nightingale m0 = (set_reset & 1 ? 0xff : 0x00) | ~mask; 607bf21cd93STycho Nightingale m1 = (set_reset & 2 ? 0xff : 0x00) | ~mask; 608bf21cd93STycho Nightingale m2 = (set_reset & 4 ? 0xff : 0x00) | ~mask; 609bf21cd93STycho Nightingale m3 = (set_reset & 8 ? 0xff : 0x00) | ~mask; 610bf21cd93STycho Nightingale 611bf21cd93STycho Nightingale c0 &= m0; 612bf21cd93STycho Nightingale c1 &= m1; 613bf21cd93STycho Nightingale c2 &= m2; 614bf21cd93STycho Nightingale c3 &= m3; 615bf21cd93STycho Nightingale break; 616bf21cd93STycho Nightingale case 0x10: /* OR */ 617bf21cd93STycho Nightingale m0 = (set_reset & 1 ? 0xff : 0x00) & mask; 618bf21cd93STycho Nightingale m1 = (set_reset & 2 ? 0xff : 0x00) & mask; 619bf21cd93STycho Nightingale m2 = (set_reset & 4 ? 0xff : 0x00) & mask; 620bf21cd93STycho Nightingale m3 = (set_reset & 8 ? 0xff : 0x00) & mask; 621bf21cd93STycho Nightingale 622bf21cd93STycho Nightingale c0 |= m0; 623bf21cd93STycho Nightingale c1 |= m1; 624bf21cd93STycho Nightingale c2 |= m2; 625bf21cd93STycho Nightingale c3 |= m3; 626bf21cd93STycho Nightingale break; 627bf21cd93STycho Nightingale case 0x18: /* XOR */ 628bf21cd93STycho Nightingale m0 = (set_reset & 1 ? 0xff : 0x00) & mask; 629bf21cd93STycho Nightingale m1 = (set_reset & 2 ? 0xff : 0x00) & mask; 630bf21cd93STycho Nightingale m2 = (set_reset & 4 ? 0xff : 0x00) & mask; 631bf21cd93STycho Nightingale m3 = (set_reset & 8 ? 0xff : 0x00) & mask; 632bf21cd93STycho Nightingale 633bf21cd93STycho Nightingale c0 ^= m0; 634bf21cd93STycho Nightingale c1 ^= m1; 635bf21cd93STycho Nightingale c2 ^= m2; 636bf21cd93STycho Nightingale c3 ^= m3; 637bf21cd93STycho Nightingale break; 638bf21cd93STycho Nightingale } 639bf21cd93STycho Nightingale break; 640bf21cd93STycho Nightingale } 641bf21cd93STycho Nightingale 642bf21cd93STycho Nightingale if (sc->vga_gc.gc_mode_oe) { 643bf21cd93STycho Nightingale if (offset & 1) { 644bf21cd93STycho Nightingale offset &= ~1; 645bf21cd93STycho Nightingale if (sc->vga_seq.seq_map_mask & 2) 646bf21cd93STycho Nightingale sc->vga_ram[offset + 1*64*KB] = c1; 647bf21cd93STycho Nightingale if (sc->vga_seq.seq_map_mask & 8) 648bf21cd93STycho Nightingale sc->vga_ram[offset + 3*64*KB] = c3; 649bf21cd93STycho Nightingale } else { 650bf21cd93STycho Nightingale if (sc->vga_seq.seq_map_mask & 1) 651bf21cd93STycho Nightingale sc->vga_ram[offset + 0*64*KB] = c0; 652bf21cd93STycho Nightingale if (sc->vga_seq.seq_map_mask & 4) 653bf21cd93STycho Nightingale sc->vga_ram[offset + 2*64*KB] = c2; 654bf21cd93STycho Nightingale } 655bf21cd93STycho Nightingale } else { 656bf21cd93STycho Nightingale if (sc->vga_seq.seq_map_mask & 1) 657bf21cd93STycho Nightingale sc->vga_ram[offset + 0*64*KB] = c0; 658bf21cd93STycho Nightingale if (sc->vga_seq.seq_map_mask & 2) 659bf21cd93STycho Nightingale sc->vga_ram[offset + 1*64*KB] = c1; 660bf21cd93STycho Nightingale if (sc->vga_seq.seq_map_mask & 4) 661bf21cd93STycho Nightingale sc->vga_ram[offset + 2*64*KB] = c2; 662bf21cd93STycho Nightingale if (sc->vga_seq.seq_map_mask & 8) 663bf21cd93STycho Nightingale sc->vga_ram[offset + 3*64*KB] = c3; 664bf21cd93STycho Nightingale } 665bf21cd93STycho Nightingale } 666bf21cd93STycho Nightingale 667bf21cd93STycho Nightingale static int 668bf21cd93STycho Nightingale vga_mem_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr, 669bf21cd93STycho Nightingale int size, uint64_t *val, void *arg1, long arg2) 670bf21cd93STycho Nightingale { 671bf21cd93STycho Nightingale if (dir == MEM_F_WRITE) { 672bf21cd93STycho Nightingale switch (size) { 673bf21cd93STycho Nightingale case 1: 674bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr, *val, arg1); 675bf21cd93STycho Nightingale break; 676bf21cd93STycho Nightingale case 2: 677bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr, *val, arg1); 678bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 1, *val >> 8, arg1); 679bf21cd93STycho Nightingale break; 680bf21cd93STycho Nightingale case 4: 681bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr, *val, arg1); 682bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 1, *val >> 8, arg1); 683bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 2, *val >> 16, arg1); 684bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 3, *val >> 24, arg1); 685bf21cd93STycho Nightingale break; 686bf21cd93STycho Nightingale case 8: 687bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr, *val, arg1); 688bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 1, *val >> 8, arg1); 689bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 2, *val >> 16, arg1); 690bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 3, *val >> 24, arg1); 691bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 4, *val >> 32, arg1); 692bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 5, *val >> 40, arg1); 693bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 6, *val >> 48, arg1); 694bf21cd93STycho Nightingale vga_mem_wr_handler(ctx, addr + 7, *val >> 56, arg1); 695bf21cd93STycho Nightingale break; 696bf21cd93STycho Nightingale } 697bf21cd93STycho Nightingale } else { 698bf21cd93STycho Nightingale switch (size) { 699bf21cd93STycho Nightingale case 1: 700bf21cd93STycho Nightingale *val = vga_mem_rd_handler(ctx, addr, arg1); 701bf21cd93STycho Nightingale break; 702bf21cd93STycho Nightingale case 2: 703bf21cd93STycho Nightingale *val = vga_mem_rd_handler(ctx, addr, arg1); 704bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 1, arg1) << 8; 705bf21cd93STycho Nightingale break; 706bf21cd93STycho Nightingale case 4: 707bf21cd93STycho Nightingale *val = vga_mem_rd_handler(ctx, addr, arg1); 708bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 1, arg1) << 8; 709bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 2, arg1) << 16; 710bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 3, arg1) << 24; 711bf21cd93STycho Nightingale break; 712bf21cd93STycho Nightingale case 8: 713bf21cd93STycho Nightingale *val = vga_mem_rd_handler(ctx, addr, arg1); 714bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 1, arg1) << 8; 715bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 2, arg1) << 16; 716bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 3, arg1) << 24; 717bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 4, arg1) << 32; 718bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 5, arg1) << 40; 719bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 6, arg1) << 48; 720bf21cd93STycho Nightingale *val |= vga_mem_rd_handler(ctx, addr + 7, arg1) << 56; 721bf21cd93STycho Nightingale break; 722bf21cd93STycho Nightingale } 723bf21cd93STycho Nightingale } 724bf21cd93STycho Nightingale 725bf21cd93STycho Nightingale return (0); 726bf21cd93STycho Nightingale } 727bf21cd93STycho Nightingale 728bf21cd93STycho Nightingale static int 729bf21cd93STycho Nightingale vga_port_in_handler(struct vmctx *ctx, int in, int port, int bytes, 730bf21cd93STycho Nightingale uint8_t *val, void *arg) 731bf21cd93STycho Nightingale { 732bf21cd93STycho Nightingale struct vga_softc *sc = arg; 733bf21cd93STycho Nightingale 734bf21cd93STycho Nightingale switch (port) { 735bf21cd93STycho Nightingale case CRTC_IDX_MONO_PORT: 736bf21cd93STycho Nightingale case CRTC_IDX_COLOR_PORT: 737bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_index; 738bf21cd93STycho Nightingale break; 739bf21cd93STycho Nightingale case CRTC_DATA_MONO_PORT: 740bf21cd93STycho Nightingale case CRTC_DATA_COLOR_PORT: 741bf21cd93STycho Nightingale switch (sc->vga_crtc.crtc_index) { 742bf21cd93STycho Nightingale case CRTC_HORIZ_TOTAL: 743bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_horiz_total; 744bf21cd93STycho Nightingale break; 745bf21cd93STycho Nightingale case CRTC_HORIZ_DISP_END: 746bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_horiz_disp_end; 747bf21cd93STycho Nightingale break; 748bf21cd93STycho Nightingale case CRTC_START_HORIZ_BLANK: 749bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_start_horiz_blank; 750bf21cd93STycho Nightingale break; 751bf21cd93STycho Nightingale case CRTC_END_HORIZ_BLANK: 752bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_end_horiz_blank; 753bf21cd93STycho Nightingale break; 754bf21cd93STycho Nightingale case CRTC_START_HORIZ_RETRACE: 755bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_start_horiz_retrace; 756bf21cd93STycho Nightingale break; 757bf21cd93STycho Nightingale case CRTC_END_HORIZ_RETRACE: 758bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_end_horiz_retrace; 759bf21cd93STycho Nightingale break; 760bf21cd93STycho Nightingale case CRTC_VERT_TOTAL: 761bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_vert_total; 762bf21cd93STycho Nightingale break; 763bf21cd93STycho Nightingale case CRTC_OVERFLOW: 764bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_overflow; 765bf21cd93STycho Nightingale break; 766bf21cd93STycho Nightingale case CRTC_PRESET_ROW_SCAN: 767bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_present_row_scan; 768bf21cd93STycho Nightingale break; 769bf21cd93STycho Nightingale case CRTC_MAX_SCAN_LINE: 770bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_max_scan_line; 771bf21cd93STycho Nightingale break; 772bf21cd93STycho Nightingale case CRTC_CURSOR_START: 773bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_cursor_start; 774bf21cd93STycho Nightingale break; 775bf21cd93STycho Nightingale case CRTC_CURSOR_END: 776bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_cursor_end; 777bf21cd93STycho Nightingale break; 778bf21cd93STycho Nightingale case CRTC_START_ADDR_HIGH: 779bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_start_addr_high; 780bf21cd93STycho Nightingale break; 781bf21cd93STycho Nightingale case CRTC_START_ADDR_LOW: 782bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_start_addr_low; 783bf21cd93STycho Nightingale break; 784bf21cd93STycho Nightingale case CRTC_CURSOR_LOC_HIGH: 785bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_cursor_loc_high; 786bf21cd93STycho Nightingale break; 787bf21cd93STycho Nightingale case CRTC_CURSOR_LOC_LOW: 788bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_cursor_loc_low; 789bf21cd93STycho Nightingale break; 790bf21cd93STycho Nightingale case CRTC_VERT_RETRACE_START: 791bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_vert_retrace_start; 792bf21cd93STycho Nightingale break; 793bf21cd93STycho Nightingale case CRTC_VERT_RETRACE_END: 794bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_vert_retrace_end; 795bf21cd93STycho Nightingale break; 796bf21cd93STycho Nightingale case CRTC_VERT_DISP_END: 797bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_vert_disp_end; 798bf21cd93STycho Nightingale break; 799bf21cd93STycho Nightingale case CRTC_OFFSET: 800bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_offset; 801bf21cd93STycho Nightingale break; 802bf21cd93STycho Nightingale case CRTC_UNDERLINE_LOC: 803bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_underline_loc; 804bf21cd93STycho Nightingale break; 805bf21cd93STycho Nightingale case CRTC_START_VERT_BLANK: 806bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_start_vert_blank; 807bf21cd93STycho Nightingale break; 808bf21cd93STycho Nightingale case CRTC_END_VERT_BLANK: 809bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_end_vert_blank; 810bf21cd93STycho Nightingale break; 811bf21cd93STycho Nightingale case CRTC_MODE_CONTROL: 812bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_mode_ctrl; 813bf21cd93STycho Nightingale break; 814bf21cd93STycho Nightingale case CRTC_LINE_COMPARE: 815bf21cd93STycho Nightingale *val = sc->vga_crtc.crtc_line_compare; 816bf21cd93STycho Nightingale break; 817bf21cd93STycho Nightingale default: 818bf21cd93STycho Nightingale //printf("XXX VGA CRTC: inb 0x%04x at index %d\n", port, sc->vga_crtc.crtc_index); 819bf21cd93STycho Nightingale assert(0); 820bf21cd93STycho Nightingale break; 821bf21cd93STycho Nightingale } 822bf21cd93STycho Nightingale break; 823bf21cd93STycho Nightingale case ATC_IDX_PORT: 824bf21cd93STycho Nightingale *val = sc->vga_atc.atc_index; 825bf21cd93STycho Nightingale break; 826bf21cd93STycho Nightingale case ATC_DATA_PORT: 827bf21cd93STycho Nightingale switch (sc->vga_atc.atc_index) { 828bf21cd93STycho Nightingale case ATC_PALETTE0 ... ATC_PALETTE15: 829bf21cd93STycho Nightingale *val = sc->vga_atc.atc_palette[sc->vga_atc.atc_index]; 830bf21cd93STycho Nightingale break; 831bf21cd93STycho Nightingale case ATC_MODE_CONTROL: 832bf21cd93STycho Nightingale *val = sc->vga_atc.atc_mode; 833bf21cd93STycho Nightingale break; 834bf21cd93STycho Nightingale case ATC_OVERSCAN_COLOR: 835bf21cd93STycho Nightingale *val = sc->vga_atc.atc_overscan_color; 836bf21cd93STycho Nightingale break; 837bf21cd93STycho Nightingale case ATC_COLOR_PLANE_ENABLE: 838bf21cd93STycho Nightingale *val = sc->vga_atc.atc_color_plane_enb; 839bf21cd93STycho Nightingale break; 840bf21cd93STycho Nightingale case ATC_HORIZ_PIXEL_PANNING: 841bf21cd93STycho Nightingale *val = sc->vga_atc.atc_horiz_pixel_panning; 842bf21cd93STycho Nightingale break; 843bf21cd93STycho Nightingale case ATC_COLOR_SELECT: 844bf21cd93STycho Nightingale *val = sc->vga_atc.atc_color_select; 845bf21cd93STycho Nightingale break; 846bf21cd93STycho Nightingale default: 847bf21cd93STycho Nightingale //printf("XXX VGA ATC inb 0x%04x at index %d\n", port , sc->vga_atc.atc_index); 848bf21cd93STycho Nightingale assert(0); 849bf21cd93STycho Nightingale break; 850bf21cd93STycho Nightingale } 851bf21cd93STycho Nightingale break; 852bf21cd93STycho Nightingale case SEQ_IDX_PORT: 853bf21cd93STycho Nightingale *val = sc->vga_seq.seq_index; 854bf21cd93STycho Nightingale break; 855bf21cd93STycho Nightingale case SEQ_DATA_PORT: 856bf21cd93STycho Nightingale switch (sc->vga_seq.seq_index) { 857bf21cd93STycho Nightingale case SEQ_RESET: 858bf21cd93STycho Nightingale *val = sc->vga_seq.seq_reset; 859bf21cd93STycho Nightingale break; 860bf21cd93STycho Nightingale case SEQ_CLOCKING_MODE: 861bf21cd93STycho Nightingale *val = sc->vga_seq.seq_clock_mode; 862bf21cd93STycho Nightingale break; 863bf21cd93STycho Nightingale case SEQ_MAP_MASK: 864bf21cd93STycho Nightingale *val = sc->vga_seq.seq_map_mask; 865bf21cd93STycho Nightingale break; 866bf21cd93STycho Nightingale case SEQ_CHAR_MAP_SELECT: 867bf21cd93STycho Nightingale *val = sc->vga_seq.seq_cmap_sel; 868bf21cd93STycho Nightingale break; 869bf21cd93STycho Nightingale case SEQ_MEMORY_MODE: 870bf21cd93STycho Nightingale *val = sc->vga_seq.seq_mm; 871bf21cd93STycho Nightingale break; 872bf21cd93STycho Nightingale default: 873bf21cd93STycho Nightingale //printf("XXX VGA SEQ: inb 0x%04x at index %d\n", port, sc->vga_seq.seq_index); 874bf21cd93STycho Nightingale assert(0); 875bf21cd93STycho Nightingale break; 876bf21cd93STycho Nightingale } 8774c87aefeSPatrick Mooney break; 878bf21cd93STycho Nightingale case DAC_DATA_PORT: 879bf21cd93STycho Nightingale *val = sc->vga_dac.dac_palette[3 * sc->vga_dac.dac_rd_index + 880bf21cd93STycho Nightingale sc->vga_dac.dac_rd_subindex]; 881bf21cd93STycho Nightingale sc->vga_dac.dac_rd_subindex++; 882bf21cd93STycho Nightingale if (sc->vga_dac.dac_rd_subindex == 3) { 883bf21cd93STycho Nightingale sc->vga_dac.dac_rd_index++; 884bf21cd93STycho Nightingale sc->vga_dac.dac_rd_subindex = 0; 885bf21cd93STycho Nightingale } 886bf21cd93STycho Nightingale break; 887bf21cd93STycho Nightingale case GC_IDX_PORT: 888bf21cd93STycho Nightingale *val = sc->vga_gc.gc_index; 889bf21cd93STycho Nightingale break; 890bf21cd93STycho Nightingale case GC_DATA_PORT: 891bf21cd93STycho Nightingale switch (sc->vga_gc.gc_index) { 892bf21cd93STycho Nightingale case GC_SET_RESET: 893bf21cd93STycho Nightingale *val = sc->vga_gc.gc_set_reset; 894bf21cd93STycho Nightingale break; 895bf21cd93STycho Nightingale case GC_ENABLE_SET_RESET: 896bf21cd93STycho Nightingale *val = sc->vga_gc.gc_enb_set_reset; 897bf21cd93STycho Nightingale break; 898bf21cd93STycho Nightingale case GC_COLOR_COMPARE: 899bf21cd93STycho Nightingale *val = sc->vga_gc.gc_color_compare; 900bf21cd93STycho Nightingale break; 901bf21cd93STycho Nightingale case GC_DATA_ROTATE: 902bf21cd93STycho Nightingale *val = sc->vga_gc.gc_rotate; 903bf21cd93STycho Nightingale break; 904bf21cd93STycho Nightingale case GC_READ_MAP_SELECT: 905bf21cd93STycho Nightingale *val = sc->vga_gc.gc_read_map_sel; 906bf21cd93STycho Nightingale break; 907bf21cd93STycho Nightingale case GC_MODE: 908bf21cd93STycho Nightingale *val = sc->vga_gc.gc_mode; 909bf21cd93STycho Nightingale break; 910bf21cd93STycho Nightingale case GC_MISCELLANEOUS: 911bf21cd93STycho Nightingale *val = sc->vga_gc.gc_misc; 912bf21cd93STycho Nightingale break; 913bf21cd93STycho Nightingale case GC_COLOR_DONT_CARE: 914bf21cd93STycho Nightingale *val = sc->vga_gc.gc_color_dont_care; 915bf21cd93STycho Nightingale break; 916bf21cd93STycho Nightingale case GC_BIT_MASK: 917bf21cd93STycho Nightingale *val = sc->vga_gc.gc_bit_mask; 918bf21cd93STycho Nightingale break; 919bf21cd93STycho Nightingale default: 920bf21cd93STycho Nightingale //printf("XXX VGA GC: inb 0x%04x at index %d\n", port, sc->vga_crtc.crtc_index); 921bf21cd93STycho Nightingale assert(0); 922bf21cd93STycho Nightingale break; 923bf21cd93STycho Nightingale } 924bf21cd93STycho Nightingale break; 925bf21cd93STycho Nightingale case GEN_MISC_OUTPUT_PORT: 926bf21cd93STycho Nightingale *val = sc->vga_misc; 927bf21cd93STycho Nightingale break; 928bf21cd93STycho Nightingale case GEN_INPUT_STS0_PORT: 929bf21cd93STycho Nightingale assert(0); 930bf21cd93STycho Nightingale break; 931bf21cd93STycho Nightingale case GEN_INPUT_STS1_MONO_PORT: 932bf21cd93STycho Nightingale case GEN_INPUT_STS1_COLOR_PORT: 933bf21cd93STycho Nightingale sc->vga_atc.atc_flipflop = 0; 9344c87aefeSPatrick Mooney #ifdef __FreeBSD__ 9354c87aefeSPatrick Mooney sc->vga_sts1 = GEN_IS1_VR | GEN_IS1_DE; 9364c87aefeSPatrick Mooney //sc->vga_sts1 ^= (GEN_IS1_VR | GEN_IS1_DE); 9374c87aefeSPatrick Mooney #else 9384c87aefeSPatrick Mooney /* 9394c87aefeSPatrick Mooney * During the bhyve bring-up process, a guest image was failing 9404c87aefeSPatrick Mooney * to successfully boot. It appeared to be spinning, waiting 9414c87aefeSPatrick Mooney * for this value to be toggled. Until it can be ruled out 9424c87aefeSPatrick Mooney * that this is unnecessary (and documentation seems to 9434c87aefeSPatrick Mooney * indicate that it should be present), the toggle should 9444c87aefeSPatrick Mooney * remain. 9454c87aefeSPatrick Mooney */ 946bf21cd93STycho Nightingale sc->vga_sts1 ^= (GEN_IS1_VR | GEN_IS1_DE); 9474c87aefeSPatrick Mooney #endif 948bf21cd93STycho Nightingale *val = sc->vga_sts1; 949bf21cd93STycho Nightingale break; 950bf21cd93STycho Nightingale case GEN_FEATURE_CTRL_PORT: 9514c87aefeSPatrick Mooney // OpenBSD calls this with bytes = 1 9524c87aefeSPatrick Mooney //assert(0); 9534c87aefeSPatrick Mooney *val = 0; 9544c87aefeSPatrick Mooney break; 9554c87aefeSPatrick Mooney case 0x3c3: 9564c87aefeSPatrick Mooney *val = 0; 957bf21cd93STycho Nightingale break; 958bf21cd93STycho Nightingale default: 959bf21cd93STycho Nightingale printf("XXX vga_port_in_handler() unhandled port 0x%x\n", port); 9604c87aefeSPatrick Mooney //assert(0); 961bf21cd93STycho Nightingale return (-1); 962bf21cd93STycho Nightingale } 963bf21cd93STycho Nightingale 964bf21cd93STycho Nightingale return (0); 965bf21cd93STycho Nightingale } 966bf21cd93STycho Nightingale 967bf21cd93STycho Nightingale static int 968bf21cd93STycho Nightingale vga_port_out_handler(struct vmctx *ctx, int in, int port, int bytes, 969bf21cd93STycho Nightingale uint8_t val, void *arg) 970bf21cd93STycho Nightingale { 971bf21cd93STycho Nightingale struct vga_softc *sc = arg; 972bf21cd93STycho Nightingale 973bf21cd93STycho Nightingale switch (port) { 974bf21cd93STycho Nightingale case CRTC_IDX_MONO_PORT: 975bf21cd93STycho Nightingale case CRTC_IDX_COLOR_PORT: 976bf21cd93STycho Nightingale sc->vga_crtc.crtc_index = val; 977bf21cd93STycho Nightingale break; 978bf21cd93STycho Nightingale case CRTC_DATA_MONO_PORT: 979bf21cd93STycho Nightingale case CRTC_DATA_COLOR_PORT: 980bf21cd93STycho Nightingale switch (sc->vga_crtc.crtc_index) { 981bf21cd93STycho Nightingale case CRTC_HORIZ_TOTAL: 982bf21cd93STycho Nightingale sc->vga_crtc.crtc_horiz_total = val; 983bf21cd93STycho Nightingale break; 984bf21cd93STycho Nightingale case CRTC_HORIZ_DISP_END: 985bf21cd93STycho Nightingale sc->vga_crtc.crtc_horiz_disp_end = val; 986bf21cd93STycho Nightingale break; 987bf21cd93STycho Nightingale case CRTC_START_HORIZ_BLANK: 988bf21cd93STycho Nightingale sc->vga_crtc.crtc_start_horiz_blank = val; 989bf21cd93STycho Nightingale break; 990bf21cd93STycho Nightingale case CRTC_END_HORIZ_BLANK: 991bf21cd93STycho Nightingale sc->vga_crtc.crtc_end_horiz_blank = val; 992bf21cd93STycho Nightingale break; 993bf21cd93STycho Nightingale case CRTC_START_HORIZ_RETRACE: 994bf21cd93STycho Nightingale sc->vga_crtc.crtc_start_horiz_retrace = val; 995bf21cd93STycho Nightingale break; 996bf21cd93STycho Nightingale case CRTC_END_HORIZ_RETRACE: 997bf21cd93STycho Nightingale sc->vga_crtc.crtc_end_horiz_retrace = val; 998bf21cd93STycho Nightingale break; 999bf21cd93STycho Nightingale case CRTC_VERT_TOTAL: 1000bf21cd93STycho Nightingale sc->vga_crtc.crtc_vert_total = val; 1001bf21cd93STycho Nightingale break; 1002bf21cd93STycho Nightingale case CRTC_OVERFLOW: 1003bf21cd93STycho Nightingale sc->vga_crtc.crtc_overflow = val; 1004bf21cd93STycho Nightingale break; 1005bf21cd93STycho Nightingale case CRTC_PRESET_ROW_SCAN: 1006bf21cd93STycho Nightingale sc->vga_crtc.crtc_present_row_scan = val; 1007bf21cd93STycho Nightingale break; 1008bf21cd93STycho Nightingale case CRTC_MAX_SCAN_LINE: 1009bf21cd93STycho Nightingale sc->vga_crtc.crtc_max_scan_line = val; 1010bf21cd93STycho Nightingale break; 1011bf21cd93STycho Nightingale case CRTC_CURSOR_START: 1012bf21cd93STycho Nightingale sc->vga_crtc.crtc_cursor_start = val; 1013bf21cd93STycho Nightingale sc->vga_crtc.crtc_cursor_on = (val & CRTC_CS_CO) == 0; 1014bf21cd93STycho Nightingale break; 1015bf21cd93STycho Nightingale case CRTC_CURSOR_END: 1016bf21cd93STycho Nightingale sc->vga_crtc.crtc_cursor_end = val; 1017bf21cd93STycho Nightingale break; 1018bf21cd93STycho Nightingale case CRTC_START_ADDR_HIGH: 1019bf21cd93STycho Nightingale sc->vga_crtc.crtc_start_addr_high = val; 1020bf21cd93STycho Nightingale sc->vga_crtc.crtc_start_addr &= 0x00ff; 1021bf21cd93STycho Nightingale sc->vga_crtc.crtc_start_addr |= (val << 8); 1022bf21cd93STycho Nightingale break; 1023bf21cd93STycho Nightingale case CRTC_START_ADDR_LOW: 1024bf21cd93STycho Nightingale sc->vga_crtc.crtc_start_addr_low = val; 1025bf21cd93STycho Nightingale sc->vga_crtc.crtc_start_addr &= 0xff00; 1026bf21cd93STycho Nightingale sc->vga_crtc.crtc_start_addr |= (val & 0xff); 1027bf21cd93STycho Nightingale break; 1028bf21cd93STycho Nightingale case CRTC_CURSOR_LOC_HIGH: 1029bf21cd93STycho Nightingale sc->vga_crtc.crtc_cursor_loc_high = val; 1030bf21cd93STycho Nightingale sc->vga_crtc.crtc_cursor_loc &= 0x00ff; 1031bf21cd93STycho Nightingale sc->vga_crtc.crtc_cursor_loc |= (val << 8); 1032bf21cd93STycho Nightingale break; 1033bf21cd93STycho Nightingale case CRTC_CURSOR_LOC_LOW: 1034bf21cd93STycho Nightingale sc->vga_crtc.crtc_cursor_loc_low = val; 1035bf21cd93STycho Nightingale sc->vga_crtc.crtc_cursor_loc &= 0xff00; 1036bf21cd93STycho Nightingale sc->vga_crtc.crtc_cursor_loc |= (val & 0xff); 1037bf21cd93STycho Nightingale break; 1038bf21cd93STycho Nightingale case CRTC_VERT_RETRACE_START: 1039bf21cd93STycho Nightingale sc->vga_crtc.crtc_vert_retrace_start = val; 1040bf21cd93STycho Nightingale break; 1041bf21cd93STycho Nightingale case CRTC_VERT_RETRACE_END: 1042bf21cd93STycho Nightingale sc->vga_crtc.crtc_vert_retrace_end = val; 1043bf21cd93STycho Nightingale break; 1044bf21cd93STycho Nightingale case CRTC_VERT_DISP_END: 1045bf21cd93STycho Nightingale sc->vga_crtc.crtc_vert_disp_end = val; 1046bf21cd93STycho Nightingale break; 1047bf21cd93STycho Nightingale case CRTC_OFFSET: 1048bf21cd93STycho Nightingale sc->vga_crtc.crtc_offset = val; 1049bf21cd93STycho Nightingale break; 1050bf21cd93STycho Nightingale case CRTC_UNDERLINE_LOC: 1051bf21cd93STycho Nightingale sc->vga_crtc.crtc_underline_loc = val; 1052bf21cd93STycho Nightingale break; 1053bf21cd93STycho Nightingale case CRTC_START_VERT_BLANK: 1054bf21cd93STycho Nightingale sc->vga_crtc.crtc_start_vert_blank = val; 1055bf21cd93STycho Nightingale break; 1056bf21cd93STycho Nightingale case CRTC_END_VERT_BLANK: 1057bf21cd93STycho Nightingale sc->vga_crtc.crtc_end_vert_blank = val; 1058bf21cd93STycho Nightingale break; 1059bf21cd93STycho Nightingale case CRTC_MODE_CONTROL: 1060bf21cd93STycho Nightingale sc->vga_crtc.crtc_mode_ctrl = val; 1061bf21cd93STycho Nightingale break; 1062bf21cd93STycho Nightingale case CRTC_LINE_COMPARE: 1063bf21cd93STycho Nightingale sc->vga_crtc.crtc_line_compare = val; 1064bf21cd93STycho Nightingale break; 1065bf21cd93STycho Nightingale default: 1066bf21cd93STycho Nightingale //printf("XXX VGA CRTC: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_crtc.crtc_index); 1067bf21cd93STycho Nightingale assert(0); 1068bf21cd93STycho Nightingale break; 1069bf21cd93STycho Nightingale } 1070bf21cd93STycho Nightingale break; 1071bf21cd93STycho Nightingale case ATC_IDX_PORT: 1072bf21cd93STycho Nightingale if (sc->vga_atc.atc_flipflop == 0) { 1073bf21cd93STycho Nightingale if (sc->vga_atc.atc_index & 0x20) 1074bf21cd93STycho Nightingale assert(0); 1075bf21cd93STycho Nightingale sc->vga_atc.atc_index = val & ATC_IDX_MASK; 1076bf21cd93STycho Nightingale } else { 1077bf21cd93STycho Nightingale switch (sc->vga_atc.atc_index) { 1078bf21cd93STycho Nightingale case ATC_PALETTE0 ... ATC_PALETTE15: 1079bf21cd93STycho Nightingale sc->vga_atc.atc_palette[sc->vga_atc.atc_index] = val & 0x3f; 1080bf21cd93STycho Nightingale break; 1081bf21cd93STycho Nightingale case ATC_MODE_CONTROL: 1082bf21cd93STycho Nightingale sc->vga_atc.atc_mode = val; 1083bf21cd93STycho Nightingale break; 1084bf21cd93STycho Nightingale case ATC_OVERSCAN_COLOR: 1085bf21cd93STycho Nightingale sc->vga_atc.atc_overscan_color = val; 1086bf21cd93STycho Nightingale break; 1087bf21cd93STycho Nightingale case ATC_COLOR_PLANE_ENABLE: 1088bf21cd93STycho Nightingale sc->vga_atc.atc_color_plane_enb = val; 1089bf21cd93STycho Nightingale break; 1090bf21cd93STycho Nightingale case ATC_HORIZ_PIXEL_PANNING: 1091bf21cd93STycho Nightingale sc->vga_atc.atc_horiz_pixel_panning = val; 1092bf21cd93STycho Nightingale break; 1093bf21cd93STycho Nightingale case ATC_COLOR_SELECT: 1094bf21cd93STycho Nightingale sc->vga_atc.atc_color_select = val; 1095bf21cd93STycho Nightingale sc->vga_atc.atc_color_select_45 = 1096bf21cd93STycho Nightingale (val & ATC_CS_C45) << 4; 1097bf21cd93STycho Nightingale sc->vga_atc.atc_color_select_67 = 10984c87aefeSPatrick Mooney ((val & ATC_CS_C67) >> 2) << 6; 1099bf21cd93STycho Nightingale break; 1100bf21cd93STycho Nightingale default: 1101bf21cd93STycho Nightingale //printf("XXX VGA ATC: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_atc.atc_index); 1102bf21cd93STycho Nightingale assert(0); 1103bf21cd93STycho Nightingale break; 1104bf21cd93STycho Nightingale } 1105bf21cd93STycho Nightingale } 1106bf21cd93STycho Nightingale sc->vga_atc.atc_flipflop ^= 1; 1107bf21cd93STycho Nightingale break; 1108bf21cd93STycho Nightingale case ATC_DATA_PORT: 1109bf21cd93STycho Nightingale break; 1110bf21cd93STycho Nightingale case SEQ_IDX_PORT: 1111bf21cd93STycho Nightingale sc->vga_seq.seq_index = val & 0x1f; 1112bf21cd93STycho Nightingale break; 1113bf21cd93STycho Nightingale case SEQ_DATA_PORT: 1114bf21cd93STycho Nightingale switch (sc->vga_seq.seq_index) { 1115bf21cd93STycho Nightingale case SEQ_RESET: 1116bf21cd93STycho Nightingale sc->vga_seq.seq_reset = val; 1117bf21cd93STycho Nightingale break; 1118bf21cd93STycho Nightingale case SEQ_CLOCKING_MODE: 1119bf21cd93STycho Nightingale sc->vga_seq.seq_clock_mode = val; 1120bf21cd93STycho Nightingale sc->vga_seq.seq_cm_dots = (val & SEQ_CM_89) ? 8 : 9; 1121bf21cd93STycho Nightingale break; 1122bf21cd93STycho Nightingale case SEQ_MAP_MASK: 1123bf21cd93STycho Nightingale sc->vga_seq.seq_map_mask = val; 1124bf21cd93STycho Nightingale break; 1125bf21cd93STycho Nightingale case SEQ_CHAR_MAP_SELECT: 1126bf21cd93STycho Nightingale sc->vga_seq.seq_cmap_sel = val; 1127bf21cd93STycho Nightingale 1128bf21cd93STycho Nightingale sc->vga_seq.seq_cmap_pri_off = ((((val & SEQ_CMS_SA) >> SEQ_CMS_SA_SHIFT) * 2) + ((val & SEQ_CMS_SAH) >> SEQ_CMS_SAH_SHIFT)) * 8 * KB; 1129bf21cd93STycho Nightingale sc->vga_seq.seq_cmap_sec_off = ((((val & SEQ_CMS_SB) >> SEQ_CMS_SB_SHIFT) * 2) + ((val & SEQ_CMS_SBH) >> SEQ_CMS_SBH_SHIFT)) * 8 * KB; 1130bf21cd93STycho Nightingale break; 1131bf21cd93STycho Nightingale case SEQ_MEMORY_MODE: 1132bf21cd93STycho Nightingale sc->vga_seq.seq_mm = val; 11334c87aefeSPatrick Mooney /* Windows queries Chain4 */ 11344c87aefeSPatrick Mooney //assert((sc->vga_seq.seq_mm & SEQ_MM_C4) == 0); 1135bf21cd93STycho Nightingale break; 1136bf21cd93STycho Nightingale default: 1137bf21cd93STycho Nightingale //printf("XXX VGA SEQ: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_seq.seq_index); 1138bf21cd93STycho Nightingale assert(0); 1139bf21cd93STycho Nightingale break; 1140bf21cd93STycho Nightingale } 1141bf21cd93STycho Nightingale break; 1142bf21cd93STycho Nightingale case DAC_MASK: 1143bf21cd93STycho Nightingale break; 1144bf21cd93STycho Nightingale case DAC_IDX_RD_PORT: 1145bf21cd93STycho Nightingale sc->vga_dac.dac_rd_index = val; 1146bf21cd93STycho Nightingale sc->vga_dac.dac_rd_subindex = 0; 1147bf21cd93STycho Nightingale break; 1148bf21cd93STycho Nightingale case DAC_IDX_WR_PORT: 1149bf21cd93STycho Nightingale sc->vga_dac.dac_wr_index = val; 1150bf21cd93STycho Nightingale sc->vga_dac.dac_wr_subindex = 0; 1151bf21cd93STycho Nightingale break; 1152bf21cd93STycho Nightingale case DAC_DATA_PORT: 1153bf21cd93STycho Nightingale sc->vga_dac.dac_palette[3 * sc->vga_dac.dac_wr_index + 1154bf21cd93STycho Nightingale sc->vga_dac.dac_wr_subindex] = val; 1155bf21cd93STycho Nightingale sc->vga_dac.dac_wr_subindex++; 1156bf21cd93STycho Nightingale if (sc->vga_dac.dac_wr_subindex == 3) { 1157bf21cd93STycho Nightingale sc->vga_dac.dac_palette_rgb[sc->vga_dac.dac_wr_index] = 1158bf21cd93STycho Nightingale ((((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 0] << 2) | 1159bf21cd93STycho Nightingale ((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 0] & 0x1) << 1) | 1160bf21cd93STycho Nightingale (sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 0] & 0x1)) << 16) | 1161bf21cd93STycho Nightingale (((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 1] << 2) | 1162bf21cd93STycho Nightingale ((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 1] & 0x1) << 1) | 1163bf21cd93STycho Nightingale (sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 1] & 0x1)) << 8) | 1164bf21cd93STycho Nightingale (((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 2] << 2) | 1165bf21cd93STycho Nightingale ((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 2] & 0x1) << 1) | 1166bf21cd93STycho Nightingale (sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 2] & 0x1)) << 0)); 1167bf21cd93STycho Nightingale 1168bf21cd93STycho Nightingale sc->vga_dac.dac_wr_index++; 1169bf21cd93STycho Nightingale sc->vga_dac.dac_wr_subindex = 0; 1170bf21cd93STycho Nightingale } 1171bf21cd93STycho Nightingale break; 1172bf21cd93STycho Nightingale case GC_IDX_PORT: 1173bf21cd93STycho Nightingale sc->vga_gc.gc_index = val; 1174bf21cd93STycho Nightingale break; 1175bf21cd93STycho Nightingale case GC_DATA_PORT: 1176bf21cd93STycho Nightingale switch (sc->vga_gc.gc_index) { 1177bf21cd93STycho Nightingale case GC_SET_RESET: 1178bf21cd93STycho Nightingale sc->vga_gc.gc_set_reset = val; 1179bf21cd93STycho Nightingale break; 1180bf21cd93STycho Nightingale case GC_ENABLE_SET_RESET: 1181bf21cd93STycho Nightingale sc->vga_gc.gc_enb_set_reset = val; 1182bf21cd93STycho Nightingale break; 1183bf21cd93STycho Nightingale case GC_COLOR_COMPARE: 1184bf21cd93STycho Nightingale sc->vga_gc.gc_color_compare = val; 1185bf21cd93STycho Nightingale break; 1186bf21cd93STycho Nightingale case GC_DATA_ROTATE: 1187bf21cd93STycho Nightingale sc->vga_gc.gc_rotate = val; 1188bf21cd93STycho Nightingale sc->vga_gc.gc_op = (val >> 3) & 0x3; 1189bf21cd93STycho Nightingale break; 1190bf21cd93STycho Nightingale case GC_READ_MAP_SELECT: 1191bf21cd93STycho Nightingale sc->vga_gc.gc_read_map_sel = val; 1192bf21cd93STycho Nightingale break; 1193bf21cd93STycho Nightingale case GC_MODE: 1194bf21cd93STycho Nightingale sc->vga_gc.gc_mode = val; 1195bf21cd93STycho Nightingale sc->vga_gc.gc_mode_c4 = (val & GC_MODE_C4) != 0; 1196bf21cd93STycho Nightingale assert(!sc->vga_gc.gc_mode_c4); 1197bf21cd93STycho Nightingale sc->vga_gc.gc_mode_oe = (val & GC_MODE_OE) != 0; 1198bf21cd93STycho Nightingale sc->vga_gc.gc_mode_rm = (val >> 3) & 0x1; 1199bf21cd93STycho Nightingale sc->vga_gc.gc_mode_wm = val & 0x3; 12004c87aefeSPatrick Mooney 12014c87aefeSPatrick Mooney if (sc->gc_image) 12024c87aefeSPatrick Mooney sc->gc_image->vgamode = 1; 1203bf21cd93STycho Nightingale break; 1204bf21cd93STycho Nightingale case GC_MISCELLANEOUS: 1205bf21cd93STycho Nightingale sc->vga_gc.gc_misc = val; 1206bf21cd93STycho Nightingale sc->vga_gc.gc_misc_gm = val & GC_MISC_GM; 1207bf21cd93STycho Nightingale sc->vga_gc.gc_misc_mm = (val & GC_MISC_MM) >> 1208bf21cd93STycho Nightingale GC_MISC_MM_SHIFT; 1209bf21cd93STycho Nightingale break; 1210bf21cd93STycho Nightingale case GC_COLOR_DONT_CARE: 1211bf21cd93STycho Nightingale sc->vga_gc.gc_color_dont_care = val; 1212bf21cd93STycho Nightingale break; 1213bf21cd93STycho Nightingale case GC_BIT_MASK: 1214bf21cd93STycho Nightingale sc->vga_gc.gc_bit_mask = val; 1215bf21cd93STycho Nightingale break; 1216bf21cd93STycho Nightingale default: 1217bf21cd93STycho Nightingale //printf("XXX VGA GC: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_gc.gc_index); 1218bf21cd93STycho Nightingale assert(0); 1219bf21cd93STycho Nightingale break; 1220bf21cd93STycho Nightingale } 1221bf21cd93STycho Nightingale break; 1222bf21cd93STycho Nightingale case GEN_INPUT_STS0_PORT: 1223bf21cd93STycho Nightingale /* write to Miscellaneous Output Register */ 1224bf21cd93STycho Nightingale sc->vga_misc = val; 1225bf21cd93STycho Nightingale break; 1226bf21cd93STycho Nightingale case GEN_INPUT_STS1_MONO_PORT: 1227bf21cd93STycho Nightingale case GEN_INPUT_STS1_COLOR_PORT: 1228bf21cd93STycho Nightingale /* write to Feature Control Register */ 1229bf21cd93STycho Nightingale break; 12304c87aefeSPatrick Mooney // case 0x3c3: 12314c87aefeSPatrick Mooney // break; 1232bf21cd93STycho Nightingale default: 12334c87aefeSPatrick Mooney printf("XXX vga_port_out_handler() unhandled port 0x%x, val 0x%x\n", port, val); 1234bf21cd93STycho Nightingale //assert(0); 1235bf21cd93STycho Nightingale return (-1); 1236bf21cd93STycho Nightingale } 1237bf21cd93STycho Nightingale return (0); 1238bf21cd93STycho Nightingale } 1239bf21cd93STycho Nightingale 1240bf21cd93STycho Nightingale static int 1241*59d65d31SAndy Fiddaman vga_port_handler(struct vmctx *ctx, int in, int port, 1242*59d65d31SAndy Fiddaman int bytes, uint32_t *eax, void *arg) 1243bf21cd93STycho Nightingale { 1244bf21cd93STycho Nightingale uint8_t val; 1245bf21cd93STycho Nightingale int error; 1246bf21cd93STycho Nightingale 1247bf21cd93STycho Nightingale switch (bytes) { 1248bf21cd93STycho Nightingale case 1: 1249bf21cd93STycho Nightingale if (in) { 1250bf21cd93STycho Nightingale *eax &= ~0xff; 1251bf21cd93STycho Nightingale error = vga_port_in_handler(ctx, in, port, 1, 1252bf21cd93STycho Nightingale &val, arg); 1253bf21cd93STycho Nightingale if (!error) { 1254bf21cd93STycho Nightingale *eax |= val & 0xff; 1255bf21cd93STycho Nightingale } 1256bf21cd93STycho Nightingale } else { 1257bf21cd93STycho Nightingale val = *eax & 0xff; 1258bf21cd93STycho Nightingale error = vga_port_out_handler(ctx, in, port, 1, 1259bf21cd93STycho Nightingale val, arg); 1260bf21cd93STycho Nightingale } 1261bf21cd93STycho Nightingale break; 1262bf21cd93STycho Nightingale case 2: 1263bf21cd93STycho Nightingale if (in) { 1264bf21cd93STycho Nightingale *eax &= ~0xffff; 1265bf21cd93STycho Nightingale error = vga_port_in_handler(ctx, in, port, 1, 1266bf21cd93STycho Nightingale &val, arg); 1267bf21cd93STycho Nightingale if (!error) { 1268bf21cd93STycho Nightingale *eax |= val & 0xff; 1269bf21cd93STycho Nightingale } 1270bf21cd93STycho Nightingale error = vga_port_in_handler(ctx, in, port + 1, 1, 1271bf21cd93STycho Nightingale &val, arg); 1272bf21cd93STycho Nightingale if (!error) { 1273bf21cd93STycho Nightingale *eax |= (val & 0xff) << 8; 1274bf21cd93STycho Nightingale } 1275bf21cd93STycho Nightingale } else { 1276bf21cd93STycho Nightingale val = *eax & 0xff; 1277bf21cd93STycho Nightingale error = vga_port_out_handler(ctx, in, port, 1, 1278bf21cd93STycho Nightingale val, arg); 1279bf21cd93STycho Nightingale val = (*eax >> 8) & 0xff; 1280bf21cd93STycho Nightingale error =vga_port_out_handler(ctx, in, port + 1, 1, 1281bf21cd93STycho Nightingale val, arg); 1282bf21cd93STycho Nightingale } 1283bf21cd93STycho Nightingale break; 1284bf21cd93STycho Nightingale default: 1285bf21cd93STycho Nightingale assert(0); 1286bf21cd93STycho Nightingale return (-1); 1287bf21cd93STycho Nightingale } 1288bf21cd93STycho Nightingale 1289bf21cd93STycho Nightingale return (error); 1290bf21cd93STycho Nightingale } 1291bf21cd93STycho Nightingale 12924c87aefeSPatrick Mooney void * 12934c87aefeSPatrick Mooney vga_init(int io_only) 1294bf21cd93STycho Nightingale { 1295bf21cd93STycho Nightingale struct inout_port iop; 1296bf21cd93STycho Nightingale struct vga_softc *sc; 1297bf21cd93STycho Nightingale int port, error; 1298bf21cd93STycho Nightingale 1299bf21cd93STycho Nightingale sc = calloc(1, sizeof(struct vga_softc)); 1300bf21cd93STycho Nightingale 1301bf21cd93STycho Nightingale bzero(&iop, sizeof(struct inout_port)); 1302bf21cd93STycho Nightingale iop.name = "VGA"; 1303bf21cd93STycho Nightingale for (port = VGA_IOPORT_START; port <= VGA_IOPORT_END; port++) { 1304bf21cd93STycho Nightingale iop.port = port; 1305bf21cd93STycho Nightingale iop.size = 1; 1306bf21cd93STycho Nightingale iop.flags = IOPORT_F_INOUT; 1307bf21cd93STycho Nightingale iop.handler = vga_port_handler; 1308bf21cd93STycho Nightingale iop.arg = sc; 1309bf21cd93STycho Nightingale 1310bf21cd93STycho Nightingale error = register_inout(&iop); 1311bf21cd93STycho Nightingale assert(error == 0); 1312bf21cd93STycho Nightingale } 1313bf21cd93STycho Nightingale 13144c87aefeSPatrick Mooney sc->gc_image = console_get_image(); 13154c87aefeSPatrick Mooney 13164c87aefeSPatrick Mooney /* only handle io ports; vga graphics is disabled */ 13174c87aefeSPatrick Mooney if (io_only) 13184c87aefeSPatrick Mooney return(sc); 13194c87aefeSPatrick Mooney 1320bf21cd93STycho Nightingale sc->mr.name = "VGA memory"; 1321bf21cd93STycho Nightingale sc->mr.flags = MEM_F_RW; 1322bf21cd93STycho Nightingale sc->mr.base = 640 * KB; 1323bf21cd93STycho Nightingale sc->mr.size = 128 * KB; 1324bf21cd93STycho Nightingale sc->mr.handler = vga_mem_handler; 1325bf21cd93STycho Nightingale sc->mr.arg1 = sc; 1326bf21cd93STycho Nightingale error = register_mem_fallback(&sc->mr); 1327bf21cd93STycho Nightingale assert(error == 0); 1328bf21cd93STycho Nightingale 1329bf21cd93STycho Nightingale sc->vga_ram = malloc(256 * KB); 1330bf21cd93STycho Nightingale memset(sc->vga_ram, 0, 256 * KB); 1331bf21cd93STycho Nightingale 13324c87aefeSPatrick Mooney { 13334c87aefeSPatrick Mooney static uint8_t palette[] = { 13344c87aefeSPatrick Mooney 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 13354c87aefeSPatrick Mooney 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a, 13364c87aefeSPatrick Mooney 0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f, 13374c87aefeSPatrick Mooney 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f, 13384c87aefeSPatrick Mooney }; 13394c87aefeSPatrick Mooney int i; 1340bf21cd93STycho Nightingale 13414c87aefeSPatrick Mooney memcpy(sc->vga_dac.dac_palette, palette, 16 * 3 * sizeof (uint8_t)); 13424c87aefeSPatrick Mooney for (i = 0; i < 16; i++) { 13434c87aefeSPatrick Mooney sc->vga_dac.dac_palette_rgb[i] = 13444c87aefeSPatrick Mooney ((((sc->vga_dac.dac_palette[3*i + 0] << 2) | 13454c87aefeSPatrick Mooney ((sc->vga_dac.dac_palette[3*i + 0] & 0x1) << 1) | 13464c87aefeSPatrick Mooney (sc->vga_dac.dac_palette[3*i + 0] & 0x1)) << 16) | 13474c87aefeSPatrick Mooney (((sc->vga_dac.dac_palette[3*i + 1] << 2) | 13484c87aefeSPatrick Mooney ((sc->vga_dac.dac_palette[3*i + 1] & 0x1) << 1) | 13494c87aefeSPatrick Mooney (sc->vga_dac.dac_palette[3*i + 1] & 0x1)) << 8) | 13504c87aefeSPatrick Mooney (((sc->vga_dac.dac_palette[3*i + 2] << 2) | 13514c87aefeSPatrick Mooney ((sc->vga_dac.dac_palette[3*i + 2] & 0x1) << 1) | 13524c87aefeSPatrick Mooney (sc->vga_dac.dac_palette[3*i + 2] & 0x1)) << 0)); 13534c87aefeSPatrick Mooney } 13544c87aefeSPatrick Mooney } 13554c87aefeSPatrick Mooney 13564c87aefeSPatrick Mooney return (sc); 1357bf21cd93STycho Nightingale } 1358