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