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