2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
30 * Copyright 2018 Joyent, Inc.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
45 #include <machine/vmm.h>
54 #define MB (1024 * 1024UL)
62 struct bhyvegc_image
*gc_image
;
78 uint8_t seq_clock_mode
;
92 uint8_t crtc_mode_ctrl
;
93 uint8_t crtc_horiz_total
;
94 uint8_t crtc_horiz_disp_end
;
95 uint8_t crtc_start_horiz_blank
;
96 uint8_t crtc_end_horiz_blank
;
97 uint8_t crtc_start_horiz_retrace
;
98 uint8_t crtc_end_horiz_retrace
;
99 uint8_t crtc_vert_total
;
100 uint8_t crtc_overflow
;
101 uint8_t crtc_present_row_scan
;
102 uint8_t crtc_max_scan_line
;
103 uint8_t crtc_cursor_start
;
104 uint8_t crtc_cursor_on
;
105 uint8_t crtc_cursor_end
;
106 uint8_t crtc_start_addr_high
;
107 uint8_t crtc_start_addr_low
;
108 uint16_t crtc_start_addr
;
109 uint8_t crtc_cursor_loc_low
;
110 uint8_t crtc_cursor_loc_high
;
111 uint16_t crtc_cursor_loc
;
112 uint8_t crtc_vert_retrace_start
;
113 uint8_t crtc_vert_retrace_end
;
114 uint8_t crtc_vert_disp_end
;
116 uint8_t crtc_underline_loc
;
117 uint8_t crtc_start_vert_blank
;
118 uint8_t crtc_end_vert_blank
;
119 uint8_t crtc_line_compare
;
123 * Graphics Controller
127 uint8_t gc_set_reset
;
128 uint8_t gc_enb_set_reset
;
129 uint8_t gc_color_compare
;
132 uint8_t gc_read_map_sel
;
134 bool gc_mode_c4
; /* chain 4 */
135 bool gc_mode_oe
; /* odd/even */
136 uint8_t gc_mode_rm
; /* read mode */
137 uint8_t gc_mode_wm
; /* write mode */
139 uint8_t gc_misc_gm
; /* graphics mode */
140 uint8_t gc_misc_mm
; /* memory map */
141 uint8_t gc_color_dont_care
;
150 * Attribute Controller
155 uint8_t atc_palette
[16];
157 uint8_t atc_overscan_color
;
158 uint8_t atc_color_plane_enb
;
159 uint8_t atc_horiz_pixel_panning
;
160 uint8_t atc_color_select
;
161 uint8_t atc_color_select_45
;
162 uint8_t atc_color_select_67
;
170 uint8_t dac_rd_index
;
171 uint8_t dac_rd_subindex
;
172 uint8_t dac_wr_index
;
173 uint8_t dac_wr_subindex
;
174 uint8_t dac_palette
[3 * 256];
175 uint32_t dac_palette_rgb
[256];
180 vga_in_reset(struct vga_softc
*sc
)
182 return (((sc
->vga_seq
.seq_clock_mode
& SEQ_CM_SO
) != 0) ||
183 ((sc
->vga_seq
.seq_reset
& SEQ_RESET_ASYNC
) == 0) ||
184 ((sc
->vga_seq
.seq_reset
& SEQ_RESET_SYNC
) == 0) ||
185 ((sc
->vga_crtc
.crtc_mode_ctrl
& CRTC_MC_TE
) == 0));
189 vga_check_size(struct bhyvegc
*gc
, struct vga_softc
*sc
)
191 int old_width
, old_height
;
193 if (vga_in_reset(sc
))
196 //old_width = sc->gc_width;
197 //old_height = sc->gc_height;
198 old_width
= sc
->gc_image
->width
;
199 old_height
= sc
->gc_image
->height
;
202 * Horizontal Display End: For text modes this is the number
203 * of characters. For graphics modes this is the number of
204 * pixels per scanlines divided by the number of pixels per
207 sc
->gc_width
= (sc
->vga_crtc
.crtc_horiz_disp_end
+ 1) *
208 sc
->vga_seq
.seq_cm_dots
;
210 sc
->gc_height
= (sc
->vga_crtc
.crtc_vert_disp_end
|
211 (((sc
->vga_crtc
.crtc_overflow
& CRTC_OF_VDE8
) >> CRTC_OF_VDE8_SHIFT
) << 8) |
212 (((sc
->vga_crtc
.crtc_overflow
& CRTC_OF_VDE9
) >> CRTC_OF_VDE9_SHIFT
) << 9)) + 1;
214 if (old_width
!= sc
->gc_width
|| old_height
!= sc
->gc_height
)
215 bhyvegc_resize(gc
, sc
->gc_width
, sc
->gc_height
);
219 vga_get_pixel(struct vga_softc
*sc
, int x
, int y
)
226 offset
= (y
* sc
->gc_width
/ 8) + (x
/ 8);
229 data
= (((sc
->vga_ram
[offset
+ 0 * 64*KB
] >> bit
) & 0x1) << 0) |
230 (((sc
->vga_ram
[offset
+ 1 * 64*KB
] >> bit
) & 0x1) << 1) |
231 (((sc
->vga_ram
[offset
+ 2 * 64*KB
] >> bit
) & 0x1) << 2) |
232 (((sc
->vga_ram
[offset
+ 3 * 64*KB
] >> bit
) & 0x1) << 3);
234 data
&= sc
->vga_atc
.atc_color_plane_enb
;
236 if (sc
->vga_atc
.atc_mode
& ATC_MC_IPS
) {
237 idx
= sc
->vga_atc
.atc_palette
[data
] & 0x0f;
238 idx
|= sc
->vga_atc
.atc_color_select_45
;
240 idx
= sc
->vga_atc
.atc_palette
[data
];
242 idx
|= sc
->vga_atc
.atc_color_select_67
;
244 return (sc
->vga_dac
.dac_palette_rgb
[idx
]);
248 vga_render_graphics(struct vga_softc
*sc
)
252 for (y
= 0; y
< sc
->gc_height
; y
++) {
253 for (x
= 0; x
< sc
->gc_width
; x
++) {
256 offset
= y
* sc
->gc_width
+ x
;
257 sc
->gc_image
->data
[offset
] = vga_get_pixel(sc
, x
, y
);
263 vga_get_text_pixel(struct vga_softc
*sc
, int x
, int y
)
265 int dots
, offset
, bit
, font_offset
;
266 uint8_t ch
, attr
, font
;
269 dots
= sc
->vga_seq
.seq_cm_dots
;
271 offset
= 2 * sc
->vga_crtc
.crtc_start_addr
;
272 offset
+= (y
/ 16 * sc
->gc_width
/ dots
) * 2 + (x
/ dots
) * 2;
274 bit
= 7 - (x
% dots
> 7 ? 7 : x
% dots
);
276 ch
= sc
->vga_ram
[offset
+ 0 * 64*KB
];
277 attr
= sc
->vga_ram
[offset
+ 1 * 64*KB
];
279 if (sc
->vga_crtc
.crtc_cursor_on
&&
280 (offset
== (sc
->vga_crtc
.crtc_cursor_loc
* 2)) &&
281 ((y
% 16) >= (sc
->vga_crtc
.crtc_cursor_start
& CRTC_CS_CS
)) &&
282 ((y
% 16) <= (sc
->vga_crtc
.crtc_cursor_end
& CRTC_CE_CE
))) {
283 idx
= sc
->vga_atc
.atc_palette
[attr
& 0xf];
284 return (sc
->vga_dac
.dac_palette_rgb
[idx
]);
287 if ((sc
->vga_seq
.seq_mm
& SEQ_MM_EM
) &&
288 sc
->vga_seq
.seq_cmap_pri_off
!= sc
->vga_seq
.seq_cmap_sec_off
) {
290 font_offset
= sc
->vga_seq
.seq_cmap_pri_off
+
293 font_offset
= sc
->vga_seq
.seq_cmap_sec_off
+
297 font_offset
= (ch
<< 5) + y
% 16;
300 font
= sc
->vga_ram
[font_offset
+ 2 * 64*KB
];
302 if (font
& (1 << bit
))
303 idx
= sc
->vga_atc
.atc_palette
[attr
& 0xf];
305 idx
= sc
->vga_atc
.atc_palette
[attr
>> 4];
307 return (sc
->vga_dac
.dac_palette_rgb
[idx
]);
311 vga_render_text(struct vga_softc
*sc
)
315 for (y
= 0; y
< sc
->gc_height
; y
++) {
316 for (x
= 0; x
< sc
->gc_width
; x
++) {
319 offset
= y
* sc
->gc_width
+ x
;
320 sc
->gc_image
->data
[offset
] = vga_get_text_pixel(sc
, x
, y
);
326 vga_render(struct bhyvegc
*gc
, void *arg
)
328 struct vga_softc
*sc
= arg
;
330 vga_check_size(gc
, sc
);
332 if (vga_in_reset(sc
)) {
333 memset(sc
->gc_image
->data
, 0,
334 sc
->gc_image
->width
* sc
->gc_image
->height
*
339 if (sc
->vga_gc
.gc_misc_gm
&& (sc
->vga_atc
.atc_mode
& ATC_MC_GA
))
340 vga_render_graphics(sc
);
346 vga_mem_rd_handler(struct vmctx
*ctx
, uint64_t addr
, void *arg1
)
348 struct vga_softc
*sc
= arg1
;
353 switch (sc
->vga_gc
.gc_misc_mm
) {
356 * extended mode: base 0xa0000 size 128k
359 offset
&= (128 * KB
- 1);
363 * EGA/VGA mode: base 0xa0000 size 64k
366 offset
&= (64 * KB
- 1);
370 * monochrome text mode: base 0xb0000 size 32kb
379 * color text mode and CGA: base 0xb8000 size 32kb
382 offset
&= (32 * KB
- 1);
387 sc
->vga_gc
.gc_latch0
= sc
->vga_ram
[offset
+ 0*64*KB
];
388 sc
->vga_gc
.gc_latch1
= sc
->vga_ram
[offset
+ 1*64*KB
];
389 sc
->vga_gc
.gc_latch2
= sc
->vga_ram
[offset
+ 2*64*KB
];
390 sc
->vga_gc
.gc_latch3
= sc
->vga_ram
[offset
+ 3*64*KB
];
392 if (sc
->vga_gc
.gc_mode_rm
) {
397 map_sel
= sc
->vga_gc
.gc_read_map_sel
;
398 if (sc
->vga_gc
.gc_mode_oe
) {
399 map_sel
|= (offset
& 1);
403 /* read mode 0: return the byte from the selected plane. */
404 offset
+= map_sel
* 64*KB
;
406 return (sc
->vga_ram
[offset
]);
410 vga_mem_wr_handler(struct vmctx
*ctx
, uint64_t addr
, uint8_t val
, void *arg1
)
412 struct vga_softc
*sc
= arg1
;
413 uint8_t c0
, c1
, c2
, c3
;
414 uint8_t m0
, m1
, m2
, m3
;
416 uint8_t enb_set_reset
;
421 switch (sc
->vga_gc
.gc_misc_mm
) {
424 * extended mode: base 0xa0000 size 128kb
427 offset
&= (128 * KB
- 1);
431 * EGA/VGA mode: base 0xa0000 size 64kb
434 offset
&= (64 * KB
- 1);
438 * monochrome text mode: base 0xb0000 size 32kb
447 * color text mode and CGA: base 0xb8000 size 32kb
450 offset
&= (32 * KB
- 1);
454 set_reset
= sc
->vga_gc
.gc_set_reset
;
455 enb_set_reset
= sc
->vga_gc
.gc_enb_set_reset
;
457 c0
= sc
->vga_gc
.gc_latch0
;
458 c1
= sc
->vga_gc
.gc_latch1
;
459 c2
= sc
->vga_gc
.gc_latch2
;
460 c3
= sc
->vga_gc
.gc_latch3
;
462 switch (sc
->vga_gc
.gc_mode_wm
) {
465 mask
= sc
->vga_gc
.gc_bit_mask
;
467 val
= (val
>> sc
->vga_gc
.gc_rotate
) |
468 (val
<< (8 - sc
->vga_gc
.gc_rotate
));
470 switch (sc
->vga_gc
.gc_op
) {
471 case 0x00: /* replace */
472 m0
= (set_reset
& 1) ? mask
: 0x00;
473 m1
= (set_reset
& 2) ? mask
: 0x00;
474 m2
= (set_reset
& 4) ? mask
: 0x00;
475 m3
= (set_reset
& 8) ? mask
: 0x00;
477 c0
= (enb_set_reset
& 1) ? (c0
& ~mask
) : (val
& mask
);
478 c1
= (enb_set_reset
& 2) ? (c1
& ~mask
) : (val
& mask
);
479 c2
= (enb_set_reset
& 4) ? (c2
& ~mask
) : (val
& mask
);
480 c3
= (enb_set_reset
& 8) ? (c3
& ~mask
) : (val
& mask
);
488 m0
= set_reset
& 1 ? 0xff : ~mask
;
489 m1
= set_reset
& 2 ? 0xff : ~mask
;
490 m2
= set_reset
& 4 ? 0xff : ~mask
;
491 m3
= set_reset
& 8 ? 0xff : ~mask
;
493 c0
= enb_set_reset
& 1 ? c0
& m0
: val
& m0
;
494 c1
= enb_set_reset
& 2 ? c1
& m1
: val
& m1
;
495 c2
= enb_set_reset
& 4 ? c2
& m2
: val
& m2
;
496 c3
= enb_set_reset
& 8 ? c3
& m3
: val
& m3
;
499 m0
= set_reset
& 1 ? mask
: 0x00;
500 m1
= set_reset
& 2 ? mask
: 0x00;
501 m2
= set_reset
& 4 ? mask
: 0x00;
502 m3
= set_reset
& 8 ? mask
: 0x00;
504 c0
= enb_set_reset
& 1 ? c0
| m0
: val
| m0
;
505 c1
= enb_set_reset
& 2 ? c1
| m1
: val
| m1
;
506 c2
= enb_set_reset
& 4 ? c2
| m2
: val
| m2
;
507 c3
= enb_set_reset
& 8 ? c3
| m3
: val
| m3
;
510 m0
= set_reset
& 1 ? mask
: 0x00;
511 m1
= set_reset
& 2 ? mask
: 0x00;
512 m2
= set_reset
& 4 ? mask
: 0x00;
513 m3
= set_reset
& 8 ? mask
: 0x00;
515 c0
= enb_set_reset
& 1 ? c0
^ m0
: val
^ m0
;
516 c1
= enb_set_reset
& 2 ? c1
^ m1
: val
^ m1
;
517 c2
= enb_set_reset
& 4 ? c2
^ m2
: val
^ m2
;
518 c3
= enb_set_reset
& 8 ? c3
^ m3
: val
^ m3
;
527 mask
= sc
->vga_gc
.gc_bit_mask
;
529 switch (sc
->vga_gc
.gc_op
) {
530 case 0x00: /* replace */
531 m0
= (val
& 1 ? 0xff : 0x00) & mask
;
532 m1
= (val
& 2 ? 0xff : 0x00) & mask
;
533 m2
= (val
& 4 ? 0xff : 0x00) & mask
;
534 m3
= (val
& 8 ? 0xff : 0x00) & mask
;
547 m0
= (val
& 1 ? 0xff : 0x00) | ~mask
;
548 m1
= (val
& 2 ? 0xff : 0x00) | ~mask
;
549 m2
= (val
& 4 ? 0xff : 0x00) | ~mask
;
550 m3
= (val
& 8 ? 0xff : 0x00) | ~mask
;
558 m0
= (val
& 1 ? 0xff : 0x00) & mask
;
559 m1
= (val
& 2 ? 0xff : 0x00) & mask
;
560 m2
= (val
& 4 ? 0xff : 0x00) & mask
;
561 m3
= (val
& 8 ? 0xff : 0x00) & mask
;
569 m0
= (val
& 1 ? 0xff : 0x00) & mask
;
570 m1
= (val
& 2 ? 0xff : 0x00) & mask
;
571 m2
= (val
& 4 ? 0xff : 0x00) & mask
;
572 m3
= (val
& 8 ? 0xff : 0x00) & mask
;
583 mask
= sc
->vga_gc
.gc_bit_mask
& val
;
585 val
= (val
>> sc
->vga_gc
.gc_rotate
) |
586 (val
<< (8 - sc
->vga_gc
.gc_rotate
));
588 switch (sc
->vga_gc
.gc_op
) {
589 case 0x00: /* replace */
590 m0
= (set_reset
& 1 ? 0xff : 0x00) & mask
;
591 m1
= (set_reset
& 2 ? 0xff : 0x00) & mask
;
592 m2
= (set_reset
& 4 ? 0xff : 0x00) & mask
;
593 m3
= (set_reset
& 8 ? 0xff : 0x00) & mask
;
606 m0
= (set_reset
& 1 ? 0xff : 0x00) | ~mask
;
607 m1
= (set_reset
& 2 ? 0xff : 0x00) | ~mask
;
608 m2
= (set_reset
& 4 ? 0xff : 0x00) | ~mask
;
609 m3
= (set_reset
& 8 ? 0xff : 0x00) | ~mask
;
617 m0
= (set_reset
& 1 ? 0xff : 0x00) & mask
;
618 m1
= (set_reset
& 2 ? 0xff : 0x00) & mask
;
619 m2
= (set_reset
& 4 ? 0xff : 0x00) & mask
;
620 m3
= (set_reset
& 8 ? 0xff : 0x00) & mask
;
628 m0
= (set_reset
& 1 ? 0xff : 0x00) & mask
;
629 m1
= (set_reset
& 2 ? 0xff : 0x00) & mask
;
630 m2
= (set_reset
& 4 ? 0xff : 0x00) & mask
;
631 m3
= (set_reset
& 8 ? 0xff : 0x00) & mask
;
642 if (sc
->vga_gc
.gc_mode_oe
) {
645 if (sc
->vga_seq
.seq_map_mask
& 2)
646 sc
->vga_ram
[offset
+ 1*64*KB
] = c1
;
647 if (sc
->vga_seq
.seq_map_mask
& 8)
648 sc
->vga_ram
[offset
+ 3*64*KB
] = c3
;
650 if (sc
->vga_seq
.seq_map_mask
& 1)
651 sc
->vga_ram
[offset
+ 0*64*KB
] = c0
;
652 if (sc
->vga_seq
.seq_map_mask
& 4)
653 sc
->vga_ram
[offset
+ 2*64*KB
] = c2
;
656 if (sc
->vga_seq
.seq_map_mask
& 1)
657 sc
->vga_ram
[offset
+ 0*64*KB
] = c0
;
658 if (sc
->vga_seq
.seq_map_mask
& 2)
659 sc
->vga_ram
[offset
+ 1*64*KB
] = c1
;
660 if (sc
->vga_seq
.seq_map_mask
& 4)
661 sc
->vga_ram
[offset
+ 2*64*KB
] = c2
;
662 if (sc
->vga_seq
.seq_map_mask
& 8)
663 sc
->vga_ram
[offset
+ 3*64*KB
] = c3
;
668 vga_mem_handler(struct vmctx
*ctx
, int vcpu
, int dir
, uint64_t addr
,
669 int size
, uint64_t *val
, void *arg1
, long arg2
)
671 if (dir
== MEM_F_WRITE
) {
674 vga_mem_wr_handler(ctx
, addr
, *val
, arg1
);
677 vga_mem_wr_handler(ctx
, addr
, *val
, arg1
);
678 vga_mem_wr_handler(ctx
, addr
+ 1, *val
>> 8, arg1
);
681 vga_mem_wr_handler(ctx
, addr
, *val
, arg1
);
682 vga_mem_wr_handler(ctx
, addr
+ 1, *val
>> 8, arg1
);
683 vga_mem_wr_handler(ctx
, addr
+ 2, *val
>> 16, arg1
);
684 vga_mem_wr_handler(ctx
, addr
+ 3, *val
>> 24, arg1
);
687 vga_mem_wr_handler(ctx
, addr
, *val
, arg1
);
688 vga_mem_wr_handler(ctx
, addr
+ 1, *val
>> 8, arg1
);
689 vga_mem_wr_handler(ctx
, addr
+ 2, *val
>> 16, arg1
);
690 vga_mem_wr_handler(ctx
, addr
+ 3, *val
>> 24, arg1
);
691 vga_mem_wr_handler(ctx
, addr
+ 4, *val
>> 32, arg1
);
692 vga_mem_wr_handler(ctx
, addr
+ 5, *val
>> 40, arg1
);
693 vga_mem_wr_handler(ctx
, addr
+ 6, *val
>> 48, arg1
);
694 vga_mem_wr_handler(ctx
, addr
+ 7, *val
>> 56, arg1
);
700 *val
= vga_mem_rd_handler(ctx
, addr
, arg1
);
703 *val
= vga_mem_rd_handler(ctx
, addr
, arg1
);
704 *val
|= vga_mem_rd_handler(ctx
, addr
+ 1, arg1
) << 8;
707 *val
= vga_mem_rd_handler(ctx
, addr
, arg1
);
708 *val
|= vga_mem_rd_handler(ctx
, addr
+ 1, arg1
) << 8;
709 *val
|= vga_mem_rd_handler(ctx
, addr
+ 2, arg1
) << 16;
710 *val
|= vga_mem_rd_handler(ctx
, addr
+ 3, arg1
) << 24;
713 *val
= vga_mem_rd_handler(ctx
, addr
, arg1
);
714 *val
|= vga_mem_rd_handler(ctx
, addr
+ 1, arg1
) << 8;
715 *val
|= vga_mem_rd_handler(ctx
, addr
+ 2, arg1
) << 16;
716 *val
|= vga_mem_rd_handler(ctx
, addr
+ 3, arg1
) << 24;
717 *val
|= vga_mem_rd_handler(ctx
, addr
+ 4, arg1
) << 32;
718 *val
|= vga_mem_rd_handler(ctx
, addr
+ 5, arg1
) << 40;
719 *val
|= vga_mem_rd_handler(ctx
, addr
+ 6, arg1
) << 48;
720 *val
|= vga_mem_rd_handler(ctx
, addr
+ 7, arg1
) << 56;
729 vga_port_in_handler(struct vmctx
*ctx
, int in
, int port
, int bytes
,
730 uint8_t *val
, void *arg
)
732 struct vga_softc
*sc
= arg
;
735 case CRTC_IDX_MONO_PORT
:
736 case CRTC_IDX_COLOR_PORT
:
737 *val
= sc
->vga_crtc
.crtc_index
;
739 case CRTC_DATA_MONO_PORT
:
740 case CRTC_DATA_COLOR_PORT
:
741 switch (sc
->vga_crtc
.crtc_index
) {
742 case CRTC_HORIZ_TOTAL
:
743 *val
= sc
->vga_crtc
.crtc_horiz_total
;
745 case CRTC_HORIZ_DISP_END
:
746 *val
= sc
->vga_crtc
.crtc_horiz_disp_end
;
748 case CRTC_START_HORIZ_BLANK
:
749 *val
= sc
->vga_crtc
.crtc_start_horiz_blank
;
751 case CRTC_END_HORIZ_BLANK
:
752 *val
= sc
->vga_crtc
.crtc_end_horiz_blank
;
754 case CRTC_START_HORIZ_RETRACE
:
755 *val
= sc
->vga_crtc
.crtc_start_horiz_retrace
;
757 case CRTC_END_HORIZ_RETRACE
:
758 *val
= sc
->vga_crtc
.crtc_end_horiz_retrace
;
760 case CRTC_VERT_TOTAL
:
761 *val
= sc
->vga_crtc
.crtc_vert_total
;
764 *val
= sc
->vga_crtc
.crtc_overflow
;
766 case CRTC_PRESET_ROW_SCAN
:
767 *val
= sc
->vga_crtc
.crtc_present_row_scan
;
769 case CRTC_MAX_SCAN_LINE
:
770 *val
= sc
->vga_crtc
.crtc_max_scan_line
;
772 case CRTC_CURSOR_START
:
773 *val
= sc
->vga_crtc
.crtc_cursor_start
;
775 case CRTC_CURSOR_END
:
776 *val
= sc
->vga_crtc
.crtc_cursor_end
;
778 case CRTC_START_ADDR_HIGH
:
779 *val
= sc
->vga_crtc
.crtc_start_addr_high
;
781 case CRTC_START_ADDR_LOW
:
782 *val
= sc
->vga_crtc
.crtc_start_addr_low
;
784 case CRTC_CURSOR_LOC_HIGH
:
785 *val
= sc
->vga_crtc
.crtc_cursor_loc_high
;
787 case CRTC_CURSOR_LOC_LOW
:
788 *val
= sc
->vga_crtc
.crtc_cursor_loc_low
;
790 case CRTC_VERT_RETRACE_START
:
791 *val
= sc
->vga_crtc
.crtc_vert_retrace_start
;
793 case CRTC_VERT_RETRACE_END
:
794 *val
= sc
->vga_crtc
.crtc_vert_retrace_end
;
796 case CRTC_VERT_DISP_END
:
797 *val
= sc
->vga_crtc
.crtc_vert_disp_end
;
800 *val
= sc
->vga_crtc
.crtc_offset
;
802 case CRTC_UNDERLINE_LOC
:
803 *val
= sc
->vga_crtc
.crtc_underline_loc
;
805 case CRTC_START_VERT_BLANK
:
806 *val
= sc
->vga_crtc
.crtc_start_vert_blank
;
808 case CRTC_END_VERT_BLANK
:
809 *val
= sc
->vga_crtc
.crtc_end_vert_blank
;
811 case CRTC_MODE_CONTROL
:
812 *val
= sc
->vga_crtc
.crtc_mode_ctrl
;
814 case CRTC_LINE_COMPARE
:
815 *val
= sc
->vga_crtc
.crtc_line_compare
;
818 //printf("XXX VGA CRTC: inb 0x%04x at index %d\n", port, sc->vga_crtc.crtc_index);
824 *val
= sc
->vga_atc
.atc_index
;
827 switch (sc
->vga_atc
.atc_index
) {
828 case ATC_PALETTE0
... ATC_PALETTE15
:
829 *val
= sc
->vga_atc
.atc_palette
[sc
->vga_atc
.atc_index
];
831 case ATC_MODE_CONTROL
:
832 *val
= sc
->vga_atc
.atc_mode
;
834 case ATC_OVERSCAN_COLOR
:
835 *val
= sc
->vga_atc
.atc_overscan_color
;
837 case ATC_COLOR_PLANE_ENABLE
:
838 *val
= sc
->vga_atc
.atc_color_plane_enb
;
840 case ATC_HORIZ_PIXEL_PANNING
:
841 *val
= sc
->vga_atc
.atc_horiz_pixel_panning
;
843 case ATC_COLOR_SELECT
:
844 *val
= sc
->vga_atc
.atc_color_select
;
847 //printf("XXX VGA ATC inb 0x%04x at index %d\n", port , sc->vga_atc.atc_index);
853 *val
= sc
->vga_seq
.seq_index
;
856 switch (sc
->vga_seq
.seq_index
) {
858 *val
= sc
->vga_seq
.seq_reset
;
860 case SEQ_CLOCKING_MODE
:
861 *val
= sc
->vga_seq
.seq_clock_mode
;
864 *val
= sc
->vga_seq
.seq_map_mask
;
866 case SEQ_CHAR_MAP_SELECT
:
867 *val
= sc
->vga_seq
.seq_cmap_sel
;
869 case SEQ_MEMORY_MODE
:
870 *val
= sc
->vga_seq
.seq_mm
;
873 //printf("XXX VGA SEQ: inb 0x%04x at index %d\n", port, sc->vga_seq.seq_index);
879 *val
= sc
->vga_dac
.dac_palette
[3 * sc
->vga_dac
.dac_rd_index
+
880 sc
->vga_dac
.dac_rd_subindex
];
881 sc
->vga_dac
.dac_rd_subindex
++;
882 if (sc
->vga_dac
.dac_rd_subindex
== 3) {
883 sc
->vga_dac
.dac_rd_index
++;
884 sc
->vga_dac
.dac_rd_subindex
= 0;
888 *val
= sc
->vga_gc
.gc_index
;
891 switch (sc
->vga_gc
.gc_index
) {
893 *val
= sc
->vga_gc
.gc_set_reset
;
895 case GC_ENABLE_SET_RESET
:
896 *val
= sc
->vga_gc
.gc_enb_set_reset
;
898 case GC_COLOR_COMPARE
:
899 *val
= sc
->vga_gc
.gc_color_compare
;
902 *val
= sc
->vga_gc
.gc_rotate
;
904 case GC_READ_MAP_SELECT
:
905 *val
= sc
->vga_gc
.gc_read_map_sel
;
908 *val
= sc
->vga_gc
.gc_mode
;
910 case GC_MISCELLANEOUS
:
911 *val
= sc
->vga_gc
.gc_misc
;
913 case GC_COLOR_DONT_CARE
:
914 *val
= sc
->vga_gc
.gc_color_dont_care
;
917 *val
= sc
->vga_gc
.gc_bit_mask
;
920 //printf("XXX VGA GC: inb 0x%04x at index %d\n", port, sc->vga_crtc.crtc_index);
925 case GEN_MISC_OUTPUT_PORT
:
928 case GEN_INPUT_STS0_PORT
:
931 case GEN_INPUT_STS1_MONO_PORT
:
932 case GEN_INPUT_STS1_COLOR_PORT
:
933 sc
->vga_atc
.atc_flipflop
= 0;
935 sc
->vga_sts1
= GEN_IS1_VR
| GEN_IS1_DE
;
936 //sc->vga_sts1 ^= (GEN_IS1_VR | GEN_IS1_DE);
939 * During the bhyve bring-up process, a guest image was failing
940 * to successfully boot. It appeared to be spinning, waiting
941 * for this value to be toggled. Until it can be ruled out
942 * that this is unnecessary (and documentation seems to
943 * indicate that it should be present), the toggle should
946 sc
->vga_sts1
^= (GEN_IS1_VR
| GEN_IS1_DE
);
950 case GEN_FEATURE_CTRL_PORT
:
951 // OpenBSD calls this with bytes = 1
959 printf("XXX vga_port_in_handler() unhandled port 0x%x\n", port
);
968 vga_port_out_handler(struct vmctx
*ctx
, int in
, int port
, int bytes
,
969 uint8_t val
, void *arg
)
971 struct vga_softc
*sc
= arg
;
974 case CRTC_IDX_MONO_PORT
:
975 case CRTC_IDX_COLOR_PORT
:
976 sc
->vga_crtc
.crtc_index
= val
;
978 case CRTC_DATA_MONO_PORT
:
979 case CRTC_DATA_COLOR_PORT
:
980 switch (sc
->vga_crtc
.crtc_index
) {
981 case CRTC_HORIZ_TOTAL
:
982 sc
->vga_crtc
.crtc_horiz_total
= val
;
984 case CRTC_HORIZ_DISP_END
:
985 sc
->vga_crtc
.crtc_horiz_disp_end
= val
;
987 case CRTC_START_HORIZ_BLANK
:
988 sc
->vga_crtc
.crtc_start_horiz_blank
= val
;
990 case CRTC_END_HORIZ_BLANK
:
991 sc
->vga_crtc
.crtc_end_horiz_blank
= val
;
993 case CRTC_START_HORIZ_RETRACE
:
994 sc
->vga_crtc
.crtc_start_horiz_retrace
= val
;
996 case CRTC_END_HORIZ_RETRACE
:
997 sc
->vga_crtc
.crtc_end_horiz_retrace
= val
;
999 case CRTC_VERT_TOTAL
:
1000 sc
->vga_crtc
.crtc_vert_total
= val
;
1003 sc
->vga_crtc
.crtc_overflow
= val
;
1005 case CRTC_PRESET_ROW_SCAN
:
1006 sc
->vga_crtc
.crtc_present_row_scan
= val
;
1008 case CRTC_MAX_SCAN_LINE
:
1009 sc
->vga_crtc
.crtc_max_scan_line
= val
;
1011 case CRTC_CURSOR_START
:
1012 sc
->vga_crtc
.crtc_cursor_start
= val
;
1013 sc
->vga_crtc
.crtc_cursor_on
= (val
& CRTC_CS_CO
) == 0;
1015 case CRTC_CURSOR_END
:
1016 sc
->vga_crtc
.crtc_cursor_end
= val
;
1018 case CRTC_START_ADDR_HIGH
:
1019 sc
->vga_crtc
.crtc_start_addr_high
= val
;
1020 sc
->vga_crtc
.crtc_start_addr
&= 0x00ff;
1021 sc
->vga_crtc
.crtc_start_addr
|= (val
<< 8);
1023 case CRTC_START_ADDR_LOW
:
1024 sc
->vga_crtc
.crtc_start_addr_low
= val
;
1025 sc
->vga_crtc
.crtc_start_addr
&= 0xff00;
1026 sc
->vga_crtc
.crtc_start_addr
|= (val
& 0xff);
1028 case CRTC_CURSOR_LOC_HIGH
:
1029 sc
->vga_crtc
.crtc_cursor_loc_high
= val
;
1030 sc
->vga_crtc
.crtc_cursor_loc
&= 0x00ff;
1031 sc
->vga_crtc
.crtc_cursor_loc
|= (val
<< 8);
1033 case CRTC_CURSOR_LOC_LOW
:
1034 sc
->vga_crtc
.crtc_cursor_loc_low
= val
;
1035 sc
->vga_crtc
.crtc_cursor_loc
&= 0xff00;
1036 sc
->vga_crtc
.crtc_cursor_loc
|= (val
& 0xff);
1038 case CRTC_VERT_RETRACE_START
:
1039 sc
->vga_crtc
.crtc_vert_retrace_start
= val
;
1041 case CRTC_VERT_RETRACE_END
:
1042 sc
->vga_crtc
.crtc_vert_retrace_end
= val
;
1044 case CRTC_VERT_DISP_END
:
1045 sc
->vga_crtc
.crtc_vert_disp_end
= val
;
1048 sc
->vga_crtc
.crtc_offset
= val
;
1050 case CRTC_UNDERLINE_LOC
:
1051 sc
->vga_crtc
.crtc_underline_loc
= val
;
1053 case CRTC_START_VERT_BLANK
:
1054 sc
->vga_crtc
.crtc_start_vert_blank
= val
;
1056 case CRTC_END_VERT_BLANK
:
1057 sc
->vga_crtc
.crtc_end_vert_blank
= val
;
1059 case CRTC_MODE_CONTROL
:
1060 sc
->vga_crtc
.crtc_mode_ctrl
= val
;
1062 case CRTC_LINE_COMPARE
:
1063 sc
->vga_crtc
.crtc_line_compare
= val
;
1066 //printf("XXX VGA CRTC: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_crtc.crtc_index);
1072 if (sc
->vga_atc
.atc_flipflop
== 0) {
1073 if (sc
->vga_atc
.atc_index
& 0x20)
1075 sc
->vga_atc
.atc_index
= val
& ATC_IDX_MASK
;
1077 switch (sc
->vga_atc
.atc_index
) {
1078 case ATC_PALETTE0
... ATC_PALETTE15
:
1079 sc
->vga_atc
.atc_palette
[sc
->vga_atc
.atc_index
] = val
& 0x3f;
1081 case ATC_MODE_CONTROL
:
1082 sc
->vga_atc
.atc_mode
= val
;
1084 case ATC_OVERSCAN_COLOR
:
1085 sc
->vga_atc
.atc_overscan_color
= val
;
1087 case ATC_COLOR_PLANE_ENABLE
:
1088 sc
->vga_atc
.atc_color_plane_enb
= val
;
1090 case ATC_HORIZ_PIXEL_PANNING
:
1091 sc
->vga_atc
.atc_horiz_pixel_panning
= val
;
1093 case ATC_COLOR_SELECT
:
1094 sc
->vga_atc
.atc_color_select
= val
;
1095 sc
->vga_atc
.atc_color_select_45
=
1096 (val
& ATC_CS_C45
) << 4;
1097 sc
->vga_atc
.atc_color_select_67
=
1098 ((val
& ATC_CS_C67
) >> 2) << 6;
1101 //printf("XXX VGA ATC: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_atc.atc_index);
1106 sc
->vga_atc
.atc_flipflop
^= 1;
1111 sc
->vga_seq
.seq_index
= val
& 0x1f;
1114 switch (sc
->vga_seq
.seq_index
) {
1116 sc
->vga_seq
.seq_reset
= val
;
1118 case SEQ_CLOCKING_MODE
:
1119 sc
->vga_seq
.seq_clock_mode
= val
;
1120 sc
->vga_seq
.seq_cm_dots
= (val
& SEQ_CM_89
) ? 8 : 9;
1123 sc
->vga_seq
.seq_map_mask
= val
;
1125 case SEQ_CHAR_MAP_SELECT
:
1126 sc
->vga_seq
.seq_cmap_sel
= val
;
1128 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
;
1129 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
;
1131 case SEQ_MEMORY_MODE
:
1132 sc
->vga_seq
.seq_mm
= val
;
1133 /* Windows queries Chain4 */
1134 //assert((sc->vga_seq.seq_mm & SEQ_MM_C4) == 0);
1137 //printf("XXX VGA SEQ: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_seq.seq_index);
1144 case DAC_IDX_RD_PORT
:
1145 sc
->vga_dac
.dac_rd_index
= val
;
1146 sc
->vga_dac
.dac_rd_subindex
= 0;
1148 case DAC_IDX_WR_PORT
:
1149 sc
->vga_dac
.dac_wr_index
= val
;
1150 sc
->vga_dac
.dac_wr_subindex
= 0;
1153 sc
->vga_dac
.dac_palette
[3 * sc
->vga_dac
.dac_wr_index
+
1154 sc
->vga_dac
.dac_wr_subindex
] = val
;
1155 sc
->vga_dac
.dac_wr_subindex
++;
1156 if (sc
->vga_dac
.dac_wr_subindex
== 3) {
1157 sc
->vga_dac
.dac_palette_rgb
[sc
->vga_dac
.dac_wr_index
] =
1158 ((((sc
->vga_dac
.dac_palette
[3*sc
->vga_dac
.dac_wr_index
+ 0] << 2) |
1159 ((sc
->vga_dac
.dac_palette
[3*sc
->vga_dac
.dac_wr_index
+ 0] & 0x1) << 1) |
1160 (sc
->vga_dac
.dac_palette
[3*sc
->vga_dac
.dac_wr_index
+ 0] & 0x1)) << 16) |
1161 (((sc
->vga_dac
.dac_palette
[3*sc
->vga_dac
.dac_wr_index
+ 1] << 2) |
1162 ((sc
->vga_dac
.dac_palette
[3*sc
->vga_dac
.dac_wr_index
+ 1] & 0x1) << 1) |
1163 (sc
->vga_dac
.dac_palette
[3*sc
->vga_dac
.dac_wr_index
+ 1] & 0x1)) << 8) |
1164 (((sc
->vga_dac
.dac_palette
[3*sc
->vga_dac
.dac_wr_index
+ 2] << 2) |
1165 ((sc
->vga_dac
.dac_palette
[3*sc
->vga_dac
.dac_wr_index
+ 2] & 0x1) << 1) |
1166 (sc
->vga_dac
.dac_palette
[3*sc
->vga_dac
.dac_wr_index
+ 2] & 0x1)) << 0));
1168 sc
->vga_dac
.dac_wr_index
++;
1169 sc
->vga_dac
.dac_wr_subindex
= 0;
1173 sc
->vga_gc
.gc_index
= val
;
1176 switch (sc
->vga_gc
.gc_index
) {
1178 sc
->vga_gc
.gc_set_reset
= val
;
1180 case GC_ENABLE_SET_RESET
:
1181 sc
->vga_gc
.gc_enb_set_reset
= val
;
1183 case GC_COLOR_COMPARE
:
1184 sc
->vga_gc
.gc_color_compare
= val
;
1186 case GC_DATA_ROTATE
:
1187 sc
->vga_gc
.gc_rotate
= val
;
1188 sc
->vga_gc
.gc_op
= (val
>> 3) & 0x3;
1190 case GC_READ_MAP_SELECT
:
1191 sc
->vga_gc
.gc_read_map_sel
= val
;
1194 sc
->vga_gc
.gc_mode
= val
;
1195 sc
->vga_gc
.gc_mode_c4
= (val
& GC_MODE_C4
) != 0;
1196 assert(!sc
->vga_gc
.gc_mode_c4
);
1197 sc
->vga_gc
.gc_mode_oe
= (val
& GC_MODE_OE
) != 0;
1198 sc
->vga_gc
.gc_mode_rm
= (val
>> 3) & 0x1;
1199 sc
->vga_gc
.gc_mode_wm
= val
& 0x3;
1202 sc
->gc_image
->vgamode
= 1;
1204 case GC_MISCELLANEOUS
:
1205 sc
->vga_gc
.gc_misc
= val
;
1206 sc
->vga_gc
.gc_misc_gm
= val
& GC_MISC_GM
;
1207 sc
->vga_gc
.gc_misc_mm
= (val
& GC_MISC_MM
) >>
1210 case GC_COLOR_DONT_CARE
:
1211 sc
->vga_gc
.gc_color_dont_care
= val
;
1214 sc
->vga_gc
.gc_bit_mask
= val
;
1217 //printf("XXX VGA GC: outb 0x%04x, 0x%02x at index %d\n", port, val, sc->vga_gc.gc_index);
1222 case GEN_INPUT_STS0_PORT
:
1223 /* write to Miscellaneous Output Register */
1226 case GEN_INPUT_STS1_MONO_PORT
:
1227 case GEN_INPUT_STS1_COLOR_PORT
:
1228 /* write to Feature Control Register */
1233 printf("XXX vga_port_out_handler() unhandled port 0x%x, val 0x%x\n", port
, val
);
1241 vga_port_handler(struct vmctx
*ctx
, int in
, int port
,
1242 int bytes
, uint32_t *eax
, void *arg
)
1251 error
= vga_port_in_handler(ctx
, in
, port
, 1,
1258 error
= vga_port_out_handler(ctx
, in
, port
, 1,
1265 error
= vga_port_in_handler(ctx
, in
, port
, 1,
1270 error
= vga_port_in_handler(ctx
, in
, port
+ 1, 1,
1273 *eax
|= (val
& 0xff) << 8;
1277 error
= vga_port_out_handler(ctx
, in
, port
, 1,
1279 val
= (*eax
>> 8) & 0xff;
1280 error
=vga_port_out_handler(ctx
, in
, port
+ 1, 1,
1293 vga_init(int io_only
)
1295 struct inout_port iop
;
1296 struct vga_softc
*sc
;
1299 sc
= calloc(1, sizeof(struct vga_softc
));
1301 bzero(&iop
, sizeof(struct inout_port
));
1303 for (port
= VGA_IOPORT_START
; port
<= VGA_IOPORT_END
; port
++) {
1306 iop
.flags
= IOPORT_F_INOUT
;
1307 iop
.handler
= vga_port_handler
;
1310 error
= register_inout(&iop
);
1314 sc
->gc_image
= console_get_image();
1316 /* only handle io ports; vga graphics is disabled */
1320 sc
->mr
.name
= "VGA memory";
1321 sc
->mr
.flags
= MEM_F_RW
;
1322 sc
->mr
.base
= 640 * KB
;
1323 sc
->mr
.size
= 128 * KB
;
1324 sc
->mr
.handler
= vga_mem_handler
;
1326 error
= register_mem_fallback(&sc
->mr
);
1329 sc
->vga_ram
= malloc(256 * KB
);
1330 memset(sc
->vga_ram
, 0, 256 * KB
);
1333 static uint8_t palette
[] = {
1334 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
1335 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,
1336 0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f,
1337 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,
1341 memcpy(sc
->vga_dac
.dac_palette
, palette
, 16 * 3 * sizeof (uint8_t));
1342 for (i
= 0; i
< 16; i
++) {
1343 sc
->vga_dac
.dac_palette_rgb
[i
] =
1344 ((((sc
->vga_dac
.dac_palette
[3*i
+ 0] << 2) |
1345 ((sc
->vga_dac
.dac_palette
[3*i
+ 0] & 0x1) << 1) |
1346 (sc
->vga_dac
.dac_palette
[3*i
+ 0] & 0x1)) << 16) |
1347 (((sc
->vga_dac
.dac_palette
[3*i
+ 1] << 2) |
1348 ((sc
->vga_dac
.dac_palette
[3*i
+ 1] & 0x1) << 1) |
1349 (sc
->vga_dac
.dac_palette
[3*i
+ 1] & 0x1)) << 8) |
1350 (((sc
->vga_dac
.dac_palette
[3*i
+ 2] << 2) |
1351 ((sc
->vga_dac
.dac_palette
[3*i
+ 2] & 0x1) << 1) |
1352 (sc
->vga_dac
.dac_palette
[3*i
+ 2] & 0x1)) << 0));