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