2 * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
39 #include <machine/vmm.h>
48 #define MB (1024 * 1024UL)
56 struct bhyvegc_image *gc_image;
72 uint8_t seq_clock_mode;
86 uint8_t crtc_mode_ctrl;
87 uint8_t crtc_horiz_total;
88 uint8_t crtc_horiz_disp_end;
89 uint8_t crtc_start_horiz_blank;
90 uint8_t crtc_end_horiz_blank;
91 uint8_t crtc_start_horiz_retrace;
92 uint8_t crtc_end_horiz_retrace;
93 uint8_t crtc_vert_total;
94 uint8_t crtc_overflow;
95 uint8_t crtc_present_row_scan;
96 uint8_t crtc_max_scan_line;
97 uint8_t crtc_cursor_start;
98 uint8_t crtc_cursor_on;
99 uint8_t crtc_cursor_end;
100 uint8_t crtc_start_addr_high;
101 uint8_t crtc_start_addr_low;
102 uint16_t crtc_start_addr;
103 uint8_t crtc_cursor_loc_low;
104 uint8_t crtc_cursor_loc_high;
105 uint16_t crtc_cursor_loc;
106 uint8_t crtc_vert_retrace_start;
107 uint8_t crtc_vert_retrace_end;
108 uint8_t crtc_vert_disp_end;
110 uint8_t crtc_underline_loc;
111 uint8_t crtc_start_vert_blank;
112 uint8_t crtc_end_vert_blank;
113 uint8_t crtc_line_compare;
117 * Graphics Controller
121 uint8_t gc_set_reset;
122 uint8_t gc_enb_set_reset;
123 uint8_t gc_color_compare;
126 uint8_t gc_read_map_sel;
128 bool gc_mode_c4; /* chain 4 */
129 bool gc_mode_oe; /* odd/even */
130 uint8_t gc_mode_rm; /* read mode */
131 uint8_t gc_mode_wm; /* write mode */
133 uint8_t gc_misc_gm; /* graphics mode */
134 uint8_t gc_misc_mm; /* memory map */
135 uint8_t gc_color_dont_care;
144 * Attribute Controller
149 uint8_t atc_palette[16];
151 uint8_t atc_overscan_color;
152 uint8_t atc_color_plane_enb;
153 uint8_t atc_horiz_pixel_panning;
154 uint8_t atc_color_select;
155 uint8_t atc_color_select_45;
156 uint8_t atc_color_select_67;
164 uint8_t dac_rd_index;
165 uint8_t dac_rd_subindex;
166 uint8_t dac_wr_index;
167 uint8_t dac_wr_subindex;
168 uint8_t dac_palette[3 * 256];
169 uint32_t dac_palette_rgb[256];
174 vga_in_reset(struct vga_softc *sc)
176 return (((sc->vga_seq.seq_clock_mode & SEQ_CM_SO) != 0) ||
177 ((sc->vga_seq.seq_reset & SEQ_RESET_ASYNC) == 0) ||
178 ((sc->vga_seq.seq_reset & SEQ_RESET_SYNC) == 0) ||
179 ((sc->vga_crtc.crtc_mode_ctrl & CRTC_MC_TE) == 0));
183 vga_check_size(struct bhyvegc *gc, struct vga_softc *sc)
185 int old_width, old_height;
187 if (vga_in_reset(sc))
190 //old_width = sc->gc_width;
191 //old_height = sc->gc_height;
192 old_width = sc->gc_image->width;
193 old_height = sc->gc_image->height;
196 * Horizontal Display End: For text modes this is the number
197 * of characters. For graphics modes this is the number of
198 * pixels per scanlines divided by the number of pixels per
201 sc->gc_width = (sc->vga_crtc.crtc_horiz_disp_end + 1) *
202 sc->vga_seq.seq_cm_dots;
204 sc->gc_height = (sc->vga_crtc.crtc_vert_disp_end |
205 (((sc->vga_crtc.crtc_overflow & CRTC_OF_VDE8) >> CRTC_OF_VDE8_SHIFT) << 8) |
206 (((sc->vga_crtc.crtc_overflow & CRTC_OF_VDE9) >> CRTC_OF_VDE9_SHIFT) << 9)) + 1;
208 if (old_width != sc->gc_width || old_height != sc->gc_height)
209 bhyvegc_resize(gc, sc->gc_width, sc->gc_height);
213 vga_get_pixel(struct vga_softc *sc, int x, int y)
220 offset = (y * sc->gc_width / 8) + (x / 8);
223 data = (((sc->vga_ram[offset + 0 * 64*KB] >> bit) & 0x1) << 0) |
224 (((sc->vga_ram[offset + 1 * 64*KB] >> bit) & 0x1) << 1) |
225 (((sc->vga_ram[offset + 2 * 64*KB] >> bit) & 0x1) << 2) |
226 (((sc->vga_ram[offset + 3 * 64*KB] >> bit) & 0x1) << 3);
228 data &= sc->vga_atc.atc_color_plane_enb;
230 if (sc->vga_atc.atc_mode & ATC_MC_IPS) {
231 idx = sc->vga_atc.atc_palette[data] & 0x0f;
232 idx |= sc->vga_atc.atc_color_select_45;
234 idx = sc->vga_atc.atc_palette[data];
236 idx |= sc->vga_atc.atc_color_select_67;
238 return (sc->vga_dac.dac_palette_rgb[idx]);
242 vga_render_graphics(struct vga_softc *sc)
246 for (y = 0; y < sc->gc_height; y++) {
247 for (x = 0; x < sc->gc_width; x++) {
250 offset = y * sc->gc_width + x;
251 sc->gc_image->data[offset] = vga_get_pixel(sc, x, y);
257 vga_get_text_pixel(struct vga_softc *sc, int x, int y)
259 int dots, offset, bit, font_offset;
260 uint8_t ch, attr, font;
263 dots = sc->vga_seq.seq_cm_dots;
265 offset = 2 * sc->vga_crtc.crtc_start_addr;
266 offset += (y / 16 * sc->gc_width / dots) * 2 + (x / dots) * 2;
268 bit = 7 - (x % dots > 7 ? 7 : x % dots);
270 ch = sc->vga_ram[offset + 0 * 64*KB];
271 attr = sc->vga_ram[offset + 1 * 64*KB];
273 if (sc->vga_crtc.crtc_cursor_on &&
274 (offset == (sc->vga_crtc.crtc_cursor_loc * 2)) &&
275 ((y % 16) >= (sc->vga_crtc.crtc_cursor_start & CRTC_CS_CS)) &&
276 ((y % 16) <= (sc->vga_crtc.crtc_cursor_end & CRTC_CE_CE))) {
277 idx = sc->vga_atc.atc_palette[attr & 0xf];
278 return (sc->vga_dac.dac_palette_rgb[idx]);
281 if ((sc->vga_seq.seq_mm & SEQ_MM_EM) &&
282 sc->vga_seq.seq_cmap_pri_off != sc->vga_seq.seq_cmap_sec_off) {
284 font_offset = sc->vga_seq.seq_cmap_pri_off +
287 font_offset = sc->vga_seq.seq_cmap_sec_off +
291 font_offset = (ch << 5) + y % 16;
294 font = sc->vga_ram[font_offset + 2 * 64*KB];
296 if (font & (1 << bit))
297 idx = sc->vga_atc.atc_palette[attr & 0xf];
299 idx = sc->vga_atc.atc_palette[attr >> 4];
301 return (sc->vga_dac.dac_palette_rgb[idx]);
305 vga_render_text(struct vga_softc *sc)
309 for (y = 0; y < sc->gc_height; y++) {
310 for (x = 0; x < sc->gc_width; x++) {
313 offset = y * sc->gc_width + x;
314 sc->gc_image->data[offset] = vga_get_text_pixel(sc, x, y);
320 vga_render(struct bhyvegc *gc, void *arg)
322 struct vga_softc *sc = arg;
324 vga_check_size(gc, sc);
326 if (vga_in_reset(sc)) {
327 memset(sc->gc_image->data, 0,
328 sc->gc_image->width * sc->gc_image->height *
333 if (sc->vga_gc.gc_misc_gm && (sc->vga_atc.atc_mode & ATC_MC_GA))
334 vga_render_graphics(sc);
340 vga_mem_rd_handler(struct vmctx *ctx, uint64_t addr, void *arg1)
342 struct vga_softc *sc = arg1;
347 switch (sc->vga_gc.gc_misc_mm) {
350 * extended mode: base 0xa0000 size 128k
353 offset &= (128 * KB - 1);
357 * EGA/VGA mode: base 0xa0000 size 64k
360 offset &= (64 * KB - 1);
364 * monochrome text mode: base 0xb0000 size 32kb
369 * color text mode and CGA: base 0xb8000 size 32kb
372 offset &= (32 * KB - 1);
377 sc->vga_gc.gc_latch0 = sc->vga_ram[offset + 0*64*KB];
378 sc->vga_gc.gc_latch1 = sc->vga_ram[offset + 1*64*KB];
379 sc->vga_gc.gc_latch2 = sc->vga_ram[offset + 2*64*KB];
380 sc->vga_gc.gc_latch3 = sc->vga_ram[offset + 3*64*KB];
382 if (sc->vga_gc.gc_mode_rm) {
387 map_sel = sc->vga_gc.gc_read_map_sel;
388 if (sc->vga_gc.gc_mode_oe) {
389 map_sel |= (offset & 1);
393 /* read mode 0: return the byte from the selected plane. */
394 offset += map_sel * 64*KB;
396 return (sc->vga_ram[offset]);
400 vga_mem_wr_handler(struct vmctx *ctx, uint64_t addr, uint8_t val, void *arg1)
402 struct vga_softc *sc = arg1;
403 uint8_t c0, c1, c2, c3;
404 uint8_t m0, m1, m2, m3;
406 uint8_t enb_set_reset;
411 switch (sc->vga_gc.gc_misc_mm) {
414 * extended mode: base 0xa0000 size 128kb
417 offset &= (128 * KB - 1);
421 * EGA/VGA mode: base 0xa0000 size 64kb
424 offset &= (64 * KB - 1);
428 * monochrome text mode: base 0xb0000 size 32kb
433 * color text mode and CGA: base 0xb8000 size 32kb
436 offset &= (32 * KB - 1);
440 set_reset = sc->vga_gc.gc_set_reset;
441 enb_set_reset = sc->vga_gc.gc_enb_set_reset;
443 c0 = sc->vga_gc.gc_latch0;
444 c1 = sc->vga_gc.gc_latch1;
445 c2 = sc->vga_gc.gc_latch2;
446 c3 = sc->vga_gc.gc_latch3;
448 switch (sc->vga_gc.gc_mode_wm) {
451 mask = sc->vga_gc.gc_bit_mask;
453 val = (val >> sc->vga_gc.gc_rotate) |
454 (val << (8 - sc->vga_gc.gc_rotate));
456 switch (sc->vga_gc.gc_op) {
457 case 0x00: /* replace */
458 m0 = (set_reset & 1) ? mask : 0x00;
459 m1 = (set_reset & 2) ? mask : 0x00;
460 m2 = (set_reset & 4) ? mask : 0x00;
461 m3 = (set_reset & 8) ? mask : 0x00;
463 c0 = (enb_set_reset & 1) ? (c0 & ~mask) : (val & mask);
464 c1 = (enb_set_reset & 2) ? (c1 & ~mask) : (val & mask);
465 c2 = (enb_set_reset & 4) ? (c2 & ~mask) : (val & mask);
466 c3 = (enb_set_reset & 8) ? (c3 & ~mask) : (val & mask);
474 m0 = set_reset & 1 ? 0xff : ~mask;
475 m1 = set_reset & 2 ? 0xff : ~mask;
476 m2 = set_reset & 4 ? 0xff : ~mask;
477 m3 = set_reset & 8 ? 0xff : ~mask;
479 c0 = enb_set_reset & 1 ? c0 & m0 : val & m0;
480 c1 = enb_set_reset & 2 ? c1 & m1 : val & m1;
481 c2 = enb_set_reset & 4 ? c2 & m2 : val & m2;
482 c3 = enb_set_reset & 8 ? c3 & m3 : val & m3;
485 m0 = set_reset & 1 ? mask : 0x00;
486 m1 = set_reset & 2 ? mask : 0x00;
487 m2 = set_reset & 4 ? mask : 0x00;
488 m3 = set_reset & 8 ? mask : 0x00;
490 c0 = enb_set_reset & 1 ? c0 | m0 : val | m0;
491 c1 = enb_set_reset & 2 ? c1 | m1 : val | m1;
492 c2 = enb_set_reset & 4 ? c2 | m2 : val | m2;
493 c3 = enb_set_reset & 8 ? c3 | m3 : val | m3;
496 m0 = set_reset & 1 ? mask : 0x00;
497 m1 = set_reset & 2 ? mask : 0x00;
498 m2 = set_reset & 4 ? mask : 0x00;
499 m3 = set_reset & 8 ? mask : 0x00;
501 c0 = enb_set_reset & 1 ? c0 ^ m0 : val ^ m0;
502 c1 = enb_set_reset & 2 ? c1 ^ m1 : val ^ m1;
503 c2 = enb_set_reset & 4 ? c2 ^ m2 : val ^ m2;
504 c3 = enb_set_reset & 8 ? c3 ^ m3 : val ^ m3;
513 mask = sc->vga_gc.gc_bit_mask;
515 switch (sc->vga_gc.gc_op) {
516 case 0x00: /* replace */
517 m0 = (val & 1 ? 0xff : 0x00) & mask;
518 m1 = (val & 2 ? 0xff : 0x00) & mask;
519 m2 = (val & 4 ? 0xff : 0x00) & mask;
520 m3 = (val & 8 ? 0xff : 0x00) & mask;
533 m0 = (val & 1 ? 0xff : 0x00) | ~mask;
534 m1 = (val & 2 ? 0xff : 0x00) | ~mask;
535 m2 = (val & 4 ? 0xff : 0x00) | ~mask;
536 m3 = (val & 8 ? 0xff : 0x00) | ~mask;
544 m0 = (val & 1 ? 0xff : 0x00) & mask;
545 m1 = (val & 2 ? 0xff : 0x00) & mask;
546 m2 = (val & 4 ? 0xff : 0x00) & mask;
547 m3 = (val & 8 ? 0xff : 0x00) & mask;
555 m0 = (val & 1 ? 0xff : 0x00) & mask;
556 m1 = (val & 2 ? 0xff : 0x00) & mask;
557 m2 = (val & 4 ? 0xff : 0x00) & mask;
558 m3 = (val & 8 ? 0xff : 0x00) & mask;
569 mask = sc->vga_gc.gc_bit_mask & val;
571 val = (val >> sc->vga_gc.gc_rotate) |
572 (val << (8 - sc->vga_gc.gc_rotate));
574 switch (sc->vga_gc.gc_op) {
575 case 0x00: /* replace */
576 m0 = (set_reset & 1 ? 0xff : 0x00) & mask;
577 m1 = (set_reset & 2 ? 0xff : 0x00) & mask;
578 m2 = (set_reset & 4 ? 0xff : 0x00) & mask;
579 m3 = (set_reset & 8 ? 0xff : 0x00) & mask;
592 m0 = (set_reset & 1 ? 0xff : 0x00) | ~mask;
593 m1 = (set_reset & 2 ? 0xff : 0x00) | ~mask;
594 m2 = (set_reset & 4 ? 0xff : 0x00) | ~mask;
595 m3 = (set_reset & 8 ? 0xff : 0x00) | ~mask;
603 m0 = (set_reset & 1 ? 0xff : 0x00) & mask;
604 m1 = (set_reset & 2 ? 0xff : 0x00) & mask;
605 m2 = (set_reset & 4 ? 0xff : 0x00) & mask;
606 m3 = (set_reset & 8 ? 0xff : 0x00) & mask;
614 m0 = (set_reset & 1 ? 0xff : 0x00) & mask;
615 m1 = (set_reset & 2 ? 0xff : 0x00) & mask;
616 m2 = (set_reset & 4 ? 0xff : 0x00) & mask;
617 m3 = (set_reset & 8 ? 0xff : 0x00) & mask;
628 if (sc->vga_gc.gc_mode_oe) {
631 if (sc->vga_seq.seq_map_mask & 2)
632 sc->vga_ram[offset + 1*64*KB] = c1;
633 if (sc->vga_seq.seq_map_mask & 8)
634 sc->vga_ram[offset + 3*64*KB] = c3;
636 if (sc->vga_seq.seq_map_mask & 1)
637 sc->vga_ram[offset + 0*64*KB] = c0;
638 if (sc->vga_seq.seq_map_mask & 4)
639 sc->vga_ram[offset + 2*64*KB] = c2;
642 if (sc->vga_seq.seq_map_mask & 1)
643 sc->vga_ram[offset + 0*64*KB] = c0;
644 if (sc->vga_seq.seq_map_mask & 2)
645 sc->vga_ram[offset + 1*64*KB] = c1;
646 if (sc->vga_seq.seq_map_mask & 4)
647 sc->vga_ram[offset + 2*64*KB] = c2;
648 if (sc->vga_seq.seq_map_mask & 8)
649 sc->vga_ram[offset + 3*64*KB] = c3;
654 vga_mem_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
655 int size, uint64_t *val, void *arg1, long arg2)
657 if (dir == MEM_F_WRITE) {
660 vga_mem_wr_handler(ctx, addr, *val, arg1);
663 vga_mem_wr_handler(ctx, addr, *val, arg1);
664 vga_mem_wr_handler(ctx, addr + 1, *val >> 8, arg1);
667 vga_mem_wr_handler(ctx, addr, *val, arg1);
668 vga_mem_wr_handler(ctx, addr + 1, *val >> 8, arg1);
669 vga_mem_wr_handler(ctx, addr + 2, *val >> 16, arg1);
670 vga_mem_wr_handler(ctx, addr + 3, *val >> 24, arg1);
673 vga_mem_wr_handler(ctx, addr, *val, arg1);
674 vga_mem_wr_handler(ctx, addr + 1, *val >> 8, arg1);
675 vga_mem_wr_handler(ctx, addr + 2, *val >> 16, arg1);
676 vga_mem_wr_handler(ctx, addr + 3, *val >> 24, arg1);
677 vga_mem_wr_handler(ctx, addr + 4, *val >> 32, arg1);
678 vga_mem_wr_handler(ctx, addr + 5, *val >> 40, arg1);
679 vga_mem_wr_handler(ctx, addr + 6, *val >> 48, arg1);
680 vga_mem_wr_handler(ctx, addr + 7, *val >> 56, arg1);
686 *val = vga_mem_rd_handler(ctx, addr, arg1);
689 *val = vga_mem_rd_handler(ctx, addr, arg1);
690 *val |= vga_mem_rd_handler(ctx, addr + 1, arg1) << 8;
693 *val = vga_mem_rd_handler(ctx, addr, arg1);
694 *val |= vga_mem_rd_handler(ctx, addr + 1, arg1) << 8;
695 *val |= vga_mem_rd_handler(ctx, addr + 2, arg1) << 16;
696 *val |= vga_mem_rd_handler(ctx, addr + 3, arg1) << 24;
699 *val = vga_mem_rd_handler(ctx, addr, arg1);
700 *val |= vga_mem_rd_handler(ctx, addr + 1, arg1) << 8;
701 *val |= vga_mem_rd_handler(ctx, addr + 2, arg1) << 16;
702 *val |= vga_mem_rd_handler(ctx, addr + 3, arg1) << 24;
703 *val |= vga_mem_rd_handler(ctx, addr + 4, arg1) << 32;
704 *val |= vga_mem_rd_handler(ctx, addr + 5, arg1) << 40;
705 *val |= vga_mem_rd_handler(ctx, addr + 6, arg1) << 48;
706 *val |= vga_mem_rd_handler(ctx, addr + 7, arg1) << 56;
715 vga_port_in_handler(struct vmctx *ctx, int in, int port, int bytes,
716 uint8_t *val, void *arg)
718 struct vga_softc *sc = arg;
721 case CRTC_IDX_MONO_PORT:
722 case CRTC_IDX_COLOR_PORT:
723 *val = sc->vga_crtc.crtc_index;
725 case CRTC_DATA_MONO_PORT:
726 case CRTC_DATA_COLOR_PORT:
727 switch (sc->vga_crtc.crtc_index) {
728 case CRTC_HORIZ_TOTAL:
729 *val = sc->vga_crtc.crtc_horiz_total;
731 case CRTC_HORIZ_DISP_END:
732 *val = sc->vga_crtc.crtc_horiz_disp_end;
734 case CRTC_START_HORIZ_BLANK:
735 *val = sc->vga_crtc.crtc_start_horiz_blank;
737 case CRTC_END_HORIZ_BLANK:
738 *val = sc->vga_crtc.crtc_end_horiz_blank;
740 case CRTC_START_HORIZ_RETRACE:
741 *val = sc->vga_crtc.crtc_start_horiz_retrace;
743 case CRTC_END_HORIZ_RETRACE:
744 *val = sc->vga_crtc.crtc_end_horiz_retrace;
746 case CRTC_VERT_TOTAL:
747 *val = sc->vga_crtc.crtc_vert_total;
750 *val = sc->vga_crtc.crtc_overflow;
752 case CRTC_PRESET_ROW_SCAN:
753 *val = sc->vga_crtc.crtc_present_row_scan;
755 case CRTC_MAX_SCAN_LINE:
756 *val = sc->vga_crtc.crtc_max_scan_line;
758 case CRTC_CURSOR_START:
759 *val = sc->vga_crtc.crtc_cursor_start;
761 case CRTC_CURSOR_END:
762 *val = sc->vga_crtc.crtc_cursor_end;
764 case CRTC_START_ADDR_HIGH:
765 *val = sc->vga_crtc.crtc_start_addr_high;
767 case CRTC_START_ADDR_LOW:
768 *val = sc->vga_crtc.crtc_start_addr_low;
770 case CRTC_CURSOR_LOC_HIGH:
771 *val = sc->vga_crtc.crtc_cursor_loc_high;
773 case CRTC_CURSOR_LOC_LOW:
774 *val = sc->vga_crtc.crtc_cursor_loc_low;
776 case CRTC_VERT_RETRACE_START:
777 *val = sc->vga_crtc.crtc_vert_retrace_start;
779 case CRTC_VERT_RETRACE_END:
780 *val = sc->vga_crtc.crtc_vert_retrace_end;
782 case CRTC_VERT_DISP_END:
783 *val = sc->vga_crtc.crtc_vert_disp_end;
786 *val = sc->vga_crtc.crtc_offset;
788 case CRTC_UNDERLINE_LOC:
789 *val = sc->vga_crtc.crtc_underline_loc;
791 case CRTC_START_VERT_BLANK:
792 *val = sc->vga_crtc.crtc_start_vert_blank;
794 case CRTC_END_VERT_BLANK:
795 *val = sc->vga_crtc.crtc_end_vert_blank;
797 case CRTC_MODE_CONTROL:
798 *val = sc->vga_crtc.crtc_mode_ctrl;
800 case CRTC_LINE_COMPARE:
801 *val = sc->vga_crtc.crtc_line_compare;
804 //printf("XXX VGA CRTC: inb 0x%04x at index %d\n", port, sc->vga_crtc.crtc_index);
810 *val = sc->vga_atc.atc_index;
813 switch (sc->vga_atc.atc_index) {
814 case ATC_PALETTE0 ... ATC_PALETTE15:
815 *val = sc->vga_atc.atc_palette[sc->vga_atc.atc_index];
817 case ATC_MODE_CONTROL:
818 *val = sc->vga_atc.atc_mode;
820 case ATC_OVERSCAN_COLOR:
821 *val = sc->vga_atc.atc_overscan_color;
823 case ATC_COLOR_PLANE_ENABLE:
824 *val = sc->vga_atc.atc_color_plane_enb;
826 case ATC_HORIZ_PIXEL_PANNING:
827 *val = sc->vga_atc.atc_horiz_pixel_panning;
829 case ATC_COLOR_SELECT:
830 *val = sc->vga_atc.atc_color_select;
833 //printf("XXX VGA ATC inb 0x%04x at index %d\n", port , sc->vga_atc.atc_index);
839 *val = sc->vga_seq.seq_index;
842 switch (sc->vga_seq.seq_index) {
844 *val = sc->vga_seq.seq_reset;
846 case SEQ_CLOCKING_MODE:
847 *val = sc->vga_seq.seq_clock_mode;
850 *val = sc->vga_seq.seq_map_mask;
852 case SEQ_CHAR_MAP_SELECT:
853 *val = sc->vga_seq.seq_cmap_sel;
855 case SEQ_MEMORY_MODE:
856 *val = sc->vga_seq.seq_mm;
859 //printf("XXX VGA SEQ: inb 0x%04x at index %d\n", port, sc->vga_seq.seq_index);
865 *val = sc->vga_dac.dac_palette[3 * sc->vga_dac.dac_rd_index +
866 sc->vga_dac.dac_rd_subindex];
867 sc->vga_dac.dac_rd_subindex++;
868 if (sc->vga_dac.dac_rd_subindex == 3) {
869 sc->vga_dac.dac_rd_index++;
870 sc->vga_dac.dac_rd_subindex = 0;
874 *val = sc->vga_gc.gc_index;
877 switch (sc->vga_gc.gc_index) {
879 *val = sc->vga_gc.gc_set_reset;
881 case GC_ENABLE_SET_RESET:
882 *val = sc->vga_gc.gc_enb_set_reset;
884 case GC_COLOR_COMPARE:
885 *val = sc->vga_gc.gc_color_compare;
888 *val = sc->vga_gc.gc_rotate;
890 case GC_READ_MAP_SELECT:
891 *val = sc->vga_gc.gc_read_map_sel;
894 *val = sc->vga_gc.gc_mode;
896 case GC_MISCELLANEOUS:
897 *val = sc->vga_gc.gc_misc;
899 case GC_COLOR_DONT_CARE:
900 *val = sc->vga_gc.gc_color_dont_care;
903 *val = sc->vga_gc.gc_bit_mask;
906 //printf("XXX VGA GC: inb 0x%04x at index %d\n", port, sc->vga_crtc.crtc_index);
911 case GEN_MISC_OUTPUT_PORT:
914 case GEN_INPUT_STS0_PORT:
917 case GEN_INPUT_STS1_MONO_PORT:
918 case GEN_INPUT_STS1_COLOR_PORT:
919 sc->vga_atc.atc_flipflop = 0;
920 sc->vga_sts1 = GEN_IS1_VR | GEN_IS1_DE;
921 //sc->vga_sts1 ^= (GEN_IS1_VR | GEN_IS1_DE);
924 case GEN_FEATURE_CTRL_PORT:
925 // OpenBSD calls this with bytes = 1
933 printf("XXX vga_port_in_handler() unhandled port 0x%x\n", port);
942 vga_port_out_handler(struct vmctx *ctx, int in, int port, int bytes,
943 uint8_t val, void *arg)
945 struct vga_softc *sc = arg;
948 case CRTC_IDX_MONO_PORT:
949 case CRTC_IDX_COLOR_PORT:
950 sc->vga_crtc.crtc_index = val;
952 case CRTC_DATA_MONO_PORT:
953 case CRTC_DATA_COLOR_PORT:
954 switch (sc->vga_crtc.crtc_index) {
955 case CRTC_HORIZ_TOTAL:
956 sc->vga_crtc.crtc_horiz_total = val;
958 case CRTC_HORIZ_DISP_END:
959 sc->vga_crtc.crtc_horiz_disp_end = val;
961 case CRTC_START_HORIZ_BLANK:
962 sc->vga_crtc.crtc_start_horiz_blank = val;
964 case CRTC_END_HORIZ_BLANK:
965 sc->vga_crtc.crtc_end_horiz_blank = val;
967 case CRTC_START_HORIZ_RETRACE:
968 sc->vga_crtc.crtc_start_horiz_retrace = val;
970 case CRTC_END_HORIZ_RETRACE:
971 sc->vga_crtc.crtc_end_horiz_retrace = val;
973 case CRTC_VERT_TOTAL:
974 sc->vga_crtc.crtc_vert_total = val;
977 sc->vga_crtc.crtc_overflow = val;
979 case CRTC_PRESET_ROW_SCAN:
980 sc->vga_crtc.crtc_present_row_scan = val;
982 case CRTC_MAX_SCAN_LINE:
983 sc->vga_crtc.crtc_max_scan_line = val;
985 case CRTC_CURSOR_START:
986 sc->vga_crtc.crtc_cursor_start = val;
987 sc->vga_crtc.crtc_cursor_on = (val & CRTC_CS_CO) == 0;
989 case CRTC_CURSOR_END:
990 sc->vga_crtc.crtc_cursor_end = val;
992 case CRTC_START_ADDR_HIGH:
993 sc->vga_crtc.crtc_start_addr_high = val;
994 sc->vga_crtc.crtc_start_addr &= 0x00ff;
995 sc->vga_crtc.crtc_start_addr |= (val << 8);
997 case CRTC_START_ADDR_LOW:
998 sc->vga_crtc.crtc_start_addr_low = val;
999 sc->vga_crtc.crtc_start_addr &= 0xff00;
1000 sc->vga_crtc.crtc_start_addr |= (val & 0xff);
1002 case CRTC_CURSOR_LOC_HIGH:
1003 sc->vga_crtc.crtc_cursor_loc_high = val;
1004 sc->vga_crtc.crtc_cursor_loc &= 0x00ff;
1005 sc->vga_crtc.crtc_cursor_loc |= (val << 8);
1007 case CRTC_CURSOR_LOC_LOW:
1008 sc->vga_crtc.crtc_cursor_loc_low = val;
1009 sc->vga_crtc.crtc_cursor_loc &= 0xff00;
1010 sc->vga_crtc.crtc_cursor_loc |= (val & 0xff);
1012 case CRTC_VERT_RETRACE_START:
1013 sc->vga_crtc.crtc_vert_retrace_start = val;
1015 case CRTC_VERT_RETRACE_END:
1016 sc->vga_crtc.crtc_vert_retrace_end = val;
1018 case CRTC_VERT_DISP_END:
1019 sc->vga_crtc.crtc_vert_disp_end = val;
1022 sc->vga_crtc.crtc_offset = val;
1024 case CRTC_UNDERLINE_LOC:
1025 sc->vga_crtc.crtc_underline_loc = val;
1027 case CRTC_START_VERT_BLANK:
1028 sc->vga_crtc.crtc_start_vert_blank = val;
1030 case CRTC_END_VERT_BLANK:
1031 sc->vga_crtc.crtc_end_vert_blank = val;
1033 case CRTC_MODE_CONTROL:
1034 sc->vga_crtc.crtc_mode_ctrl = val;
1036 case CRTC_LINE_COMPARE:
1037 sc->vga_crtc.crtc_line_compare = val;
1040 //printf("XXX VGA CRTC: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_crtc.crtc_index);
1046 if (sc->vga_atc.atc_flipflop == 0) {
1047 if (sc->vga_atc.atc_index & 0x20)
1049 sc->vga_atc.atc_index = val & ATC_IDX_MASK;
1051 switch (sc->vga_atc.atc_index) {
1052 case ATC_PALETTE0 ... ATC_PALETTE15:
1053 sc->vga_atc.atc_palette[sc->vga_atc.atc_index] = val & 0x3f;
1055 case ATC_MODE_CONTROL:
1056 sc->vga_atc.atc_mode = val;
1058 case ATC_OVERSCAN_COLOR:
1059 sc->vga_atc.atc_overscan_color = val;
1061 case ATC_COLOR_PLANE_ENABLE:
1062 sc->vga_atc.atc_color_plane_enb = val;
1064 case ATC_HORIZ_PIXEL_PANNING:
1065 sc->vga_atc.atc_horiz_pixel_panning = val;
1067 case ATC_COLOR_SELECT:
1068 sc->vga_atc.atc_color_select = val;
1069 sc->vga_atc.atc_color_select_45 =
1070 (val & ATC_CS_C45) << 4;
1071 sc->vga_atc.atc_color_select_67 =
1072 ((val & ATC_CS_C67) >> 2) << 6;
1075 //printf("XXX VGA ATC: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_atc.atc_index);
1080 sc->vga_atc.atc_flipflop ^= 1;
1085 sc->vga_seq.seq_index = val & 0x1f;
1088 switch (sc->vga_seq.seq_index) {
1090 sc->vga_seq.seq_reset = val;
1092 case SEQ_CLOCKING_MODE:
1093 sc->vga_seq.seq_clock_mode = val;
1094 sc->vga_seq.seq_cm_dots = (val & SEQ_CM_89) ? 8 : 9;
1097 sc->vga_seq.seq_map_mask = val;
1099 case SEQ_CHAR_MAP_SELECT:
1100 sc->vga_seq.seq_cmap_sel = val;
1102 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;
1103 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;
1105 case SEQ_MEMORY_MODE:
1106 sc->vga_seq.seq_mm = val;
1107 /* Windows queries Chain4 */
1108 //assert((sc->vga_seq.seq_mm & SEQ_MM_C4) == 0);
1111 //printf("XXX VGA SEQ: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_seq.seq_index);
1118 case DAC_IDX_RD_PORT:
1119 sc->vga_dac.dac_rd_index = val;
1120 sc->vga_dac.dac_rd_subindex = 0;
1122 case DAC_IDX_WR_PORT:
1123 sc->vga_dac.dac_wr_index = val;
1124 sc->vga_dac.dac_wr_subindex = 0;
1127 sc->vga_dac.dac_palette[3 * sc->vga_dac.dac_wr_index +
1128 sc->vga_dac.dac_wr_subindex] = val;
1129 sc->vga_dac.dac_wr_subindex++;
1130 if (sc->vga_dac.dac_wr_subindex == 3) {
1131 sc->vga_dac.dac_palette_rgb[sc->vga_dac.dac_wr_index] =
1132 ((((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 0] << 2) |
1133 ((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 0] & 0x1) << 1) |
1134 (sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 0] & 0x1)) << 16) |
1135 (((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 1] << 2) |
1136 ((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 1] & 0x1) << 1) |
1137 (sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 1] & 0x1)) << 8) |
1138 (((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 2] << 2) |
1139 ((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 2] & 0x1) << 1) |
1140 (sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 2] & 0x1)) << 0));
1142 sc->vga_dac.dac_wr_index++;
1143 sc->vga_dac.dac_wr_subindex = 0;
1147 sc->vga_gc.gc_index = val;
1150 switch (sc->vga_gc.gc_index) {
1152 sc->vga_gc.gc_set_reset = val;
1154 case GC_ENABLE_SET_RESET:
1155 sc->vga_gc.gc_enb_set_reset = val;
1157 case GC_COLOR_COMPARE:
1158 sc->vga_gc.gc_color_compare = val;
1160 case GC_DATA_ROTATE:
1161 sc->vga_gc.gc_rotate = val;
1162 sc->vga_gc.gc_op = (val >> 3) & 0x3;
1164 case GC_READ_MAP_SELECT:
1165 sc->vga_gc.gc_read_map_sel = val;
1168 sc->vga_gc.gc_mode = val;
1169 sc->vga_gc.gc_mode_c4 = (val & GC_MODE_C4) != 0;
1170 assert(!sc->vga_gc.gc_mode_c4);
1171 sc->vga_gc.gc_mode_oe = (val & GC_MODE_OE) != 0;
1172 sc->vga_gc.gc_mode_rm = (val >> 3) & 0x1;
1173 sc->vga_gc.gc_mode_wm = val & 0x3;
1176 sc->gc_image->vgamode = 1;
1178 case GC_MISCELLANEOUS:
1179 sc->vga_gc.gc_misc = val;
1180 sc->vga_gc.gc_misc_gm = val & GC_MISC_GM;
1181 sc->vga_gc.gc_misc_mm = (val & GC_MISC_MM) >>
1184 case GC_COLOR_DONT_CARE:
1185 sc->vga_gc.gc_color_dont_care = val;
1188 sc->vga_gc.gc_bit_mask = val;
1191 //printf("XXX VGA GC: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_gc.gc_index);
1196 case GEN_INPUT_STS0_PORT:
1197 /* write to Miscellaneous Output Register */
1200 case GEN_INPUT_STS1_MONO_PORT:
1201 case GEN_INPUT_STS1_COLOR_PORT:
1202 /* write to Feature Control Register */
1207 printf("XXX vga_port_out_handler() unhandled port 0x%x, val 0x%x\n", port, val);
1215 vga_port_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
1216 uint32_t *eax, void *arg)
1225 error = vga_port_in_handler(ctx, in, port, 1,
1232 error = vga_port_out_handler(ctx, in, port, 1,
1239 error = vga_port_in_handler(ctx, in, port, 1,
1244 error = vga_port_in_handler(ctx, in, port + 1, 1,
1247 *eax |= (val & 0xff) << 8;
1251 error = vga_port_out_handler(ctx, in, port, 1,
1253 val = (*eax >> 8) & 0xff;
1254 error =vga_port_out_handler(ctx, in, port + 1, 1,
1267 vga_init(int io_only)
1269 struct inout_port iop;
1270 struct vga_softc *sc;
1273 sc = calloc(1, sizeof(struct vga_softc));
1275 bzero(&iop, sizeof(struct inout_port));
1277 for (port = VGA_IOPORT_START; port <= VGA_IOPORT_END; port++) {
1280 iop.flags = IOPORT_F_INOUT;
1281 iop.handler = vga_port_handler;
1284 error = register_inout(&iop);
1288 sc->gc_image = console_get_image();
1290 /* only handle io ports; vga graphics is disabled */
1294 sc->mr.name = "VGA memory";
1295 sc->mr.flags = MEM_F_RW;
1296 sc->mr.base = 640 * KB;
1297 sc->mr.size = 128 * KB;
1298 sc->mr.handler = vga_mem_handler;
1300 error = register_mem_fallback(&sc->mr);
1303 sc->vga_ram = malloc(256 * KB);
1304 memset(sc->vga_ram, 0, 256 * KB);
1307 static uint8_t palette[] = {
1308 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
1309 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,
1310 0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f,
1311 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,
1315 memcpy(sc->vga_dac.dac_palette, palette, 16 * 3 * sizeof (uint8_t));
1316 for (i = 0; i < 16; i++) {
1317 sc->vga_dac.dac_palette_rgb[i] =
1318 ((((sc->vga_dac.dac_palette[3*i + 0] << 2) |
1319 ((sc->vga_dac.dac_palette[3*i + 0] & 0x1) << 1) |
1320 (sc->vga_dac.dac_palette[3*i + 0] & 0x1)) << 16) |
1321 (((sc->vga_dac.dac_palette[3*i + 1] << 2) |
1322 ((sc->vga_dac.dac_palette[3*i + 1] & 0x1) << 1) |
1323 (sc->vga_dac.dac_palette[3*i + 1] & 0x1)) << 8) |
1324 (((sc->vga_dac.dac_palette[3*i + 2] << 2) |
1325 ((sc->vga_dac.dac_palette[3*i + 2] & 0x1) << 1) |
1326 (sc->vga_dac.dac_palette[3*i + 2] & 0x1)) << 0));