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