1fc97bb5bSPaolo Bonzini /*
2fc97bb5bSPaolo Bonzini * QEMU VGA Emulator.
3fc97bb5bSPaolo Bonzini *
4fc97bb5bSPaolo Bonzini * Copyright (c) 2003 Fabrice Bellard
5fc97bb5bSPaolo Bonzini *
6fc97bb5bSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
7fc97bb5bSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
8fc97bb5bSPaolo Bonzini * in the Software without restriction, including without limitation the rights
9fc97bb5bSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10fc97bb5bSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
11fc97bb5bSPaolo Bonzini * furnished to do so, subject to the following conditions:
12fc97bb5bSPaolo Bonzini *
13fc97bb5bSPaolo Bonzini * The above copyright notice and this permission notice shall be included in
14fc97bb5bSPaolo Bonzini * all copies or substantial portions of the Software.
15fc97bb5bSPaolo Bonzini *
16fc97bb5bSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17fc97bb5bSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18fc97bb5bSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19fc97bb5bSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20fc97bb5bSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21fc97bb5bSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22fc97bb5bSPaolo Bonzini * THE SOFTWARE.
23fc97bb5bSPaolo Bonzini */
2471e8a915SMarkus Armbruster
2547df5154SPeter Maydell #include "qemu/osdep.h"
26f0353b0dSPhilippe Mathieu-Daudé #include "qemu/units.h"
2771e8a915SMarkus Armbruster #include "sysemu/reset.h"
28da34e65cSMarkus Armbruster #include "qapi/error.h"
2942508261SPhilippe Mathieu-Daudé #include "exec/tswap.h"
30866e2b37SPhilippe Mathieu-Daudé #include "hw/display/vga.h"
319eb7e7e8SThomas Huth #include "hw/i386/x86.h"
32fc97bb5bSPaolo Bonzini #include "hw/pci/pci.h"
3347b43a1fSPaolo Bonzini #include "vga_int.h"
34d10d69e3SPhilippe Mathieu-Daudé #include "vga_regs.h"
35fc97bb5bSPaolo Bonzini #include "ui/pixel_ops.h"
3628cf3960SMichael S. Tsirkin #include "ui/console.h"
37fc97bb5bSPaolo Bonzini #include "qemu/timer.h"
38fc97bb5bSPaolo Bonzini #include "hw/xen/xen.h"
39d6454270SMarkus Armbruster #include "migration/vmstate.h"
40fc97bb5bSPaolo Bonzini #include "trace.h"
41fc97bb5bSPaolo Bonzini
42fc97bb5bSPaolo Bonzini //#define DEBUG_VGA_MEM
43fc97bb5bSPaolo Bonzini //#define DEBUG_VGA_REG
44fc97bb5bSPaolo Bonzini
4548ecfbf1SGerd Hoffmann bool have_vga = true;
4648ecfbf1SGerd Hoffmann
47fc97bb5bSPaolo Bonzini /* 16 state changes per vertical frame @60 Hz */
48fc97bb5bSPaolo Bonzini #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
49fc97bb5bSPaolo Bonzini
509b53b95aSPaolo Bonzini /* Address mask for non-VESA modes. */
519b53b95aSPaolo Bonzini #define VGA_VRAM_SIZE (256 * KiB)
529b53b95aSPaolo Bonzini
53973a724eSPaolo Bonzini /* This value corresponds to a shift of zero pixels
54973a724eSPaolo Bonzini * in 9-dot text mode. In other modes, bit 3 is undefined;
55973a724eSPaolo Bonzini * we just ignore it, so that 8 corresponds to zero pixels
56973a724eSPaolo Bonzini * in all modes.
57973a724eSPaolo Bonzini */
58973a724eSPaolo Bonzini #define VGA_HPEL_NEUTRAL 8
59973a724eSPaolo Bonzini
60fc97bb5bSPaolo Bonzini /*
61fc97bb5bSPaolo Bonzini * Video Graphics Array (VGA)
62fc97bb5bSPaolo Bonzini *
63fc97bb5bSPaolo Bonzini * Chipset docs for original IBM VGA:
64fc97bb5bSPaolo Bonzini * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
65fc97bb5bSPaolo Bonzini *
66fc97bb5bSPaolo Bonzini * FreeVGA site:
67fc97bb5bSPaolo Bonzini * http://www.osdever.net/FreeVGA/home.htm
68fc97bb5bSPaolo Bonzini *
69fc97bb5bSPaolo Bonzini * Standard VGA features and Bochs VBE extensions are implemented.
70fc97bb5bSPaolo Bonzini */
71fc97bb5bSPaolo Bonzini
72fc97bb5bSPaolo Bonzini /* force some bits to zero */
73fc97bb5bSPaolo Bonzini const uint8_t sr_mask[8] = {
74fc97bb5bSPaolo Bonzini 0x03,
75fc97bb5bSPaolo Bonzini 0x3d,
76fc97bb5bSPaolo Bonzini 0x0f,
77fc97bb5bSPaolo Bonzini 0x3f,
78fc97bb5bSPaolo Bonzini 0x0e,
79fc97bb5bSPaolo Bonzini 0x00,
80fc97bb5bSPaolo Bonzini 0x00,
81fc97bb5bSPaolo Bonzini 0xff,
82fc97bb5bSPaolo Bonzini };
83fc97bb5bSPaolo Bonzini
84fc97bb5bSPaolo Bonzini const uint8_t gr_mask[16] = {
85fc97bb5bSPaolo Bonzini 0x0f, /* 0x00 */
86fc97bb5bSPaolo Bonzini 0x0f, /* 0x01 */
87fc97bb5bSPaolo Bonzini 0x0f, /* 0x02 */
88fc97bb5bSPaolo Bonzini 0x1f, /* 0x03 */
89fc97bb5bSPaolo Bonzini 0x03, /* 0x04 */
90fc97bb5bSPaolo Bonzini 0x7b, /* 0x05 */
91fc97bb5bSPaolo Bonzini 0x0f, /* 0x06 */
92fc97bb5bSPaolo Bonzini 0x0f, /* 0x07 */
93fc97bb5bSPaolo Bonzini 0xff, /* 0x08 */
94fc97bb5bSPaolo Bonzini 0x00, /* 0x09 */
95fc97bb5bSPaolo Bonzini 0x00, /* 0x0a */
96fc97bb5bSPaolo Bonzini 0x00, /* 0x0b */
97fc97bb5bSPaolo Bonzini 0x00, /* 0x0c */
98fc97bb5bSPaolo Bonzini 0x00, /* 0x0d */
99fc97bb5bSPaolo Bonzini 0x00, /* 0x0e */
100fc97bb5bSPaolo Bonzini 0x00, /* 0x0f */
101fc97bb5bSPaolo Bonzini };
102fc97bb5bSPaolo Bonzini
103937de9a9SPaolo Bonzini #define GET_PLANE(data, p) ((cpu_to_le32(data) >> ((p) * 8)) & 0xff)
104fc97bb5bSPaolo Bonzini
105fc97bb5bSPaolo Bonzini static const uint32_t mask16[16] = {
106937de9a9SPaolo Bonzini const_le32(0x00000000),
107937de9a9SPaolo Bonzini const_le32(0x000000ff),
108937de9a9SPaolo Bonzini const_le32(0x0000ff00),
109937de9a9SPaolo Bonzini const_le32(0x0000ffff),
110937de9a9SPaolo Bonzini const_le32(0x00ff0000),
111937de9a9SPaolo Bonzini const_le32(0x00ff00ff),
112937de9a9SPaolo Bonzini const_le32(0x00ffff00),
113937de9a9SPaolo Bonzini const_le32(0x00ffffff),
114937de9a9SPaolo Bonzini const_le32(0xff000000),
115937de9a9SPaolo Bonzini const_le32(0xff0000ff),
116937de9a9SPaolo Bonzini const_le32(0xff00ff00),
117937de9a9SPaolo Bonzini const_le32(0xff00ffff),
118937de9a9SPaolo Bonzini const_le32(0xffff0000),
119937de9a9SPaolo Bonzini const_le32(0xffff00ff),
120937de9a9SPaolo Bonzini const_le32(0xffffff00),
121937de9a9SPaolo Bonzini const_le32(0xffffffff),
122fc97bb5bSPaolo Bonzini };
123fc97bb5bSPaolo Bonzini
124fc97bb5bSPaolo Bonzini static uint32_t expand4[256];
125fc97bb5bSPaolo Bonzini static uint16_t expand2[256];
126fc97bb5bSPaolo Bonzini static uint8_t expand4to8[16];
127fc97bb5bSPaolo Bonzini
128fd3c136bSGerd Hoffmann static void vbe_update_vgaregs(VGACommonState *s);
129fd3c136bSGerd Hoffmann
vbe_enabled(VGACommonState * s)130bfa0f151SGerd Hoffmann static inline bool vbe_enabled(VGACommonState *s)
131bfa0f151SGerd Hoffmann {
132bfa0f151SGerd Hoffmann return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
133bfa0f151SGerd Hoffmann }
134bfa0f151SGerd Hoffmann
sr(VGACommonState * s,int idx)13594ef4f33SGerd Hoffmann static inline uint8_t sr(VGACommonState *s, int idx)
13694ef4f33SGerd Hoffmann {
13794ef4f33SGerd Hoffmann return vbe_enabled(s) ? s->sr_vbe[idx] : s->sr[idx];
13894ef4f33SGerd Hoffmann }
13994ef4f33SGerd Hoffmann
vga_update_memory_access(VGACommonState * s)140fc97bb5bSPaolo Bonzini static void vga_update_memory_access(VGACommonState *s)
141fc97bb5bSPaolo Bonzini {
142fc97bb5bSPaolo Bonzini hwaddr base, offset, size;
143fc97bb5bSPaolo Bonzini
14463e3e24dSGerd Hoffmann if (s->legacy_address_space == NULL) {
14563e3e24dSGerd Hoffmann return;
14663e3e24dSGerd Hoffmann }
14763e3e24dSGerd Hoffmann
148ad37168cSPaolo Bonzini if (s->has_chain4_alias) {
149ad37168cSPaolo Bonzini memory_region_del_subregion(s->legacy_address_space, &s->chain4_alias);
150d8d95814SPaolo Bonzini object_unparent(OBJECT(&s->chain4_alias));
151ad37168cSPaolo Bonzini s->has_chain4_alias = false;
152ad37168cSPaolo Bonzini s->plane_updated = 0xf;
153ad37168cSPaolo Bonzini }
15494ef4f33SGerd Hoffmann if ((sr(s, VGA_SEQ_PLANE_WRITE) & VGA_SR02_ALL_PLANES) ==
15594ef4f33SGerd Hoffmann VGA_SR02_ALL_PLANES && sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
156fc97bb5bSPaolo Bonzini offset = 0;
157fc97bb5bSPaolo Bonzini switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
158fc97bb5bSPaolo Bonzini case 0:
159fc97bb5bSPaolo Bonzini base = 0xa0000;
160fc97bb5bSPaolo Bonzini size = 0x20000;
161fc97bb5bSPaolo Bonzini break;
162fc97bb5bSPaolo Bonzini case 1:
163fc97bb5bSPaolo Bonzini base = 0xa0000;
164fc97bb5bSPaolo Bonzini size = 0x10000;
165fc97bb5bSPaolo Bonzini offset = s->bank_offset;
166fc97bb5bSPaolo Bonzini break;
167fc97bb5bSPaolo Bonzini case 2:
168fc97bb5bSPaolo Bonzini base = 0xb0000;
169fc97bb5bSPaolo Bonzini size = 0x8000;
170fc97bb5bSPaolo Bonzini break;
171fc97bb5bSPaolo Bonzini case 3:
172fc97bb5bSPaolo Bonzini default:
173fc97bb5bSPaolo Bonzini base = 0xb8000;
174fc97bb5bSPaolo Bonzini size = 0x8000;
175fc97bb5bSPaolo Bonzini break;
176fc97bb5bSPaolo Bonzini }
1773bf18170SGerd Hoffmann assert(offset + size <= s->vram_size);
178ad37168cSPaolo Bonzini memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
17942e038feSPaolo Bonzini "vga.chain4", &s->vram, offset, size);
180fc97bb5bSPaolo Bonzini memory_region_add_subregion_overlap(s->legacy_address_space, base,
181ad37168cSPaolo Bonzini &s->chain4_alias, 2);
182ad37168cSPaolo Bonzini s->has_chain4_alias = true;
183fc97bb5bSPaolo Bonzini }
184fc97bb5bSPaolo Bonzini }
185fc97bb5bSPaolo Bonzini
vga_dumb_update_retrace_info(VGACommonState * s)186fc97bb5bSPaolo Bonzini static void vga_dumb_update_retrace_info(VGACommonState *s)
187fc97bb5bSPaolo Bonzini {
188fc97bb5bSPaolo Bonzini (void) s;
189fc97bb5bSPaolo Bonzini }
190fc97bb5bSPaolo Bonzini
vga_precise_update_retrace_info(VGACommonState * s)191fc97bb5bSPaolo Bonzini static void vga_precise_update_retrace_info(VGACommonState *s)
192fc97bb5bSPaolo Bonzini {
193fc97bb5bSPaolo Bonzini int htotal_chars;
194fc97bb5bSPaolo Bonzini int hretr_start_char;
195fc97bb5bSPaolo Bonzini int hretr_skew_chars;
196fc97bb5bSPaolo Bonzini int hretr_end_char;
197fc97bb5bSPaolo Bonzini
198fc97bb5bSPaolo Bonzini int vtotal_lines;
199fc97bb5bSPaolo Bonzini int vretr_start_line;
200fc97bb5bSPaolo Bonzini int vretr_end_line;
201fc97bb5bSPaolo Bonzini
202fc97bb5bSPaolo Bonzini int dots;
203fc97bb5bSPaolo Bonzini #if 0
204fc97bb5bSPaolo Bonzini int div2, sldiv2;
205fc97bb5bSPaolo Bonzini #endif
206fc97bb5bSPaolo Bonzini int clocking_mode;
207fc97bb5bSPaolo Bonzini int clock_sel;
208fc97bb5bSPaolo Bonzini const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
209fc97bb5bSPaolo Bonzini int64_t chars_per_sec;
210fc97bb5bSPaolo Bonzini struct vga_precise_retrace *r = &s->retrace_info.precise;
211fc97bb5bSPaolo Bonzini
212fc97bb5bSPaolo Bonzini htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
213fc97bb5bSPaolo Bonzini hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
214fc97bb5bSPaolo Bonzini hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
215fc97bb5bSPaolo Bonzini hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
216fc97bb5bSPaolo Bonzini
217fc97bb5bSPaolo Bonzini vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
218fc97bb5bSPaolo Bonzini (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
219fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
220fc97bb5bSPaolo Bonzini vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
221fc97bb5bSPaolo Bonzini ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
222fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
223fc97bb5bSPaolo Bonzini vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
224fc97bb5bSPaolo Bonzini
22594ef4f33SGerd Hoffmann clocking_mode = (sr(s, VGA_SEQ_CLOCK_MODE) >> 3) & 1;
226fc97bb5bSPaolo Bonzini clock_sel = (s->msr >> 2) & 3;
227fc97bb5bSPaolo Bonzini dots = (s->msr & 1) ? 8 : 9;
228fc97bb5bSPaolo Bonzini
229fc97bb5bSPaolo Bonzini chars_per_sec = clk_hz[clock_sel] / dots;
230fc97bb5bSPaolo Bonzini
231fc97bb5bSPaolo Bonzini htotal_chars <<= clocking_mode;
232fc97bb5bSPaolo Bonzini
233fc97bb5bSPaolo Bonzini r->total_chars = vtotal_lines * htotal_chars;
234fc97bb5bSPaolo Bonzini if (r->freq) {
23573bcb24dSRutuja Shah r->ticks_per_char = NANOSECONDS_PER_SECOND / (r->total_chars * r->freq);
236fc97bb5bSPaolo Bonzini } else {
23773bcb24dSRutuja Shah r->ticks_per_char = NANOSECONDS_PER_SECOND / chars_per_sec;
238fc97bb5bSPaolo Bonzini }
239fc97bb5bSPaolo Bonzini
240fc97bb5bSPaolo Bonzini r->vstart = vretr_start_line;
241fc97bb5bSPaolo Bonzini r->vend = r->vstart + vretr_end_line + 1;
242fc97bb5bSPaolo Bonzini
243fc97bb5bSPaolo Bonzini r->hstart = hretr_start_char + hretr_skew_chars;
244fc97bb5bSPaolo Bonzini r->hend = r->hstart + hretr_end_char + 1;
245fc97bb5bSPaolo Bonzini r->htotal = htotal_chars;
246fc97bb5bSPaolo Bonzini
247fc97bb5bSPaolo Bonzini #if 0
248fc97bb5bSPaolo Bonzini div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
249fc97bb5bSPaolo Bonzini sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
250fc97bb5bSPaolo Bonzini printf (
251fc97bb5bSPaolo Bonzini "hz=%f\n"
252fc97bb5bSPaolo Bonzini "htotal = %d\n"
253fc97bb5bSPaolo Bonzini "hretr_start = %d\n"
254fc97bb5bSPaolo Bonzini "hretr_skew = %d\n"
255fc97bb5bSPaolo Bonzini "hretr_end = %d\n"
256fc97bb5bSPaolo Bonzini "vtotal = %d\n"
257fc97bb5bSPaolo Bonzini "vretr_start = %d\n"
258fc97bb5bSPaolo Bonzini "vretr_end = %d\n"
259fc97bb5bSPaolo Bonzini "div2 = %d sldiv2 = %d\n"
260fc97bb5bSPaolo Bonzini "clocking_mode = %d\n"
261fc97bb5bSPaolo Bonzini "clock_sel = %d %d\n"
262fc97bb5bSPaolo Bonzini "dots = %d\n"
263fc97bb5bSPaolo Bonzini "ticks/char = %" PRId64 "\n"
264fc97bb5bSPaolo Bonzini "\n",
26573bcb24dSRutuja Shah (double) NANOSECONDS_PER_SECOND / (r->ticks_per_char * r->total_chars),
266fc97bb5bSPaolo Bonzini htotal_chars,
267fc97bb5bSPaolo Bonzini hretr_start_char,
268fc97bb5bSPaolo Bonzini hretr_skew_chars,
269fc97bb5bSPaolo Bonzini hretr_end_char,
270fc97bb5bSPaolo Bonzini vtotal_lines,
271fc97bb5bSPaolo Bonzini vretr_start_line,
272fc97bb5bSPaolo Bonzini vretr_end_line,
273fc97bb5bSPaolo Bonzini div2, sldiv2,
274fc97bb5bSPaolo Bonzini clocking_mode,
275fc97bb5bSPaolo Bonzini clock_sel,
276fc97bb5bSPaolo Bonzini clk_hz[clock_sel],
277fc97bb5bSPaolo Bonzini dots,
278fc97bb5bSPaolo Bonzini r->ticks_per_char
279fc97bb5bSPaolo Bonzini );
280fc97bb5bSPaolo Bonzini #endif
281fc97bb5bSPaolo Bonzini }
282fc97bb5bSPaolo Bonzini
vga_precise_retrace(VGACommonState * s)283fc97bb5bSPaolo Bonzini static uint8_t vga_precise_retrace(VGACommonState *s)
284fc97bb5bSPaolo Bonzini {
285fc97bb5bSPaolo Bonzini struct vga_precise_retrace *r = &s->retrace_info.precise;
286fc97bb5bSPaolo Bonzini uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
287fc97bb5bSPaolo Bonzini
288fc97bb5bSPaolo Bonzini if (r->total_chars) {
289fc97bb5bSPaolo Bonzini int cur_line, cur_line_char, cur_char;
290fc97bb5bSPaolo Bonzini int64_t cur_tick;
291fc97bb5bSPaolo Bonzini
292bc72ad67SAlex Bligh cur_tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
293fc97bb5bSPaolo Bonzini
294fc97bb5bSPaolo Bonzini cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
295fc97bb5bSPaolo Bonzini cur_line = cur_char / r->htotal;
296fc97bb5bSPaolo Bonzini
297fc97bb5bSPaolo Bonzini if (cur_line >= r->vstart && cur_line <= r->vend) {
298fc97bb5bSPaolo Bonzini val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
299fc97bb5bSPaolo Bonzini } else {
300fc97bb5bSPaolo Bonzini cur_line_char = cur_char % r->htotal;
301fc97bb5bSPaolo Bonzini if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
302fc97bb5bSPaolo Bonzini val |= ST01_DISP_ENABLE;
303fc97bb5bSPaolo Bonzini }
304fc97bb5bSPaolo Bonzini }
305fc97bb5bSPaolo Bonzini
306fc97bb5bSPaolo Bonzini return val;
307fc97bb5bSPaolo Bonzini } else {
308fc97bb5bSPaolo Bonzini return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
309fc97bb5bSPaolo Bonzini }
310fc97bb5bSPaolo Bonzini }
311fc97bb5bSPaolo Bonzini
vga_dumb_retrace(VGACommonState * s)312fc97bb5bSPaolo Bonzini static uint8_t vga_dumb_retrace(VGACommonState *s)
313fc97bb5bSPaolo Bonzini {
314fc97bb5bSPaolo Bonzini return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
315fc97bb5bSPaolo Bonzini }
316fc97bb5bSPaolo Bonzini
vga_ioport_invalid(VGACommonState * s,uint32_t addr)317fc97bb5bSPaolo Bonzini int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
318fc97bb5bSPaolo Bonzini {
319fc97bb5bSPaolo Bonzini if (s->msr & VGA_MIS_COLOR) {
320fc97bb5bSPaolo Bonzini /* Color */
321fc97bb5bSPaolo Bonzini return (addr >= 0x3b0 && addr <= 0x3bf);
322fc97bb5bSPaolo Bonzini } else {
323fc97bb5bSPaolo Bonzini /* Monochrome */
324fc97bb5bSPaolo Bonzini return (addr >= 0x3d0 && addr <= 0x3df);
325fc97bb5bSPaolo Bonzini }
326fc97bb5bSPaolo Bonzini }
327fc97bb5bSPaolo Bonzini
vga_ioport_read(void * opaque,uint32_t addr)328fc97bb5bSPaolo Bonzini uint32_t vga_ioport_read(void *opaque, uint32_t addr)
329fc97bb5bSPaolo Bonzini {
330fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
331fc97bb5bSPaolo Bonzini int val, index;
332fc97bb5bSPaolo Bonzini
333fc97bb5bSPaolo Bonzini if (vga_ioport_invalid(s, addr)) {
334fc97bb5bSPaolo Bonzini val = 0xff;
335fc97bb5bSPaolo Bonzini } else {
336fc97bb5bSPaolo Bonzini switch(addr) {
337fc97bb5bSPaolo Bonzini case VGA_ATT_W:
338fc97bb5bSPaolo Bonzini if (s->ar_flip_flop == 0) {
339fc97bb5bSPaolo Bonzini val = s->ar_index;
340fc97bb5bSPaolo Bonzini } else {
341fc97bb5bSPaolo Bonzini val = 0;
342fc97bb5bSPaolo Bonzini }
343fc97bb5bSPaolo Bonzini break;
344fc97bb5bSPaolo Bonzini case VGA_ATT_R:
345fc97bb5bSPaolo Bonzini index = s->ar_index & 0x1f;
346fc97bb5bSPaolo Bonzini if (index < VGA_ATT_C) {
347fc97bb5bSPaolo Bonzini val = s->ar[index];
348fc97bb5bSPaolo Bonzini } else {
349fc97bb5bSPaolo Bonzini val = 0;
350fc97bb5bSPaolo Bonzini }
351fc97bb5bSPaolo Bonzini break;
352fc97bb5bSPaolo Bonzini case VGA_MIS_W:
353fc97bb5bSPaolo Bonzini val = s->st00;
354fc97bb5bSPaolo Bonzini break;
355fc97bb5bSPaolo Bonzini case VGA_SEQ_I:
356fc97bb5bSPaolo Bonzini val = s->sr_index;
357fc97bb5bSPaolo Bonzini break;
358fc97bb5bSPaolo Bonzini case VGA_SEQ_D:
359fc97bb5bSPaolo Bonzini val = s->sr[s->sr_index];
360fc97bb5bSPaolo Bonzini #ifdef DEBUG_VGA_REG
361fc97bb5bSPaolo Bonzini printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
362fc97bb5bSPaolo Bonzini #endif
363fc97bb5bSPaolo Bonzini break;
364fc97bb5bSPaolo Bonzini case VGA_PEL_IR:
365fc97bb5bSPaolo Bonzini val = s->dac_state;
366fc97bb5bSPaolo Bonzini break;
367fc97bb5bSPaolo Bonzini case VGA_PEL_IW:
368fc97bb5bSPaolo Bonzini val = s->dac_write_index;
369fc97bb5bSPaolo Bonzini break;
370fc97bb5bSPaolo Bonzini case VGA_PEL_D:
371fc97bb5bSPaolo Bonzini val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
372fc97bb5bSPaolo Bonzini if (++s->dac_sub_index == 3) {
373fc97bb5bSPaolo Bonzini s->dac_sub_index = 0;
374fc97bb5bSPaolo Bonzini s->dac_read_index++;
375fc97bb5bSPaolo Bonzini }
376fc97bb5bSPaolo Bonzini break;
377fc97bb5bSPaolo Bonzini case VGA_FTC_R:
378fc97bb5bSPaolo Bonzini val = s->fcr;
379fc97bb5bSPaolo Bonzini break;
380fc97bb5bSPaolo Bonzini case VGA_MIS_R:
381fc97bb5bSPaolo Bonzini val = s->msr;
382fc97bb5bSPaolo Bonzini break;
383fc97bb5bSPaolo Bonzini case VGA_GFX_I:
384fc97bb5bSPaolo Bonzini val = s->gr_index;
385fc97bb5bSPaolo Bonzini break;
386fc97bb5bSPaolo Bonzini case VGA_GFX_D:
387fc97bb5bSPaolo Bonzini val = s->gr[s->gr_index];
388fc97bb5bSPaolo Bonzini #ifdef DEBUG_VGA_REG
389fc97bb5bSPaolo Bonzini printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
390fc97bb5bSPaolo Bonzini #endif
391fc97bb5bSPaolo Bonzini break;
392fc97bb5bSPaolo Bonzini case VGA_CRT_IM:
393fc97bb5bSPaolo Bonzini case VGA_CRT_IC:
394fc97bb5bSPaolo Bonzini val = s->cr_index;
395fc97bb5bSPaolo Bonzini break;
396fc97bb5bSPaolo Bonzini case VGA_CRT_DM:
397fc97bb5bSPaolo Bonzini case VGA_CRT_DC:
398fc97bb5bSPaolo Bonzini val = s->cr[s->cr_index];
399fc97bb5bSPaolo Bonzini #ifdef DEBUG_VGA_REG
400fc97bb5bSPaolo Bonzini printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
401fc97bb5bSPaolo Bonzini #endif
402fc97bb5bSPaolo Bonzini break;
403fc97bb5bSPaolo Bonzini case VGA_IS1_RM:
404fc97bb5bSPaolo Bonzini case VGA_IS1_RC:
405fc97bb5bSPaolo Bonzini /* just toggle to fool polling */
406fc97bb5bSPaolo Bonzini val = s->st01 = s->retrace(s);
407fc97bb5bSPaolo Bonzini s->ar_flip_flop = 0;
408fc97bb5bSPaolo Bonzini break;
409fc97bb5bSPaolo Bonzini default:
410fc97bb5bSPaolo Bonzini val = 0x00;
411fc97bb5bSPaolo Bonzini break;
412fc97bb5bSPaolo Bonzini }
413fc97bb5bSPaolo Bonzini }
414cf7dabeeSGerd Hoffmann trace_vga_std_read_io(addr, val);
415fc97bb5bSPaolo Bonzini return val;
416fc97bb5bSPaolo Bonzini }
417fc97bb5bSPaolo Bonzini
vga_ioport_write(void * opaque,uint32_t addr,uint32_t val)418fc97bb5bSPaolo Bonzini void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
419fc97bb5bSPaolo Bonzini {
420fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
421fc97bb5bSPaolo Bonzini int index;
422fc97bb5bSPaolo Bonzini
423fc97bb5bSPaolo Bonzini /* check port range access depending on color/monochrome mode */
424fc97bb5bSPaolo Bonzini if (vga_ioport_invalid(s, addr)) {
425fc97bb5bSPaolo Bonzini return;
426fc97bb5bSPaolo Bonzini }
427cf7dabeeSGerd Hoffmann trace_vga_std_write_io(addr, val);
428fc97bb5bSPaolo Bonzini
429fc97bb5bSPaolo Bonzini switch(addr) {
430fc97bb5bSPaolo Bonzini case VGA_ATT_W:
431fc97bb5bSPaolo Bonzini if (s->ar_flip_flop == 0) {
432fc97bb5bSPaolo Bonzini val &= 0x3f;
433fc97bb5bSPaolo Bonzini s->ar_index = val;
434fc97bb5bSPaolo Bonzini } else {
435fc97bb5bSPaolo Bonzini index = s->ar_index & 0x1f;
436fc97bb5bSPaolo Bonzini switch(index) {
437fc97bb5bSPaolo Bonzini case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
438fc97bb5bSPaolo Bonzini s->ar[index] = val & 0x3f;
439fc97bb5bSPaolo Bonzini break;
440fc97bb5bSPaolo Bonzini case VGA_ATC_MODE:
441fc97bb5bSPaolo Bonzini s->ar[index] = val & ~0x10;
442fc97bb5bSPaolo Bonzini break;
443fc97bb5bSPaolo Bonzini case VGA_ATC_OVERSCAN:
444fc97bb5bSPaolo Bonzini s->ar[index] = val;
445fc97bb5bSPaolo Bonzini break;
446fc97bb5bSPaolo Bonzini case VGA_ATC_PLANE_ENABLE:
447fc97bb5bSPaolo Bonzini s->ar[index] = val & ~0xc0;
448fc97bb5bSPaolo Bonzini break;
449fc97bb5bSPaolo Bonzini case VGA_ATC_PEL:
450fc97bb5bSPaolo Bonzini s->ar[index] = val & ~0xf0;
451fc97bb5bSPaolo Bonzini break;
452fc97bb5bSPaolo Bonzini case VGA_ATC_COLOR_PAGE:
453fc97bb5bSPaolo Bonzini s->ar[index] = val & ~0xf0;
454fc97bb5bSPaolo Bonzini break;
455fc97bb5bSPaolo Bonzini default:
456fc97bb5bSPaolo Bonzini break;
457fc97bb5bSPaolo Bonzini }
458fc97bb5bSPaolo Bonzini }
459fc97bb5bSPaolo Bonzini s->ar_flip_flop ^= 1;
460fc97bb5bSPaolo Bonzini break;
461fc97bb5bSPaolo Bonzini case VGA_MIS_W:
462fc97bb5bSPaolo Bonzini s->msr = val & ~0x10;
463fc97bb5bSPaolo Bonzini s->update_retrace_info(s);
464fc97bb5bSPaolo Bonzini break;
465fc97bb5bSPaolo Bonzini case VGA_SEQ_I:
466fc97bb5bSPaolo Bonzini s->sr_index = val & 7;
467fc97bb5bSPaolo Bonzini break;
468fc97bb5bSPaolo Bonzini case VGA_SEQ_D:
469fc97bb5bSPaolo Bonzini #ifdef DEBUG_VGA_REG
470fc97bb5bSPaolo Bonzini printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
471fc97bb5bSPaolo Bonzini #endif
472fc97bb5bSPaolo Bonzini s->sr[s->sr_index] = val & sr_mask[s->sr_index];
473fc97bb5bSPaolo Bonzini if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
474fc97bb5bSPaolo Bonzini s->update_retrace_info(s);
475fc97bb5bSPaolo Bonzini }
476fc97bb5bSPaolo Bonzini vga_update_memory_access(s);
477fc97bb5bSPaolo Bonzini break;
478fc97bb5bSPaolo Bonzini case VGA_PEL_IR:
479fc97bb5bSPaolo Bonzini s->dac_read_index = val;
480fc97bb5bSPaolo Bonzini s->dac_sub_index = 0;
481fc97bb5bSPaolo Bonzini s->dac_state = 3;
482fc97bb5bSPaolo Bonzini break;
483fc97bb5bSPaolo Bonzini case VGA_PEL_IW:
484fc97bb5bSPaolo Bonzini s->dac_write_index = val;
485fc97bb5bSPaolo Bonzini s->dac_sub_index = 0;
486fc97bb5bSPaolo Bonzini s->dac_state = 0;
487fc97bb5bSPaolo Bonzini break;
488fc97bb5bSPaolo Bonzini case VGA_PEL_D:
489fc97bb5bSPaolo Bonzini s->dac_cache[s->dac_sub_index] = val;
490fc97bb5bSPaolo Bonzini if (++s->dac_sub_index == 3) {
491fc97bb5bSPaolo Bonzini memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
492fc97bb5bSPaolo Bonzini s->dac_sub_index = 0;
493fc97bb5bSPaolo Bonzini s->dac_write_index++;
494fc97bb5bSPaolo Bonzini }
495fc97bb5bSPaolo Bonzini break;
496fc97bb5bSPaolo Bonzini case VGA_GFX_I:
497fc97bb5bSPaolo Bonzini s->gr_index = val & 0x0f;
498fc97bb5bSPaolo Bonzini break;
499fc97bb5bSPaolo Bonzini case VGA_GFX_D:
500fc97bb5bSPaolo Bonzini #ifdef DEBUG_VGA_REG
501fc97bb5bSPaolo Bonzini printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
502fc97bb5bSPaolo Bonzini #endif
503fc97bb5bSPaolo Bonzini s->gr[s->gr_index] = val & gr_mask[s->gr_index];
504fd3c136bSGerd Hoffmann vbe_update_vgaregs(s);
505fc97bb5bSPaolo Bonzini vga_update_memory_access(s);
506fc97bb5bSPaolo Bonzini break;
507fc97bb5bSPaolo Bonzini case VGA_CRT_IM:
508fc97bb5bSPaolo Bonzini case VGA_CRT_IC:
509fc97bb5bSPaolo Bonzini s->cr_index = val;
510fc97bb5bSPaolo Bonzini break;
511fc97bb5bSPaolo Bonzini case VGA_CRT_DM:
512fc97bb5bSPaolo Bonzini case VGA_CRT_DC:
513fc97bb5bSPaolo Bonzini #ifdef DEBUG_VGA_REG
514fc97bb5bSPaolo Bonzini printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
515fc97bb5bSPaolo Bonzini #endif
516fc97bb5bSPaolo Bonzini /* handle CR0-7 protection */
517fc97bb5bSPaolo Bonzini if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
518fc97bb5bSPaolo Bonzini s->cr_index <= VGA_CRTC_OVERFLOW) {
519fc97bb5bSPaolo Bonzini /* can always write bit 4 of CR7 */
520fc97bb5bSPaolo Bonzini if (s->cr_index == VGA_CRTC_OVERFLOW) {
521fc97bb5bSPaolo Bonzini s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
522fc97bb5bSPaolo Bonzini (val & 0x10);
523fd3c136bSGerd Hoffmann vbe_update_vgaregs(s);
524fc97bb5bSPaolo Bonzini }
525fc97bb5bSPaolo Bonzini return;
526fc97bb5bSPaolo Bonzini }
527fc97bb5bSPaolo Bonzini s->cr[s->cr_index] = val;
528fd3c136bSGerd Hoffmann vbe_update_vgaregs(s);
529fc97bb5bSPaolo Bonzini
530fc97bb5bSPaolo Bonzini switch(s->cr_index) {
531fc97bb5bSPaolo Bonzini case VGA_CRTC_H_TOTAL:
532fc97bb5bSPaolo Bonzini case VGA_CRTC_H_SYNC_START:
533fc97bb5bSPaolo Bonzini case VGA_CRTC_H_SYNC_END:
534fc97bb5bSPaolo Bonzini case VGA_CRTC_V_TOTAL:
535fc97bb5bSPaolo Bonzini case VGA_CRTC_OVERFLOW:
536fc97bb5bSPaolo Bonzini case VGA_CRTC_V_SYNC_END:
537fc97bb5bSPaolo Bonzini case VGA_CRTC_MODE:
538fc97bb5bSPaolo Bonzini s->update_retrace_info(s);
539fc97bb5bSPaolo Bonzini break;
540fc97bb5bSPaolo Bonzini }
541fc97bb5bSPaolo Bonzini break;
542fc97bb5bSPaolo Bonzini case VGA_IS1_RM:
543fc97bb5bSPaolo Bonzini case VGA_IS1_RC:
544fc97bb5bSPaolo Bonzini s->fcr = val & 0x10;
545fc97bb5bSPaolo Bonzini break;
546fc97bb5bSPaolo Bonzini }
547fc97bb5bSPaolo Bonzini }
548fc97bb5bSPaolo Bonzini
549c1b886c4SGerd Hoffmann /*
550c1b886c4SGerd Hoffmann * Sanity check vbe register writes.
551c1b886c4SGerd Hoffmann *
552c1b886c4SGerd Hoffmann * As we don't have a way to signal errors to the guest in the bochs
553c1b886c4SGerd Hoffmann * dispi interface we'll go adjust the registers to the closest valid
554c1b886c4SGerd Hoffmann * value.
555c1b886c4SGerd Hoffmann */
vbe_fixup_regs(VGACommonState * s)556c1b886c4SGerd Hoffmann static void vbe_fixup_regs(VGACommonState *s)
557c1b886c4SGerd Hoffmann {
558c1b886c4SGerd Hoffmann uint16_t *r = s->vbe_regs;
559c1b886c4SGerd Hoffmann uint32_t bits, linelength, maxy, offset;
560c1b886c4SGerd Hoffmann
561bfa0f151SGerd Hoffmann if (!vbe_enabled(s)) {
562c1b886c4SGerd Hoffmann /* vbe is turned off -- nothing to do */
563c1b886c4SGerd Hoffmann return;
564c1b886c4SGerd Hoffmann }
565c1b886c4SGerd Hoffmann
566c1b886c4SGerd Hoffmann /* check depth */
567c1b886c4SGerd Hoffmann switch (r[VBE_DISPI_INDEX_BPP]) {
568c1b886c4SGerd Hoffmann case 4:
569c1b886c4SGerd Hoffmann case 8:
570c1b886c4SGerd Hoffmann case 16:
571c1b886c4SGerd Hoffmann case 24:
572c1b886c4SGerd Hoffmann case 32:
573c1b886c4SGerd Hoffmann bits = r[VBE_DISPI_INDEX_BPP];
574c1b886c4SGerd Hoffmann break;
575c1b886c4SGerd Hoffmann case 15:
576c1b886c4SGerd Hoffmann bits = 16;
577c1b886c4SGerd Hoffmann break;
578c1b886c4SGerd Hoffmann default:
579c1b886c4SGerd Hoffmann bits = r[VBE_DISPI_INDEX_BPP] = 8;
580c1b886c4SGerd Hoffmann break;
581c1b886c4SGerd Hoffmann }
582c1b886c4SGerd Hoffmann
583c1b886c4SGerd Hoffmann /* check width */
584c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_XRES] &= ~7u;
585c1b886c4SGerd Hoffmann if (r[VBE_DISPI_INDEX_XRES] == 0) {
586c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_XRES] = 8;
587c1b886c4SGerd Hoffmann }
588c1b886c4SGerd Hoffmann if (r[VBE_DISPI_INDEX_XRES] > VBE_DISPI_MAX_XRES) {
589c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES;
590c1b886c4SGerd Hoffmann }
591c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_VIRT_WIDTH] &= ~7u;
592c1b886c4SGerd Hoffmann if (r[VBE_DISPI_INDEX_VIRT_WIDTH] > VBE_DISPI_MAX_XRES) {
593c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES;
594c1b886c4SGerd Hoffmann }
595c1b886c4SGerd Hoffmann if (r[VBE_DISPI_INDEX_VIRT_WIDTH] < r[VBE_DISPI_INDEX_XRES]) {
596c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES];
597c1b886c4SGerd Hoffmann }
598c1b886c4SGerd Hoffmann
599c1b886c4SGerd Hoffmann /* check height */
600c1b886c4SGerd Hoffmann linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8;
601c1b886c4SGerd Hoffmann maxy = s->vbe_size / linelength;
602c1b886c4SGerd Hoffmann if (r[VBE_DISPI_INDEX_YRES] == 0) {
603c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_YRES] = 1;
604c1b886c4SGerd Hoffmann }
605c1b886c4SGerd Hoffmann if (r[VBE_DISPI_INDEX_YRES] > VBE_DISPI_MAX_YRES) {
606c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES;
607c1b886c4SGerd Hoffmann }
608c1b886c4SGerd Hoffmann if (r[VBE_DISPI_INDEX_YRES] > maxy) {
609c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_YRES] = maxy;
610c1b886c4SGerd Hoffmann }
611c1b886c4SGerd Hoffmann
612c1b886c4SGerd Hoffmann /* check offset */
613c1b886c4SGerd Hoffmann if (r[VBE_DISPI_INDEX_X_OFFSET] > VBE_DISPI_MAX_XRES) {
614c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES;
615c1b886c4SGerd Hoffmann }
616c1b886c4SGerd Hoffmann if (r[VBE_DISPI_INDEX_Y_OFFSET] > VBE_DISPI_MAX_YRES) {
617c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES;
618c1b886c4SGerd Hoffmann }
619c1b886c4SGerd Hoffmann offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
620c1b886c4SGerd Hoffmann offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength;
621c1b886c4SGerd Hoffmann if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
622c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_Y_OFFSET] = 0;
623c1b886c4SGerd Hoffmann offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
624c1b886c4SGerd Hoffmann if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
625c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_X_OFFSET] = 0;
626c1b886c4SGerd Hoffmann offset = 0;
627c1b886c4SGerd Hoffmann }
628c1b886c4SGerd Hoffmann }
629c1b886c4SGerd Hoffmann
630c1b886c4SGerd Hoffmann /* update vga state */
631c1b886c4SGerd Hoffmann r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy;
632c1b886c4SGerd Hoffmann s->vbe_line_offset = linelength;
633c1b886c4SGerd Hoffmann s->vbe_start_addr = offset / 4;
634c1b886c4SGerd Hoffmann }
635c1b886c4SGerd Hoffmann
6367fa5c2c5SGerd Hoffmann /* we initialize the VGA graphic mode */
vbe_update_vgaregs(VGACommonState * s)6377fa5c2c5SGerd Hoffmann static void vbe_update_vgaregs(VGACommonState *s)
6387fa5c2c5SGerd Hoffmann {
6397fa5c2c5SGerd Hoffmann int h, shift_control;
6407fa5c2c5SGerd Hoffmann
6417fa5c2c5SGerd Hoffmann if (!vbe_enabled(s)) {
6427fa5c2c5SGerd Hoffmann /* vbe is turned off -- nothing to do */
6437fa5c2c5SGerd Hoffmann return;
6447fa5c2c5SGerd Hoffmann }
6457fa5c2c5SGerd Hoffmann
6467fa5c2c5SGerd Hoffmann /* graphic mode + memory map 1 */
6477fa5c2c5SGerd Hoffmann s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
6487fa5c2c5SGerd Hoffmann VGA_GR06_GRAPHICS_MODE;
6497fa5c2c5SGerd Hoffmann s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
6507fa5c2c5SGerd Hoffmann s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
6517fa5c2c5SGerd Hoffmann /* width */
6527fa5c2c5SGerd Hoffmann s->cr[VGA_CRTC_H_DISP] =
6537fa5c2c5SGerd Hoffmann (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
6547fa5c2c5SGerd Hoffmann /* height (only meaningful if < 1024) */
6557fa5c2c5SGerd Hoffmann h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
6567fa5c2c5SGerd Hoffmann s->cr[VGA_CRTC_V_DISP_END] = h;
6577fa5c2c5SGerd Hoffmann s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
6587fa5c2c5SGerd Hoffmann ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
6597fa5c2c5SGerd Hoffmann /* line compare to 1023 */
6607fa5c2c5SGerd Hoffmann s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
6617fa5c2c5SGerd Hoffmann s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
6627fa5c2c5SGerd Hoffmann s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
6637fa5c2c5SGerd Hoffmann
6647fa5c2c5SGerd Hoffmann if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
6657fa5c2c5SGerd Hoffmann shift_control = 0;
66694ef4f33SGerd Hoffmann s->sr_vbe[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
6677fa5c2c5SGerd Hoffmann } else {
6687fa5c2c5SGerd Hoffmann shift_control = 2;
6697fa5c2c5SGerd Hoffmann /* set chain 4 mode */
67094ef4f33SGerd Hoffmann s->sr_vbe[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
6717fa5c2c5SGerd Hoffmann /* activate all planes */
67294ef4f33SGerd Hoffmann s->sr_vbe[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
6737fa5c2c5SGerd Hoffmann }
6747fa5c2c5SGerd Hoffmann s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
6757fa5c2c5SGerd Hoffmann (shift_control << 5);
6767fa5c2c5SGerd Hoffmann s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
6777fa5c2c5SGerd Hoffmann }
6787fa5c2c5SGerd Hoffmann
vbe_ioport_read_index(void * opaque,uint32_t addr)679fc97bb5bSPaolo Bonzini static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
680fc97bb5bSPaolo Bonzini {
681fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
6829be38598SEduardo Habkost return s->vbe_index;
683fc97bb5bSPaolo Bonzini }
684fc97bb5bSPaolo Bonzini
vbe_ioport_read_data(void * opaque,uint32_t addr)685fc97bb5bSPaolo Bonzini uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
686fc97bb5bSPaolo Bonzini {
687fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
688fc97bb5bSPaolo Bonzini uint32_t val;
689fc97bb5bSPaolo Bonzini
690fc97bb5bSPaolo Bonzini if (s->vbe_index < VBE_DISPI_INDEX_NB) {
691fc97bb5bSPaolo Bonzini if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
692fc97bb5bSPaolo Bonzini switch(s->vbe_index) {
693fc97bb5bSPaolo Bonzini /* XXX: do not hardcode ? */
694fc97bb5bSPaolo Bonzini case VBE_DISPI_INDEX_XRES:
695fc97bb5bSPaolo Bonzini val = VBE_DISPI_MAX_XRES;
696fc97bb5bSPaolo Bonzini break;
697fc97bb5bSPaolo Bonzini case VBE_DISPI_INDEX_YRES:
698fc97bb5bSPaolo Bonzini val = VBE_DISPI_MAX_YRES;
699fc97bb5bSPaolo Bonzini break;
700fc97bb5bSPaolo Bonzini case VBE_DISPI_INDEX_BPP:
701fc97bb5bSPaolo Bonzini val = VBE_DISPI_MAX_BPP;
702fc97bb5bSPaolo Bonzini break;
703fc97bb5bSPaolo Bonzini default:
704fc97bb5bSPaolo Bonzini val = s->vbe_regs[s->vbe_index];
705fc97bb5bSPaolo Bonzini break;
706fc97bb5bSPaolo Bonzini }
707fc97bb5bSPaolo Bonzini } else {
708fc97bb5bSPaolo Bonzini val = s->vbe_regs[s->vbe_index];
709fc97bb5bSPaolo Bonzini }
710fc97bb5bSPaolo Bonzini } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
711f0353b0dSPhilippe Mathieu-Daudé val = s->vbe_size / (64 * KiB);
712fc97bb5bSPaolo Bonzini } else {
713fc97bb5bSPaolo Bonzini val = 0;
714fc97bb5bSPaolo Bonzini }
715cf7dabeeSGerd Hoffmann trace_vga_vbe_read(s->vbe_index, val);
716fc97bb5bSPaolo Bonzini return val;
717fc97bb5bSPaolo Bonzini }
718fc97bb5bSPaolo Bonzini
vbe_ioport_write_index(void * opaque,uint32_t addr,uint32_t val)719fc97bb5bSPaolo Bonzini void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
720fc97bb5bSPaolo Bonzini {
721fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
722fc97bb5bSPaolo Bonzini s->vbe_index = val;
723fc97bb5bSPaolo Bonzini }
724fc97bb5bSPaolo Bonzini
vbe_ioport_write_data(void * opaque,uint32_t addr,uint32_t val)725fc97bb5bSPaolo Bonzini void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
726fc97bb5bSPaolo Bonzini {
727fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
728fc97bb5bSPaolo Bonzini
729fc97bb5bSPaolo Bonzini if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
730cf7dabeeSGerd Hoffmann trace_vga_vbe_write(s->vbe_index, val);
731fc97bb5bSPaolo Bonzini switch(s->vbe_index) {
732fc97bb5bSPaolo Bonzini case VBE_DISPI_INDEX_ID:
733fc97bb5bSPaolo Bonzini if (val == VBE_DISPI_ID0 ||
734fc97bb5bSPaolo Bonzini val == VBE_DISPI_ID1 ||
735fc97bb5bSPaolo Bonzini val == VBE_DISPI_ID2 ||
736fc97bb5bSPaolo Bonzini val == VBE_DISPI_ID3 ||
73705ece98fSDennis Wölfing val == VBE_DISPI_ID4 ||
73805ece98fSDennis Wölfing val == VBE_DISPI_ID5) {
739fc97bb5bSPaolo Bonzini s->vbe_regs[s->vbe_index] = val;
740fc97bb5bSPaolo Bonzini }
741fc97bb5bSPaolo Bonzini break;
742fc97bb5bSPaolo Bonzini case VBE_DISPI_INDEX_XRES:
743fc97bb5bSPaolo Bonzini case VBE_DISPI_INDEX_YRES:
744fc97bb5bSPaolo Bonzini case VBE_DISPI_INDEX_BPP:
745c1b886c4SGerd Hoffmann case VBE_DISPI_INDEX_VIRT_WIDTH:
746c1b886c4SGerd Hoffmann case VBE_DISPI_INDEX_X_OFFSET:
747c1b886c4SGerd Hoffmann case VBE_DISPI_INDEX_Y_OFFSET:
748fc97bb5bSPaolo Bonzini s->vbe_regs[s->vbe_index] = val;
749c1b886c4SGerd Hoffmann vbe_fixup_regs(s);
7502068192dSGerd Hoffmann vbe_update_vgaregs(s);
751fc97bb5bSPaolo Bonzini break;
752fc97bb5bSPaolo Bonzini case VBE_DISPI_INDEX_BANK:
753fc97bb5bSPaolo Bonzini val &= s->vbe_bank_mask;
754fc97bb5bSPaolo Bonzini s->vbe_regs[s->vbe_index] = val;
755fc97bb5bSPaolo Bonzini s->bank_offset = (val << 16);
756fc97bb5bSPaolo Bonzini vga_update_memory_access(s);
757fc97bb5bSPaolo Bonzini break;
758fc97bb5bSPaolo Bonzini case VBE_DISPI_INDEX_ENABLE:
759fc97bb5bSPaolo Bonzini if ((val & VBE_DISPI_ENABLED) &&
760fc97bb5bSPaolo Bonzini !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
761fc97bb5bSPaolo Bonzini
762c1b886c4SGerd Hoffmann s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
763fc97bb5bSPaolo Bonzini s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
764fc97bb5bSPaolo Bonzini s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
765c1b886c4SGerd Hoffmann s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
766c1b886c4SGerd Hoffmann vbe_fixup_regs(s);
7677fa5c2c5SGerd Hoffmann vbe_update_vgaregs(s);
768fc97bb5bSPaolo Bonzini
769ace89b8fSBenjamin Herrenschmidt /* clear the screen */
770fc97bb5bSPaolo Bonzini if (!(val & VBE_DISPI_NOCLEARMEM)) {
771fc97bb5bSPaolo Bonzini memset(s->vram_ptr, 0,
772fc97bb5bSPaolo Bonzini s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
773fc97bb5bSPaolo Bonzini }
774fc97bb5bSPaolo Bonzini } else {
775fc97bb5bSPaolo Bonzini s->bank_offset = 0;
776fc97bb5bSPaolo Bonzini }
777fc97bb5bSPaolo Bonzini s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
778fc97bb5bSPaolo Bonzini s->vbe_regs[s->vbe_index] = val;
779fc97bb5bSPaolo Bonzini vga_update_memory_access(s);
780fc97bb5bSPaolo Bonzini break;
781fc97bb5bSPaolo Bonzini default:
782fc97bb5bSPaolo Bonzini break;
783fc97bb5bSPaolo Bonzini }
784fc97bb5bSPaolo Bonzini }
785fc97bb5bSPaolo Bonzini }
786fc97bb5bSPaolo Bonzini
787fc97bb5bSPaolo Bonzini /* called for accesses between 0xa0000 and 0xc0000 */
vga_mem_readb(VGACommonState * s,hwaddr addr)788fc97bb5bSPaolo Bonzini uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
789fc97bb5bSPaolo Bonzini {
790fc97bb5bSPaolo Bonzini int memory_map_mode, plane;
791fc97bb5bSPaolo Bonzini uint32_t ret;
792fc97bb5bSPaolo Bonzini
793fc97bb5bSPaolo Bonzini /* convert to VGA memory offset */
794fc97bb5bSPaolo Bonzini memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
795fc97bb5bSPaolo Bonzini addr &= 0x1ffff;
796fc97bb5bSPaolo Bonzini switch(memory_map_mode) {
797fc97bb5bSPaolo Bonzini case 0:
798fc97bb5bSPaolo Bonzini break;
799fc97bb5bSPaolo Bonzini case 1:
800fc97bb5bSPaolo Bonzini if (addr >= 0x10000)
801fc97bb5bSPaolo Bonzini return 0xff;
802fc97bb5bSPaolo Bonzini addr += s->bank_offset;
803fc97bb5bSPaolo Bonzini break;
804fc97bb5bSPaolo Bonzini case 2:
805fc97bb5bSPaolo Bonzini addr -= 0x10000;
806fc97bb5bSPaolo Bonzini if (addr >= 0x8000)
807fc97bb5bSPaolo Bonzini return 0xff;
808fc97bb5bSPaolo Bonzini break;
809fc97bb5bSPaolo Bonzini default:
810fc97bb5bSPaolo Bonzini case 3:
811fc97bb5bSPaolo Bonzini addr -= 0x18000;
812fc97bb5bSPaolo Bonzini if (addr >= 0x8000)
813fc97bb5bSPaolo Bonzini return 0xff;
814fc97bb5bSPaolo Bonzini break;
815fc97bb5bSPaolo Bonzini }
816fc97bb5bSPaolo Bonzini
81794ef4f33SGerd Hoffmann if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
81843526260SPaolo Bonzini /* chain4 mode */
81943526260SPaolo Bonzini plane = addr & 3;
82043526260SPaolo Bonzini addr &= ~3;
82143526260SPaolo Bonzini } else if (s->gr[VGA_GFX_MODE] & VGA_GR05_HOST_ODD_EVEN) {
822fc97bb5bSPaolo Bonzini /* odd/even mode (aka text mode mapping) */
823fc97bb5bSPaolo Bonzini plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
8243f834350SPaolo Bonzini } else {
825fc97bb5bSPaolo Bonzini /* standard VGA latched access */
826ae9d71a0SPaolo Bonzini plane = s->gr[VGA_GFX_PLANE_READ];
8273f834350SPaolo Bonzini }
8283f834350SPaolo Bonzini
82943526260SPaolo Bonzini if (s->gr[VGA_GFX_MISC] & VGA_GR06_CHAIN_ODD_EVEN) {
83043526260SPaolo Bonzini addr &= ~1;
83143526260SPaolo Bonzini }
83243526260SPaolo Bonzini
83343526260SPaolo Bonzini /* Doubleword/word mode. See comment in vga_mem_writeb */
83443526260SPaolo Bonzini if (s->cr[VGA_CRTC_UNDERLINE] & VGA_CR14_DW) {
83543526260SPaolo Bonzini addr >>= 2;
83643526260SPaolo Bonzini } else if ((s->gr[VGA_GFX_MODE] & VGA_GR05_HOST_ODD_EVEN) &&
83743526260SPaolo Bonzini (s->cr[VGA_CRTC_MODE] & VGA_CR17_WORD_BYTE) == 0) {
83843526260SPaolo Bonzini addr >>= 1;
83943526260SPaolo Bonzini }
84043526260SPaolo Bonzini
8413bf18170SGerd Hoffmann if (addr * sizeof(uint32_t) >= s->vram_size) {
8423bf18170SGerd Hoffmann return 0xff;
8433bf18170SGerd Hoffmann }
84443526260SPaolo Bonzini
84543526260SPaolo Bonzini if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
84643526260SPaolo Bonzini /* chain 4 mode: simplified access (but it should use the same
84743526260SPaolo Bonzini * algorithms as below, see e.g. vga_mem_writeb's plane mask check).
84843526260SPaolo Bonzini */
84943526260SPaolo Bonzini return s->vram_ptr[(addr << 2) | plane];
85043526260SPaolo Bonzini }
85143526260SPaolo Bonzini
852fc97bb5bSPaolo Bonzini s->latch = ((uint32_t *)s->vram_ptr)[addr];
853fc97bb5bSPaolo Bonzini if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
854fc97bb5bSPaolo Bonzini /* read mode 0 */
855fc97bb5bSPaolo Bonzini ret = GET_PLANE(s->latch, plane);
856fc97bb5bSPaolo Bonzini } else {
857fc97bb5bSPaolo Bonzini /* read mode 1 */
858fc97bb5bSPaolo Bonzini ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
859fc97bb5bSPaolo Bonzini mask16[s->gr[VGA_GFX_COMPARE_MASK]];
860fc97bb5bSPaolo Bonzini ret |= ret >> 16;
861fc97bb5bSPaolo Bonzini ret |= ret >> 8;
862fc97bb5bSPaolo Bonzini ret = (~ret) & 0xff;
863fc97bb5bSPaolo Bonzini }
864ae9d71a0SPaolo Bonzini
865fc97bb5bSPaolo Bonzini return ret;
866fc97bb5bSPaolo Bonzini }
867fc97bb5bSPaolo Bonzini
868fc97bb5bSPaolo Bonzini /* called for accesses between 0xa0000 and 0xc0000 */
vga_mem_writeb(VGACommonState * s,hwaddr addr,uint32_t val)869fc97bb5bSPaolo Bonzini void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
870fc97bb5bSPaolo Bonzini {
87143526260SPaolo Bonzini int memory_map_mode, write_mode, b, func_select, mask;
872fc97bb5bSPaolo Bonzini uint32_t write_mask, bit_mask, set_mask;
87343526260SPaolo Bonzini int plane = 0;
874fc97bb5bSPaolo Bonzini
875fc97bb5bSPaolo Bonzini #ifdef DEBUG_VGA_MEM
876883f2c59SPhilippe Mathieu-Daudé printf("vga: [0x" HWADDR_FMT_plx "] = 0x%02x\n", addr, val);
877fc97bb5bSPaolo Bonzini #endif
878fc97bb5bSPaolo Bonzini /* convert to VGA memory offset */
879fc97bb5bSPaolo Bonzini memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
880fc97bb5bSPaolo Bonzini addr &= 0x1ffff;
881fc97bb5bSPaolo Bonzini switch(memory_map_mode) {
882fc97bb5bSPaolo Bonzini case 0:
883fc97bb5bSPaolo Bonzini break;
884fc97bb5bSPaolo Bonzini case 1:
885fc97bb5bSPaolo Bonzini if (addr >= 0x10000)
886fc97bb5bSPaolo Bonzini return;
887fc97bb5bSPaolo Bonzini addr += s->bank_offset;
888fc97bb5bSPaolo Bonzini break;
889fc97bb5bSPaolo Bonzini case 2:
890fc97bb5bSPaolo Bonzini addr -= 0x10000;
891fc97bb5bSPaolo Bonzini if (addr >= 0x8000)
892fc97bb5bSPaolo Bonzini return;
893fc97bb5bSPaolo Bonzini break;
894fc97bb5bSPaolo Bonzini default:
895fc97bb5bSPaolo Bonzini case 3:
896fc97bb5bSPaolo Bonzini addr -= 0x18000;
897fc97bb5bSPaolo Bonzini if (addr >= 0x8000)
898fc97bb5bSPaolo Bonzini return;
899fc97bb5bSPaolo Bonzini break;
900fc97bb5bSPaolo Bonzini }
901fc97bb5bSPaolo Bonzini
9023f834350SPaolo Bonzini mask = sr(s, VGA_SEQ_PLANE_WRITE);
90394ef4f33SGerd Hoffmann if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
904fc97bb5bSPaolo Bonzini /* chain 4 mode : simplest access */
905fc97bb5bSPaolo Bonzini plane = addr & 3;
9063f834350SPaolo Bonzini mask &= (1 << plane);
90743526260SPaolo Bonzini addr &= ~3;
90843526260SPaolo Bonzini } else {
90943526260SPaolo Bonzini if ((sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_SEQ_MODE) == 0) {
91043526260SPaolo Bonzini mask &= (addr & 1) ? 0x0a : 0x05;
91143526260SPaolo Bonzini }
91243526260SPaolo Bonzini if (s->gr[VGA_GFX_MISC] & VGA_GR06_CHAIN_ODD_EVEN) {
91343526260SPaolo Bonzini addr &= ~1;
91443526260SPaolo Bonzini }
91543526260SPaolo Bonzini }
91643526260SPaolo Bonzini
91743526260SPaolo Bonzini /* Doubleword/word mode. These should be honored when displaying,
91843526260SPaolo Bonzini * not when reading/writing to memory! For example, chain4 modes
91943526260SPaolo Bonzini * use double-word mode and, on real hardware, would fetch bytes
92043526260SPaolo Bonzini * 0,1,2,3, 16,17,18,19, 32,33,34,35, etc. Text modes use word
92143526260SPaolo Bonzini * mode and, on real hardware, would fetch bytes 0,1, 8,9, etc.
92243526260SPaolo Bonzini *
92343526260SPaolo Bonzini * QEMU instead shifted addresses on memory accesses because it
92443526260SPaolo Bonzini * allows more optimizations (e.g. chain4_alias) and simplifies
92543526260SPaolo Bonzini * the draw_line handlers. Unfortunately, there is one case where
92643526260SPaolo Bonzini * the difference shows. When fetching font data, accesses are
92743526260SPaolo Bonzini * always in consecutive bytes, even if the text/attribute pairs
92843526260SPaolo Bonzini * are done in word mode. Hence, doing a right shift when operating
92943526260SPaolo Bonzini * on font data is wrong. So check the odd/even mode bits together with
93043526260SPaolo Bonzini * word mode bit. The odd/even read bit is 0 when reading font data,
93143526260SPaolo Bonzini * and the odd/even write bit is 1 when writing it.
93243526260SPaolo Bonzini */
93343526260SPaolo Bonzini if (s->cr[VGA_CRTC_UNDERLINE] & VGA_CR14_DW) {
93443526260SPaolo Bonzini addr >>= 2;
93543526260SPaolo Bonzini } else if ((sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_SEQ_MODE) == 0 &&
93643526260SPaolo Bonzini (s->cr[VGA_CRTC_MODE] & VGA_CR17_WORD_BYTE) == 0) {
93743526260SPaolo Bonzini addr >>= 1;
93843526260SPaolo Bonzini }
93943526260SPaolo Bonzini
94043526260SPaolo Bonzini if (addr * sizeof(uint32_t) >= s->vram_size) {
94143526260SPaolo Bonzini return;
94243526260SPaolo Bonzini }
94343526260SPaolo Bonzini
94443526260SPaolo Bonzini if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
9453f834350SPaolo Bonzini if (mask) {
94643526260SPaolo Bonzini s->vram_ptr[(addr << 2) | plane] = val;
947fc97bb5bSPaolo Bonzini #ifdef DEBUG_VGA_MEM
948883f2c59SPhilippe Mathieu-Daudé printf("vga: chain4: [0x" HWADDR_FMT_plx "]\n", addr);
949fc97bb5bSPaolo Bonzini #endif
950fc97bb5bSPaolo Bonzini s->plane_updated |= mask; /* only used to detect font change */
951fc97bb5bSPaolo Bonzini memory_region_set_dirty(&s->vram, addr, 1);
952fc97bb5bSPaolo Bonzini }
953ae9d71a0SPaolo Bonzini return;
954ae9d71a0SPaolo Bonzini }
955ae9d71a0SPaolo Bonzini
956fc97bb5bSPaolo Bonzini /* standard VGA latched access */
957fc97bb5bSPaolo Bonzini write_mode = s->gr[VGA_GFX_MODE] & 3;
958fc97bb5bSPaolo Bonzini switch(write_mode) {
959fc97bb5bSPaolo Bonzini default:
960fc97bb5bSPaolo Bonzini case 0:
961fc97bb5bSPaolo Bonzini /* rotate */
962fc97bb5bSPaolo Bonzini b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
963fc97bb5bSPaolo Bonzini val = ((val >> b) | (val << (8 - b))) & 0xff;
964fc97bb5bSPaolo Bonzini val |= val << 8;
965fc97bb5bSPaolo Bonzini val |= val << 16;
966fc97bb5bSPaolo Bonzini
967fc97bb5bSPaolo Bonzini /* apply set/reset mask */
968fc97bb5bSPaolo Bonzini set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
969fc97bb5bSPaolo Bonzini val = (val & ~set_mask) |
970fc97bb5bSPaolo Bonzini (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
971fc97bb5bSPaolo Bonzini bit_mask = s->gr[VGA_GFX_BIT_MASK];
972fc97bb5bSPaolo Bonzini break;
973fc97bb5bSPaolo Bonzini case 1:
974fc97bb5bSPaolo Bonzini val = s->latch;
975fc97bb5bSPaolo Bonzini goto do_write;
976fc97bb5bSPaolo Bonzini case 2:
977fc97bb5bSPaolo Bonzini val = mask16[val & 0x0f];
978fc97bb5bSPaolo Bonzini bit_mask = s->gr[VGA_GFX_BIT_MASK];
979fc97bb5bSPaolo Bonzini break;
980fc97bb5bSPaolo Bonzini case 3:
981fc97bb5bSPaolo Bonzini /* rotate */
982fc97bb5bSPaolo Bonzini b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
983fc97bb5bSPaolo Bonzini val = (val >> b) | (val << (8 - b));
984fc97bb5bSPaolo Bonzini
985fc97bb5bSPaolo Bonzini bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
986fc97bb5bSPaolo Bonzini val = mask16[s->gr[VGA_GFX_SR_VALUE]];
987fc97bb5bSPaolo Bonzini break;
988fc97bb5bSPaolo Bonzini }
989fc97bb5bSPaolo Bonzini
990fc97bb5bSPaolo Bonzini /* apply logical operation */
991fc97bb5bSPaolo Bonzini func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
992fc97bb5bSPaolo Bonzini switch(func_select) {
993fc97bb5bSPaolo Bonzini case 0:
994fc97bb5bSPaolo Bonzini default:
995fc97bb5bSPaolo Bonzini /* nothing to do */
996fc97bb5bSPaolo Bonzini break;
997fc97bb5bSPaolo Bonzini case 1:
998fc97bb5bSPaolo Bonzini /* and */
999fc97bb5bSPaolo Bonzini val &= s->latch;
1000fc97bb5bSPaolo Bonzini break;
1001fc97bb5bSPaolo Bonzini case 2:
1002fc97bb5bSPaolo Bonzini /* or */
1003fc97bb5bSPaolo Bonzini val |= s->latch;
1004fc97bb5bSPaolo Bonzini break;
1005fc97bb5bSPaolo Bonzini case 3:
1006fc97bb5bSPaolo Bonzini /* xor */
1007fc97bb5bSPaolo Bonzini val ^= s->latch;
1008fc97bb5bSPaolo Bonzini break;
1009fc97bb5bSPaolo Bonzini }
1010fc97bb5bSPaolo Bonzini
1011fc97bb5bSPaolo Bonzini /* apply bit mask */
1012fc97bb5bSPaolo Bonzini bit_mask |= bit_mask << 8;
1013fc97bb5bSPaolo Bonzini bit_mask |= bit_mask << 16;
1014fc97bb5bSPaolo Bonzini val = (val & bit_mask) | (s->latch & ~bit_mask);
1015fc97bb5bSPaolo Bonzini
1016fc97bb5bSPaolo Bonzini do_write:
1017fc97bb5bSPaolo Bonzini /* mask data according to sr[2] */
1018fc97bb5bSPaolo Bonzini s->plane_updated |= mask; /* only used to detect font change */
1019fc97bb5bSPaolo Bonzini write_mask = mask16[mask];
1020fc97bb5bSPaolo Bonzini ((uint32_t *)s->vram_ptr)[addr] =
1021fc97bb5bSPaolo Bonzini (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
1022fc97bb5bSPaolo Bonzini (val & write_mask);
1023fc97bb5bSPaolo Bonzini #ifdef DEBUG_VGA_MEM
1024883f2c59SPhilippe Mathieu-Daudé printf("vga: latch: [0x" HWADDR_FMT_plx "] mask=0x%08x val=0x%08x\n",
1025fc97bb5bSPaolo Bonzini addr * 4, write_mask, val);
1026fc97bb5bSPaolo Bonzini #endif
1027fc97bb5bSPaolo Bonzini memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
1028fc97bb5bSPaolo Bonzini }
1029fc97bb5bSPaolo Bonzini
1030973a724eSPaolo Bonzini typedef void *vga_draw_line_func(VGACommonState *s1, uint8_t *d,
1031973a724eSPaolo Bonzini uint32_t srcaddr, int width, int hpel);
1032fc97bb5bSPaolo Bonzini
1033145e543eSGerd Hoffmann #include "vga-access.h"
1034e657d8efSBenjamin Herrenschmidt #include "vga-helpers.h"
1035fc97bb5bSPaolo Bonzini
1036fc97bb5bSPaolo Bonzini /* return true if the palette was modified */
update_palette16(VGACommonState * s)1037fc97bb5bSPaolo Bonzini static int update_palette16(VGACommonState *s)
1038fc97bb5bSPaolo Bonzini {
1039fc97bb5bSPaolo Bonzini int full_update, i;
1040fc97bb5bSPaolo Bonzini uint32_t v, col, *palette;
1041fc97bb5bSPaolo Bonzini
1042fc97bb5bSPaolo Bonzini full_update = 0;
1043fc97bb5bSPaolo Bonzini palette = s->last_palette;
1044fc97bb5bSPaolo Bonzini for(i = 0; i < 16; i++) {
1045fc97bb5bSPaolo Bonzini v = s->ar[i];
1046fc97bb5bSPaolo Bonzini if (s->ar[VGA_ATC_MODE] & 0x80) {
1047fc97bb5bSPaolo Bonzini v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
1048fc97bb5bSPaolo Bonzini } else {
1049fc97bb5bSPaolo Bonzini v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
1050fc97bb5bSPaolo Bonzini }
1051fc97bb5bSPaolo Bonzini v = v * 3;
1052d3c2343aSBenjamin Herrenschmidt col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1053fc97bb5bSPaolo Bonzini c6_to_8(s->palette[v + 1]),
1054fc97bb5bSPaolo Bonzini c6_to_8(s->palette[v + 2]));
1055fc97bb5bSPaolo Bonzini if (col != palette[i]) {
1056fc97bb5bSPaolo Bonzini full_update = 1;
1057fc97bb5bSPaolo Bonzini palette[i] = col;
1058fc97bb5bSPaolo Bonzini }
1059fc97bb5bSPaolo Bonzini }
1060fc97bb5bSPaolo Bonzini return full_update;
1061fc97bb5bSPaolo Bonzini }
1062fc97bb5bSPaolo Bonzini
1063fc97bb5bSPaolo Bonzini /* return true if the palette was modified */
update_palette256(VGACommonState * s)1064fc97bb5bSPaolo Bonzini static int update_palette256(VGACommonState *s)
1065fc97bb5bSPaolo Bonzini {
1066fc97bb5bSPaolo Bonzini int full_update, i;
1067fc97bb5bSPaolo Bonzini uint32_t v, col, *palette;
1068fc97bb5bSPaolo Bonzini
1069fc97bb5bSPaolo Bonzini full_update = 0;
1070fc97bb5bSPaolo Bonzini palette = s->last_palette;
1071fc97bb5bSPaolo Bonzini v = 0;
1072fc97bb5bSPaolo Bonzini for(i = 0; i < 256; i++) {
1073fc97bb5bSPaolo Bonzini if (s->dac_8bit) {
1074d3c2343aSBenjamin Herrenschmidt col = rgb_to_pixel32(s->palette[v],
1075fc97bb5bSPaolo Bonzini s->palette[v + 1],
1076fc97bb5bSPaolo Bonzini s->palette[v + 2]);
1077fc97bb5bSPaolo Bonzini } else {
1078d3c2343aSBenjamin Herrenschmidt col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1079fc97bb5bSPaolo Bonzini c6_to_8(s->palette[v + 1]),
1080fc97bb5bSPaolo Bonzini c6_to_8(s->palette[v + 2]));
1081fc97bb5bSPaolo Bonzini }
1082fc97bb5bSPaolo Bonzini if (col != palette[i]) {
1083fc97bb5bSPaolo Bonzini full_update = 1;
1084fc97bb5bSPaolo Bonzini palette[i] = col;
1085fc97bb5bSPaolo Bonzini }
1086fc97bb5bSPaolo Bonzini v += 3;
1087fc97bb5bSPaolo Bonzini }
1088fc97bb5bSPaolo Bonzini return full_update;
1089fc97bb5bSPaolo Bonzini }
1090fc97bb5bSPaolo Bonzini
vga_get_params(VGACommonState * s,VGADisplayParams * params)1091f9b925fdSPaolo Bonzini static void vga_get_params(VGACommonState *s,
1092f9b925fdSPaolo Bonzini VGADisplayParams *params)
1093fc97bb5bSPaolo Bonzini {
1094bfa0f151SGerd Hoffmann if (vbe_enabled(s)) {
1095f9b925fdSPaolo Bonzini params->line_offset = s->vbe_line_offset;
1096f9b925fdSPaolo Bonzini params->start_addr = s->vbe_start_addr;
1097f9b925fdSPaolo Bonzini params->line_compare = 65535;
1098973a724eSPaolo Bonzini params->hpel = VGA_HPEL_NEUTRAL;
1099973a724eSPaolo Bonzini params->hpel_split = false;
1100fc97bb5bSPaolo Bonzini } else {
1101fc97bb5bSPaolo Bonzini /* compute line_offset in bytes */
1102f9b925fdSPaolo Bonzini params->line_offset = s->cr[VGA_CRTC_OFFSET] << 3;
1103fc97bb5bSPaolo Bonzini
1104fc97bb5bSPaolo Bonzini /* starting address */
1105f9b925fdSPaolo Bonzini params->start_addr = s->cr[VGA_CRTC_START_LO] |
1106fc97bb5bSPaolo Bonzini (s->cr[VGA_CRTC_START_HI] << 8);
1107fc97bb5bSPaolo Bonzini
1108fc97bb5bSPaolo Bonzini /* line compare */
1109f9b925fdSPaolo Bonzini params->line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
1110fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
1111fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
1112973a724eSPaolo Bonzini
1113973a724eSPaolo Bonzini params->hpel = s->ar[VGA_ATC_PEL];
1114973a724eSPaolo Bonzini params->hpel_split = s->ar[VGA_ATC_MODE] & 0x20;
1115fc97bb5bSPaolo Bonzini }
1116fc97bb5bSPaolo Bonzini }
1117fc97bb5bSPaolo Bonzini
1118fc97bb5bSPaolo Bonzini /* update start_addr and line_offset. Return TRUE if modified */
update_basic_params(VGACommonState * s)1119fc97bb5bSPaolo Bonzini static int update_basic_params(VGACommonState *s)
1120fc97bb5bSPaolo Bonzini {
1121fc97bb5bSPaolo Bonzini int full_update;
1122f9b925fdSPaolo Bonzini VGADisplayParams current;
1123fc97bb5bSPaolo Bonzini
1124fc97bb5bSPaolo Bonzini full_update = 0;
1125fc97bb5bSPaolo Bonzini
1126f9b925fdSPaolo Bonzini s->get_params(s, ¤t);
1127fc97bb5bSPaolo Bonzini
1128f9b925fdSPaolo Bonzini if (memcmp(¤t, &s->params, sizeof(current))) {
1129f9b925fdSPaolo Bonzini s->params = current;
1130fc97bb5bSPaolo Bonzini full_update = 1;
1131fc97bb5bSPaolo Bonzini }
1132fc97bb5bSPaolo Bonzini return full_update;
1133fc97bb5bSPaolo Bonzini }
1134fc97bb5bSPaolo Bonzini
1135fc97bb5bSPaolo Bonzini
1136fc97bb5bSPaolo Bonzini static const uint8_t cursor_glyph[32 * 4] = {
1137fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1138fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1139fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1140fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1141fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1142fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1143fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1144fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1145fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1146fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1147fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1148fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1149fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1150fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1151fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1152fc97bb5bSPaolo Bonzini 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1153fc97bb5bSPaolo Bonzini };
1154fc97bb5bSPaolo Bonzini
vga_get_text_resolution(VGACommonState * s,int * pwidth,int * pheight,int * pcwidth,int * pcheight)1155fc97bb5bSPaolo Bonzini static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1156fc97bb5bSPaolo Bonzini int *pcwidth, int *pcheight)
1157fc97bb5bSPaolo Bonzini {
1158fc97bb5bSPaolo Bonzini int width, cwidth, height, cheight;
1159fc97bb5bSPaolo Bonzini
1160fc97bb5bSPaolo Bonzini /* total width & height */
1161fc97bb5bSPaolo Bonzini cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
1162fc97bb5bSPaolo Bonzini cwidth = 8;
116394ef4f33SGerd Hoffmann if (!(sr(s, VGA_SEQ_CLOCK_MODE) & VGA_SR01_CHAR_CLK_8DOTS)) {
1164fc97bb5bSPaolo Bonzini cwidth = 9;
1165fc97bb5bSPaolo Bonzini }
116694ef4f33SGerd Hoffmann if (sr(s, VGA_SEQ_CLOCK_MODE) & 0x08) {
1167fc97bb5bSPaolo Bonzini cwidth = 16; /* NOTE: no 18 pixel wide */
1168fc97bb5bSPaolo Bonzini }
1169fc97bb5bSPaolo Bonzini width = (s->cr[VGA_CRTC_H_DISP] + 1);
1170fc97bb5bSPaolo Bonzini if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
1171fc97bb5bSPaolo Bonzini /* ugly hack for CGA 160x100x16 - explain me the logic */
1172fc97bb5bSPaolo Bonzini height = 100;
1173fc97bb5bSPaolo Bonzini } else {
1174fc97bb5bSPaolo Bonzini height = s->cr[VGA_CRTC_V_DISP_END] |
1175fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1176fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1177fc97bb5bSPaolo Bonzini height = (height + 1) / cheight;
1178fc97bb5bSPaolo Bonzini }
1179fc97bb5bSPaolo Bonzini
1180fc97bb5bSPaolo Bonzini *pwidth = width;
1181fc97bb5bSPaolo Bonzini *pheight = height;
1182fc97bb5bSPaolo Bonzini *pcwidth = cwidth;
1183fc97bb5bSPaolo Bonzini *pcheight = cheight;
1184fc97bb5bSPaolo Bonzini }
1185fc97bb5bSPaolo Bonzini
1186fc97bb5bSPaolo Bonzini /*
1187fc97bb5bSPaolo Bonzini * Text mode update
1188fc97bb5bSPaolo Bonzini * Missing:
1189fc97bb5bSPaolo Bonzini * - double scan
1190fc97bb5bSPaolo Bonzini * - double width
1191fc97bb5bSPaolo Bonzini * - underline
1192fc97bb5bSPaolo Bonzini * - flashing
1193fc97bb5bSPaolo Bonzini */
vga_draw_text(VGACommonState * s,int full_update)1194fc97bb5bSPaolo Bonzini static void vga_draw_text(VGACommonState *s, int full_update)
1195fc97bb5bSPaolo Bonzini {
1196fc97bb5bSPaolo Bonzini DisplaySurface *surface = qemu_console_surface(s->con);
1197fc97bb5bSPaolo Bonzini int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1198fc97bb5bSPaolo Bonzini int cx_min, cx_max, linesize, x_incr, line, line1;
1199fc97bb5bSPaolo Bonzini uint32_t offset, fgcol, bgcol, v, cursor_offset;
1200fc97bb5bSPaolo Bonzini uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1201fc97bb5bSPaolo Bonzini const uint8_t *font_ptr, *font_base[2];
12029e057c0bSBenjamin Herrenschmidt int dup9, line_offset;
1203fc97bb5bSPaolo Bonzini uint32_t *palette;
1204fc97bb5bSPaolo Bonzini uint32_t *ch_attr_ptr;
1205bc72ad67SAlex Bligh int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
1206fc97bb5bSPaolo Bonzini
1207fc97bb5bSPaolo Bonzini /* compute font data address (in plane 2) */
120894ef4f33SGerd Hoffmann v = sr(s, VGA_SEQ_CHARACTER_MAP);
1209fc97bb5bSPaolo Bonzini offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1210fc97bb5bSPaolo Bonzini if (offset != s->font_offsets[0]) {
1211fc97bb5bSPaolo Bonzini s->font_offsets[0] = offset;
1212fc97bb5bSPaolo Bonzini full_update = 1;
1213fc97bb5bSPaolo Bonzini }
1214fc97bb5bSPaolo Bonzini font_base[0] = s->vram_ptr + offset;
1215fc97bb5bSPaolo Bonzini
1216fc97bb5bSPaolo Bonzini offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1217fc97bb5bSPaolo Bonzini font_base[1] = s->vram_ptr + offset;
1218fc97bb5bSPaolo Bonzini if (offset != s->font_offsets[1]) {
1219fc97bb5bSPaolo Bonzini s->font_offsets[1] = offset;
1220fc97bb5bSPaolo Bonzini full_update = 1;
1221fc97bb5bSPaolo Bonzini }
1222ad37168cSPaolo Bonzini if (s->plane_updated & (1 << 2) || s->has_chain4_alias) {
1223fc97bb5bSPaolo Bonzini /* if the plane 2 was modified since the last display, it
1224fc97bb5bSPaolo Bonzini indicates the font may have been modified */
1225fc97bb5bSPaolo Bonzini s->plane_updated = 0;
1226fc97bb5bSPaolo Bonzini full_update = 1;
1227fc97bb5bSPaolo Bonzini }
1228fc97bb5bSPaolo Bonzini full_update |= update_basic_params(s);
1229fc97bb5bSPaolo Bonzini
1230f9b925fdSPaolo Bonzini line_offset = s->params.line_offset;
1231fc97bb5bSPaolo Bonzini
1232fc97bb5bSPaolo Bonzini vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1233fc97bb5bSPaolo Bonzini if ((height * width) <= 1) {
1234fc97bb5bSPaolo Bonzini /* better than nothing: exit if transient size is too small */
1235fc97bb5bSPaolo Bonzini return;
1236fc97bb5bSPaolo Bonzini }
1237fc97bb5bSPaolo Bonzini if ((height * width) > CH_ATTR_SIZE) {
1238fc97bb5bSPaolo Bonzini /* better than nothing: exit if transient size is too big */
1239fc97bb5bSPaolo Bonzini return;
1240fc97bb5bSPaolo Bonzini }
1241fc97bb5bSPaolo Bonzini
1242fc97bb5bSPaolo Bonzini if (width != s->last_width || height != s->last_height ||
1243fc97bb5bSPaolo Bonzini cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1244fc97bb5bSPaolo Bonzini s->last_scr_width = width * cw;
1245fc97bb5bSPaolo Bonzini s->last_scr_height = height * cheight;
1246fc97bb5bSPaolo Bonzini qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1247fc97bb5bSPaolo Bonzini surface = qemu_console_surface(s->con);
1248fc97bb5bSPaolo Bonzini dpy_text_resize(s->con, width, height);
1249fc97bb5bSPaolo Bonzini s->last_depth = 0;
1250fc97bb5bSPaolo Bonzini s->last_width = width;
1251fc97bb5bSPaolo Bonzini s->last_height = height;
1252fc97bb5bSPaolo Bonzini s->last_ch = cheight;
1253fc97bb5bSPaolo Bonzini s->last_cw = cw;
1254fc97bb5bSPaolo Bonzini full_update = 1;
1255fc97bb5bSPaolo Bonzini }
1256fc97bb5bSPaolo Bonzini full_update |= update_palette16(s);
1257fc97bb5bSPaolo Bonzini palette = s->last_palette;
1258fc97bb5bSPaolo Bonzini x_incr = cw * surface_bytes_per_pixel(surface);
1259fc97bb5bSPaolo Bonzini
1260fc97bb5bSPaolo Bonzini if (full_update) {
1261fc97bb5bSPaolo Bonzini s->full_update_text = 1;
1262fc97bb5bSPaolo Bonzini }
1263fc97bb5bSPaolo Bonzini if (s->full_update_gfx) {
1264fc97bb5bSPaolo Bonzini s->full_update_gfx = 0;
1265fc97bb5bSPaolo Bonzini full_update |= 1;
1266fc97bb5bSPaolo Bonzini }
1267fc97bb5bSPaolo Bonzini
1268fc97bb5bSPaolo Bonzini cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1269f9b925fdSPaolo Bonzini s->cr[VGA_CRTC_CURSOR_LO]) - s->params.start_addr;
1270fc97bb5bSPaolo Bonzini if (cursor_offset != s->cursor_offset ||
1271fc97bb5bSPaolo Bonzini s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1272fc97bb5bSPaolo Bonzini s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
1273fc97bb5bSPaolo Bonzini /* if the cursor position changed, we update the old and new
1274fc97bb5bSPaolo Bonzini chars */
1275fc97bb5bSPaolo Bonzini if (s->cursor_offset < CH_ATTR_SIZE)
1276fc97bb5bSPaolo Bonzini s->last_ch_attr[s->cursor_offset] = -1;
1277fc97bb5bSPaolo Bonzini if (cursor_offset < CH_ATTR_SIZE)
1278fc97bb5bSPaolo Bonzini s->last_ch_attr[cursor_offset] = -1;
1279fc97bb5bSPaolo Bonzini s->cursor_offset = cursor_offset;
1280fc97bb5bSPaolo Bonzini s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1281fc97bb5bSPaolo Bonzini s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
1282fc97bb5bSPaolo Bonzini }
1283f9b925fdSPaolo Bonzini cursor_ptr = s->vram_ptr + (s->params.start_addr + cursor_offset) * 4;
1284fc97bb5bSPaolo Bonzini if (now >= s->cursor_blink_time) {
1285fc97bb5bSPaolo Bonzini s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
1286fc97bb5bSPaolo Bonzini s->cursor_visible_phase = !s->cursor_visible_phase;
1287fc97bb5bSPaolo Bonzini }
1288fc97bb5bSPaolo Bonzini
1289fc97bb5bSPaolo Bonzini dest = surface_data(surface);
1290fc97bb5bSPaolo Bonzini linesize = surface_stride(surface);
1291fc97bb5bSPaolo Bonzini ch_attr_ptr = s->last_ch_attr;
1292fc97bb5bSPaolo Bonzini line = 0;
1293f9b925fdSPaolo Bonzini offset = s->params.start_addr * 4;
1294fc97bb5bSPaolo Bonzini for(cy = 0; cy < height; cy++) {
1295fc97bb5bSPaolo Bonzini d1 = dest;
1296fc97bb5bSPaolo Bonzini src = s->vram_ptr + offset;
1297fc97bb5bSPaolo Bonzini cx_min = width;
1298fc97bb5bSPaolo Bonzini cx_max = -1;
1299fc97bb5bSPaolo Bonzini for(cx = 0; cx < width; cx++) {
1300191f59dcSlinzhecheng if (src + sizeof(uint16_t) > s->vram_ptr + s->vram_size) {
1301191f59dcSlinzhecheng break;
1302191f59dcSlinzhecheng }
1303fc97bb5bSPaolo Bonzini ch_attr = *(uint16_t *)src;
1304fc97bb5bSPaolo Bonzini if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
1305fc97bb5bSPaolo Bonzini if (cx < cx_min)
1306fc97bb5bSPaolo Bonzini cx_min = cx;
1307fc97bb5bSPaolo Bonzini if (cx > cx_max)
1308fc97bb5bSPaolo Bonzini cx_max = cx;
1309fc97bb5bSPaolo Bonzini *ch_attr_ptr = ch_attr;
1310e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
1311fc97bb5bSPaolo Bonzini ch = ch_attr >> 8;
1312fc97bb5bSPaolo Bonzini cattr = ch_attr & 0xff;
1313fc97bb5bSPaolo Bonzini #else
1314fc97bb5bSPaolo Bonzini ch = ch_attr & 0xff;
1315fc97bb5bSPaolo Bonzini cattr = ch_attr >> 8;
1316fc97bb5bSPaolo Bonzini #endif
1317fc97bb5bSPaolo Bonzini font_ptr = font_base[(cattr >> 3) & 1];
1318fc97bb5bSPaolo Bonzini font_ptr += 32 * 4 * ch;
1319fc97bb5bSPaolo Bonzini bgcol = palette[cattr >> 4];
1320fc97bb5bSPaolo Bonzini fgcol = palette[cattr & 0x0f];
13219e057c0bSBenjamin Herrenschmidt if (cw == 16) {
1322d2e043a8SBenjamin Herrenschmidt vga_draw_glyph16(d1, linesize,
13239e057c0bSBenjamin Herrenschmidt font_ptr, cheight, fgcol, bgcol);
13249e057c0bSBenjamin Herrenschmidt } else if (cw != 9) {
1325d2e043a8SBenjamin Herrenschmidt vga_draw_glyph8(d1, linesize,
1326fc97bb5bSPaolo Bonzini font_ptr, cheight, fgcol, bgcol);
1327fc97bb5bSPaolo Bonzini } else {
1328fc97bb5bSPaolo Bonzini dup9 = 0;
1329fc97bb5bSPaolo Bonzini if (ch >= 0xb0 && ch <= 0xdf &&
1330fc97bb5bSPaolo Bonzini (s->ar[VGA_ATC_MODE] & 0x04)) {
1331fc97bb5bSPaolo Bonzini dup9 = 1;
1332fc97bb5bSPaolo Bonzini }
1333d2e043a8SBenjamin Herrenschmidt vga_draw_glyph9(d1, linesize,
1334fc97bb5bSPaolo Bonzini font_ptr, cheight, fgcol, bgcol, dup9);
1335fc97bb5bSPaolo Bonzini }
1336fc97bb5bSPaolo Bonzini if (src == cursor_ptr &&
1337fc97bb5bSPaolo Bonzini !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
1338fc97bb5bSPaolo Bonzini s->cursor_visible_phase) {
1339fc97bb5bSPaolo Bonzini int line_start, line_last, h;
1340fc97bb5bSPaolo Bonzini /* draw the cursor */
1341fc97bb5bSPaolo Bonzini line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
1342fc97bb5bSPaolo Bonzini line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
1343fc97bb5bSPaolo Bonzini /* XXX: check that */
1344fc97bb5bSPaolo Bonzini if (line_last > cheight - 1)
1345fc97bb5bSPaolo Bonzini line_last = cheight - 1;
1346fc97bb5bSPaolo Bonzini if (line_last >= line_start && line_start < cheight) {
1347fc97bb5bSPaolo Bonzini h = line_last - line_start + 1;
1348fc97bb5bSPaolo Bonzini d = d1 + linesize * line_start;
13499e057c0bSBenjamin Herrenschmidt if (cw == 16) {
1350d2e043a8SBenjamin Herrenschmidt vga_draw_glyph16(d, linesize,
13519e057c0bSBenjamin Herrenschmidt cursor_glyph, h, fgcol, bgcol);
13529e057c0bSBenjamin Herrenschmidt } else if (cw != 9) {
1353d2e043a8SBenjamin Herrenschmidt vga_draw_glyph8(d, linesize,
1354fc97bb5bSPaolo Bonzini cursor_glyph, h, fgcol, bgcol);
1355fc97bb5bSPaolo Bonzini } else {
1356d2e043a8SBenjamin Herrenschmidt vga_draw_glyph9(d, linesize,
1357fc97bb5bSPaolo Bonzini cursor_glyph, h, fgcol, bgcol, 1);
1358fc97bb5bSPaolo Bonzini }
1359fc97bb5bSPaolo Bonzini }
1360fc97bb5bSPaolo Bonzini }
1361fc97bb5bSPaolo Bonzini }
1362fc97bb5bSPaolo Bonzini d1 += x_incr;
1363fc97bb5bSPaolo Bonzini src += 4;
1364fc97bb5bSPaolo Bonzini ch_attr_ptr++;
1365fc97bb5bSPaolo Bonzini }
1366fc97bb5bSPaolo Bonzini if (cx_max != -1) {
1367fc97bb5bSPaolo Bonzini dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
1368fc97bb5bSPaolo Bonzini (cx_max - cx_min + 1) * cw, cheight);
1369fc97bb5bSPaolo Bonzini }
1370fc97bb5bSPaolo Bonzini dest += linesize * cheight;
1371fc97bb5bSPaolo Bonzini line1 = line + cheight;
1372fc97bb5bSPaolo Bonzini offset += line_offset;
1373f9b925fdSPaolo Bonzini if (line < s->params.line_compare && line1 >= s->params.line_compare) {
1374fc97bb5bSPaolo Bonzini offset = 0;
1375fc97bb5bSPaolo Bonzini }
1376fc97bb5bSPaolo Bonzini line = line1;
1377fc97bb5bSPaolo Bonzini }
1378fc97bb5bSPaolo Bonzini }
1379fc97bb5bSPaolo Bonzini
1380fc97bb5bSPaolo Bonzini enum {
1381fc97bb5bSPaolo Bonzini VGA_DRAW_LINE2,
1382fc97bb5bSPaolo Bonzini VGA_DRAW_LINE2D2,
1383fc97bb5bSPaolo Bonzini VGA_DRAW_LINE4,
1384fc97bb5bSPaolo Bonzini VGA_DRAW_LINE4D2,
1385fc97bb5bSPaolo Bonzini VGA_DRAW_LINE8D2,
1386fc97bb5bSPaolo Bonzini VGA_DRAW_LINE8,
138746c3a8c8SBenjamin Herrenschmidt VGA_DRAW_LINE15_LE,
138846c3a8c8SBenjamin Herrenschmidt VGA_DRAW_LINE16_LE,
138946c3a8c8SBenjamin Herrenschmidt VGA_DRAW_LINE24_LE,
139046c3a8c8SBenjamin Herrenschmidt VGA_DRAW_LINE32_LE,
139146c3a8c8SBenjamin Herrenschmidt VGA_DRAW_LINE15_BE,
139246c3a8c8SBenjamin Herrenschmidt VGA_DRAW_LINE16_BE,
139346c3a8c8SBenjamin Herrenschmidt VGA_DRAW_LINE24_BE,
139446c3a8c8SBenjamin Herrenschmidt VGA_DRAW_LINE32_BE,
1395fc97bb5bSPaolo Bonzini VGA_DRAW_LINE_NB,
1396fc97bb5bSPaolo Bonzini };
1397fc97bb5bSPaolo Bonzini
13989e057c0bSBenjamin Herrenschmidt static vga_draw_line_func * const vga_draw_line_table[VGA_DRAW_LINE_NB] = {
1399d2e043a8SBenjamin Herrenschmidt vga_draw_line2,
1400d2e043a8SBenjamin Herrenschmidt vga_draw_line2d2,
1401d2e043a8SBenjamin Herrenschmidt vga_draw_line4,
1402d2e043a8SBenjamin Herrenschmidt vga_draw_line4d2,
1403d2e043a8SBenjamin Herrenschmidt vga_draw_line8d2,
1404d2e043a8SBenjamin Herrenschmidt vga_draw_line8,
140546c3a8c8SBenjamin Herrenschmidt vga_draw_line15_le,
140646c3a8c8SBenjamin Herrenschmidt vga_draw_line16_le,
140746c3a8c8SBenjamin Herrenschmidt vga_draw_line24_le,
140846c3a8c8SBenjamin Herrenschmidt vga_draw_line32_le,
140946c3a8c8SBenjamin Herrenschmidt vga_draw_line15_be,
141046c3a8c8SBenjamin Herrenschmidt vga_draw_line16_be,
141146c3a8c8SBenjamin Herrenschmidt vga_draw_line24_be,
141246c3a8c8SBenjamin Herrenschmidt vga_draw_line32_be,
1413fc97bb5bSPaolo Bonzini };
1414fc97bb5bSPaolo Bonzini
vga_get_bpp(VGACommonState * s)1415fc97bb5bSPaolo Bonzini static int vga_get_bpp(VGACommonState *s)
1416fc97bb5bSPaolo Bonzini {
1417fc97bb5bSPaolo Bonzini int ret;
1418fc97bb5bSPaolo Bonzini
1419bfa0f151SGerd Hoffmann if (vbe_enabled(s)) {
1420fc97bb5bSPaolo Bonzini ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1421fc97bb5bSPaolo Bonzini } else {
1422fc97bb5bSPaolo Bonzini ret = 0;
1423fc97bb5bSPaolo Bonzini }
1424fc97bb5bSPaolo Bonzini return ret;
1425fc97bb5bSPaolo Bonzini }
1426fc97bb5bSPaolo Bonzini
vga_get_resolution(VGACommonState * s,int * pwidth,int * pheight)1427fc97bb5bSPaolo Bonzini static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1428fc97bb5bSPaolo Bonzini {
1429fc97bb5bSPaolo Bonzini int width, height;
1430fc97bb5bSPaolo Bonzini
1431bfa0f151SGerd Hoffmann if (vbe_enabled(s)) {
1432fc97bb5bSPaolo Bonzini width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1433fc97bb5bSPaolo Bonzini height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1434fc97bb5bSPaolo Bonzini } else {
1435fc97bb5bSPaolo Bonzini width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
1436fc97bb5bSPaolo Bonzini height = s->cr[VGA_CRTC_V_DISP_END] |
1437fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1438fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1439fc97bb5bSPaolo Bonzini height = (height + 1);
1440fc97bb5bSPaolo Bonzini }
1441fc97bb5bSPaolo Bonzini *pwidth = width;
1442fc97bb5bSPaolo Bonzini *pheight = height;
1443fc97bb5bSPaolo Bonzini }
1444fc97bb5bSPaolo Bonzini
vga_invalidate_scanlines(VGACommonState * s,int y1,int y2)1445fc97bb5bSPaolo Bonzini void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1446fc97bb5bSPaolo Bonzini {
1447fc97bb5bSPaolo Bonzini int y;
1448fc97bb5bSPaolo Bonzini if (y1 >= VGA_MAX_HEIGHT)
1449fc97bb5bSPaolo Bonzini return;
1450fc97bb5bSPaolo Bonzini if (y2 >= VGA_MAX_HEIGHT)
1451fc97bb5bSPaolo Bonzini y2 = VGA_MAX_HEIGHT;
1452fc97bb5bSPaolo Bonzini for(y = y1; y < y2; y++) {
1453fc97bb5bSPaolo Bonzini s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1454fc97bb5bSPaolo Bonzini }
1455fc97bb5bSPaolo Bonzini }
1456fc97bb5bSPaolo Bonzini
vga_scanline_invalidated(VGACommonState * s,int y)1457f3289f6fSGerd Hoffmann static bool vga_scanline_invalidated(VGACommonState *s, int y)
1458f3289f6fSGerd Hoffmann {
1459f3289f6fSGerd Hoffmann if (y >= VGA_MAX_HEIGHT) {
1460f3289f6fSGerd Hoffmann return false;
1461f3289f6fSGerd Hoffmann }
1462f3289f6fSGerd Hoffmann return s->invalidated_y_table[y >> 5] & (1 << (y & 0x1f));
1463f3289f6fSGerd Hoffmann }
1464f3289f6fSGerd Hoffmann
vga_dirty_log_start(VGACommonState * s)1465fc97bb5bSPaolo Bonzini void vga_dirty_log_start(VGACommonState *s)
1466fc97bb5bSPaolo Bonzini {
1467fc97bb5bSPaolo Bonzini memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
1468fc97bb5bSPaolo Bonzini }
1469fc97bb5bSPaolo Bonzini
vga_dirty_log_stop(VGACommonState * s)1470fc97bb5bSPaolo Bonzini void vga_dirty_log_stop(VGACommonState *s)
1471fc97bb5bSPaolo Bonzini {
1472fc97bb5bSPaolo Bonzini memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
1473fc97bb5bSPaolo Bonzini }
1474fc97bb5bSPaolo Bonzini
1475fc97bb5bSPaolo Bonzini /*
1476fc97bb5bSPaolo Bonzini * graphic modes
1477fc97bb5bSPaolo Bonzini */
vga_draw_graphic(VGACommonState * s,int full_update)1478fc97bb5bSPaolo Bonzini static void vga_draw_graphic(VGACommonState *s, int full_update)
1479fc97bb5bSPaolo Bonzini {
1480fc97bb5bSPaolo Bonzini DisplaySurface *surface = qemu_console_surface(s->con);
1481fc97bb5bSPaolo Bonzini int y1, y, update, linesize, y_start, double_scan, mask, depth;
1482362f8117SGerd Hoffmann int width, height, shift_control, bwidth, bits;
148328f77de2SGerd Hoffmann ram_addr_t page0, page1, region_start, region_end;
1484fec5e8c9SGerd Hoffmann DirtyBitmapSnapshot *snap = NULL;
1485fc97bb5bSPaolo Bonzini int disp_width, multi_scan, multi_run;
1486973a724eSPaolo Bonzini int hpel;
1487fc97bb5bSPaolo Bonzini uint8_t *d;
1488fc97bb5bSPaolo Bonzini uint32_t v, addr1, addr;
14892c7d8736SBenjamin Herrenschmidt vga_draw_line_func *vga_draw_line = NULL;
1490abd749b5SGerd Hoffmann bool allocate_surface, force_shadow = false;
149149743df3SBenjamin Herrenschmidt pixman_format_code_t format;
1492e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
14932c7d8736SBenjamin Herrenschmidt bool byteswap = !s->big_endian_fb;
1494fc97bb5bSPaolo Bonzini #else
14952c7d8736SBenjamin Herrenschmidt bool byteswap = s->big_endian_fb;
1496fc97bb5bSPaolo Bonzini #endif
1497fc97bb5bSPaolo Bonzini
1498fc97bb5bSPaolo Bonzini full_update |= update_basic_params(s);
1499fc97bb5bSPaolo Bonzini
1500fc97bb5bSPaolo Bonzini s->get_resolution(s, &width, &height);
1501fc97bb5bSPaolo Bonzini disp_width = width;
1502a89fe6c3SGerd Hoffmann depth = s->get_bpp(s);
1503fc97bb5bSPaolo Bonzini
150437e7b867SPaolo Bonzini /* bits 5-6: 0 = 16-color mode, 1 = 4-color mode, 2 = 256-color mode. */
1505fc97bb5bSPaolo Bonzini shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
1506fc97bb5bSPaolo Bonzini double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
150737e7b867SPaolo Bonzini if (s->cr[VGA_CRTC_MODE] & 1) {
1508fc97bb5bSPaolo Bonzini multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
1509fc97bb5bSPaolo Bonzini - 1;
1510fc97bb5bSPaolo Bonzini } else {
1511fc97bb5bSPaolo Bonzini /* in CGA modes, multi_scan is ignored */
1512fc97bb5bSPaolo Bonzini /* XXX: is it correct ? */
1513fc97bb5bSPaolo Bonzini multi_scan = double_scan;
1514fc97bb5bSPaolo Bonzini }
1515fc97bb5bSPaolo Bonzini multi_run = multi_scan;
1516fc97bb5bSPaolo Bonzini if (shift_control != s->shift_control ||
1517fc97bb5bSPaolo Bonzini double_scan != s->double_scan) {
1518fc97bb5bSPaolo Bonzini full_update = 1;
1519fc97bb5bSPaolo Bonzini s->shift_control = shift_control;
1520fc97bb5bSPaolo Bonzini s->double_scan = double_scan;
1521fc97bb5bSPaolo Bonzini }
1522fc97bb5bSPaolo Bonzini
1523fc97bb5bSPaolo Bonzini if (shift_control == 0) {
15245c00acebSPaolo Bonzini full_update |= update_palette16(s);
152594ef4f33SGerd Hoffmann if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
1526fc97bb5bSPaolo Bonzini disp_width <<= 1;
15275c00acebSPaolo Bonzini v = VGA_DRAW_LINE4D2;
15285c00acebSPaolo Bonzini } else {
15295c00acebSPaolo Bonzini v = VGA_DRAW_LINE4;
1530fc97bb5bSPaolo Bonzini }
15315c00acebSPaolo Bonzini bits = 4;
15325c00acebSPaolo Bonzini
1533fc97bb5bSPaolo Bonzini } else if (shift_control == 1) {
15345c00acebSPaolo Bonzini full_update |= update_palette16(s);
153594ef4f33SGerd Hoffmann if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
1536fc97bb5bSPaolo Bonzini disp_width <<= 1;
15375c00acebSPaolo Bonzini v = VGA_DRAW_LINE2D2;
15385c00acebSPaolo Bonzini } else {
15395c00acebSPaolo Bonzini v = VGA_DRAW_LINE2;
15405c00acebSPaolo Bonzini }
15415c00acebSPaolo Bonzini bits = 4;
15425c00acebSPaolo Bonzini
15435c00acebSPaolo Bonzini } else {
15445c00acebSPaolo Bonzini switch (depth) {
15455c00acebSPaolo Bonzini default:
15465c00acebSPaolo Bonzini case 0:
15475c00acebSPaolo Bonzini full_update |= update_palette256(s);
15485c00acebSPaolo Bonzini v = VGA_DRAW_LINE8D2;
15495c00acebSPaolo Bonzini bits = 4;
15505c00acebSPaolo Bonzini break;
15515c00acebSPaolo Bonzini case 8:
15525c00acebSPaolo Bonzini full_update |= update_palette256(s);
15535c00acebSPaolo Bonzini v = VGA_DRAW_LINE8;
15545c00acebSPaolo Bonzini bits = 8;
15555c00acebSPaolo Bonzini break;
15565c00acebSPaolo Bonzini case 15:
15575c00acebSPaolo Bonzini v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE;
15585c00acebSPaolo Bonzini bits = 16;
15595c00acebSPaolo Bonzini break;
15605c00acebSPaolo Bonzini case 16:
15615c00acebSPaolo Bonzini v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE;
15625c00acebSPaolo Bonzini bits = 16;
15635c00acebSPaolo Bonzini break;
15645c00acebSPaolo Bonzini case 24:
15655c00acebSPaolo Bonzini v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE;
15665c00acebSPaolo Bonzini bits = 24;
15675c00acebSPaolo Bonzini break;
15685c00acebSPaolo Bonzini case 32:
15695c00acebSPaolo Bonzini v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE;
15705c00acebSPaolo Bonzini bits = 32;
15715c00acebSPaolo Bonzini break;
1572fc97bb5bSPaolo Bonzini }
1573fc97bb5bSPaolo Bonzini }
15741d1ee7e0SPaolo Bonzini
15751d1ee7e0SPaolo Bonzini /* Horizontal pel panning bit 3 is only used in text mode. */
15761d1ee7e0SPaolo Bonzini hpel = bits <= 8 ? s->params.hpel & 7 : 0;
1577ab75ecb7SPaolo Bonzini bwidth = DIV_ROUND_UP(width * bits, 8); /* scanline length */
1578ab75ecb7SPaolo Bonzini if (hpel) {
1579ab75ecb7SPaolo Bonzini bwidth += 4;
1580ab75ecb7SPaolo Bonzini }
1581fc97bb5bSPaolo Bonzini
15823826a372SPaolo Bonzini region_start = (s->params.start_addr * 4);
1583ab75ecb7SPaolo Bonzini region_end = region_start + (ram_addr_t)s->params.line_offset * (height - 1) + bwidth;
1584ab75ecb7SPaolo Bonzini if (region_end > s->vbe_size) {
15853826a372SPaolo Bonzini /*
1586ab75ecb7SPaolo Bonzini * On wrap around take the safe and slow route:
15873826a372SPaolo Bonzini * - create a dirty bitmap snapshot for all vga memory.
15883826a372SPaolo Bonzini * - force shadowing (so all vga memory access goes
15893826a372SPaolo Bonzini * through vga_read_*() helpers).
15903826a372SPaolo Bonzini *
15913826a372SPaolo Bonzini * Given this affects only vga features which are pretty much
15923826a372SPaolo Bonzini * unused by modern guests there should be no performance
15933826a372SPaolo Bonzini * impact.
15943826a372SPaolo Bonzini */
15953826a372SPaolo Bonzini region_start = 0;
15963826a372SPaolo Bonzini region_end = s->vbe_size;
15973826a372SPaolo Bonzini force_shadow = true;
15983826a372SPaolo Bonzini }
1599f89761d3SPaolo Bonzini if (s->params.line_compare < height) {
1600f89761d3SPaolo Bonzini /* split screen mode */
1601f89761d3SPaolo Bonzini region_start = 0;
1602f89761d3SPaolo Bonzini }
16033826a372SPaolo Bonzini
160449743df3SBenjamin Herrenschmidt /*
160549743df3SBenjamin Herrenschmidt * Check whether we can share the surface with the backend
160649743df3SBenjamin Herrenschmidt * or whether we need a shadow surface. We share native
160749743df3SBenjamin Herrenschmidt * endian surfaces for 15bpp and above and byteswapped
160849743df3SBenjamin Herrenschmidt * surfaces for 24bpp and above.
160949743df3SBenjamin Herrenschmidt */
161049743df3SBenjamin Herrenschmidt format = qemu_default_pixman_format(depth, !byteswap);
161149743df3SBenjamin Herrenschmidt if (format) {
1612abd749b5SGerd Hoffmann allocate_surface = !dpy_gfx_check_format(s->con, format)
1613abd749b5SGerd Hoffmann || s->force_shadow || force_shadow;
161449743df3SBenjamin Herrenschmidt } else {
1615abd749b5SGerd Hoffmann allocate_surface = true;
161649743df3SBenjamin Herrenschmidt }
16176bc2fd57SGerd Hoffmann
1618f9b925fdSPaolo Bonzini if (s->params.line_offset != s->last_line_offset ||
1619fc97bb5bSPaolo Bonzini disp_width != s->last_width ||
1620fc97bb5bSPaolo Bonzini height != s->last_height ||
1621c3b10605SBenjamin Herrenschmidt s->last_depth != depth ||
162255080993SBenjamin Herrenschmidt s->last_byteswap != byteswap ||
1623abd749b5SGerd Hoffmann allocate_surface != surface_is_allocated(surface)) {
16246bc2fd57SGerd Hoffmann /* display parameters changed -> need new display surface */
16256bc2fd57SGerd Hoffmann s->last_scr_width = disp_width;
16266bc2fd57SGerd Hoffmann s->last_scr_height = height;
16276bc2fd57SGerd Hoffmann s->last_width = disp_width;
16286bc2fd57SGerd Hoffmann s->last_height = height;
1629f9b925fdSPaolo Bonzini s->last_line_offset = s->params.line_offset;
16306bc2fd57SGerd Hoffmann s->last_depth = depth;
16316bc2fd57SGerd Hoffmann s->last_byteswap = byteswap;
1632973a724eSPaolo Bonzini /* 16 extra pixels are needed for double-width planar modes. */
1633973a724eSPaolo Bonzini s->panning_buf = g_realloc(s->panning_buf,
1634973a724eSPaolo Bonzini (disp_width + 16) * sizeof(uint32_t));
16356bc2fd57SGerd Hoffmann full_update = 1;
16366bc2fd57SGerd Hoffmann }
1637f9b925fdSPaolo Bonzini if (surface_data(surface) != s->vram_ptr + (s->params.start_addr * 4)
1638abd749b5SGerd Hoffmann && !surface_is_allocated(surface)) {
16396bc2fd57SGerd Hoffmann /* base address changed (page flip) -> shared display surfaces
16406bc2fd57SGerd Hoffmann * must be updated with the new base address */
16416bc2fd57SGerd Hoffmann full_update = 1;
16426bc2fd57SGerd Hoffmann }
16436bc2fd57SGerd Hoffmann
16446bc2fd57SGerd Hoffmann if (full_update) {
1645abd749b5SGerd Hoffmann if (!allocate_surface) {
1646fc97bb5bSPaolo Bonzini surface = qemu_create_displaysurface_from(disp_width,
1647f9b925fdSPaolo Bonzini height, format, s->params.line_offset,
1648f9b925fdSPaolo Bonzini s->vram_ptr + (s->params.start_addr * 4));
1649fc97bb5bSPaolo Bonzini dpy_gfx_replace_surface(s->con, surface);
1650fc97bb5bSPaolo Bonzini } else {
1651fc97bb5bSPaolo Bonzini qemu_console_resize(s->con, disp_width, height);
1652fc97bb5bSPaolo Bonzini surface = qemu_console_surface(s->con);
1653fc97bb5bSPaolo Bonzini }
1654fc97bb5bSPaolo Bonzini }
1655fc97bb5bSPaolo Bonzini
16569e057c0bSBenjamin Herrenschmidt vga_draw_line = vga_draw_line_table[v];
1657fc97bb5bSPaolo Bonzini
1658abd749b5SGerd Hoffmann if (surface_is_allocated(surface) && s->cursor_invalidate) {
1659fc97bb5bSPaolo Bonzini s->cursor_invalidate(s);
1660fc97bb5bSPaolo Bonzini }
1661fc97bb5bSPaolo Bonzini
1662fc97bb5bSPaolo Bonzini #if 0
1663fc97bb5bSPaolo Bonzini printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
1664fc97bb5bSPaolo Bonzini width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
1665f9b925fdSPaolo Bonzini s->params.line_compare, sr(s, VGA_SEQ_CLOCK_MODE));
1666fc97bb5bSPaolo Bonzini #endif
1667f9b925fdSPaolo Bonzini addr1 = (s->params.start_addr * 4);
1668fc97bb5bSPaolo Bonzini y_start = -1;
1669fc97bb5bSPaolo Bonzini d = surface_data(surface);
1670fc97bb5bSPaolo Bonzini linesize = surface_stride(surface);
1671fc97bb5bSPaolo Bonzini y1 = 0;
1672fec5e8c9SGerd Hoffmann
1673fec5e8c9SGerd Hoffmann if (!full_update) {
1674e6529415SGerd Hoffmann snap = memory_region_snapshot_and_clear_dirty(&s->vram, region_start,
1675e6529415SGerd Hoffmann region_end - region_start,
1676fec5e8c9SGerd Hoffmann DIRTY_MEMORY_VGA);
1677fec5e8c9SGerd Hoffmann }
1678fec5e8c9SGerd Hoffmann
1679fc97bb5bSPaolo Bonzini for(y = 0; y < height; y++) {
1680fc97bb5bSPaolo Bonzini addr = addr1;
1681fc97bb5bSPaolo Bonzini if (!(s->cr[VGA_CRTC_MODE] & 1)) {
1682fc97bb5bSPaolo Bonzini int shift;
1683fc97bb5bSPaolo Bonzini /* CGA compatibility handling */
1684fc97bb5bSPaolo Bonzini shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
1685fc97bb5bSPaolo Bonzini addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1686fc97bb5bSPaolo Bonzini }
1687fc97bb5bSPaolo Bonzini if (!(s->cr[VGA_CRTC_MODE] & 2)) {
1688fc97bb5bSPaolo Bonzini addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1689fc97bb5bSPaolo Bonzini }
169028f77de2SGerd Hoffmann page0 = addr & s->vbe_size_mask;
169128f77de2SGerd Hoffmann page1 = (addr + bwidth - 1) & s->vbe_size_mask;
1692fec5e8c9SGerd Hoffmann if (full_update) {
1693fec5e8c9SGerd Hoffmann update = 1;
169428f77de2SGerd Hoffmann } else if (page1 < page0) {
169528f77de2SGerd Hoffmann /* scanline wraps from end of video memory to the start */
169628f77de2SGerd Hoffmann assert(force_shadow);
169728f77de2SGerd Hoffmann update = memory_region_snapshot_get_dirty(&s->vram, snap,
1698115788d7SGerd Hoffmann page0, s->vbe_size - page0);
169928f77de2SGerd Hoffmann update |= memory_region_snapshot_get_dirty(&s->vram, snap,
1700115788d7SGerd Hoffmann 0, page1);
1701fec5e8c9SGerd Hoffmann } else {
1702fec5e8c9SGerd Hoffmann update = memory_region_snapshot_get_dirty(&s->vram, snap,
1703fec5e8c9SGerd Hoffmann page0, page1 - page0);
1704fec5e8c9SGerd Hoffmann }
1705f3289f6fSGerd Hoffmann /* explicit invalidation for the hardware cursor (cirrus only) */
1706f3289f6fSGerd Hoffmann update |= vga_scanline_invalidated(s, y);
1707fc97bb5bSPaolo Bonzini if (update) {
1708fc97bb5bSPaolo Bonzini if (y_start < 0)
1709fc97bb5bSPaolo Bonzini y_start = y;
1710abd749b5SGerd Hoffmann if (surface_is_allocated(surface)) {
1711973a724eSPaolo Bonzini uint8_t *p;
1712973a724eSPaolo Bonzini p = vga_draw_line(s, d, addr, width, hpel);
1713973a724eSPaolo Bonzini if (p) {
1714973a724eSPaolo Bonzini memcpy(d, p, disp_width * sizeof(uint32_t));
1715973a724eSPaolo Bonzini }
1716fc97bb5bSPaolo Bonzini if (s->cursor_draw_line)
1717fc97bb5bSPaolo Bonzini s->cursor_draw_line(s, d, y);
1718fc97bb5bSPaolo Bonzini }
1719fc97bb5bSPaolo Bonzini } else {
1720fc97bb5bSPaolo Bonzini if (y_start >= 0) {
1721fc97bb5bSPaolo Bonzini /* flush to display */
1722fc97bb5bSPaolo Bonzini dpy_gfx_update(s->con, 0, y_start,
1723fc97bb5bSPaolo Bonzini disp_width, y - y_start);
1724fc97bb5bSPaolo Bonzini y_start = -1;
1725fc97bb5bSPaolo Bonzini }
1726fc97bb5bSPaolo Bonzini }
1727fc97bb5bSPaolo Bonzini if (!multi_run) {
1728fc97bb5bSPaolo Bonzini mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
1729fc97bb5bSPaolo Bonzini if ((y1 & mask) == mask)
1730f9b925fdSPaolo Bonzini addr1 += s->params.line_offset;
1731fc97bb5bSPaolo Bonzini y1++;
1732fc97bb5bSPaolo Bonzini multi_run = multi_scan;
1733fc97bb5bSPaolo Bonzini } else {
1734fc97bb5bSPaolo Bonzini multi_run--;
1735fc97bb5bSPaolo Bonzini }
1736fc97bb5bSPaolo Bonzini /* line compare acts on the displayed lines */
1737973a724eSPaolo Bonzini if (y == s->params.line_compare) {
1738973a724eSPaolo Bonzini if (s->params.hpel_split) {
1739973a724eSPaolo Bonzini hpel = VGA_HPEL_NEUTRAL;
1740973a724eSPaolo Bonzini }
1741fc97bb5bSPaolo Bonzini addr1 = 0;
1742973a724eSPaolo Bonzini }
1743fc97bb5bSPaolo Bonzini d += linesize;
1744fc97bb5bSPaolo Bonzini }
1745fc97bb5bSPaolo Bonzini if (y_start >= 0) {
1746fc97bb5bSPaolo Bonzini /* flush to display */
1747fc97bb5bSPaolo Bonzini dpy_gfx_update(s->con, 0, y_start,
1748fc97bb5bSPaolo Bonzini disp_width, y - y_start);
1749fc97bb5bSPaolo Bonzini }
1750fec5e8c9SGerd Hoffmann g_free(snap);
1751f3289f6fSGerd Hoffmann memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
1752fc97bb5bSPaolo Bonzini }
1753fc97bb5bSPaolo Bonzini
vga_draw_blank(VGACommonState * s,int full_update)1754fc97bb5bSPaolo Bonzini static void vga_draw_blank(VGACommonState *s, int full_update)
1755fc97bb5bSPaolo Bonzini {
1756fc97bb5bSPaolo Bonzini DisplaySurface *surface = qemu_console_surface(s->con);
17572c79f2a2SBenjamin Herrenschmidt int i, w;
1758fc97bb5bSPaolo Bonzini uint8_t *d;
1759fc97bb5bSPaolo Bonzini
1760fc97bb5bSPaolo Bonzini if (!full_update)
1761fc97bb5bSPaolo Bonzini return;
1762fc97bb5bSPaolo Bonzini if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1763fc97bb5bSPaolo Bonzini return;
1764fc97bb5bSPaolo Bonzini
1765abd749b5SGerd Hoffmann if (!surface_is_allocated(surface)) {
1766b1cf266cSGerd Hoffmann /* unshare buffer, otherwise the blanking corrupts vga vram */
1767b1cf266cSGerd Hoffmann surface = qemu_create_displaysurface(s->last_scr_width,
1768b1cf266cSGerd Hoffmann s->last_scr_height);
1769b1cf266cSGerd Hoffmann dpy_gfx_replace_surface(s->con, surface);
1770b1cf266cSGerd Hoffmann }
1771b1cf266cSGerd Hoffmann
1772fc97bb5bSPaolo Bonzini w = s->last_scr_width * surface_bytes_per_pixel(surface);
1773fc97bb5bSPaolo Bonzini d = surface_data(surface);
1774fc97bb5bSPaolo Bonzini for(i = 0; i < s->last_scr_height; i++) {
17752c79f2a2SBenjamin Herrenschmidt memset(d, 0, w);
1776fc97bb5bSPaolo Bonzini d += surface_stride(surface);
1777fc97bb5bSPaolo Bonzini }
177891155f8bSGerd Hoffmann dpy_gfx_update_full(s->con);
1779fc97bb5bSPaolo Bonzini }
1780fc97bb5bSPaolo Bonzini
1781fc97bb5bSPaolo Bonzini #define GMODE_TEXT 0
1782fc97bb5bSPaolo Bonzini #define GMODE_GRAPH 1
1783fc97bb5bSPaolo Bonzini #define GMODE_BLANK 2
1784fc97bb5bSPaolo Bonzini
vga_update_display(void * opaque)1785fc97bb5bSPaolo Bonzini static void vga_update_display(void *opaque)
1786fc97bb5bSPaolo Bonzini {
1787fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
1788fc97bb5bSPaolo Bonzini DisplaySurface *surface = qemu_console_surface(s->con);
1789fc97bb5bSPaolo Bonzini int full_update, graphic_mode;
1790fc97bb5bSPaolo Bonzini
1791fc97bb5bSPaolo Bonzini qemu_flush_coalesced_mmio_buffer();
1792fc97bb5bSPaolo Bonzini
1793fc97bb5bSPaolo Bonzini if (surface_bits_per_pixel(surface) == 0) {
1794fc97bb5bSPaolo Bonzini /* nothing to do */
1795fc97bb5bSPaolo Bonzini } else {
1796fc97bb5bSPaolo Bonzini full_update = 0;
1797fc97bb5bSPaolo Bonzini if (!(s->ar_index & 0x20)) {
1798fc97bb5bSPaolo Bonzini graphic_mode = GMODE_BLANK;
1799fc97bb5bSPaolo Bonzini } else {
1800fc97bb5bSPaolo Bonzini graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1801fc97bb5bSPaolo Bonzini }
1802fc97bb5bSPaolo Bonzini if (graphic_mode != s->graphic_mode) {
1803fc97bb5bSPaolo Bonzini s->graphic_mode = graphic_mode;
1804bc72ad67SAlex Bligh s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
1805fc97bb5bSPaolo Bonzini full_update = 1;
1806fc97bb5bSPaolo Bonzini }
1807fc97bb5bSPaolo Bonzini switch(graphic_mode) {
1808fc97bb5bSPaolo Bonzini case GMODE_TEXT:
1809fc97bb5bSPaolo Bonzini vga_draw_text(s, full_update);
1810fc97bb5bSPaolo Bonzini break;
1811fc97bb5bSPaolo Bonzini case GMODE_GRAPH:
1812fc97bb5bSPaolo Bonzini vga_draw_graphic(s, full_update);
1813fc97bb5bSPaolo Bonzini break;
1814fc97bb5bSPaolo Bonzini case GMODE_BLANK:
1815fc97bb5bSPaolo Bonzini default:
1816fc97bb5bSPaolo Bonzini vga_draw_blank(s, full_update);
1817fc97bb5bSPaolo Bonzini break;
1818fc97bb5bSPaolo Bonzini }
1819fc97bb5bSPaolo Bonzini }
1820fc97bb5bSPaolo Bonzini }
1821fc97bb5bSPaolo Bonzini
1822fc97bb5bSPaolo Bonzini /* force a full display refresh */
vga_invalidate_display(void * opaque)1823fc97bb5bSPaolo Bonzini static void vga_invalidate_display(void *opaque)
1824fc97bb5bSPaolo Bonzini {
1825fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
1826fc97bb5bSPaolo Bonzini
1827fc97bb5bSPaolo Bonzini s->last_width = -1;
1828fc97bb5bSPaolo Bonzini s->last_height = -1;
1829fc97bb5bSPaolo Bonzini }
1830fc97bb5bSPaolo Bonzini
vga_common_reset(VGACommonState * s)1831fc97bb5bSPaolo Bonzini void vga_common_reset(VGACommonState *s)
1832fc97bb5bSPaolo Bonzini {
1833fc97bb5bSPaolo Bonzini s->sr_index = 0;
1834fc97bb5bSPaolo Bonzini memset(s->sr, '\0', sizeof(s->sr));
183594ef4f33SGerd Hoffmann memset(s->sr_vbe, '\0', sizeof(s->sr_vbe));
1836fc97bb5bSPaolo Bonzini s->gr_index = 0;
1837fc97bb5bSPaolo Bonzini memset(s->gr, '\0', sizeof(s->gr));
1838fc97bb5bSPaolo Bonzini s->ar_index = 0;
1839fc97bb5bSPaolo Bonzini memset(s->ar, '\0', sizeof(s->ar));
1840fc97bb5bSPaolo Bonzini s->ar_flip_flop = 0;
1841fc97bb5bSPaolo Bonzini s->cr_index = 0;
1842fc97bb5bSPaolo Bonzini memset(s->cr, '\0', sizeof(s->cr));
1843fc97bb5bSPaolo Bonzini s->msr = 0;
1844fc97bb5bSPaolo Bonzini s->fcr = 0;
1845fc97bb5bSPaolo Bonzini s->st00 = 0;
1846fc97bb5bSPaolo Bonzini s->st01 = 0;
1847fc97bb5bSPaolo Bonzini s->dac_state = 0;
1848fc97bb5bSPaolo Bonzini s->dac_sub_index = 0;
1849fc97bb5bSPaolo Bonzini s->dac_read_index = 0;
1850fc97bb5bSPaolo Bonzini s->dac_write_index = 0;
1851fc97bb5bSPaolo Bonzini memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1852fc97bb5bSPaolo Bonzini s->dac_8bit = 0;
1853fc97bb5bSPaolo Bonzini memset(s->palette, '\0', sizeof(s->palette));
1854fc97bb5bSPaolo Bonzini s->bank_offset = 0;
1855fc97bb5bSPaolo Bonzini s->vbe_index = 0;
1856fc97bb5bSPaolo Bonzini memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1857fc97bb5bSPaolo Bonzini s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1858fc97bb5bSPaolo Bonzini s->vbe_start_addr = 0;
1859fc97bb5bSPaolo Bonzini s->vbe_line_offset = 0;
1860fc97bb5bSPaolo Bonzini s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1861fc97bb5bSPaolo Bonzini memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1862fc97bb5bSPaolo Bonzini s->graphic_mode = -1; /* force full update */
1863fc97bb5bSPaolo Bonzini s->shift_control = 0;
1864fc97bb5bSPaolo Bonzini s->double_scan = 0;
1865f9b925fdSPaolo Bonzini memset(&s->params, '\0', sizeof(s->params));
1866fc97bb5bSPaolo Bonzini s->plane_updated = 0;
1867fc97bb5bSPaolo Bonzini s->last_cw = 0;
1868fc97bb5bSPaolo Bonzini s->last_ch = 0;
1869fc97bb5bSPaolo Bonzini s->last_width = 0;
1870fc97bb5bSPaolo Bonzini s->last_height = 0;
1871fc97bb5bSPaolo Bonzini s->last_scr_width = 0;
1872fc97bb5bSPaolo Bonzini s->last_scr_height = 0;
1873fc97bb5bSPaolo Bonzini s->cursor_start = 0;
1874fc97bb5bSPaolo Bonzini s->cursor_end = 0;
1875fc97bb5bSPaolo Bonzini s->cursor_offset = 0;
1876fc97bb5bSPaolo Bonzini memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1877fc97bb5bSPaolo Bonzini memset(s->last_palette, '\0', sizeof(s->last_palette));
1878fc97bb5bSPaolo Bonzini memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1879fc97bb5bSPaolo Bonzini switch (vga_retrace_method) {
1880fc97bb5bSPaolo Bonzini case VGA_RETRACE_DUMB:
1881fc97bb5bSPaolo Bonzini break;
1882fc97bb5bSPaolo Bonzini case VGA_RETRACE_PRECISE:
1883fc97bb5bSPaolo Bonzini memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1884fc97bb5bSPaolo Bonzini break;
1885fc97bb5bSPaolo Bonzini }
1886fc97bb5bSPaolo Bonzini vga_update_memory_access(s);
1887fc97bb5bSPaolo Bonzini }
1888fc97bb5bSPaolo Bonzini
vga_reset(void * opaque)1889fc97bb5bSPaolo Bonzini static void vga_reset(void *opaque)
1890fc97bb5bSPaolo Bonzini {
1891fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
1892fc97bb5bSPaolo Bonzini vga_common_reset(s);
1893fc97bb5bSPaolo Bonzini }
1894fc97bb5bSPaolo Bonzini
1895fc97bb5bSPaolo Bonzini #define TEXTMODE_X(x) ((x) % width)
1896fc97bb5bSPaolo Bonzini #define TEXTMODE_Y(x) ((x) / width)
1897fc97bb5bSPaolo Bonzini #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1898fc97bb5bSPaolo Bonzini ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1899fc97bb5bSPaolo Bonzini /* relay text rendering to the display driver
1900fc97bb5bSPaolo Bonzini * instead of doing a full vga_update_display() */
vga_update_text(void * opaque,console_ch_t * chardata)1901fc97bb5bSPaolo Bonzini static void vga_update_text(void *opaque, console_ch_t *chardata)
1902fc97bb5bSPaolo Bonzini {
1903fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
1904fc97bb5bSPaolo Bonzini int graphic_mode, i, cursor_offset, cursor_visible;
1905fc97bb5bSPaolo Bonzini int cw, cheight, width, height, size, c_min, c_max;
1906fc97bb5bSPaolo Bonzini uint32_t *src;
1907fc97bb5bSPaolo Bonzini console_ch_t *dst, val;
1908fc97bb5bSPaolo Bonzini char msg_buffer[80];
1909fc97bb5bSPaolo Bonzini int full_update = 0;
1910fc97bb5bSPaolo Bonzini
1911fc97bb5bSPaolo Bonzini qemu_flush_coalesced_mmio_buffer();
1912fc97bb5bSPaolo Bonzini
1913fc97bb5bSPaolo Bonzini if (!(s->ar_index & 0x20)) {
1914fc97bb5bSPaolo Bonzini graphic_mode = GMODE_BLANK;
1915fc97bb5bSPaolo Bonzini } else {
1916fc97bb5bSPaolo Bonzini graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1917fc97bb5bSPaolo Bonzini }
1918fc97bb5bSPaolo Bonzini if (graphic_mode != s->graphic_mode) {
1919fc97bb5bSPaolo Bonzini s->graphic_mode = graphic_mode;
1920fc97bb5bSPaolo Bonzini full_update = 1;
1921fc97bb5bSPaolo Bonzini }
1922fc97bb5bSPaolo Bonzini if (s->last_width == -1) {
1923fc97bb5bSPaolo Bonzini s->last_width = 0;
1924fc97bb5bSPaolo Bonzini full_update = 1;
1925fc97bb5bSPaolo Bonzini }
1926fc97bb5bSPaolo Bonzini
1927fc97bb5bSPaolo Bonzini switch (graphic_mode) {
1928fc97bb5bSPaolo Bonzini case GMODE_TEXT:
1929fc97bb5bSPaolo Bonzini /* TODO: update palette */
1930fc97bb5bSPaolo Bonzini full_update |= update_basic_params(s);
1931fc97bb5bSPaolo Bonzini
1932fc97bb5bSPaolo Bonzini /* total width & height */
1933fc97bb5bSPaolo Bonzini cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
1934fc97bb5bSPaolo Bonzini cw = 8;
193594ef4f33SGerd Hoffmann if (!(sr(s, VGA_SEQ_CLOCK_MODE) & VGA_SR01_CHAR_CLK_8DOTS)) {
1936fc97bb5bSPaolo Bonzini cw = 9;
1937fc97bb5bSPaolo Bonzini }
193894ef4f33SGerd Hoffmann if (sr(s, VGA_SEQ_CLOCK_MODE) & 0x08) {
1939fc97bb5bSPaolo Bonzini cw = 16; /* NOTE: no 18 pixel wide */
1940fc97bb5bSPaolo Bonzini }
1941fc97bb5bSPaolo Bonzini width = (s->cr[VGA_CRTC_H_DISP] + 1);
1942fc97bb5bSPaolo Bonzini if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
1943fc97bb5bSPaolo Bonzini /* ugly hack for CGA 160x100x16 - explain me the logic */
1944fc97bb5bSPaolo Bonzini height = 100;
1945fc97bb5bSPaolo Bonzini } else {
1946fc97bb5bSPaolo Bonzini height = s->cr[VGA_CRTC_V_DISP_END] |
1947fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1948fc97bb5bSPaolo Bonzini ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1949fc97bb5bSPaolo Bonzini height = (height + 1) / cheight;
1950fc97bb5bSPaolo Bonzini }
1951fc97bb5bSPaolo Bonzini
1952fc97bb5bSPaolo Bonzini size = (height * width);
1953fc97bb5bSPaolo Bonzini if (size > CH_ATTR_SIZE) {
1954fc97bb5bSPaolo Bonzini if (!full_update)
1955fc97bb5bSPaolo Bonzini return;
1956fc97bb5bSPaolo Bonzini
1957fc97bb5bSPaolo Bonzini snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
1958fc97bb5bSPaolo Bonzini width, height);
1959fc97bb5bSPaolo Bonzini break;
1960fc97bb5bSPaolo Bonzini }
1961fc97bb5bSPaolo Bonzini
1962fc97bb5bSPaolo Bonzini if (width != s->last_width || height != s->last_height ||
1963fc97bb5bSPaolo Bonzini cw != s->last_cw || cheight != s->last_ch) {
1964fc97bb5bSPaolo Bonzini s->last_scr_width = width * cw;
1965fc97bb5bSPaolo Bonzini s->last_scr_height = height * cheight;
1966fc97bb5bSPaolo Bonzini qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1967fc97bb5bSPaolo Bonzini dpy_text_resize(s->con, width, height);
1968fc97bb5bSPaolo Bonzini s->last_depth = 0;
1969fc97bb5bSPaolo Bonzini s->last_width = width;
1970fc97bb5bSPaolo Bonzini s->last_height = height;
1971fc97bb5bSPaolo Bonzini s->last_ch = cheight;
1972fc97bb5bSPaolo Bonzini s->last_cw = cw;
1973fc97bb5bSPaolo Bonzini full_update = 1;
1974fc97bb5bSPaolo Bonzini }
1975fc97bb5bSPaolo Bonzini
1976fc97bb5bSPaolo Bonzini if (full_update) {
1977fc97bb5bSPaolo Bonzini s->full_update_gfx = 1;
1978fc97bb5bSPaolo Bonzini }
1979fc97bb5bSPaolo Bonzini if (s->full_update_text) {
1980fc97bb5bSPaolo Bonzini s->full_update_text = 0;
1981fc97bb5bSPaolo Bonzini full_update |= 1;
1982fc97bb5bSPaolo Bonzini }
1983fc97bb5bSPaolo Bonzini
1984fc97bb5bSPaolo Bonzini /* Update "hardware" cursor */
1985fc97bb5bSPaolo Bonzini cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1986f9b925fdSPaolo Bonzini s->cr[VGA_CRTC_CURSOR_LO]) - s->params.start_addr;
1987fc97bb5bSPaolo Bonzini if (cursor_offset != s->cursor_offset ||
1988fc97bb5bSPaolo Bonzini s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1989fc97bb5bSPaolo Bonzini s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
1990fc97bb5bSPaolo Bonzini cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
1991fc97bb5bSPaolo Bonzini if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
1992fc97bb5bSPaolo Bonzini dpy_text_cursor(s->con,
1993fc97bb5bSPaolo Bonzini TEXTMODE_X(cursor_offset),
1994fc97bb5bSPaolo Bonzini TEXTMODE_Y(cursor_offset));
1995fc97bb5bSPaolo Bonzini else
1996fc97bb5bSPaolo Bonzini dpy_text_cursor(s->con, -1, -1);
1997fc97bb5bSPaolo Bonzini s->cursor_offset = cursor_offset;
1998fc97bb5bSPaolo Bonzini s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1999fc97bb5bSPaolo Bonzini s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
2000fc97bb5bSPaolo Bonzini }
2001fc97bb5bSPaolo Bonzini
2002f9b925fdSPaolo Bonzini src = (uint32_t *) s->vram_ptr + s->params.start_addr;
2003fc97bb5bSPaolo Bonzini dst = chardata;
2004fc97bb5bSPaolo Bonzini
2005fc97bb5bSPaolo Bonzini if (full_update) {
2006fc97bb5bSPaolo Bonzini for (i = 0; i < size; src ++, dst ++, i ++)
2007fc97bb5bSPaolo Bonzini console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
2008fc97bb5bSPaolo Bonzini
2009fc97bb5bSPaolo Bonzini dpy_text_update(s->con, 0, 0, width, height);
2010fc97bb5bSPaolo Bonzini } else {
2011fc97bb5bSPaolo Bonzini c_max = 0;
2012fc97bb5bSPaolo Bonzini
2013fc97bb5bSPaolo Bonzini for (i = 0; i < size; src ++, dst ++, i ++) {
2014fc97bb5bSPaolo Bonzini console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2015fc97bb5bSPaolo Bonzini if (*dst != val) {
2016fc97bb5bSPaolo Bonzini *dst = val;
2017fc97bb5bSPaolo Bonzini c_max = i;
2018fc97bb5bSPaolo Bonzini break;
2019fc97bb5bSPaolo Bonzini }
2020fc97bb5bSPaolo Bonzini }
2021fc97bb5bSPaolo Bonzini c_min = i;
2022fc97bb5bSPaolo Bonzini for (; i < size; src ++, dst ++, i ++) {
2023fc97bb5bSPaolo Bonzini console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2024fc97bb5bSPaolo Bonzini if (*dst != val) {
2025fc97bb5bSPaolo Bonzini *dst = val;
2026fc97bb5bSPaolo Bonzini c_max = i;
2027fc97bb5bSPaolo Bonzini }
2028fc97bb5bSPaolo Bonzini }
2029fc97bb5bSPaolo Bonzini
2030fc97bb5bSPaolo Bonzini if (c_min <= c_max) {
2031fc97bb5bSPaolo Bonzini i = TEXTMODE_Y(c_min);
2032fc97bb5bSPaolo Bonzini dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2033fc97bb5bSPaolo Bonzini }
2034fc97bb5bSPaolo Bonzini }
2035fc97bb5bSPaolo Bonzini
2036fc97bb5bSPaolo Bonzini return;
2037fc97bb5bSPaolo Bonzini case GMODE_GRAPH:
2038fc97bb5bSPaolo Bonzini if (!full_update)
2039fc97bb5bSPaolo Bonzini return;
2040fc97bb5bSPaolo Bonzini
2041fc97bb5bSPaolo Bonzini s->get_resolution(s, &width, &height);
2042fc97bb5bSPaolo Bonzini snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2043fc97bb5bSPaolo Bonzini width, height);
2044fc97bb5bSPaolo Bonzini break;
2045fc97bb5bSPaolo Bonzini case GMODE_BLANK:
2046fc97bb5bSPaolo Bonzini default:
2047fc97bb5bSPaolo Bonzini if (!full_update)
2048fc97bb5bSPaolo Bonzini return;
2049fc97bb5bSPaolo Bonzini
2050fc97bb5bSPaolo Bonzini snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2051fc97bb5bSPaolo Bonzini break;
2052fc97bb5bSPaolo Bonzini }
2053fc97bb5bSPaolo Bonzini
2054fc97bb5bSPaolo Bonzini /* Display a message */
2055fc97bb5bSPaolo Bonzini s->last_width = 60;
2056fc97bb5bSPaolo Bonzini s->last_height = height = 3;
2057fc97bb5bSPaolo Bonzini dpy_text_cursor(s->con, -1, -1);
2058fc97bb5bSPaolo Bonzini dpy_text_resize(s->con, s->last_width, height);
2059fc97bb5bSPaolo Bonzini
2060fc97bb5bSPaolo Bonzini for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2061fc97bb5bSPaolo Bonzini console_write_ch(dst ++, ' ');
2062fc97bb5bSPaolo Bonzini
2063fc97bb5bSPaolo Bonzini size = strlen(msg_buffer);
2064fc97bb5bSPaolo Bonzini width = (s->last_width - size) / 2;
2065fc97bb5bSPaolo Bonzini dst = chardata + s->last_width + width;
2066fc97bb5bSPaolo Bonzini for (i = 0; i < size; i ++)
20674083733dSOGAWA Hirofumi console_write_ch(dst ++, ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE,
20684083733dSOGAWA Hirofumi QEMU_COLOR_BLACK, 1));
2069fc97bb5bSPaolo Bonzini
2070fc97bb5bSPaolo Bonzini dpy_text_update(s->con, 0, 0, s->last_width, height);
2071fc97bb5bSPaolo Bonzini }
2072fc97bb5bSPaolo Bonzini
vga_mem_read(void * opaque,hwaddr addr,unsigned size)2073fc97bb5bSPaolo Bonzini static uint64_t vga_mem_read(void *opaque, hwaddr addr,
2074fc97bb5bSPaolo Bonzini unsigned size)
2075fc97bb5bSPaolo Bonzini {
2076fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
2077fc97bb5bSPaolo Bonzini
2078fc97bb5bSPaolo Bonzini return vga_mem_readb(s, addr);
2079fc97bb5bSPaolo Bonzini }
2080fc97bb5bSPaolo Bonzini
vga_mem_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)2081fc97bb5bSPaolo Bonzini static void vga_mem_write(void *opaque, hwaddr addr,
2082fc97bb5bSPaolo Bonzini uint64_t data, unsigned size)
2083fc97bb5bSPaolo Bonzini {
2084fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
2085fc97bb5bSPaolo Bonzini
2086e7ae771fSStefan Weil vga_mem_writeb(s, addr, data);
2087fc97bb5bSPaolo Bonzini }
2088fc97bb5bSPaolo Bonzini
2089fc97bb5bSPaolo Bonzini const MemoryRegionOps vga_mem_ops = {
2090fc97bb5bSPaolo Bonzini .read = vga_mem_read,
2091fc97bb5bSPaolo Bonzini .write = vga_mem_write,
2092fc97bb5bSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
2093fc97bb5bSPaolo Bonzini .impl = {
2094fc97bb5bSPaolo Bonzini .min_access_size = 1,
2095fc97bb5bSPaolo Bonzini .max_access_size = 1,
2096fc97bb5bSPaolo Bonzini },
2097fc97bb5bSPaolo Bonzini };
2098fc97bb5bSPaolo Bonzini
vga_common_post_load(void * opaque,int version_id)2099fc97bb5bSPaolo Bonzini static int vga_common_post_load(void *opaque, int version_id)
2100fc97bb5bSPaolo Bonzini {
2101fc97bb5bSPaolo Bonzini VGACommonState *s = opaque;
2102fc97bb5bSPaolo Bonzini
2103fc97bb5bSPaolo Bonzini /* force refresh */
2104fc97bb5bSPaolo Bonzini s->graphic_mode = -1;
210594ef4f33SGerd Hoffmann vbe_update_vgaregs(s);
2106138bc2dfSDr. David Alan Gilbert vga_update_memory_access(s);
2107fc97bb5bSPaolo Bonzini return 0;
2108fc97bb5bSPaolo Bonzini }
2109fc97bb5bSPaolo Bonzini
vga_endian_state_needed(void * opaque)2110c3b10605SBenjamin Herrenschmidt static bool vga_endian_state_needed(void *opaque)
2111c3b10605SBenjamin Herrenschmidt {
2112c3b10605SBenjamin Herrenschmidt VGACommonState *s = opaque;
2113c3b10605SBenjamin Herrenschmidt
2114c3b10605SBenjamin Herrenschmidt /*
2115c3b10605SBenjamin Herrenschmidt * Only send the endian state if it's different from the
2116c3b10605SBenjamin Herrenschmidt * default one, thus ensuring backward compatibility for
2117c3b10605SBenjamin Herrenschmidt * migration of the common case
2118c3b10605SBenjamin Herrenschmidt */
2119c3b10605SBenjamin Herrenschmidt return s->default_endian_fb != s->big_endian_fb;
2120c3b10605SBenjamin Herrenschmidt }
2121c3b10605SBenjamin Herrenschmidt
212273d22cafSStefan Weil static const VMStateDescription vmstate_vga_endian = {
2123c3b10605SBenjamin Herrenschmidt .name = "vga.endian",
2124c3b10605SBenjamin Herrenschmidt .version_id = 1,
2125c3b10605SBenjamin Herrenschmidt .minimum_version_id = 1,
21265cd8cadaSJuan Quintela .needed = vga_endian_state_needed,
2127f0613160SRichard Henderson .fields = (const VMStateField[]) {
2128c3b10605SBenjamin Herrenschmidt VMSTATE_BOOL(big_endian_fb, VGACommonState),
2129c3b10605SBenjamin Herrenschmidt VMSTATE_END_OF_LIST()
2130c3b10605SBenjamin Herrenschmidt }
2131c3b10605SBenjamin Herrenschmidt };
2132c3b10605SBenjamin Herrenschmidt
2133fc97bb5bSPaolo Bonzini const VMStateDescription vmstate_vga_common = {
2134fc97bb5bSPaolo Bonzini .name = "vga",
2135fc97bb5bSPaolo Bonzini .version_id = 2,
2136fc97bb5bSPaolo Bonzini .minimum_version_id = 2,
2137fc97bb5bSPaolo Bonzini .post_load = vga_common_post_load,
2138f0613160SRichard Henderson .fields = (const VMStateField[]) {
2139fc97bb5bSPaolo Bonzini VMSTATE_UINT32(latch, VGACommonState),
2140fc97bb5bSPaolo Bonzini VMSTATE_UINT8(sr_index, VGACommonState),
2141fc97bb5bSPaolo Bonzini VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2142fc97bb5bSPaolo Bonzini VMSTATE_UINT8(gr_index, VGACommonState),
2143fc97bb5bSPaolo Bonzini VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2144fc97bb5bSPaolo Bonzini VMSTATE_UINT8(ar_index, VGACommonState),
2145fc97bb5bSPaolo Bonzini VMSTATE_BUFFER(ar, VGACommonState),
2146fc97bb5bSPaolo Bonzini VMSTATE_INT32(ar_flip_flop, VGACommonState),
2147fc97bb5bSPaolo Bonzini VMSTATE_UINT8(cr_index, VGACommonState),
2148fc97bb5bSPaolo Bonzini VMSTATE_BUFFER(cr, VGACommonState),
2149fc97bb5bSPaolo Bonzini VMSTATE_UINT8(msr, VGACommonState),
2150fc97bb5bSPaolo Bonzini VMSTATE_UINT8(fcr, VGACommonState),
2151fc97bb5bSPaolo Bonzini VMSTATE_UINT8(st00, VGACommonState),
2152fc97bb5bSPaolo Bonzini VMSTATE_UINT8(st01, VGACommonState),
2153fc97bb5bSPaolo Bonzini
2154fc97bb5bSPaolo Bonzini VMSTATE_UINT8(dac_state, VGACommonState),
2155fc97bb5bSPaolo Bonzini VMSTATE_UINT8(dac_sub_index, VGACommonState),
2156fc97bb5bSPaolo Bonzini VMSTATE_UINT8(dac_read_index, VGACommonState),
2157fc97bb5bSPaolo Bonzini VMSTATE_UINT8(dac_write_index, VGACommonState),
2158fc97bb5bSPaolo Bonzini VMSTATE_BUFFER(dac_cache, VGACommonState),
2159fc97bb5bSPaolo Bonzini VMSTATE_BUFFER(palette, VGACommonState),
2160fc97bb5bSPaolo Bonzini
2161fc97bb5bSPaolo Bonzini VMSTATE_INT32(bank_offset, VGACommonState),
2162d2164ad3SHalil Pasic VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState, NULL),
2163fc97bb5bSPaolo Bonzini VMSTATE_UINT16(vbe_index, VGACommonState),
2164fc97bb5bSPaolo Bonzini VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2165fc97bb5bSPaolo Bonzini VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2166fc97bb5bSPaolo Bonzini VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2167fc97bb5bSPaolo Bonzini VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2168fc97bb5bSPaolo Bonzini VMSTATE_END_OF_LIST()
2169c3b10605SBenjamin Herrenschmidt },
2170f0613160SRichard Henderson .subsections = (const VMStateDescription * const []) {
21715cd8cadaSJuan Quintela &vmstate_vga_endian,
21725cd8cadaSJuan Quintela NULL
2173fc97bb5bSPaolo Bonzini }
2174fc97bb5bSPaolo Bonzini };
2175fc97bb5bSPaolo Bonzini
2176380cd056SGerd Hoffmann static const GraphicHwOps vga_ops = {
2177380cd056SGerd Hoffmann .invalidate = vga_invalidate_display,
2178380cd056SGerd Hoffmann .gfx_update = vga_update_display,
2179380cd056SGerd Hoffmann .text_update = vga_update_text,
2180380cd056SGerd Hoffmann };
2181380cd056SGerd Hoffmann
uint_clamp(uint32_t val,uint32_t vmin,uint32_t vmax)2182619616ceSRadim Krčmář static inline uint32_t uint_clamp(uint32_t val, uint32_t vmin, uint32_t vmax)
2183619616ceSRadim Krčmář {
2184619616ceSRadim Krčmář if (val < vmin) {
2185619616ceSRadim Krčmář return vmin;
2186619616ceSRadim Krčmář }
2187619616ceSRadim Krčmář if (val > vmax) {
2188619616ceSRadim Krčmář return vmax;
2189619616ceSRadim Krčmář }
2190619616ceSRadim Krčmář return val;
2191619616ceSRadim Krčmář }
2192619616ceSRadim Krčmář
vga_common_init(VGACommonState * s,Object * obj,Error ** errp)21936832deb8SThomas Huth bool vga_common_init(VGACommonState *s, Object *obj, Error **errp)
2194fc97bb5bSPaolo Bonzini {
2195fc97bb5bSPaolo Bonzini int i, j, v, b;
21966832deb8SThomas Huth Error *local_err = NULL;
2197fc97bb5bSPaolo Bonzini
2198fc97bb5bSPaolo Bonzini for(i = 0;i < 256; i++) {
2199fc97bb5bSPaolo Bonzini v = 0;
2200fc97bb5bSPaolo Bonzini for(j = 0; j < 8; j++) {
2201fc97bb5bSPaolo Bonzini v |= ((i >> j) & 1) << (j * 4);
2202fc97bb5bSPaolo Bonzini }
2203fc97bb5bSPaolo Bonzini expand4[i] = v;
2204fc97bb5bSPaolo Bonzini
2205fc97bb5bSPaolo Bonzini v = 0;
2206fc97bb5bSPaolo Bonzini for(j = 0; j < 4; j++) {
2207fc97bb5bSPaolo Bonzini v |= ((i >> (2 * j)) & 3) << (j * 4);
2208fc97bb5bSPaolo Bonzini }
2209fc97bb5bSPaolo Bonzini expand2[i] = v;
2210fc97bb5bSPaolo Bonzini }
2211fc97bb5bSPaolo Bonzini for(i = 0; i < 16; i++) {
2212fc97bb5bSPaolo Bonzini v = 0;
2213fc97bb5bSPaolo Bonzini for(j = 0; j < 4; j++) {
2214fc97bb5bSPaolo Bonzini b = ((i >> j) & 1);
2215fc97bb5bSPaolo Bonzini v |= b << (2 * j);
2216fc97bb5bSPaolo Bonzini v |= b << (2 * j + 1);
2217fc97bb5bSPaolo Bonzini }
2218fc97bb5bSPaolo Bonzini expand4to8[i] = v;
2219fc97bb5bSPaolo Bonzini }
2220fc97bb5bSPaolo Bonzini
2221619616ceSRadim Krčmář s->vram_size_mb = uint_clamp(s->vram_size_mb, 1, 512);
2222619616ceSRadim Krčmář s->vram_size_mb = pow2ceil(s->vram_size_mb);
2223f0353b0dSPhilippe Mathieu-Daudé s->vram_size = s->vram_size_mb * MiB;
2224619616ceSRadim Krčmář
222554a85d46SGerd Hoffmann if (!s->vbe_size) {
222654a85d46SGerd Hoffmann s->vbe_size = s->vram_size;
222754a85d46SGerd Hoffmann }
22283d90c625SGerd Hoffmann s->vbe_size_mask = s->vbe_size - 1;
2229fc97bb5bSPaolo Bonzini
2230fc97bb5bSPaolo Bonzini s->is_vbe_vmstate = 1;
22319eb840a2SThomas Huth
22329eb840a2SThomas Huth if (s->global_vmstate && qemu_ram_block_by_name("vga.vram")) {
22339eb840a2SThomas Huth error_setg(errp, "Only one global VGA device can be used at a time");
22349eb840a2SThomas Huth return false;
22359eb840a2SThomas Huth }
22369eb840a2SThomas Huth
22371cfe48c1SPeter Maydell memory_region_init_ram_nomigrate(&s->vram, obj, "vga.vram", s->vram_size,
22386832deb8SThomas Huth &local_err);
22396832deb8SThomas Huth if (local_err) {
22406832deb8SThomas Huth error_propagate(errp, local_err);
22416832deb8SThomas Huth return false;
22426832deb8SThomas Huth }
22431fcfdc43SGerd Hoffmann vmstate_register_ram(&s->vram, s->global_vmstate ? NULL : DEVICE(obj));
2244fc97bb5bSPaolo Bonzini xen_register_framebuffer(&s->vram);
2245fc97bb5bSPaolo Bonzini s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
2246fc97bb5bSPaolo Bonzini s->get_bpp = vga_get_bpp;
2247f9b925fdSPaolo Bonzini s->get_params = vga_get_params;
2248fc97bb5bSPaolo Bonzini s->get_resolution = vga_get_resolution;
2249380cd056SGerd Hoffmann s->hw_ops = &vga_ops;
2250fc97bb5bSPaolo Bonzini switch (vga_retrace_method) {
2251fc97bb5bSPaolo Bonzini case VGA_RETRACE_DUMB:
2252fc97bb5bSPaolo Bonzini s->retrace = vga_dumb_retrace;
2253fc97bb5bSPaolo Bonzini s->update_retrace_info = vga_dumb_update_retrace_info;
2254fc97bb5bSPaolo Bonzini break;
2255fc97bb5bSPaolo Bonzini
2256fc97bb5bSPaolo Bonzini case VGA_RETRACE_PRECISE:
2257fc97bb5bSPaolo Bonzini s->retrace = vga_precise_retrace;
2258fc97bb5bSPaolo Bonzini s->update_retrace_info = vga_precise_update_retrace_info;
2259fc97bb5bSPaolo Bonzini break;
2260fc97bb5bSPaolo Bonzini }
22612c7d8736SBenjamin Herrenschmidt
22622c7d8736SBenjamin Herrenschmidt /*
2263c3b10605SBenjamin Herrenschmidt * Set default fb endian based on target, could probably be turned
22642c7d8736SBenjamin Herrenschmidt * into a device attribute set by the machine/platform to remove
22652c7d8736SBenjamin Herrenschmidt * all target endian dependencies from this file.
22662c7d8736SBenjamin Herrenschmidt */
22679eb7e7e8SThomas Huth s->default_endian_fb = target_words_bigendian();
2268*302075f8SPhilippe Mathieu-Daudé s->big_endian_fb = s->default_endian_fb;
22699eb7e7e8SThomas Huth
2270fc97bb5bSPaolo Bonzini vga_dirty_log_start(s);
22716832deb8SThomas Huth
22726832deb8SThomas Huth return true;
2273fc97bb5bSPaolo Bonzini }
2274fc97bb5bSPaolo Bonzini
2275fc97bb5bSPaolo Bonzini static const MemoryRegionPortio vga_portio_list[] = {
2276fc97bb5bSPaolo Bonzini { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
2277fc97bb5bSPaolo Bonzini { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
2278fc97bb5bSPaolo Bonzini { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
2279fc97bb5bSPaolo Bonzini { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
2280fc97bb5bSPaolo Bonzini { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
2281fc97bb5bSPaolo Bonzini PORTIO_END_OF_LIST(),
2282fc97bb5bSPaolo Bonzini };
2283fc97bb5bSPaolo Bonzini
22849eb7e7e8SThomas Huth static const MemoryRegionPortio vbe_portio_list_x86[] = {
2285fc97bb5bSPaolo Bonzini { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2286fc97bb5bSPaolo Bonzini { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
22879eb7e7e8SThomas Huth { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
22889eb7e7e8SThomas Huth PORTIO_END_OF_LIST(),
22899eb7e7e8SThomas Huth };
22909eb7e7e8SThomas Huth
22919eb7e7e8SThomas Huth static const MemoryRegionPortio vbe_portio_list_no_x86[] = {
22929eb7e7e8SThomas Huth { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2293fc97bb5bSPaolo Bonzini { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2294fc97bb5bSPaolo Bonzini PORTIO_END_OF_LIST(),
2295fc97bb5bSPaolo Bonzini };
2296fc97bb5bSPaolo Bonzini
2297fc97bb5bSPaolo Bonzini /* Used by both ISA and PCI */
vga_init_io(VGACommonState * s,Object * obj,const MemoryRegionPortio ** vga_ports,const MemoryRegionPortio ** vbe_ports)2298c84b28eeSPaolo Bonzini MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
2299fc97bb5bSPaolo Bonzini const MemoryRegionPortio **vga_ports,
2300fc97bb5bSPaolo Bonzini const MemoryRegionPortio **vbe_ports)
2301fc97bb5bSPaolo Bonzini {
2302fc97bb5bSPaolo Bonzini MemoryRegion *vga_mem;
23039eb7e7e8SThomas Huth MachineState *ms = MACHINE(qdev_get_machine());
23049eb7e7e8SThomas Huth
23059eb7e7e8SThomas Huth /*
23069eb7e7e8SThomas Huth * We unfortunately need two VBE lists since non-x86 machines might
23079eb7e7e8SThomas Huth * not be able to do 16-bit accesses at unaligned addresses (0x1cf)
23089eb7e7e8SThomas Huth */
23099eb7e7e8SThomas Huth if (object_dynamic_cast(OBJECT(ms), TYPE_X86_MACHINE)) {
23109eb7e7e8SThomas Huth *vbe_ports = vbe_portio_list_x86;
23119eb7e7e8SThomas Huth } else {
23129eb7e7e8SThomas Huth *vbe_ports = vbe_portio_list_no_x86;
23139eb7e7e8SThomas Huth }
2314fc97bb5bSPaolo Bonzini
2315fc97bb5bSPaolo Bonzini *vga_ports = vga_portio_list;
2316fc97bb5bSPaolo Bonzini
2317fc97bb5bSPaolo Bonzini vga_mem = g_malloc(sizeof(*vga_mem));
2318c84b28eeSPaolo Bonzini memory_region_init_io(vga_mem, obj, &vga_mem_ops, s,
2319fc97bb5bSPaolo Bonzini "vga-lowmem", 0x20000);
2320fc97bb5bSPaolo Bonzini memory_region_set_flush_coalesced(vga_mem);
2321fc97bb5bSPaolo Bonzini
2322fc97bb5bSPaolo Bonzini return vga_mem;
2323fc97bb5bSPaolo Bonzini }
2324fc97bb5bSPaolo Bonzini
vga_init(VGACommonState * s,Object * obj,MemoryRegion * address_space,MemoryRegion * address_space_io,bool init_vga_ports)2325712f0cc7SPaolo Bonzini void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
2326fc97bb5bSPaolo Bonzini MemoryRegion *address_space_io, bool init_vga_ports)
2327fc97bb5bSPaolo Bonzini {
2328fc97bb5bSPaolo Bonzini MemoryRegion *vga_io_memory;
2329fc97bb5bSPaolo Bonzini const MemoryRegionPortio *vga_ports, *vbe_ports;
2330fc97bb5bSPaolo Bonzini
2331fc97bb5bSPaolo Bonzini qemu_register_reset(vga_reset, s);
2332fc97bb5bSPaolo Bonzini
2333fc97bb5bSPaolo Bonzini s->bank_offset = 0;
2334fc97bb5bSPaolo Bonzini
2335fc97bb5bSPaolo Bonzini s->legacy_address_space = address_space;
2336fc97bb5bSPaolo Bonzini
2337c84b28eeSPaolo Bonzini vga_io_memory = vga_init_io(s, obj, &vga_ports, &vbe_ports);
2338fc97bb5bSPaolo Bonzini memory_region_add_subregion_overlap(address_space,
2339b19c1c08SHervé Poussineau 0x000a0000,
2340fc97bb5bSPaolo Bonzini vga_io_memory,
2341fc97bb5bSPaolo Bonzini 1);
2342fc97bb5bSPaolo Bonzini memory_region_set_coalescing(vga_io_memory);
2343fc97bb5bSPaolo Bonzini if (init_vga_ports) {
2344848696bfSKirill Batuzov portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga");
2345848696bfSKirill Batuzov portio_list_set_flush_coalesced(&s->vga_port_list);
2346848696bfSKirill Batuzov portio_list_add(&s->vga_port_list, address_space_io, 0x3b0);
2347fc97bb5bSPaolo Bonzini }
2348fc97bb5bSPaolo Bonzini if (vbe_ports) {
2349848696bfSKirill Batuzov portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe");
2350848696bfSKirill Batuzov portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce);
2351fc97bb5bSPaolo Bonzini }
2352fc97bb5bSPaolo Bonzini }
2353