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