1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/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
52struct 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
175static bool
176vga_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
184static void
185vga_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
214static uint32_t
215vga_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
243static void
244vga_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
258static uint32_t
259vga_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
306static void
307vga_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
321void
322vga_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
341static uint64_t
342vga_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
401static void
402vga_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
655static int
656vga_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
716static int
717vga_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
943static int
944vga_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
1216static int
1217vga_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
1268void *
1269vga_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