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