VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA.cpp@ 4849

Last change on this file since 4849 was 4712, checked in by vboxsync, 17 years ago

Implemented 8-bit DAC support. The VESA BIOS could aready turn it on
but DevVGA.cpp never bothered to check the setting.

  • Property svn:eol-style set to native
File size: 159.5 KB
Line 
1#ifdef VBOX
2/** @file
3 *
4 * VBox VGA/VESA device
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 * --------------------------------------------------------------------
18 *
19 * This code is based on:
20 *
21 * QEMU VGA Emulator.
22 *
23 * Copyright (c) 2003 Fabrice Bellard
24 *
25 * Permission is hereby granted, free of charge, to any person obtaining a copy
26 * of this software and associated documentation files (the "Software"), to deal
27 * in the Software without restriction, including without limitation the rights
28 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 * copies of the Software, and to permit persons to whom the Software is
30 * furnished to do so, subject to the following conditions:
31 *
32 * The above copyright notice and this permission notice shall be included in
33 * all copies or substantial portions of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41 * THE SOFTWARE.
42 */
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47/** The default amount of VRAM. */
48#define VGA_VRAM_DEFAULT (_4M)
49/** The maximum amount of VRAM. */
50#define VGA_VRAM_MAX (128 * _1M)
51/** The minimum amount of VRAM. */
52#define VGA_VRAM_MIN (_1M)
53
54/** The size of the VGA GC mapping.
55 * This is supposed to be all the VGA memory accessible to the guest.
56 * The initial value was 256KB but NTAllInOne.iso appears to access more
57 * thus the limit was upped to 512KB.
58 *
59 * @todo Someone with some VGA knowhow should make a better guess at this value.
60 */
61#define VGA_MAPPING_SIZE _512K
62
63/** Converts a vga adaptor state pointer to a device instance pointer. */
64#define VGASTATE2DEVINS(pVgaState) ((pVgaState)->CTXSUFF(pDevIns))
65
66/** Use VBE bytewise I/O */
67#define VBE_BYTEWISE_IO
68
69/** Use VBE new dynamic mode list.
70 * If this is not defined, no checks are carried out to see if the modes all
71 * fit into the framebuffer! See the VRAM_SIZE_FIX define. */
72#define VBE_NEW_DYN_LIST
73
74/** Check that the video modes fit into virtual video memory.
75 * Only works when VBE_NEW_DYN_LIST is defined! */
76#define VRAM_SIZE_FIX
77
78/** Some fixes to ensure that logical scan-line lengths are not overwritten. */
79#define KEEP_SCAN_LINE_LENGTH
80
81
82/*******************************************************************************
83* Header Files *
84*******************************************************************************/
85#define LOG_GROUP LOG_GROUP_DEV_VGA
86#include <VBox/pdmdev.h>
87#include <VBox/pgm.h>
88#include <iprt/assert.h>
89#include <iprt/asm.h>
90#include <iprt/string.h>
91
92#include <VBox/VBoxGuest.h>
93#include <VBox/VBoxVideo.h>
94
95#if defined(VBE_NEW_DYN_LIST) && defined(IN_RING3) && !defined(VBOX_DEVICE_STRUCT_TESTCASE)
96# include "DevVGAModes.h"
97# include <stdio.h> /* sscan */
98#endif
99
100#include "vl_vbox.h"
101#include "DevVGA.h"
102#include "Builtins.h"
103#include "Builtins2.h"
104
105
106#ifndef VBOX_DEVICE_STRUCT_TESTCASE
107/*******************************************************************************
108* Internal Functions *
109*******************************************************************************/
110__BEGIN_DECLS
111
112PDMBOTHCBDECL(int) vgaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
113PDMBOTHCBDECL(int) vgaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
114PDMBOTHCBDECL(int) vgaIOPortWriteVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
115PDMBOTHCBDECL(int) vgaIOPortWriteVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
116PDMBOTHCBDECL(int) vgaIOPortReadVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
117PDMBOTHCBDECL(int) vgaIOPortReadVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
118PDMBOTHCBDECL(int) vgaMMIOFill(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems);
119PDMBOTHCBDECL(int) vgaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
120PDMBOTHCBDECL(int) vgaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
121#ifdef IN_GC
122PDMBOTHCBDECL(int) vgaGCLFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
123#endif
124#ifdef IN_RING0
125PDMBOTHCBDECL(int) vgaR0LFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
126#endif
127#ifdef IN_RING3
128# ifdef VBE_NEW_DYN_LIST
129PDMBOTHCBDECL(int) vbeIOPortReadVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
130PDMBOTHCBDECL(int) vbeIOPortWriteVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
131# endif
132#endif /* IN_RING3 */
133
134
135__END_DECLS
136
137
138/**
139 * Set a VRAM page dirty.
140 *
141 * @param pData VGA instance data.
142 * @param offVRAM The VRAM offset of the page to set.
143 */
144DECLINLINE(void) vga_set_dirty(VGAState *pData, RTGCPHYS offVRAM)
145{
146 AssertMsg(offVRAM < pData->vram_size, ("offVRAM = %p, pData->vram_size = %p\n", offVRAM, pData->vram_size));
147 ASMBitSet(&pData->au32DirtyBitmap[0], offVRAM >> PAGE_SHIFT);
148 pData->fHaveDirtyBits = true;
149}
150
151/**
152 * Tests if a VRAM page is dirty.
153 *
154 * @returns true if dirty.
155 * @returns false if clean.
156 * @param pData VGA instance data.
157 * @param offVRAM The VRAM offset of the page to check.
158 */
159DECLINLINE(bool) vga_is_dirty(VGAState *pData, RTGCPHYS offVRAM)
160{
161 AssertMsg(offVRAM < pData->vram_size, ("offVRAM = %p, pData->vram_size = %p\n", offVRAM, pData->vram_size));
162 return ASMBitTest(&pData->au32DirtyBitmap[0], offVRAM >> PAGE_SHIFT);
163}
164
165/**
166 * Reset dirty flags in a give range.
167 *
168 * @param pData VGA instance data.
169 * @param offVRAMStart Offset into the VRAM buffer of the first page.
170 * @param offVRAMEnd Offset into the VRAM buffer of the last page - exclusive.
171 */
172DECLINLINE(void) vga_reset_dirty(VGAState *pData, RTGCPHYS offVRAMStart, RTGCPHYS offVRAMEnd)
173{
174 Assert(offVRAMStart < pData->vram_size);
175 Assert(offVRAMEnd <= pData->vram_size);
176 Assert(offVRAMStart < offVRAMEnd);
177 ASMBitClearRange(&pData->au32DirtyBitmap[0], offVRAMStart >> PAGE_SHIFT, offVRAMEnd >> PAGE_SHIFT);
178}
179
180#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
181#endif /* VBOX */
182#ifndef VBOX_DEVICE_STRUCT_TESTCASE
183
184#ifndef VBOX
185#include "vl.h"
186#include "vga_int.h"
187#endif /* !VBOX */
188
189#ifdef LOG_ENABLED
190//#define DEBUG_VGA
191//#define DEBUG_VGA_MEM
192//#define DEBUG_VGA_REG
193
194#define DEBUG_BOCHS_VBE
195
196#endif
197
198/* force some bits to zero */
199#ifdef VBOX
200static
201#endif /* VBOX */
202const uint8_t sr_mask[8] = {
203 (uint8_t)~0xfc,
204 (uint8_t)~0xc2,
205 (uint8_t)~0xf0,
206 (uint8_t)~0xc0,
207 (uint8_t)~0xf1,
208 (uint8_t)~0xff,
209 (uint8_t)~0xff,
210 (uint8_t)~0x00,
211};
212
213#ifdef VBOX
214static
215#endif /* VBOX */
216const uint8_t gr_mask[16] = {
217 (uint8_t)~0xf0, /* 0x00 */
218 (uint8_t)~0xf0, /* 0x01 */
219 (uint8_t)~0xf0, /* 0x02 */
220 (uint8_t)~0xe0, /* 0x03 */
221 (uint8_t)~0xfc, /* 0x04 */
222 (uint8_t)~0x84, /* 0x05 */
223 (uint8_t)~0xf0, /* 0x06 */
224 (uint8_t)~0xf0, /* 0x07 */
225 (uint8_t)~0x00, /* 0x08 */
226 (uint8_t)~0xff, /* 0x09 */
227 (uint8_t)~0xff, /* 0x0a */
228 (uint8_t)~0xff, /* 0x0b */
229 (uint8_t)~0xff, /* 0x0c */
230 (uint8_t)~0xff, /* 0x0d */
231 (uint8_t)~0xff, /* 0x0e */
232 (uint8_t)~0xff, /* 0x0f */
233};
234
235#define cbswap_32(__x) \
236((uint32_t)( \
237 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
238 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
239 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
240 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
241
242#ifdef WORDS_BIGENDIAN
243#define PAT(x) cbswap_32(x)
244#else
245#define PAT(x) (x)
246#endif
247
248#ifdef WORDS_BIGENDIAN
249#define BIG 1
250#else
251#define BIG 0
252#endif
253
254#ifdef WORDS_BIGENDIAN
255#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
256#else
257#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
258#endif
259
260static const uint32_t mask16[16] = {
261 PAT(0x00000000),
262 PAT(0x000000ff),
263 PAT(0x0000ff00),
264 PAT(0x0000ffff),
265 PAT(0x00ff0000),
266 PAT(0x00ff00ff),
267 PAT(0x00ffff00),
268 PAT(0x00ffffff),
269 PAT(0xff000000),
270 PAT(0xff0000ff),
271 PAT(0xff00ff00),
272 PAT(0xff00ffff),
273 PAT(0xffff0000),
274 PAT(0xffff00ff),
275 PAT(0xffffff00),
276 PAT(0xffffffff),
277};
278
279#undef PAT
280
281#ifdef WORDS_BIGENDIAN
282#define PAT(x) (x)
283#else
284#define PAT(x) cbswap_32(x)
285#endif
286
287static const uint32_t dmask16[16] = {
288 PAT(0x00000000),
289 PAT(0x000000ff),
290 PAT(0x0000ff00),
291 PAT(0x0000ffff),
292 PAT(0x00ff0000),
293 PAT(0x00ff00ff),
294 PAT(0x00ffff00),
295 PAT(0x00ffffff),
296 PAT(0xff000000),
297 PAT(0xff0000ff),
298 PAT(0xff00ff00),
299 PAT(0xff00ffff),
300 PAT(0xffff0000),
301 PAT(0xffff00ff),
302 PAT(0xffffff00),
303 PAT(0xffffffff),
304};
305
306static const uint32_t dmask4[4] = {
307 PAT(0x00000000),
308 PAT(0x0000ffff),
309 PAT(0xffff0000),
310 PAT(0xffffffff),
311};
312
313#if defined(VBOX) && defined(IN_RING3)
314static uint32_t expand4[256];
315static uint16_t expand2[256];
316static uint8_t expand4to8[16];
317#endif /* VBOX && IN_RING3 */
318
319#ifndef VBOX
320VGAState *vga_state;
321int vga_io_memory;
322#endif /* !VBOX */
323
324static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
325{
326 VGAState *s = (VGAState*)opaque;
327 int val, index;
328
329 /* check port range access depending on color/monochrome mode */
330 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
331 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
332 val = 0xff;
333 } else {
334 switch(addr) {
335 case 0x3c0:
336 if (s->ar_flip_flop == 0) {
337 val = s->ar_index;
338 } else {
339 val = 0;
340 }
341 break;
342 case 0x3c1:
343 index = s->ar_index & 0x1f;
344 if (index < 21)
345 val = s->ar[index];
346 else
347 val = 0;
348 break;
349 case 0x3c2:
350 val = s->st00;
351 break;
352 case 0x3c4:
353 val = s->sr_index;
354 break;
355 case 0x3c5:
356 val = s->sr[s->sr_index];
357#ifdef DEBUG_VGA_REG
358 Log(("vga: read SR%x = 0x%02x\n", s->sr_index, val));
359#endif
360 break;
361 case 0x3c7:
362 val = s->dac_state;
363 break;
364 case 0x3c8:
365 val = s->dac_write_index;
366 break;
367 case 0x3c9:
368 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
369 if (++s->dac_sub_index == 3) {
370 s->dac_sub_index = 0;
371 s->dac_read_index++;
372 }
373 break;
374 case 0x3ca:
375 val = s->fcr;
376 break;
377 case 0x3cc:
378 val = s->msr;
379 break;
380 case 0x3ce:
381 val = s->gr_index;
382 break;
383 case 0x3cf:
384 val = s->gr[s->gr_index];
385#ifdef DEBUG_VGA_REG
386 Log(("vga: read GR%x = 0x%02x\n", s->gr_index, val));
387#endif
388 break;
389 case 0x3b4:
390 case 0x3d4:
391 val = s->cr_index;
392 break;
393 case 0x3b5:
394 case 0x3d5:
395 val = s->cr[s->cr_index];
396#ifdef DEBUG_VGA_REG
397 Log(("vga: read CR%x = 0x%02x\n", s->cr_index, val));
398#endif
399 break;
400 case 0x3ba:
401 case 0x3da:
402 /* just toggle to fool polling */
403 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
404 val = s->st01;
405 s->ar_flip_flop = 0;
406 break;
407 default:
408 val = 0x00;
409 break;
410 }
411 }
412#if defined(DEBUG_VGA)
413 Log(("VGA: read addr=0x%04x data=0x%02x\n", addr, val));
414#endif
415 return val;
416}
417
418static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
419{
420 VGAState *s = (VGAState*)opaque;
421 int index;
422
423 /* check port range access depending on color/monochrome mode */
424 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
425 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
426 return;
427
428#ifdef DEBUG_VGA
429 Log(("VGA: write addr=0x%04x data=0x%02x\n", addr, val));
430#endif
431
432 switch(addr) {
433 case 0x3c0:
434 if (s->ar_flip_flop == 0) {
435 val &= 0x3f;
436 s->ar_index = val;
437 } else {
438 index = s->ar_index & 0x1f;
439 switch(index) {
440#ifndef VBOX
441 case 0x00 ... 0x0f:
442#else /* VBOX */
443 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
444 case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
445#endif /* VBOX */
446 s->ar[index] = val & 0x3f;
447 break;
448 case 0x10:
449 s->ar[index] = val & ~0x10;
450 break;
451 case 0x11:
452 s->ar[index] = val;
453 break;
454 case 0x12:
455 s->ar[index] = val & ~0xc0;
456 break;
457 case 0x13:
458 s->ar[index] = val & ~0xf0;
459 break;
460 case 0x14:
461 s->ar[index] = val & ~0xf0;
462 break;
463 default:
464 break;
465 }
466 }
467 s->ar_flip_flop ^= 1;
468 break;
469 case 0x3c2:
470 s->msr = val & ~0x10;
471 break;
472 case 0x3c4:
473 s->sr_index = val & 7;
474 break;
475 case 0x3c5:
476#ifdef DEBUG_VGA_REG
477 Log(("vga: write SR%x = 0x%02x\n", s->sr_index, val));
478#endif
479 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
480 break;
481 case 0x3c7:
482 s->dac_read_index = val;
483 s->dac_sub_index = 0;
484 s->dac_state = 3;
485 break;
486 case 0x3c8:
487 s->dac_write_index = val;
488 s->dac_sub_index = 0;
489 s->dac_state = 0;
490 break;
491 case 0x3c9:
492 s->dac_cache[s->dac_sub_index] = val;
493 if (++s->dac_sub_index == 3) {
494 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
495 s->dac_sub_index = 0;
496 s->dac_write_index++;
497 }
498 break;
499 case 0x3ce:
500 s->gr_index = val & 0x0f;
501 break;
502 case 0x3cf:
503#ifdef DEBUG_VGA_REG
504 Log(("vga: write GR%x = 0x%02x\n", s->gr_index, val));
505#endif
506 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
507 break;
508 case 0x3b4:
509 case 0x3d4:
510 s->cr_index = val;
511 break;
512 case 0x3b5:
513 case 0x3d5:
514#ifdef DEBUG_VGA_REG
515 Log(("vga: write CR%x = 0x%02x\n", s->cr_index, val));
516#endif
517 /* handle CR0-7 protection */
518 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
519 /* can always write bit 4 of CR7 */
520 if (s->cr_index == 7)
521 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
522 return;
523 }
524 switch(s->cr_index) {
525 case 0x01: /* horizontal display end */
526 case 0x07:
527 case 0x09:
528 case 0x0c:
529 case 0x0d:
530 case 0x12: /* veritcal display end */
531 s->cr[s->cr_index] = val;
532 break;
533
534 default:
535 s->cr[s->cr_index] = val;
536 break;
537 }
538 break;
539 case 0x3ba:
540 case 0x3da:
541 s->fcr = val & 0x10;
542 break;
543 }
544}
545
546#ifdef CONFIG_BOCHS_VBE
547static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
548{
549 VGAState *s = (VGAState*)opaque;
550 uint32_t val;
551 val = s->vbe_index;
552 return val;
553}
554
555static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
556{
557 VGAState *s = (VGAState*)opaque;
558 uint32_t val;
559
560 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
561 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
562 switch(s->vbe_index) {
563 /* XXX: do not hardcode ? */
564 case VBE_DISPI_INDEX_XRES:
565 val = VBE_DISPI_MAX_XRES;
566 break;
567 case VBE_DISPI_INDEX_YRES:
568 val = VBE_DISPI_MAX_YRES;
569 break;
570 case VBE_DISPI_INDEX_BPP:
571 val = VBE_DISPI_MAX_BPP;
572 break;
573 default:
574 val = s->vbe_regs[s->vbe_index];
575 break;
576 }
577 } else if (s->vbe_index == VBE_DISPI_INDEX_VBOX_VIDEO) {
578 /* Reading from the port means that the old additions are requesting the number of monitors. */
579 val = 1;
580 } else {
581 val = s->vbe_regs[s->vbe_index];
582 }
583 } else {
584 val = 0;
585 }
586#ifdef DEBUG_BOCHS_VBE
587 Log(("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val));
588#endif
589 return val;
590}
591
592static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
593{
594 VGAState *s = (VGAState*)opaque;
595 s->vbe_index = val;
596}
597
598static int vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
599{
600 VGAState *s = (VGAState*)opaque;
601
602 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
603#ifdef DEBUG_BOCHS_VBE
604 Log(("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val));
605#endif
606 switch(s->vbe_index) {
607 case VBE_DISPI_INDEX_ID:
608 if (val == VBE_DISPI_ID0 ||
609 val == VBE_DISPI_ID1 ||
610 val == VBE_DISPI_ID2) {
611 s->vbe_regs[s->vbe_index] = val;
612 }
613#ifdef VBOX
614 if (val == VBE_DISPI_ID_VBOX_VIDEO) {
615 s->vbe_regs[s->vbe_index] = val;
616 }
617#endif /* VBOX */
618 break;
619 case VBE_DISPI_INDEX_XRES:
620 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
621 s->vbe_regs[s->vbe_index] = val;
622#ifdef KEEP_SCAN_LINE_LENGTH
623 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
624 s->vbe_line_offset = val >> 1;
625 else
626 s->vbe_line_offset = val * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
627 /* XXX: support weird bochs semantics ? */
628 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = s->vbe_line_offset;
629 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
630 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
631 s->vbe_start_addr = 0;
632#endif /* KEEP_SCAN_LINE_LENGTH defined */
633 }
634 break;
635 case VBE_DISPI_INDEX_YRES:
636 if (val <= VBE_DISPI_MAX_YRES) {
637 s->vbe_regs[s->vbe_index] = val;
638#ifdef KEEP_SCAN_LINE_LENGTH
639 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = val;
640 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
641 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
642 s->vbe_start_addr = 0;
643#endif /* KEEP_SCAN_LINE_LENGTH defined */
644 }
645 break;
646 case VBE_DISPI_INDEX_BPP:
647 if (val == 0)
648 val = 8;
649 if (val == 4 || val == 8 || val == 15 ||
650 val == 16 || val == 24 || val == 32) {
651 s->vbe_regs[s->vbe_index] = val;
652#ifdef KEEP_SCAN_LINE_LENGTH
653 if (val == 4)
654 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
655 else
656 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * ((val + 7) >> 3);
657 /* XXX: support weird bochs semantics ? */
658 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = s->vbe_line_offset;
659 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
660 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
661 s->vbe_start_addr = 0;
662#endif /* KEEP_SCAN_LINE_LENGTH defined */
663 }
664 break;
665 case VBE_DISPI_INDEX_BANK:
666 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
667 val &= (s->vbe_bank_mask >> 2);
668 } else {
669 val &= s->vbe_bank_mask;
670 }
671 val &= s->vbe_bank_mask;
672 s->vbe_regs[s->vbe_index] = val;
673 s->bank_offset = (val << 16);
674 break;
675 case VBE_DISPI_INDEX_ENABLE:
676#ifndef IN_RING3
677 return VINF_IOM_HC_IOPORT_WRITE;
678#else
679 if (val & VBE_DISPI_ENABLED) {
680 int h, shift_control;
681#ifdef VBOX
682 /* Check the values before we screw up with a resolution which is too big or small. */
683 size_t cb = s->vbe_regs[VBE_DISPI_INDEX_XRES];
684 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
685 cb = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
686 else
687 cb = s->vbe_regs[VBE_DISPI_INDEX_XRES] * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
688 cb *= s->vbe_regs[VBE_DISPI_INDEX_YRES];
689#ifndef KEEP_SCAN_LINE_LENGTH
690 if ( !s->vbe_regs[VBE_DISPI_INDEX_XRES]
691 || !s->vbe_regs[VBE_DISPI_INDEX_YRES]
692 || cb > s->vram_size)
693 {
694 AssertMsgFailed(("XRES=%d YRES=%d cb=%d vram_size=%d\n",
695 s->vbe_regs[VBE_DISPI_INDEX_XRES], s->vbe_regs[VBE_DISPI_INDEX_YRES], cb, s->vram_size));
696 return VINF_SUCCESS; /* Note: silent failure like before */
697 }
698#else /* KEEP_SCAN_LINE_LENGTH defined */
699 if ( !s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH]
700 || !s->vbe_regs[VBE_DISPI_INDEX_YRES]
701 || cb > s->vram_size)
702 {
703 AssertMsgFailed(("VIRT WIDTH=%d YRES=%d cb=%d vram_size=%d\n",
704 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH], s->vbe_regs[VBE_DISPI_INDEX_YRES], cb, s->vram_size));
705 return VINF_SUCCESS; /* Note: silent failure like before */
706 }
707#endif /* KEEP_SCAN_LINE_LENGTH defined */
708#endif /* VBOX */
709
710#ifndef KEEP_SCAN_LINE_LENGTH
711 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
712 s->vbe_regs[VBE_DISPI_INDEX_XRES];
713 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
714 s->vbe_regs[VBE_DISPI_INDEX_YRES];
715 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
716 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
717
718 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
719 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
720 else
721 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
722 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
723 s->vbe_start_addr = 0;
724#endif /* KEEP_SCAN_LINE_LENGTH not defined */
725
726 /* clear the screen (should be done in BIOS) */
727 if (!(val & VBE_DISPI_NOCLEARMEM)) {
728#ifndef VBOX
729 memset(s->vram_ptr, 0,
730 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
731#else /* VBOX */
732 memset(CTXSUFF(s->vram_ptr), 0,
733 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
734#endif /* VBOX */
735 }
736
737 /* we initialize the VGA graphic mode (should be done
738 in BIOS) */
739 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
740 s->cr[0x17] |= 3; /* no CGA modes */
741 s->cr[0x13] = s->vbe_line_offset >> 3;
742 /* width */
743 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
744 /* height (only meaningful if < 1024) */
745 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
746 s->cr[0x12] = h;
747 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
748 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
749 /* line compare to 1023 */
750 s->cr[0x18] = 0xff;
751 s->cr[0x07] |= 0x10;
752 s->cr[0x09] |= 0x40;
753
754 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
755 shift_control = 0;
756 s->sr[0x01] &= ~8; /* no double line */
757 } else {
758 shift_control = 2;
759 s->sr[4] |= 0x08; /* set chain 4 mode */
760 s->sr[2] |= 0x0f; /* activate all planes */
761 }
762 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
763 s->cr[0x09] &= ~0x9f; /* no double scan */
764#ifdef VBOX
765 /* sunlover 30.05.2007
766 * The ar_index remains with bit 0x20 cleared after a switch from fullscreen
767 * DOS mode on Windows XP guest. That leads to GMODE_BLANK in vga_update_display.
768 * But the VBE mode is graphics, so not a blank anymore.
769 */
770 s->ar_index |= 0x20;
771#endif /* VBOX */
772 } else {
773 /* XXX: the bios should do that */
774#ifdef VBOX
775 /* sunlover 21.12.2006
776 * Here is probably more to reset. When this was executed in GC
777 * then the *update* functions could not detect a mode change.
778 * Or may be these update function should take the s->vbe_regs[s->vbe_index]
779 * into account when detecting a mode change.
780 *
781 * The 'mode reset not detected' problem is now fixed by executing the
782 * VBE_DISPI_INDEX_ENABLE case always in RING3 in order to call the
783 * LFBChange callback.
784 */
785#endif /* VBOX */
786 s->bank_offset = 0;
787 }
788 s->vbe_regs[s->vbe_index] = val;
789 /*
790 * LFB video mode is either disabled or changed. This notification
791 * is used by the display to disable VBVA.
792 */
793 s->pDrv->pfnLFBModeChange(s->pDrv, (val & VBE_DISPI_ENABLED) != 0);
794 break;
795#endif /* IN_RING3 */
796 case VBE_DISPI_INDEX_VIRT_WIDTH:
797 {
798 int w, h, line_offset;
799
800 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
801 return VINF_SUCCESS;
802 w = val;
803 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
804 line_offset = w >> 1;
805 else
806 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
807 h = s->vram_size / line_offset;
808 /* XXX: support weird bochs semantics ? */
809 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
810 return VINF_SUCCESS;
811 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
812 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
813 s->vbe_line_offset = line_offset;
814 }
815 break;
816 case VBE_DISPI_INDEX_X_OFFSET:
817 case VBE_DISPI_INDEX_Y_OFFSET:
818 {
819 int x;
820 s->vbe_regs[s->vbe_index] = val;
821 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
822 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
823 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
824 s->vbe_start_addr += x >> 1;
825 else
826 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
827 s->vbe_start_addr >>= 2;
828 }
829 break;
830 case VBE_DISPI_INDEX_VBOX_VIDEO:
831#ifdef VBOX
832#ifndef IN_RING3
833 return VINF_IOM_HC_IOPORT_WRITE;
834#else
835 /* Changes in the VGA device are minimal. The device is bypassed. The driver does all work. */
836 if (val == VBOX_VIDEO_DISABLE_ADAPTER_MEMORY)
837 {
838 s->pDrv->pfnProcessAdapterData(s->pDrv, NULL, 0);
839 }
840 else if (val == VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY)
841 {
842 s->pDrv->pfnProcessAdapterData(s->pDrv, s->CTXSUFF(vram_ptr), s->vram_size);
843 }
844 else if ((val & 0xFFFF0000) == VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE)
845 {
846 s->pDrv->pfnProcessDisplayData(s->pDrv, s->CTXSUFF(vram_ptr), val & 0xFFFF);
847 }
848#endif /* IN_RING3 */
849#endif /* VBOX */
850 break;
851 default:
852 break;
853 }
854 }
855 return VINF_SUCCESS;
856}
857#endif
858
859/* called for accesses between 0xa0000 and 0xc0000 */
860#ifdef VBOX
861static
862#endif /* VBOX */
863uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
864{
865 VGAState *s = (VGAState*)opaque;
866 int memory_map_mode, plane;
867 uint32_t ret;
868
869 /* convert to VGA memory offset */
870 memory_map_mode = (s->gr[6] >> 2) & 3;
871 addr &= 0x1ffff;
872 switch(memory_map_mode) {
873 case 0:
874 break;
875 case 1:
876 if (addr >= 0x10000)
877 return 0xff;
878 addr += s->bank_offset;
879 break;
880 case 2:
881 addr -= 0x10000;
882 if (addr >= 0x8000)
883 return 0xff;
884 break;
885 default:
886 case 3:
887 addr -= 0x18000;
888 if (addr >= 0x8000)
889 return 0xff;
890 break;
891 }
892
893#ifdef IN_GC
894 if (addr >= VGA_MAPPING_SIZE)
895 return VINF_IOM_HC_MMIO_WRITE;
896#endif
897
898 if (s->sr[4] & 0x08) {
899 /* chain 4 mode : simplest access */
900#ifndef VBOX
901 ret = s->vram_ptr[addr];
902#else /* VBOX */
903 ret = s->CTXSUFF(vram_ptr)[addr];
904#endif /* VBOX */
905 } else if (s->gr[5] & 0x10) {
906 /* odd/even mode (aka text mode mapping) */
907 plane = (s->gr[4] & 2) | (addr & 1);
908#ifndef VBOX
909 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
910#else /* VBOX */
911 /* See the comment for a similar line in vga_mem_writeb. */
912 ret = s->CTXSUFF(vram_ptr)[((addr & ~1) << 2) | plane];
913#endif /* VBOX */
914 } else {
915 /* standard VGA latched access */
916#ifndef VBOX
917 s->latch = ((uint32_t *)s->vram_ptr)[addr];
918#else /* VBOX && IN_GC */
919 s->latch = ((uint32_t *)s->CTXSUFF(vram_ptr))[addr];
920#endif /* VBOX && IN_GC */
921
922 if (!(s->gr[5] & 0x08)) {
923 /* read mode 0 */
924 plane = s->gr[4];
925 ret = GET_PLANE(s->latch, plane);
926 } else {
927 /* read mode 1 */
928 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
929 ret |= ret >> 16;
930 ret |= ret >> 8;
931 ret = (~ret) & 0xff;
932 }
933 }
934 return ret;
935}
936
937#ifndef VBOX
938static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
939{
940 uint32_t v;
941#ifdef TARGET_WORDS_BIGENDIAN
942 v = vga_mem_readb(opaque, addr) << 8;
943 v |= vga_mem_readb(opaque, addr + 1);
944#else
945 v = vga_mem_readb(opaque, addr);
946 v |= vga_mem_readb(opaque, addr + 1) << 8;
947#endif
948 return v;
949}
950
951static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
952{
953 uint32_t v;
954#ifdef TARGET_WORDS_BIGENDIAN
955 v = vga_mem_readb(opaque, addr) << 24;
956 v |= vga_mem_readb(opaque, addr + 1) << 16;
957 v |= vga_mem_readb(opaque, addr + 2) << 8;
958 v |= vga_mem_readb(opaque, addr + 3);
959#else
960 v = vga_mem_readb(opaque, addr);
961 v |= vga_mem_readb(opaque, addr + 1) << 8;
962 v |= vga_mem_readb(opaque, addr + 2) << 16;
963 v |= vga_mem_readb(opaque, addr + 3) << 24;
964#endif
965 return v;
966}
967#endif /* !VBOX */
968
969/* called for accesses between 0xa0000 and 0xc0000 */
970#ifdef VBOX
971static
972#endif /* VBOX */
973int vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
974{
975 VGAState *s = (VGAState*)opaque;
976 int memory_map_mode, plane, write_mode, b, func_select, mask;
977 uint32_t write_mask, bit_mask, set_mask;
978
979#ifdef DEBUG_VGA_MEM
980 Log(("vga: [0x%x] = 0x%02x\n", addr, val));
981#endif
982 /* convert to VGA memory offset */
983 memory_map_mode = (s->gr[6] >> 2) & 3;
984 addr &= 0x1ffff;
985 switch(memory_map_mode) {
986 case 0:
987 break;
988 case 1:
989 if (addr >= 0x10000)
990 return VINF_SUCCESS;
991 addr += s->bank_offset;
992 break;
993 case 2:
994 addr -= 0x10000;
995 if (addr >= 0x8000)
996 return VINF_SUCCESS;
997 break;
998 default:
999 case 3:
1000 addr -= 0x18000;
1001 if (addr >= 0x8000)
1002 return VINF_SUCCESS;
1003 break;
1004 }
1005
1006 if (s->sr[4] & 0x08) {
1007 /* chain 4 mode : simplest access */
1008 plane = addr & 3;
1009 mask = (1 << plane);
1010 if (s->sr[2] & mask) {
1011#ifndef VBOX
1012 s->vram_ptr[addr] = val;
1013#else /* VBOX */
1014#ifdef IN_GC
1015 if (addr >= VGA_MAPPING_SIZE)
1016 return VINF_IOM_HC_MMIO_WRITE;
1017#else
1018 if (addr >= s->vram_size)
1019 {
1020 AssertMsgFailed(("addr=%VGp - this needs to be done in HC! bank_offset=%08x memory_map_mode=%d\n",
1021 addr, s->bank_offset, memory_map_mode));
1022 return VINF_SUCCESS;
1023 }
1024#endif
1025 s->CTXSUFF(vram_ptr)[addr] = val;
1026#endif /* VBOX */
1027#ifdef DEBUG_VGA_MEM
1028 Log(("vga: chain4: [0x%x]\n", addr));
1029#endif
1030 s->plane_updated |= mask; /* only used to detect font change */
1031#ifndef VBOX
1032 cpu_physical_memory_set_dirty(s->vram_offset + addr);
1033#else /* VBOX */
1034 vga_set_dirty(s, addr);
1035#endif /* VBOX */
1036 }
1037 } else if (s->gr[5] & 0x10) {
1038 /* odd/even mode (aka text mode mapping) */
1039 plane = (s->gr[4] & 2) | (addr & 1);
1040 mask = (1 << plane);
1041 if (s->sr[2] & mask) {
1042#ifndef VBOX
1043 addr = ((addr & ~1) << 1) | plane;
1044#else
1045 /* 'addr' is offset in a plane, bit 0 selects the plane.
1046 * Mask the bit 0, convert plane index to vram offset,
1047 * that is multiply by the number of planes,
1048 * and select the plane byte in the vram offset.
1049 */
1050 addr = ((addr & ~1) << 2) | plane;
1051#endif /* VBOX */
1052#ifndef VBOX
1053 s->vram_ptr[addr] = val;
1054#else /* VBOX */
1055#ifdef IN_GC
1056 if (addr >= VGA_MAPPING_SIZE)
1057 return VINF_IOM_HC_MMIO_WRITE;
1058#else
1059 if (addr >= s->vram_size)
1060 {
1061 AssertMsgFailed(("addr=%VGp - this needs to be done in HC! bank_offset=%08x memory_map_mode=%d\n",
1062 addr, s->bank_offset, memory_map_mode));
1063 return VINF_SUCCESS;
1064 }
1065#endif
1066 s->CTXSUFF(vram_ptr)[addr] = val;
1067#endif /* VBOX */
1068#ifdef DEBUG_VGA_MEM
1069 Log(("vga: odd/even: [0x%x]\n", addr));
1070#endif
1071 s->plane_updated |= mask; /* only used to detect font change */
1072#ifndef VBOX
1073 cpu_physical_memory_set_dirty(s->vram_offset + addr);
1074#else /* VBOX */
1075 vga_set_dirty(s, addr);
1076#endif /* VBOX */
1077 }
1078 } else {
1079#ifdef IN_GC
1080 if (addr * 4 >= VGA_MAPPING_SIZE)
1081 return VINF_IOM_HC_MMIO_WRITE;
1082#else
1083 if (addr * 4 >= s->vram_size)
1084 {
1085 AssertMsgFailed(("addr=%VGp - this needs to be done in HC! bank_offset=%08x memory_map_mode=%d\n",
1086 addr * 4, s->bank_offset, memory_map_mode));
1087 return VINF_SUCCESS;
1088 }
1089#endif
1090
1091 /* standard VGA latched access */
1092 write_mode = s->gr[5] & 3;
1093 switch(write_mode) {
1094 default:
1095 case 0:
1096 /* rotate */
1097 b = s->gr[3] & 7;
1098 val = ((val >> b) | (val << (8 - b))) & 0xff;
1099 val |= val << 8;
1100 val |= val << 16;
1101
1102 /* apply set/reset mask */
1103 set_mask = mask16[s->gr[1]];
1104 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
1105 bit_mask = s->gr[8];
1106 break;
1107 case 1:
1108 val = s->latch;
1109 goto do_write;
1110 case 2:
1111 val = mask16[val & 0x0f];
1112 bit_mask = s->gr[8];
1113 break;
1114 case 3:
1115 /* rotate */
1116 b = s->gr[3] & 7;
1117 val = (val >> b) | (val << (8 - b));
1118
1119 bit_mask = s->gr[8] & val;
1120 val = mask16[s->gr[0]];
1121 break;
1122 }
1123
1124 /* apply logical operation */
1125 func_select = s->gr[3] >> 3;
1126 switch(func_select) {
1127 case 0:
1128 default:
1129 /* nothing to do */
1130 break;
1131 case 1:
1132 /* and */
1133 val &= s->latch;
1134 break;
1135 case 2:
1136 /* or */
1137 val |= s->latch;
1138 break;
1139 case 3:
1140 /* xor */
1141 val ^= s->latch;
1142 break;
1143 }
1144
1145 /* apply bit mask */
1146 bit_mask |= bit_mask << 8;
1147 bit_mask |= bit_mask << 16;
1148 val = (val & bit_mask) | (s->latch & ~bit_mask);
1149
1150 do_write:
1151 /* mask data according to sr[2] */
1152 mask = s->sr[2];
1153 s->plane_updated |= mask; /* only used to detect font change */
1154 write_mask = mask16[mask];
1155#ifndef VBOX
1156 ((uint32_t *)s->vram_ptr)[addr] =
1157 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
1158 (val & write_mask);
1159#else /* VBOX */
1160 ((uint32_t *)s->CTXSUFF(vram_ptr))[addr] =
1161 (((uint32_t *)s->CTXSUFF(vram_ptr))[addr] & ~write_mask) |
1162 (val & write_mask);
1163#endif /* VBOX */
1164#ifdef DEBUG_VGA_MEM
1165 Log(("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
1166 addr * 4, write_mask, val));
1167#endif
1168#ifndef VBOX
1169 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
1170#else /* VBOX */
1171 vga_set_dirty(s, (addr << 2));
1172#endif /* VBOX */
1173 }
1174
1175 return VINF_SUCCESS;
1176}
1177
1178#ifndef VBOX
1179static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
1180{
1181#ifdef TARGET_WORDS_BIGENDIAN
1182 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
1183 vga_mem_writeb(opaque, addr + 1, val & 0xff);
1184#else
1185 vga_mem_writeb(opaque, addr, val & 0xff);
1186 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
1187#endif
1188}
1189
1190static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
1191{
1192#ifdef TARGET_WORDS_BIGENDIAN
1193 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
1194 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
1195 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
1196 vga_mem_writeb(opaque, addr + 3, val & 0xff);
1197#else
1198 vga_mem_writeb(opaque, addr, val & 0xff);
1199 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
1200 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
1201 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
1202#endif
1203}
1204#endif /* !VBOX */
1205
1206#if !defined(VBOX) || defined(IN_RING3)
1207typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
1208 const uint8_t *font_ptr, int h,
1209 uint32_t fgcol, uint32_t bgcol);
1210typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
1211 const uint8_t *font_ptr, int h,
1212 uint32_t fgcol, uint32_t bgcol, int dup9);
1213typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
1214 const uint8_t *s, int width);
1215
1216static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
1217{
1218 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
1219}
1220
1221static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
1222{
1223 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
1224}
1225
1226static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
1227{
1228 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1229}
1230
1231static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
1232{
1233 return (r << 16) | (g << 8) | b;
1234}
1235
1236#define DEPTH 8
1237#include "DevVGATmpl.h"
1238
1239#define DEPTH 15
1240#include "DevVGATmpl.h"
1241
1242#define DEPTH 16
1243#include "DevVGATmpl.h"
1244
1245#define DEPTH 32
1246#include "DevVGATmpl.h"
1247
1248static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
1249{
1250 unsigned int col;
1251 col = rgb_to_pixel8(r, g, b);
1252 col |= col << 8;
1253 col |= col << 16;
1254 return col;
1255}
1256
1257static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
1258{
1259 unsigned int col;
1260 col = rgb_to_pixel15(r, g, b);
1261 col |= col << 16;
1262 return col;
1263}
1264
1265static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1266{
1267 unsigned int col;
1268 col = rgb_to_pixel16(r, g, b);
1269 col |= col << 16;
1270 return col;
1271}
1272
1273static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1274{
1275 unsigned int col;
1276 col = rgb_to_pixel32(r, g, b);
1277 return col;
1278}
1279
1280/* return true if the palette was modified */
1281static int update_palette16(VGAState *s)
1282{
1283 int full_update, i;
1284 uint32_t v, col, *palette;
1285
1286 full_update = 0;
1287 palette = s->last_palette;
1288 for(i = 0; i < 16; i++) {
1289 v = s->ar[i];
1290 if (s->ar[0x10] & 0x80)
1291 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1292 else
1293 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1294 v = v * 3;
1295 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1296 c6_to_8(s->palette[v + 1]),
1297 c6_to_8(s->palette[v + 2]));
1298 if (col != palette[i]) {
1299 full_update = 1;
1300 palette[i] = col;
1301 }
1302 }
1303 return full_update;
1304}
1305
1306/* return true if the palette was modified */
1307static int update_palette256(VGAState *s)
1308{
1309 int full_update, i;
1310 uint32_t v, col, *palette;
1311 int wide_dac;
1312
1313 full_update = 0;
1314 palette = s->last_palette;
1315 v = 0;
1316 wide_dac = (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & (VBE_DISPI_ENABLED | VBE_DISPI_8BIT_DAC))
1317 == (VBE_DISPI_ENABLED | VBE_DISPI_8BIT_DAC);
1318 for(i = 0; i < 256; i++) {
1319 if (wide_dac)
1320 col = s->rgb_to_pixel(s->palette[v],
1321 s->palette[v + 1],
1322 s->palette[v + 2]);
1323 else
1324 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1325 c6_to_8(s->palette[v + 1]),
1326 c6_to_8(s->palette[v + 2]));
1327 if (col != palette[i]) {
1328 full_update = 1;
1329 palette[i] = col;
1330 }
1331 v += 3;
1332 }
1333 return full_update;
1334}
1335
1336static void vga_get_offsets(VGAState *s,
1337 uint32_t *pline_offset,
1338 uint32_t *pstart_addr,
1339 uint32_t *pline_compare)
1340{
1341 uint32_t start_addr, line_offset, line_compare;
1342#ifdef CONFIG_BOCHS_VBE
1343 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1344 line_offset = s->vbe_line_offset;
1345 start_addr = s->vbe_start_addr;
1346 line_compare = 65535;
1347 } else
1348#endif
1349 {
1350 /* compute line_offset in bytes */
1351 line_offset = s->cr[0x13];
1352 line_offset <<= 3;
1353#ifdef VBOX
1354 if (!(s->cr[0x14] & 0x40) && !(s->cr[0x17] & 0x40))
1355 {
1356 /* Word mode. Used for odd/even modes. */
1357 line_offset *= 2;
1358 }
1359#endif /* VBOX */
1360
1361 /* starting address */
1362 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1363
1364 /* line compare */
1365 line_compare = s->cr[0x18] |
1366 ((s->cr[0x07] & 0x10) << 4) |
1367 ((s->cr[0x09] & 0x40) << 3);
1368 }
1369 *pline_offset = line_offset;
1370 *pstart_addr = start_addr;
1371 *pline_compare = line_compare;
1372}
1373
1374/* update start_addr and line_offset. Return TRUE if modified */
1375static int update_basic_params(VGAState *s)
1376{
1377 int full_update;
1378 uint32_t start_addr, line_offset, line_compare;
1379
1380 full_update = 0;
1381
1382 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1383
1384 if (line_offset != s->line_offset ||
1385 start_addr != s->start_addr ||
1386 line_compare != s->line_compare) {
1387 s->line_offset = line_offset;
1388 s->start_addr = start_addr;
1389 s->line_compare = line_compare;
1390 full_update = 1;
1391 }
1392 return full_update;
1393}
1394
1395static inline int get_depth_index(int depth)
1396{
1397 switch(depth) {
1398 default:
1399 case 8:
1400 return 0;
1401 case 15:
1402 return 1;
1403 case 16:
1404 return 2;
1405 case 32:
1406 return 3;
1407 }
1408}
1409
1410static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1411 vga_draw_glyph8_8,
1412 vga_draw_glyph8_16,
1413 vga_draw_glyph8_16,
1414 vga_draw_glyph8_32,
1415};
1416
1417static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1418 vga_draw_glyph16_8,
1419 vga_draw_glyph16_16,
1420 vga_draw_glyph16_16,
1421 vga_draw_glyph16_32,
1422};
1423
1424static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1425 vga_draw_glyph9_8,
1426 vga_draw_glyph9_16,
1427 vga_draw_glyph9_16,
1428 vga_draw_glyph9_32,
1429};
1430
1431static const uint8_t cursor_glyph[32 * 4] = {
1432 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1433 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1434 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1435 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1436 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1437 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1438 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1439 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1440 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1441 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1442 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1443 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1444 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1445 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1446 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1447 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1448};
1449
1450/*
1451 * Text mode update
1452 * Missing:
1453 * - double scan
1454 * - double width
1455 * - underline
1456 * - flashing
1457 */
1458#ifndef VBOX
1459static void vga_draw_text(VGAState *s, int full_update)
1460#else
1461static int vga_draw_text(VGAState *s, int full_update)
1462#endif /* !VBOX */
1463{
1464 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1465 int cx_min, cx_max, linesize, x_incr;
1466 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1467 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1468 const uint8_t *font_ptr, *font_base[2];
1469 int dup9, line_offset, depth_index;
1470 uint32_t *palette;
1471 uint32_t *ch_attr_ptr;
1472 vga_draw_glyph8_func *vga_draw_glyph8;
1473 vga_draw_glyph9_func *vga_draw_glyph9;
1474
1475 full_update |= update_palette16(s);
1476 palette = s->last_palette;
1477
1478 /* compute font data address (in plane 2) */
1479 v = s->sr[3];
1480 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1481 if (offset != s->font_offsets[0]) {
1482 s->font_offsets[0] = offset;
1483 full_update = 1;
1484 }
1485#ifndef VBOX
1486 font_base[0] = s->vram_ptr + offset;
1487#else /* VBOX */
1488 font_base[0] = s->CTXSUFF(vram_ptr) + offset;
1489#endif /* VBOX */
1490
1491 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1492#ifndef VBOX
1493 font_base[1] = s->vram_ptr + offset;
1494#else /* VBOX */
1495 font_base[1] = s->CTXSUFF(vram_ptr) + offset;
1496#endif /* VBOX */
1497 if (offset != s->font_offsets[1]) {
1498 s->font_offsets[1] = offset;
1499 full_update = 1;
1500 }
1501 if (s->plane_updated & (1 << 2)) {
1502 /* if the plane 2 was modified since the last display, it
1503 indicates the font may have been modified */
1504 s->plane_updated = 0;
1505 full_update = 1;
1506 }
1507 full_update |= update_basic_params(s);
1508
1509 line_offset = s->line_offset;
1510#ifndef VBOX
1511 s1 = s->vram_ptr + (s->start_addr * 4);
1512#else /* VBOX */
1513 s1 = s->CTXSUFF(vram_ptr) + (s->start_addr * 8);
1514#endif /* VBOX */
1515
1516 /* total width & height */
1517 cheight = (s->cr[9] & 0x1f) + 1;
1518 cw = 8;
1519 if (!(s->sr[1] & 0x01))
1520 cw = 9;
1521 if (s->sr[1] & 0x08)
1522 cw = 16; /* NOTE: no 18 pixel wide */
1523#ifndef VBOX
1524 x_incr = cw * ((s->ds->depth + 7) >> 3);
1525#else /* VBOX */
1526 x_incr = cw * ((s->pDrv->cBits + 7) >> 3);
1527#endif /* VBOX */
1528 width = (s->cr[0x01] + 1);
1529 if (s->cr[0x06] == 100) {
1530 /* ugly hack for CGA 160x100x16 - explain me the logic */
1531 height = 100;
1532 } else {
1533 height = s->cr[0x12] |
1534 ((s->cr[0x07] & 0x02) << 7) |
1535 ((s->cr[0x07] & 0x40) << 3);
1536 height = (height + 1) / cheight;
1537 }
1538 if ((height * width) > CH_ATTR_SIZE) {
1539 /* better than nothing: exit if transient size is too big */
1540#ifndef VBOX
1541 return;
1542#else
1543 return VINF_SUCCESS;
1544#endif /* VBOX */
1545 }
1546
1547 if (width != (int)s->last_width || height != (int)s->last_height ||
1548 cw != s->last_cw || cheight != s->last_ch) {
1549 s->last_scr_width = width * cw;
1550 s->last_scr_height = height * cheight;
1551#ifndef VBOX
1552 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1553 s->last_width = width;
1554 s->last_height = height;
1555 s->last_ch = cheight;
1556 s->last_cw = cw;
1557 full_update = 1;
1558#else /* VBOX */
1559 /* For text modes the direct use of guest VRAM is not implemented, so bpp and cbLine are 0 here. */
1560 int rc = s->pDrv->pfnResize(s->pDrv, 0, NULL, 0, s->last_scr_width, s->last_scr_height);
1561 s->last_width = width;
1562 s->last_height = height;
1563 s->last_ch = cheight;
1564 s->last_cw = cw;
1565 full_update = 1;
1566 if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
1567 return rc;
1568 AssertRC(rc);
1569#endif /* VBOX */
1570 }
1571 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1572 if (cursor_offset != s->cursor_offset ||
1573 s->cr[0xa] != s->cursor_start ||
1574 s->cr[0xb] != s->cursor_end) {
1575 /* if the cursor position changed, we update the old and new
1576 chars */
1577 if (s->cursor_offset < CH_ATTR_SIZE)
1578 s->last_ch_attr[s->cursor_offset] = ~0;
1579 if (cursor_offset < CH_ATTR_SIZE)
1580 s->last_ch_attr[cursor_offset] = ~0;
1581 s->cursor_offset = cursor_offset;
1582 s->cursor_start = s->cr[0xa];
1583 s->cursor_end = s->cr[0xb];
1584 }
1585#ifndef VBOX
1586 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1587
1588 depth_index = get_depth_index(s->ds->depth);
1589#else /* VBOX */
1590 cursor_ptr = s->CTXSUFF(vram_ptr) + (s->start_addr + cursor_offset) * 8;
1591 depth_index = get_depth_index(s->pDrv->cBits);
1592#endif /* VBOX */
1593 if (cw == 16)
1594 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1595 else
1596 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1597 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1598
1599#ifndef VBOX
1600 dest = s->ds->data;
1601 linesize = s->ds->linesize;
1602#else /* VBOX */
1603 dest = s->pDrv->pu8Data;
1604 linesize = s->pDrv->cbScanline;
1605#endif /* VBOX */
1606 ch_attr_ptr = s->last_ch_attr;
1607
1608 for(cy = 0; cy < height; cy++) {
1609 d1 = dest;
1610 src = s1;
1611 cx_min = width;
1612 cx_max = -1;
1613 for(cx = 0; cx < width; cx++) {
1614 ch_attr = *(uint16_t *)src;
1615 if (full_update || ch_attr != (int)*ch_attr_ptr) {
1616 if (cx < cx_min)
1617 cx_min = cx;
1618 if (cx > cx_max)
1619 cx_max = cx;
1620 *ch_attr_ptr = ch_attr;
1621#ifdef WORDS_BIGENDIAN
1622 ch = ch_attr >> 8;
1623 cattr = ch_attr & 0xff;
1624#else
1625 ch = ch_attr & 0xff;
1626 cattr = ch_attr >> 8;
1627#endif
1628 font_ptr = font_base[(cattr >> 3) & 1];
1629 font_ptr += 32 * 4 * ch;
1630 bgcol = palette[cattr >> 4];
1631 fgcol = palette[cattr & 0x0f];
1632 if (cw != 9) {
1633 vga_draw_glyph8(d1, linesize,
1634 font_ptr, cheight, fgcol, bgcol);
1635 } else {
1636 dup9 = 0;
1637 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1638 dup9 = 1;
1639 vga_draw_glyph9(d1, linesize,
1640 font_ptr, cheight, fgcol, bgcol, dup9);
1641 }
1642 if (src == cursor_ptr &&
1643 !(s->cr[0x0a] & 0x20)) {
1644 int line_start, line_last, h;
1645 /* draw the cursor */
1646 line_start = s->cr[0x0a] & 0x1f;
1647 line_last = s->cr[0x0b] & 0x1f;
1648 /* XXX: check that */
1649 if (line_last > cheight - 1)
1650 line_last = cheight - 1;
1651 if (line_last >= line_start && line_start < cheight) {
1652 h = line_last - line_start + 1;
1653 d = d1 + linesize * line_start;
1654 if (cw != 9) {
1655 vga_draw_glyph8(d, linesize,
1656 cursor_glyph, h, fgcol, bgcol);
1657 } else {
1658 vga_draw_glyph9(d, linesize,
1659 cursor_glyph, h, fgcol, bgcol, 1);
1660 }
1661 }
1662 }
1663 }
1664 d1 += x_incr;
1665#ifndef VBOX
1666 src += 4;
1667#else
1668 src += 8; /* Every second byte of a plane is used in text mode. */
1669#endif
1670
1671 ch_attr_ptr++;
1672 }
1673#ifndef VBOX
1674 if (cx_max != -1) {
1675 dpy_update(s->ds, cx_min * cw, cy * cheight,
1676 (cx_max - cx_min + 1) * cw, cheight);
1677 }
1678#else
1679 if (cx_max != -1)
1680 s->pDrv->pfnUpdateRect(s->pDrv, cx_min * cw, cy * cheight, (cx_max - cx_min + 1) * cw, cheight);
1681#endif
1682 dest += linesize * cheight;
1683 s1 += line_offset;
1684 }
1685#ifdef VBOX
1686 return VINF_SUCCESS;
1687#endif /* VBOX */
1688}
1689
1690enum {
1691 VGA_DRAW_LINE2,
1692 VGA_DRAW_LINE2D2,
1693 VGA_DRAW_LINE4,
1694 VGA_DRAW_LINE4D2,
1695 VGA_DRAW_LINE8D2,
1696 VGA_DRAW_LINE8,
1697 VGA_DRAW_LINE15,
1698 VGA_DRAW_LINE16,
1699 VGA_DRAW_LINE24,
1700 VGA_DRAW_LINE32,
1701 VGA_DRAW_LINE_NB
1702};
1703
1704static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1705 vga_draw_line2_8,
1706 vga_draw_line2_16,
1707 vga_draw_line2_16,
1708 vga_draw_line2_32,
1709
1710 vga_draw_line2d2_8,
1711 vga_draw_line2d2_16,
1712 vga_draw_line2d2_16,
1713 vga_draw_line2d2_32,
1714
1715 vga_draw_line4_8,
1716 vga_draw_line4_16,
1717 vga_draw_line4_16,
1718 vga_draw_line4_32,
1719
1720 vga_draw_line4d2_8,
1721 vga_draw_line4d2_16,
1722 vga_draw_line4d2_16,
1723 vga_draw_line4d2_32,
1724
1725 vga_draw_line8d2_8,
1726 vga_draw_line8d2_16,
1727 vga_draw_line8d2_16,
1728 vga_draw_line8d2_32,
1729
1730 vga_draw_line8_8,
1731 vga_draw_line8_16,
1732 vga_draw_line8_16,
1733 vga_draw_line8_32,
1734
1735 vga_draw_line15_8,
1736 vga_draw_line15_15,
1737 vga_draw_line15_16,
1738 vga_draw_line15_32,
1739
1740 vga_draw_line16_8,
1741 vga_draw_line16_15,
1742 vga_draw_line16_16,
1743 vga_draw_line16_32,
1744
1745 vga_draw_line24_8,
1746 vga_draw_line24_15,
1747 vga_draw_line24_16,
1748 vga_draw_line24_32,
1749
1750 vga_draw_line32_8,
1751 vga_draw_line32_15,
1752 vga_draw_line32_16,
1753 vga_draw_line32_32,
1754};
1755
1756static int vga_get_bpp(VGAState *s)
1757{
1758 int ret;
1759#ifdef CONFIG_BOCHS_VBE
1760 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1761 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1762 } else
1763#endif
1764 {
1765 ret = 0;
1766 }
1767 return ret;
1768}
1769
1770static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1771{
1772 int width, height;
1773#ifdef CONFIG_BOCHS_VBE
1774 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1775 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1776 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1777 } else
1778#endif
1779 {
1780 width = (s->cr[0x01] + 1) * 8;
1781 height = s->cr[0x12] |
1782 ((s->cr[0x07] & 0x02) << 7) |
1783 ((s->cr[0x07] & 0x40) << 3);
1784 height = (height + 1);
1785 }
1786 *pwidth = width;
1787 *pheight = height;
1788}
1789
1790#ifndef VBOX
1791void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1792{
1793 int y;
1794 if (y1 >= VGA_MAX_HEIGHT)
1795 return;
1796 if (y2 >= VGA_MAX_HEIGHT)
1797 y2 = VGA_MAX_HEIGHT;
1798 for(y = y1; y < y2; y++) {
1799 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1800 }
1801}
1802#endif /* !VBOX*/
1803
1804#ifdef VBOX
1805/**
1806 * Performs the display driver resizing when in graphics mode.
1807 *
1808 * This will recalc / update any status data depending on the driver
1809 * properties (bit depth mostly).
1810 *
1811 * @returns VINF_SUCCESS on success.
1812 * @returns VINF_VGA_RESIZE_IN_PROGRESS if the operation wasn't complete.
1813 * @param s Pointer to the vga status.
1814 * @param cx The width.
1815 * @param cy The height.
1816 */
1817static int vga_resize_graphic(VGAState *s, int cx, int cy, int v)
1818{
1819 const unsigned cBits = s->get_bpp(s);
1820 /** @todo r=sunlover: If the guest changes VBE_DISPI_INDEX_X_OFFSET, VBE_DISPI_INDEX_Y_OFFSET
1821 * registers, then the third parameter of the following call should be
1822 * probably 's->CTXSUFF(vram_ptr) + s->vbe_start_addr'.
1823 */
1824 int rc = s->pDrv->pfnResize(s->pDrv, cBits, s->CTXSUFF(vram_ptr), s->line_offset, cx, cy);
1825
1826 /* last stuff */
1827 s->last_bpp = cBits;
1828 s->last_scr_width = cx;
1829 s->last_scr_height = cy;
1830 s->last_width = cx;
1831 s->last_height = cy;
1832
1833 if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
1834 return rc;
1835 AssertRC(rc);
1836
1837 /* update palette */
1838 switch (s->pDrv->cBits)
1839 {
1840 case 32: s->rgb_to_pixel = rgb_to_pixel32_dup; break;
1841 case 16:
1842 default: s->rgb_to_pixel = rgb_to_pixel16_dup; break;
1843 case 15: s->rgb_to_pixel = rgb_to_pixel15_dup; break;
1844 case 8: s->rgb_to_pixel = rgb_to_pixel8_dup; break;
1845 }
1846 if (s->shift_control == 0)
1847 update_palette16(s);
1848 else if (s->shift_control == 1)
1849 update_palette16(s);
1850 return VINF_SUCCESS;
1851}
1852#endif /* VBOX */
1853
1854/*
1855 * graphic modes
1856 */
1857#ifndef VBOX
1858static void vga_draw_graphic(VGAState *s, int full_update)
1859#else
1860static int vga_draw_graphic(VGAState *s, int full_update)
1861#endif /* !VBOX */
1862{
1863 int y1, y2, y, update, page_min, page_max, linesize, y_start, double_scan;
1864 int width, height, shift_control, line_offset, page0, page1, bwidth;
1865 int disp_width, multi_run;
1866 uint8_t *d;
1867 uint32_t v, addr1, addr;
1868 vga_draw_line_func *vga_draw_line;
1869 bool offsets_changed;
1870
1871 offsets_changed = update_basic_params(s);
1872
1873 full_update |= offsets_changed;
1874
1875 s->get_resolution(s, &width, &height);
1876 disp_width = width;
1877
1878 shift_control = (s->gr[0x05] >> 5) & 3;
1879 double_scan = (s->cr[0x09] >> 7);
1880 multi_run = double_scan;
1881 if (shift_control != s->shift_control ||
1882 double_scan != s->double_scan) {
1883 full_update = 1;
1884 s->shift_control = shift_control;
1885 s->double_scan = double_scan;
1886 }
1887
1888 if (shift_control == 0) {
1889 full_update |= update_palette16(s);
1890 if (s->sr[0x01] & 8) {
1891 v = VGA_DRAW_LINE4D2;
1892 disp_width <<= 1;
1893 } else {
1894 v = VGA_DRAW_LINE4;
1895 }
1896 } else if (shift_control == 1) {
1897 full_update |= update_palette16(s);
1898 if (s->sr[0x01] & 8) {
1899 v = VGA_DRAW_LINE2D2;
1900 disp_width <<= 1;
1901 } else {
1902 v = VGA_DRAW_LINE2;
1903 }
1904 } else {
1905 switch(s->get_bpp(s)) {
1906 default:
1907 case 0:
1908 full_update |= update_palette256(s);
1909 v = VGA_DRAW_LINE8D2;
1910 break;
1911 case 8:
1912 full_update |= update_palette256(s);
1913 v = VGA_DRAW_LINE8;
1914 break;
1915 case 15:
1916 v = VGA_DRAW_LINE15;
1917 break;
1918 case 16:
1919 v = VGA_DRAW_LINE16;
1920 break;
1921 case 24:
1922 v = VGA_DRAW_LINE24;
1923 break;
1924 case 32:
1925 v = VGA_DRAW_LINE32;
1926 break;
1927 }
1928 }
1929#ifndef VBOX
1930 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1931
1932 if (disp_width != s->last_width ||
1933 height != s->last_height) {
1934 dpy_resize(s->ds, disp_width, height);
1935 s->last_scr_width = disp_width;
1936 s->last_scr_height = height;
1937 s->last_width = disp_width;
1938 s->last_height = height;
1939 full_update = 1;
1940 }
1941#else /* VBOX */
1942 if ( disp_width != (int)s->last_width
1943 || height != (int)s->last_height
1944 || s->get_bpp(s) != (int)s->last_bpp
1945 || offsets_changed)
1946 {
1947 int rc = vga_resize_graphic(s, disp_width, height, v);
1948 if (rc != VINF_SUCCESS) /* Return any rc, particularly VINF_VGA_RESIZE_IN_PROGRESS, to the caller. */
1949 return rc;
1950 full_update = 1;
1951 }
1952 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->pDrv->cBits)];
1953
1954#endif /* VBOX */
1955 if (s->cursor_invalidate)
1956 s->cursor_invalidate(s);
1957
1958 line_offset = s->line_offset;
1959#if 0
1960 Log(("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
1961 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]));
1962#endif
1963 addr1 = (s->start_addr * 4);
1964#ifndef VBOX
1965 bwidth = width * 4;
1966#else /* VBOX */
1967 /* The width of VRAM scanline. */
1968 bwidth = s->line_offset;
1969 /* In some cases the variable is not yet set, probably due to incomplete
1970 * programming of the virtual hardware ports. Just return.
1971 */
1972 if (bwidth == 0) return VINF_SUCCESS;
1973#endif /* VBOX */
1974 y_start = -1;
1975 page_min = 0x7fffffff;
1976 page_max = -1;
1977#ifndef VBOX
1978 d = s->ds->data;
1979 linesize = s->ds->linesize;
1980#else /* VBOX */
1981 d = s->pDrv->pu8Data;
1982 linesize = s->pDrv->cbScanline;
1983#endif /* VBOX */
1984
1985 y1 = 0;
1986 y2 = s->cr[0x09] & 0x1F; /* starting row scan count */
1987 for(y = 0; y < height; y++) {
1988 addr = addr1;
1989 /* CGA/MDA compatibility. Note that these addresses are all
1990 * shifted left by two compared to VGA specs.
1991 */
1992 if (!(s->cr[0x17] & 1)) {
1993 addr = (addr & ~(1 << 15)) | ((y1 & 1) << 15);
1994 }
1995 if (!(s->cr[0x17] & 2)) {
1996 addr = (addr & ~(1 << 16)) | ((y1 & 2) << 15);
1997 }
1998#ifndef VBOX
1999 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
2000 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
2001 update = full_update |
2002 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
2003 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
2004 if ((page1 - page0) > TARGET_PAGE_SIZE) {
2005 /* if wide line, can use another page */
2006 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
2007 VGA_DIRTY_FLAG);
2008 }
2009#else /* VBOX */
2010 page0 = addr & TARGET_PAGE_MASK;
2011 page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
2012 update = full_update | vga_is_dirty(s, page0) | vga_is_dirty(s, page1);
2013 if (page1 - page0 > TARGET_PAGE_SIZE) {
2014 /* if wide line, can use another page */
2015 update |= vga_is_dirty(s, page0 + TARGET_PAGE_SIZE);
2016 }
2017#endif /* VBOX */
2018 /* explicit invalidation for the hardware cursor */
2019 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
2020 if (update) {
2021 if (y_start < 0)
2022 y_start = y;
2023 if (page0 < page_min)
2024 page_min = page0;
2025 if (page1 > page_max)
2026 page_max = page1;
2027#ifndef VBOX
2028 vga_draw_line(s, d, s->vram_ptr + addr, width);
2029#else /* VBOX */
2030 if (s->fRenderVRAM)
2031 vga_draw_line(s, d, s->CTXSUFF(vram_ptr) + addr, width);
2032#endif /* VBOX */
2033 if (s->cursor_draw_line)
2034 s->cursor_draw_line(s, d, y);
2035 } else {
2036 if (y_start >= 0) {
2037 /* flush to display */
2038#ifndef VBOX
2039 dpy_update(s->ds, 0, y_start,
2040 disp_width, y - y_start);
2041#else /* VBOX */
2042 s->pDrv->pfnUpdateRect(s->pDrv, 0, y_start, disp_width, y - y_start);
2043#endif /* VBOX */
2044 y_start = -1;
2045 }
2046 }
2047 if (!multi_run) {
2048 y1++;
2049 multi_run = double_scan;
2050
2051 if (y2 == 0) {
2052 y2 = s->cr[0x09] & 0x1F;
2053 addr1 += line_offset;
2054 } else {
2055 --y2;
2056 }
2057 } else {
2058 multi_run--;
2059 }
2060 /* line compare acts on the displayed lines */
2061 if ((uint32_t)y == s->line_compare)
2062 addr1 = 0;
2063 d += linesize;
2064 }
2065 if (y_start >= 0) {
2066 /* flush to display */
2067#ifndef VBOX
2068 dpy_update(s->ds, 0, y_start,
2069 disp_width, y - y_start);
2070#else /* VBOX */
2071 s->pDrv->pfnUpdateRect(s->pDrv, 0, y_start, disp_width, y - y_start);
2072#endif /* VBOX */
2073 }
2074 /* reset modified pages */
2075 if (page_max != -1) {
2076#ifndef VBOX
2077 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
2078 VGA_DIRTY_FLAG);
2079#else /* VBOX */
2080 vga_reset_dirty(s, page_min, page_max + TARGET_PAGE_SIZE);
2081#endif /* VBOX */
2082 }
2083 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
2084#ifdef VBOX
2085 return VINF_SUCCESS;
2086#endif /* VBOX */
2087}
2088
2089static void vga_draw_blank(VGAState *s, int full_update)
2090{
2091#ifndef VBOX
2092 int i, w, val;
2093 uint8_t *d;
2094
2095 if (!full_update)
2096 return;
2097 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
2098 return;
2099 if (s->ds->depth == 8)
2100 val = s->rgb_to_pixel(0, 0, 0);
2101 else
2102 val = 0;
2103 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
2104 d = s->ds->data;
2105 for(i = 0; i < s->last_scr_height; i++) {
2106 memset(d, val, w);
2107 d += s->ds->linesize;
2108 }
2109 dpy_update(s->ds, 0, 0,
2110 s->last_scr_width, s->last_scr_height);
2111#else /* VBOX */
2112
2113 int i, w, val;
2114 uint8_t *d;
2115 uint32_t cbScanline = s->pDrv->cbScanline;
2116
2117 if (!full_update)
2118 return;
2119 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
2120 return;
2121 if (s->pDrv->cBits == 8)
2122 val = s->rgb_to_pixel(0, 0, 0);
2123 else
2124 val = 0;
2125 w = s->last_scr_width * ((s->pDrv->cBits + 7) >> 3);
2126 d = s->pDrv->pu8Data;
2127 for(i = 0; i < (int)s->last_scr_height; i++) {
2128 memset(d, val, w);
2129 d += cbScanline;
2130 }
2131 s->pDrv->pfnUpdateRect(s->pDrv, 0, 0, s->last_scr_width, s->last_scr_height);
2132#endif /* VBOX */
2133}
2134
2135#define GMODE_TEXT 0
2136#define GMODE_GRAPH 1
2137#define GMODE_BLANK 2
2138
2139#ifndef VBOX
2140void vga_update_display(void)
2141{
2142 VGAState *s = vga_state;
2143#else /* VBOX */
2144static int vga_update_display(PVGASTATE s)
2145{
2146 int rc = VINF_SUCCESS;
2147#endif /* VBOX */
2148 int full_update, graphic_mode;
2149
2150#ifndef VBOX
2151 if (s->ds->depth == 0) {
2152#else /* VBOX */
2153 if (s->pDrv->cBits == 0) {
2154#endif /* VBOX */
2155 /* nothing to do */
2156 } else {
2157#ifndef VBOX
2158 switch(s->ds->depth) {
2159#else /* VBOX */
2160 switch(s->pDrv->cBits) {
2161#endif /* VBOX */
2162 case 8:
2163 s->rgb_to_pixel = rgb_to_pixel8_dup;
2164 break;
2165 case 15:
2166 s->rgb_to_pixel = rgb_to_pixel15_dup;
2167 break;
2168 default:
2169 case 16:
2170 s->rgb_to_pixel = rgb_to_pixel16_dup;
2171 break;
2172 case 32:
2173 s->rgb_to_pixel = rgb_to_pixel32_dup;
2174 break;
2175 }
2176
2177 full_update = 0;
2178 if (!(s->ar_index & 0x20)) {
2179 graphic_mode = GMODE_BLANK;
2180 } else {
2181 graphic_mode = s->gr[6] & 1;
2182 }
2183 if (graphic_mode != s->graphic_mode) {
2184 s->graphic_mode = graphic_mode;
2185 full_update = 1;
2186 }
2187 switch(graphic_mode) {
2188 case GMODE_TEXT:
2189#ifdef VBOX
2190 rc =
2191#endif /* VBOX */
2192 vga_draw_text(s, full_update);
2193 break;
2194 case GMODE_GRAPH:
2195#ifdef VBOX
2196 rc =
2197#endif /* VBOX */
2198 vga_draw_graphic(s, full_update);
2199 break;
2200 case GMODE_BLANK:
2201 default:
2202 vga_draw_blank(s, full_update);
2203 break;
2204 }
2205 }
2206#ifdef VBOX
2207 return rc;
2208#endif /* VBOX */
2209}
2210
2211/* force a full display refresh */
2212#ifndef VBOX
2213void vga_invalidate_display(void)
2214{
2215 VGAState *s = vga_state;
2216
2217 s->last_width = -1;
2218 s->last_height = -1;
2219}
2220#endif /* !VBOX */
2221
2222#ifndef VBOX /* see vgaR3Reset() */
2223static void vga_reset(VGAState *s)
2224{
2225 memset(s, 0, sizeof(VGAState));
2226 s->graphic_mode = -1; /* force full update */
2227}
2228#endif /* !VBOX */
2229
2230#ifndef VBOX
2231static CPUReadMemoryFunc *vga_mem_read[3] = {
2232 vga_mem_readb,
2233 vga_mem_readw,
2234 vga_mem_readl,
2235};
2236
2237static CPUWriteMemoryFunc *vga_mem_write[3] = {
2238 vga_mem_writeb,
2239 vga_mem_writew,
2240 vga_mem_writel,
2241};
2242#endif /* !VBOX */
2243
2244static void vga_save(QEMUFile *f, void *opaque)
2245{
2246 VGAState *s = (VGAState*)opaque;
2247 int i;
2248
2249 qemu_put_be32s(f, &s->latch);
2250 qemu_put_8s(f, &s->sr_index);
2251 qemu_put_buffer(f, s->sr, 8);
2252 qemu_put_8s(f, &s->gr_index);
2253 qemu_put_buffer(f, s->gr, 16);
2254 qemu_put_8s(f, &s->ar_index);
2255 qemu_put_buffer(f, s->ar, 21);
2256 qemu_put_be32s(f, &s->ar_flip_flop);
2257 qemu_put_8s(f, &s->cr_index);
2258 qemu_put_buffer(f, s->cr, 256);
2259 qemu_put_8s(f, &s->msr);
2260 qemu_put_8s(f, &s->fcr);
2261 qemu_put_8s(f, &s->st00);
2262 qemu_put_8s(f, &s->st01);
2263
2264 qemu_put_8s(f, &s->dac_state);
2265 qemu_put_8s(f, &s->dac_sub_index);
2266 qemu_put_8s(f, &s->dac_read_index);
2267 qemu_put_8s(f, &s->dac_write_index);
2268 qemu_put_buffer(f, s->dac_cache, 3);
2269 qemu_put_buffer(f, s->palette, 768);
2270
2271 qemu_put_be32s(f, &s->bank_offset);
2272#ifdef CONFIG_BOCHS_VBE
2273 qemu_put_byte(f, 1);
2274 qemu_put_be16s(f, &s->vbe_index);
2275 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2276 qemu_put_be16s(f, &s->vbe_regs[i]);
2277 qemu_put_be32s(f, &s->vbe_start_addr);
2278 qemu_put_be32s(f, &s->vbe_line_offset);
2279 qemu_put_be32s(f, &s->vbe_bank_mask);
2280#else
2281 qemu_put_byte(f, 0);
2282#endif
2283}
2284
2285static int vga_load(QEMUFile *f, void *opaque, int version_id)
2286{
2287 VGAState *s = (VGAState*)opaque;
2288 int is_vbe, i;
2289
2290 if (version_id != 1)
2291#ifndef VBOX
2292 return -EINVAL;
2293#else /* VBOX */
2294 {
2295 Log(("vga_load: version_id=%d - UNKNOWN\n", version_id));
2296 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2297 }
2298#endif /* VBOX */
2299
2300 qemu_get_be32s(f, &s->latch);
2301 qemu_get_8s(f, &s->sr_index);
2302 qemu_get_buffer(f, s->sr, 8);
2303 qemu_get_8s(f, &s->gr_index);
2304 qemu_get_buffer(f, s->gr, 16);
2305 qemu_get_8s(f, &s->ar_index);
2306 qemu_get_buffer(f, s->ar, 21);
2307 qemu_get_be32s(f, (uint32_t *)&s->ar_flip_flop);
2308 qemu_get_8s(f, &s->cr_index);
2309 qemu_get_buffer(f, s->cr, 256);
2310 qemu_get_8s(f, &s->msr);
2311 qemu_get_8s(f, &s->fcr);
2312 qemu_get_8s(f, &s->st00);
2313 qemu_get_8s(f, &s->st01);
2314
2315 qemu_get_8s(f, &s->dac_state);
2316 qemu_get_8s(f, &s->dac_sub_index);
2317 qemu_get_8s(f, &s->dac_read_index);
2318 qemu_get_8s(f, &s->dac_write_index);
2319 qemu_get_buffer(f, s->dac_cache, 3);
2320 qemu_get_buffer(f, s->palette, 768);
2321
2322 qemu_get_be32s(f, (uint32_t *)&s->bank_offset);
2323 is_vbe = qemu_get_byte(f);
2324#ifdef CONFIG_BOCHS_VBE
2325 if (!is_vbe)
2326#ifndef VBOX
2327 return -EINVAL;
2328#else /* VBOX */
2329 {
2330 Log(("vga_load: !is_vbe !!\n"));
2331 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2332 }
2333#endif /* VBOX */
2334 qemu_get_be16s(f, &s->vbe_index);
2335 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2336 qemu_get_be16s(f, &s->vbe_regs[i]);
2337 qemu_get_be32s(f, &s->vbe_start_addr);
2338 qemu_get_be32s(f, &s->vbe_line_offset);
2339 qemu_get_be32s(f, &s->vbe_bank_mask);
2340#else
2341 if (is_vbe)
2342#ifndef VBOX
2343 return -EINVAL;
2344#else /* VBOX */
2345 {
2346 Log(("vga_load: is_vbe !!\n"));
2347 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2348 }
2349#endif /* VBOX */
2350#endif
2351
2352 /* force refresh */
2353 s->graphic_mode = -1;
2354 return 0;
2355}
2356
2357#ifndef VBOX /* see vgaR3IORegionMap */
2358static void vga_map(PCIDevice *pci_dev, int region_num,
2359 uint32_t addr, uint32_t size, int type)
2360{
2361 VGAState *s = vga_state;
2362
2363 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
2364}
2365#endif
2366
2367#ifndef VBOX /* see vgaR3Construct */
2368void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
2369 unsigned long vga_ram_offset, int vga_ram_size)
2370#else
2371static void vga_init_expand(void)
2372#endif
2373{
2374 int i, j, v, b;
2375
2376 for(i = 0;i < 256; i++) {
2377 v = 0;
2378 for(j = 0; j < 8; j++) {
2379 v |= ((i >> j) & 1) << (j * 4);
2380 }
2381 expand4[i] = v;
2382
2383 v = 0;
2384 for(j = 0; j < 4; j++) {
2385 v |= ((i >> (2 * j)) & 3) << (j * 4);
2386 }
2387 expand2[i] = v;
2388 }
2389 for(i = 0; i < 16; i++) {
2390 v = 0;
2391 for(j = 0; j < 4; j++) {
2392 b = ((i >> j) & 1);
2393 v |= b << (2 * j);
2394 v |= b << (2 * j + 1);
2395 }
2396 expand4to8[i] = v;
2397 }
2398#ifdef VBOX
2399}
2400#else /* !VBOX */
2401 vga_reset(s);
2402
2403 s->vram_ptr = vga_ram_base;
2404 s->vram_offset = vga_ram_offset;
2405 s->vram_size = vga_ram_size;
2406 s->ds = ds;
2407 s->get_bpp = vga_get_bpp;
2408 s->get_offsets = vga_get_offsets;
2409 s->get_resolution = vga_get_resolution;
2410 /* XXX: currently needed for display */
2411 vga_state = s;
2412}
2413
2414
2415int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
2416 unsigned long vga_ram_offset, int vga_ram_size)
2417{
2418 VGAState *s;
2419
2420 s = qemu_mallocz(sizeof(VGAState));
2421 if (!s)
2422 return -1;
2423
2424 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2425
2426 register_savevm("vga", 0, 1, vga_save, vga_load, s);
2427
2428 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2429
2430 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2431 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2432 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2433 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2434
2435 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2436
2437 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2438 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2439 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2440 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2441 s->bank_offset = 0;
2442
2443#ifdef CONFIG_BOCHS_VBE
2444 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
2445 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
2446#if defined (TARGET_I386)
2447 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2448 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2449
2450 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2451 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2452
2453 /* old Bochs IO ports */
2454 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2455 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2456
2457 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2458 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2459#else
2460 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2461 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2462
2463 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2464 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2465#endif
2466#endif /* CONFIG_BOCHS_VBE */
2467
2468 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2469 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2470 vga_io_memory);
2471
2472 if (bus) {
2473 PCIDevice *d;
2474 uint8_t *pci_conf;
2475
2476 d = pci_register_device(bus, "VGA",
2477 sizeof(PCIDevice),
2478 -1, NULL, NULL);
2479 pci_conf = d->config;
2480 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2481 pci_conf[0x01] = 0x12;
2482 pci_conf[0x02] = 0x11;
2483 pci_conf[0x03] = 0x11;
2484 pci_conf[0x0a] = 0x00; // VGA controller
2485 pci_conf[0x0b] = 0x03;
2486 pci_conf[0x0e] = 0x00; // header_type
2487
2488 /* XXX: vga_ram_size must be a power of two */
2489 pci_register_io_region(d, 0, vga_ram_size,
2490 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2491 } else {
2492#ifdef CONFIG_BOCHS_VBE
2493 /* XXX: use optimized standard vga accesses */
2494 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2495 vga_ram_size, vga_ram_offset);
2496#endif
2497 }
2498 return 0;
2499}
2500#endif /* !VBOX */
2501
2502
2503#ifndef VBOX
2504/********************************************************/
2505/* vga screen dump */
2506
2507static int vga_save_w, vga_save_h;
2508
2509static void vga_save_dpy_update(DisplayState *s,
2510 int x, int y, int w, int h)
2511{
2512}
2513
2514static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2515{
2516 s->linesize = w * 4;
2517#ifndef VBOX
2518 s->data = qemu_malloc(h * s->linesize);
2519#else /* VBOX */
2520 if (!s->data)
2521 {
2522 PPDMDEVINS pDevIns = VGASTATE2DEVINS((PVGASTATE)s->pvVgaState);
2523 s->data = PDMDevHlpMMHeapAlloc(pDevIns, h * s->linesize);
2524 }
2525 else // (32-bpp buffer is allocated by the caller)
2526 s->linesize = ((w * 32 + 31) / 32) * 4;
2527#endif /* VBOX */
2528 vga_save_w = w;
2529 vga_save_h = h;
2530}
2531
2532static void vga_save_dpy_refresh(DisplayState *s)
2533{
2534}
2535
2536static int ppm_save(const char *filename, uint8_t *data,
2537 int w, int h, int linesize)
2538{
2539 FILE *f;
2540 uint8_t *d, *d1;
2541 unsigned int v;
2542 int y, x;
2543
2544 f = fopen(filename, "wb");
2545 if (!f)
2546 return -1;
2547 fprintf(f, "P6\n%d %d\n%d\n",
2548 w, h, 255);
2549 d1 = data;
2550 for(y = 0; y < h; y++) {
2551 d = d1;
2552 for(x = 0; x < w; x++) {
2553 v = *(uint32_t *)d;
2554 fputc((v >> 16) & 0xff, f);
2555 fputc((v >> 8) & 0xff, f);
2556 fputc((v) & 0xff, f);
2557 d += 4;
2558 }
2559 d1 += linesize;
2560 }
2561 fclose(f);
2562 return 0;
2563}
2564
2565/* save the vga display in a PPM image even if no display is
2566 available */
2567void vga_screen_dump(const char *filename)
2568{
2569 VGAState *s = vga_state;
2570 DisplayState *saved_ds, ds1, *ds = &ds1;
2571
2572 /* XXX: this is a little hackish */
2573 vga_invalidate_display();
2574 saved_ds = s->ds;
2575
2576 memset(ds, 0, sizeof(DisplayState));
2577 ds->dpy_update = vga_save_dpy_update;
2578 ds->dpy_resize = vga_save_dpy_resize;
2579 ds->dpy_refresh = vga_save_dpy_refresh;
2580 ds->depth = 32;
2581
2582 s->ds = ds;
2583 s->graphic_mode = -1;
2584 vga_update_display();
2585
2586 if (ds->data) {
2587 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
2588 s->ds->linesize);
2589 qemu_free(ds->data);
2590 }
2591 s->ds = saved_ds;
2592}
2593#endif /* !VBOX */
2594
2595
2596#if 0 //def VBOX
2597/* copy the vga display contents to the given buffer. the size of the buffer
2598 must be sufficient to store the screen copy (see below). the width and height
2599 parameters determine the required dimensions of the copy. If they differ
2600 from the actual screen dimensions, then the returned copy is shrinked or
2601 stretched accordingly. The copy is always a 32-bit image, so the size of
2602 the buffer supplied must be at least (((width * 32 + 31) / 32) * 4) * height,
2603 i.e. dword-aligned. returns zero if the operation was successfull and -1
2604 otherwise. */
2605
2606static int vga_copy_screen_to(PVGASTATE s, uint8_t *buf, int width, int height)
2607{
2608 DisplayState *saved_ds, ds1, *ds = &ds1;
2609 if (!buf || width <= 0 || height <= 0)
2610 return -1;
2611
2612 /* XXX: this is a little hackish */
2613 vga_invalidate_display(s);
2614 saved_ds = s->ds;
2615
2616 memset(ds, 0, sizeof(DisplayState));
2617 ds->dpy_update = vga_save_dpy_update;
2618 ds->dpy_resize = vga_save_dpy_resize;
2619 ds->dpy_refresh = vga_save_dpy_refresh;
2620 ds->depth = 32;
2621 ds->data = buf;
2622 ds->pvVgaState = s;
2623
2624 s->ds = ds;
2625 s->graphic_mode = -1;
2626 vga_update_display(s);
2627
2628//@@TODO (dmik): implement stretching/shrinking!
2629
2630 s->ds = saved_ds;
2631 return 0;
2632}
2633
2634/* copy the given buffer to the vga display. width and height define the
2635 dimensions of the image in the buffer. x and y define the point on the
2636 vga display to copy the image to. the buffer is assumed to contain a 32-bit
2637 image, so the size of one scanline must be ((width * 32 + 31) / 32) * 4),
2638 i.e. dword-aligned. returns zero if the operation was successfull and -1
2639 otherwise. */
2640static int vga_copy_screen_from(PVGASTATE s, uint8_t *buf, int x, int y, int width, int height)
2641{
2642 int bpl = ((width * 32 + 31) / 32) * 4;
2643 int linesize = s->ds->linesize;
2644 uint8_t *dst;
2645 uint8_t *src;
2646 int bpp;
2647 vga_draw_line_func *vga_draw_line;
2648
2649 if (!buf || x < 0 || y < 0 || width <= 0 || height <= 0
2650 || x + width > s->ds->width || y + height > s->ds->height)
2651 return -1;
2652
2653 vga_draw_line = vga_draw_line_table[VGA_DRAW_LINE32 * 4 + get_depth_index(s->ds->depth)];
2654 switch (s->ds->depth) {
2655 case 8: bpp = 1; break;
2656 case 15:
2657 case 16: bpp = 2; break;
2658 case 32: bpp = 4; break;
2659 default: return -1;
2660 }
2661
2662 dst = s->ds->data + y * linesize + x * bpp;
2663 src = buf;
2664 for (y = 0; y < height; y ++)
2665 {
2666 vga_draw_line(s, dst, src, width);
2667 dst += linesize;
2668 src += bpl;
2669 }
2670
2671 return 0;
2672}
2673#endif
2674
2675#endif /* !VBOX || !IN_GC || !IN_RING0 */
2676
2677
2678
2679#ifdef VBOX /* innotek code start */
2680
2681
2682/* -=-=-=-=-=- all contexts -=-=-=-=-=- */
2683
2684/**
2685 * Port I/O Handler for VGA OUT operations.
2686 *
2687 * @returns VBox status code.
2688 *
2689 * @param pDevIns The device instance.
2690 * @param pvUser User argument - ignored.
2691 * @param Port Port number used for the IN operation.
2692 * @param u32 The value to output.
2693 * @param cb The value size in bytes.
2694 */
2695PDMBOTHCBDECL(int) vgaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2696{
2697 NOREF(pvUser);
2698 if (cb == 1)
2699 vga_ioport_write(PDMINS2DATA(pDevIns, PVGASTATE), Port, u32);
2700 else if (cb == 2)
2701 {
2702 vga_ioport_write(PDMINS2DATA(pDevIns, PVGASTATE), Port, u32 & 0xff);
2703 vga_ioport_write(PDMINS2DATA(pDevIns, PVGASTATE), Port + 1, u32 >> 8);
2704 }
2705 return VINF_SUCCESS;
2706}
2707
2708
2709/**
2710 * Port I/O Handler for VGA IN operations.
2711 *
2712 * @returns VBox status code.
2713 *
2714 * @param pDevIns The device instance.
2715 * @param pvUser User argument - ignored.
2716 * @param Port Port number used for the IN operation.
2717 * @param pu32 Where to store the result.
2718 * @param cb Number of bytes read.
2719 */
2720PDMBOTHCBDECL(int) vgaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2721{
2722 NOREF(pvUser);
2723 if (cb == 1)
2724 {
2725 *pu32 = vga_ioport_read(PDMINS2DATA(pDevIns, PVGASTATE), Port);
2726 return VINF_SUCCESS;
2727 }
2728 else if (cb == 2)
2729 {
2730 *pu32 = vga_ioport_read(PDMINS2DATA(pDevIns, PVGASTATE), Port)
2731 | (vga_ioport_read(PDMINS2DATA(pDevIns, PVGASTATE), Port + 1) << 8);
2732 return VINF_SUCCESS;
2733 }
2734 return VERR_IOM_IOPORT_UNUSED;
2735}
2736
2737
2738/**
2739 * Port I/O Handler for VBE OUT operations.
2740 *
2741 * @returns VBox status code.
2742 *
2743 * @param pDevIns The device instance.
2744 * @param pvUser User argument - ignored.
2745 * @param Port Port number used for the IN operation.
2746 * @param u32 The value to output.
2747 * @param cb The value size in bytes.
2748 */
2749PDMBOTHCBDECL(int) vgaIOPortWriteVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2750{
2751 VGAState *s = PDMINS2DATA(pDevIns, PVGASTATE);
2752
2753 NOREF(pvUser);
2754
2755#ifndef IN_RING3
2756 /*
2757 * This has to be done on the host in order to execute the connector callbacks.
2758 */
2759 if (s->vbe_index == VBE_DISPI_INDEX_ENABLE
2760 || s->vbe_index == VBE_DISPI_INDEX_VBOX_VIDEO)
2761 {
2762 Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE - Switching to host...\n"));
2763 return VINF_IOM_HC_IOPORT_WRITE;
2764 }
2765#endif
2766#ifdef VBE_BYTEWISE_IO
2767 if (cb == 1)
2768 {
2769 if (!s->fWriteVBEData)
2770 {
2771 if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
2772 && (u32 & VBE_DISPI_ENABLED))
2773 {
2774 s->fWriteVBEData = false;
2775 return vbe_ioport_write_data(s, Port, u32 & 0xFF);
2776 }
2777 else
2778 {
2779 s->cbWriteVBEData = u32 & 0xFF;
2780 s->fWriteVBEData = true;
2781 return VINF_SUCCESS;
2782 }
2783 }
2784 else
2785 {
2786 u32 = (s->cbWriteVBEData << 8) | (u32 & 0xFF);
2787 s->fWriteVBEData = false;
2788 cb = 2;
2789 }
2790 }
2791#endif
2792 if (cb == 2 || cb == 4)
2793 {
2794//#ifdef IN_GC
2795// /*
2796// * The VBE_DISPI_INDEX_ENABLE memsets the entire frame buffer.
2797// * Since we're not mapping the entire framebuffer any longer that
2798// * has to be done on the host.
2799// */
2800// if ( (s->vbe_index == VBE_DISPI_INDEX_ENABLE)
2801// && (u32 & VBE_DISPI_ENABLED))
2802// {
2803// Log(("vgaIOPortWriteVBEData: VBE_DISPI_INDEX_ENABLE & VBE_DISPI_ENABLED - Switching to host...\n"));
2804// return VINF_IOM_HC_IOPORT_WRITE;
2805// }
2806//#endif
2807 return vbe_ioport_write_data(s, Port, u32);
2808 }
2809 else
2810 AssertMsgFailed(("vgaIOPortWriteVBEData: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2811 return VINF_SUCCESS;
2812}
2813
2814
2815/**
2816 * Port I/O Handler for VBE OUT operations.
2817 *
2818 * @returns VBox status code.
2819 *
2820 * @param pDevIns The device instance.
2821 * @param pvUser User argument - ignored.
2822 * @param Port Port number used for the IN operation.
2823 * @param u32 The value to output.
2824 * @param cb The value size in bytes.
2825 */
2826PDMBOTHCBDECL(int) vgaIOPortWriteVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2827{
2828 NOREF(pvUser);
2829#ifdef VBE_BYTEWISE_IO
2830 if (cb == 1)
2831 {
2832 VGAState *s = PDMINS2DATA(pDevIns, PVGASTATE);
2833 if (!s->fWriteVBEIndex)
2834 {
2835 s->cbWriteVBEIndex = u32 & 0x00FF;
2836 s->fWriteVBEIndex = true;
2837 return VINF_SUCCESS;
2838 }
2839 else
2840 {
2841 s->fWriteVBEIndex = false;
2842 vbe_ioport_write_index(s, Port, (s->cbWriteVBEIndex << 8) | (u32 & 0x00FF));
2843 return VINF_SUCCESS;
2844 }
2845 }
2846 else
2847#endif
2848 if (cb == 2)
2849 vbe_ioport_write_index(PDMINS2DATA(pDevIns, PVGASTATE), Port, u32);
2850 else
2851 AssertMsgFailed(("vgaIOPortWriteVBEIndex: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2852 return VINF_SUCCESS;
2853}
2854
2855
2856/**
2857 * Port I/O Handler for VBE IN operations.
2858 *
2859 * @returns VBox status code.
2860 *
2861 * @param pDevIns The device instance.
2862 * @param pvUser User argument - ignored.
2863 * @param Port Port number used for the IN operation.
2864 * @param pu32 Where to store the result.
2865 * @param cb Number of bytes to read.
2866 */
2867PDMBOTHCBDECL(int) vgaIOPortReadVBEData(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2868{
2869 NOREF(pvUser);
2870#ifdef VBE_BYTEWISE_IO
2871 if (cb == 1)
2872 {
2873 VGAState *s = PDMINS2DATA(pDevIns, PVGASTATE);
2874
2875 if (!s->fReadVBEData)
2876 {
2877 *pu32 = (vbe_ioport_read_data(s, Port) >> 8) & 0xFF;
2878 s->fReadVBEData = true;
2879 return VINF_SUCCESS;
2880 }
2881 else
2882 {
2883 *pu32 = vbe_ioport_read_data(s, Port) & 0xFF;
2884 s->fReadVBEData = false;
2885 return VINF_SUCCESS;
2886 }
2887 }
2888 else
2889#endif
2890 if (cb == 2)
2891 {
2892 *pu32 = vbe_ioport_read_data(PDMINS2DATA(pDevIns, PVGASTATE), Port);
2893 return VINF_SUCCESS;
2894 }
2895 else if (cb == 4)
2896 {
2897 VGAState *s = PDMINS2DATA(pDevIns, PVGASTATE);
2898 /* Quick hack for getting the vram size. */
2899 *pu32 = s->vram_size;
2900 return VINF_SUCCESS;
2901 }
2902 AssertMsgFailed(("vgaIOPortReadVBEData: Port=%#x cb=%d\n", Port, cb));
2903 return VERR_IOM_IOPORT_UNUSED;
2904}
2905
2906
2907/**
2908 * Port I/O Handler for VBE IN operations.
2909 *
2910 * @returns VBox status code.
2911 *
2912 * @param pDevIns The device instance.
2913 * @param pvUser User argument - ignored.
2914 * @param Port Port number used for the IN operation.
2915 * @param pu32 Where to store the result.
2916 * @param cb Number of bytes to read.
2917 */
2918PDMBOTHCBDECL(int) vgaIOPortReadVBEIndex(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2919{
2920 NOREF(pvUser);
2921#ifdef VBE_BYTEWISE_IO
2922 if (cb == 1)
2923 {
2924 VGAState *s = PDMINS2DATA(pDevIns, PVGASTATE);
2925
2926 if (!s->fReadVBEIndex)
2927 {
2928 *pu32 = (vbe_ioport_read_index(s, Port) >> 8) & 0xFF;
2929 s->fReadVBEIndex = true;
2930 return VINF_SUCCESS;
2931 }
2932 else
2933 {
2934 *pu32 = vbe_ioport_read_index(s, Port) & 0xFF;
2935 s->fReadVBEIndex = false;
2936 return VINF_SUCCESS;
2937 }
2938 }
2939 else
2940#endif
2941 if (cb == 2)
2942 {
2943 *pu32 = vbe_ioport_read_index(PDMINS2DATA(pDevIns, PVGASTATE), Port);
2944 return VINF_SUCCESS;
2945 }
2946 AssertMsgFailed(("vgaIOPortReadVBEIndex: Port=%#x cb=%d\n", Port, cb));
2947 return VERR_IOM_IOPORT_UNUSED;
2948}
2949
2950
2951
2952
2953
2954/* -=-=-=-=-=- Guest Context -=-=-=-=-=- */
2955
2956/*
2957 * Internal. For use inside VGAGCMemoryFillWrite only.
2958 * Macro for apply logical operation and bit mask.
2959 */
2960#define APPLY_LOGICAL_AND_MASK(s, val, bit_mask) \
2961 /* apply logical operation */ \
2962 switch(s->gr[3] >> 3) \
2963 { \
2964 case 0: \
2965 default: \
2966 /* nothing to do */ \
2967 break; \
2968 case 1: \
2969 /* and */ \
2970 val &= s->latch; \
2971 break; \
2972 case 2: \
2973 /* or */ \
2974 val |= s->latch; \
2975 break; \
2976 case 3: \
2977 /* xor */ \
2978 val ^= s->latch; \
2979 break; \
2980 } \
2981 /* apply bit mask */ \
2982 val = (val & bit_mask) | (s->latch & ~bit_mask)
2983
2984/**
2985 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM and from the inside of VGADeviceGC.cpp.
2986 * This is the advanced version of vga_mem_writeb function.
2987 *
2988 * @returns VBox status code.
2989 * @param pDevIns Pointer device instance.
2990 * @param pvUser User argument - ignored.
2991 * @param GCPhysAddr Physical address of memory to write.
2992 * @param u32Item Data to write, up to 4 bytes.
2993 * @param cbItem Size of data Item, only 1/2/4 bytes is allowed for now.
2994 * @param cItems Number of data items to write.
2995 */
2996PDMBOTHCBDECL(int) vgaMMIOFill(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems)
2997{
2998 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
2999 uint32_t b;
3000 uint32_t write_mask, bit_mask, set_mask;
3001 uint32_t aVal[4]; /** @todo r=bird: Why is this an 32-bit array? */
3002 unsigned i;
3003 NOREF(pvUser);
3004 for (i = 0; i < cbItem; i++)
3005 {
3006 aVal[i] = u32Item & 0xff;
3007 u32Item >>= 8;
3008 }
3009
3010 /* convert to VGA memory offset */
3011 /// @todo add check for the end of region
3012 GCPhysAddr &= 0x1ffff;
3013 switch((pData->gr[6] >> 2) & 3) {
3014 case 0:
3015 break;
3016 case 1:
3017 if (GCPhysAddr >= 0x10000)
3018 return VINF_SUCCESS;
3019 GCPhysAddr += pData->bank_offset;
3020 break;
3021 case 2:
3022 GCPhysAddr -= 0x10000;
3023 if (GCPhysAddr >= 0x8000)
3024 return VINF_SUCCESS;
3025 break;
3026 default:
3027 case 3:
3028 GCPhysAddr -= 0x18000;
3029 if (GCPhysAddr >= 0x8000)
3030 return VINF_SUCCESS;
3031 break;
3032 }
3033
3034 if (pData->sr[4] & 0x08) {
3035 /* chain 4 mode : simplest access */
3036#ifdef IN_GC
3037 if (GCPhysAddr + cItems * cbItem >= VGA_MAPPING_SIZE)
3038 return VINF_IOM_HC_MMIO_WRITE;
3039#else
3040 if (GCPhysAddr + cItems * cbItem >= pData->vram_size)
3041 {
3042 AssertMsgFailed(("GCPhysAddr=%VGp cItems=%#x cbItem=%d\n", GCPhysAddr, cItems, cbItem));
3043 return VINF_SUCCESS;
3044 }
3045#endif
3046
3047 while (cItems-- > 0)
3048 for (i = 0; i < cbItem; i++)
3049 {
3050 if (pData->sr[2] & (1 << (GCPhysAddr & 3)))
3051 {
3052 CTXSUFF(pData->vram_ptr)[GCPhysAddr] = aVal[i];
3053 vga_set_dirty(pData, GCPhysAddr);
3054 }
3055 GCPhysAddr++;
3056 }
3057 } else if (pData->gr[5] & 0x10) {
3058 /* odd/even mode (aka text mode mapping) */
3059#ifdef IN_GC
3060 if (GCPhysAddr * 2 + cItems * cbItem >= VGA_MAPPING_SIZE)
3061 return VINF_IOM_HC_MMIO_WRITE;
3062#else
3063 if (GCPhysAddr * 2 + cItems * cbItem >= pData->vram_size)
3064 {
3065 AssertMsgFailed(("GCPhysAddr=%VGp cItems=%#x cbItem=%d\n", GCPhysAddr, cItems, cbItem));
3066 return VINF_SUCCESS;
3067 }
3068#endif
3069 while (cItems-- > 0)
3070 for (i = 0; i < cbItem; i++)
3071 {
3072 unsigned plane = (pData->gr[4] & 2) | (GCPhysAddr & 1);
3073 if (pData->sr[2] & (1 << plane)) {
3074 RTGCPHYS PhysAddr2 = ((GCPhysAddr & ~1) << 2) | plane;
3075 CTXSUFF(pData->vram_ptr)[PhysAddr2] = aVal[i];
3076 vga_set_dirty(pData, PhysAddr2);
3077 }
3078 GCPhysAddr++;
3079 }
3080 } else {
3081#ifdef IN_GC
3082 if (GCPhysAddr + cItems * cbItem >= VGA_MAPPING_SIZE)
3083 return VINF_IOM_HC_MMIO_WRITE;
3084#else
3085 if (GCPhysAddr + cItems * cbItem >= pData->vram_size)
3086 {
3087 AssertMsgFailed(("GCPhysAddr=%VGp cItems=%#x cbItem=%d\n", GCPhysAddr, cItems, cbItem));
3088 return VINF_SUCCESS;
3089 }
3090#endif
3091
3092 /* standard VGA latched access */
3093 switch(pData->gr[5] & 3) {
3094 default:
3095 case 0:
3096 /* rotate */
3097 b = pData->gr[3] & 7;
3098 bit_mask = pData->gr[8];
3099 bit_mask |= bit_mask << 8;
3100 bit_mask |= bit_mask << 16;
3101 set_mask = mask16[pData->gr[1]];
3102
3103 for (i = 0; i < cbItem; i++)
3104 {
3105 aVal[i] = ((aVal[i] >> b) | (aVal[i] << (8 - b))) & 0xff;
3106 aVal[i] |= aVal[i] << 8;
3107 aVal[i] |= aVal[i] << 16;
3108
3109 /* apply set/reset mask */
3110 aVal[i] = (aVal[i] & ~set_mask) | (mask16[pData->gr[0]] & set_mask);
3111
3112 APPLY_LOGICAL_AND_MASK(pData, aVal[i], bit_mask);
3113 }
3114 break;
3115 case 1:
3116 for (i = 0; i < cbItem; i++)
3117 aVal[i] = pData->latch;
3118 break;
3119 case 2:
3120 bit_mask = pData->gr[8];
3121 bit_mask |= bit_mask << 8;
3122 bit_mask |= bit_mask << 16;
3123 for (i = 0; i < cbItem; i++)
3124 {
3125 aVal[i] = mask16[aVal[i] & 0x0f];
3126
3127 APPLY_LOGICAL_AND_MASK(pData, aVal[i], bit_mask);
3128 }
3129 break;
3130 case 3:
3131 /* rotate */
3132 b = pData->gr[3] & 7;
3133
3134 for (i = 0; i < cbItem; i++)
3135 {
3136 aVal[i] = (aVal[i] >> b) | (aVal[i] << (8 - b));
3137 bit_mask = pData->gr[8] & aVal[i];
3138 bit_mask |= bit_mask << 8;
3139 bit_mask |= bit_mask << 16;
3140 aVal[i] = mask16[pData->gr[0]];
3141
3142 APPLY_LOGICAL_AND_MASK(pData, aVal[i], bit_mask);
3143 }
3144 break;
3145 }
3146
3147 /* mask data according to sr[2] */
3148 write_mask = mask16[pData->sr[2]];
3149
3150 /* actually write data */
3151 if (cbItem == 1)
3152 {
3153 /* The most frequently case is 1 byte I/O. */
3154 while (cItems-- > 0)
3155 {
3156 ((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
3157 vga_set_dirty(pData, GCPhysAddr << 2);
3158 GCPhysAddr++;
3159 }
3160 }
3161 else if (cbItem == 2)
3162 {
3163 /* The second case is 2 bytes I/O. */
3164 while (cItems-- > 0)
3165 {
3166 ((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[0] & write_mask);
3167 vga_set_dirty(pData, GCPhysAddr << 2);
3168 GCPhysAddr++;
3169
3170 ((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[1] & write_mask);
3171 vga_set_dirty(pData, GCPhysAddr << 2);
3172 GCPhysAddr++;
3173 }
3174 }
3175 else
3176 {
3177 /* And the rest is 4 bytes. */
3178 Assert(cbItem == 4);
3179 while (cItems-- > 0)
3180 for (i = 0; i < cbItem; i++)
3181 {
3182 ((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] = (((uint32_t *)pData->CTXSUFF(vram_ptr))[GCPhysAddr] & ~write_mask) | (aVal[i] & write_mask);
3183 vga_set_dirty(pData, GCPhysAddr << 2);
3184 GCPhysAddr++;
3185 }
3186 }
3187 }
3188 return VINF_SUCCESS;
3189}
3190#undef APPLY_LOGICAL_AND_MASK
3191
3192
3193/**
3194 * Legacy VGA memory (0xa0000 - 0xbffff) read hook, to be called from IOM.
3195 *
3196 * @returns VBox status code.
3197 * @param pDevIns Pointer device instance.
3198 * @param pvUser User argument - ignored.
3199 * @param GCPhysAddr Physical address of memory to read.
3200 * @param pv Where to store readed data.
3201 * @param cb Bytes to read.
3202 */
3203PDMBOTHCBDECL(int) vgaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3204{
3205 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
3206 STAM_PROFILE_START(&pData->StatGCMemoryRead, a);
3207 NOREF(pvUser);
3208 switch (cb)
3209 {
3210 case 1:
3211 *(uint8_t *)pv = vga_mem_readb(pData, GCPhysAddr); break;
3212 case 2:
3213 *(uint16_t *)pv = vga_mem_readb(pData, GCPhysAddr)
3214 | (vga_mem_readb(pData, GCPhysAddr + 1) << 8);
3215 break;
3216 case 4:
3217 *(uint32_t *)pv = vga_mem_readb(pData, GCPhysAddr)
3218 | (vga_mem_readb(pData, GCPhysAddr + 1) << 8)
3219 | (vga_mem_readb(pData, GCPhysAddr + 2) << 16)
3220 | (vga_mem_readb(pData, GCPhysAddr + 3) << 24);
3221 break;
3222
3223 default:
3224 {
3225 uint8_t *pu8Data = (uint8_t *)pv;
3226 while (cb-- > 0)
3227 *pu8Data++ = vga_mem_readb(pData, GCPhysAddr++);
3228 }
3229 }
3230 STAM_PROFILE_STOP(&pData->StatGCMemoryRead, a);
3231 return VINF_SUCCESS;
3232}
3233
3234/**
3235 * Legacy VGA memory (0xa0000 - 0xbffff) write hook, to be called from IOM.
3236 *
3237 * @returns VBox status code.
3238 * @param pDevIns Pointer device instance.
3239 * @param pvUser User argument - ignored.
3240 * @param GCPhysAddr Physical address of memory to write.
3241 * @param pv Pointer to data.
3242 * @param cb Bytes to write.
3243 */
3244PDMBOTHCBDECL(int) vgaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3245{
3246 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
3247 uint8_t *pu8 = (uint8_t *)pv;
3248 int rc = VINF_SUCCESS;
3249 STAM_PROFILE_START(&pData->StatGCMemoryWrite, a);
3250
3251 switch (cb)
3252 {
3253 case 1:
3254 rc = vga_mem_writeb(pData, GCPhysAddr, *pu8);
3255 break;
3256#if 1
3257 case 2:
3258 rc = vga_mem_writeb(pData, GCPhysAddr + 0, pu8[0]);
3259 if (RT_LIKELY(rc == VINF_SUCCESS))
3260 rc = vga_mem_writeb(pData, GCPhysAddr + 1, pu8[1]);
3261 break;
3262 case 4:
3263 rc = vga_mem_writeb(pData, GCPhysAddr + 0, pu8[0]);
3264 if (RT_LIKELY(rc == VINF_SUCCESS))
3265 rc = vga_mem_writeb(pData, GCPhysAddr + 1, pu8[1]);
3266 if (RT_LIKELY(rc == VINF_SUCCESS))
3267 rc = vga_mem_writeb(pData, GCPhysAddr + 2, pu8[2]);
3268 if (RT_LIKELY(rc == VINF_SUCCESS))
3269 rc = vga_mem_writeb(pData, GCPhysAddr + 3, pu8[3]);
3270 break;
3271#else
3272 case 2:
3273 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint16_t *)pv, 2, 1);
3274 break;
3275 case 4:
3276 rc = vgaMMIOFill(pDevIns, GCPhysAddr, *(uint32_t *)pv, 4, 1);
3277 break;
3278#endif
3279 default:
3280 while (cb-- > 0 && rc == VINF_SUCCESS)
3281 rc = vga_mem_writeb(pData, GCPhysAddr++, *pu8++);
3282 break;
3283
3284 }
3285 STAM_PROFILE_STOP(&pData->StatGCMemoryWrite, a);
3286 return rc;
3287}
3288
3289
3290/**
3291 * Handle LFB access.
3292 * @returns VBox status code.
3293 * @param pVM VM handle.
3294 * @param pData VGA device instance data.
3295 * @param GCPhys The access physical address.
3296 * @param GCPtr The access virtual address (only GC).
3297 */
3298static int vgaLFBAccess(PVM pVM, PVGASTATE pData, RTGCPHYS GCPhys, RTGCPTR GCPtr)
3299{
3300 int rc;
3301
3302 /*
3303 * Set page dirty bit.
3304 */
3305 vga_set_dirty(pData, GCPhys - pData->GCPhysVRAM);
3306 pData->fLFBUpdated = true;
3307
3308 /*
3309 * Turn of the write handler for this particular page and make it R/W.
3310 * Then return telling the caller to restart the guest instruction.
3311 * ASSUME: the guest always maps video memory RW.
3312 */
3313 rc = PGMHandlerPhysicalPageTempOff(pVM, pData->GCPhysVRAM, GCPhys);
3314 if (VBOX_SUCCESS(rc))
3315 {
3316#ifndef IN_RING3
3317 rc = PGMShwModifyPage(pVM, GCPtr, 1, X86_PTE_RW, ~(uint64_t)X86_PTE_RW);
3318 if (VBOX_SUCCESS(rc))
3319 return VINF_SUCCESS;
3320 else
3321 AssertMsgFailed(("PGMShwModifyPage -> rc=%d\n", rc));
3322#else /* IN_RING3 : We don't have any virtual page address of the access here. */
3323 Assert(GCPtr == 0);
3324 return VINF_SUCCESS;
3325#endif
3326 }
3327 else
3328 AssertMsgFailed(("PGMHandlerPhysicalPageTempOff -> rc=%d\n", rc));
3329
3330 return rc;
3331}
3332
3333
3334#ifdef IN_GC
3335/**
3336 * #PF Handler for VBE LFB access.
3337 *
3338 * @returns VBox status code (appropriate for GC return).
3339 * @param pVM VM Handle.
3340 * @param uErrorCode CPU Error code.
3341 * @param pRegFrame Trap register frame.
3342 * @param pvFault The fault address (cr2).
3343 * @param GCPhysFault The GC physical address corresponding to pvFault.
3344 * @param pvUser User argument, ignored.
3345 */
3346PDMBOTHCBDECL(int) vgaGCLFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
3347{
3348 PVGASTATE pData = (PVGASTATE)pvUser;
3349 Assert(pData);
3350 Assert(GCPhysFault >= pData->GCPhysVRAM);
3351 AssertMsg(uErrorCode & X86_TRAP_PF_RW, ("uErrorCode=%#x\n", uErrorCode));
3352
3353 return vgaLFBAccess(pVM, pData, GCPhysFault, pvFault);
3354}
3355
3356#elif IN_RING0
3357
3358/**
3359 * #PF Handler for VBE LFB access.
3360 *
3361 * @returns VBox status code (appropriate for GC return).
3362 * @param pVM VM Handle.
3363 * @param uErrorCode CPU Error code.
3364 * @param pRegFrame Trap register frame.
3365 * @param pvFault The fault address (cr2).
3366 * @param GCPhysFault The GC physical address corresponding to pvFault.
3367 * @param pvUser User argument, ignored.
3368 */
3369PDMBOTHCBDECL(int) vgaR0LFBAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
3370{
3371 PVGASTATE pData = (PVGASTATE)pvUser;
3372 Assert(pData);
3373 Assert(GCPhysFault >= pData->GCPhysVRAM);
3374 AssertMsg(uErrorCode & X86_TRAP_PF_RW, ("uErrorCode=%#x\n", uErrorCode));
3375
3376 return vgaLFBAccess(pVM, pData, GCPhysFault, pvFault);
3377}
3378
3379#else /* IN_RING3 */
3380
3381/**
3382 * HC access handler for the LFB.
3383 *
3384 * @returns VINF_SUCCESS if the handler have carried out the operation.
3385 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
3386 * @param pVM VM Handle.
3387 * @param GCPhys The physical address the guest is writing to.
3388 * @param pvPhys The HC mapping of that address.
3389 * @param pvBuf What the guest is reading/writing.
3390 * @param cbBuf How much it's reading/writing.
3391 * @param enmAccessType The access type.
3392 * @param pvUser User argument.
3393 */
3394static DECLCALLBACK(int) vgaR3LFBAccessHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
3395{
3396 PVGASTATE pData = (PVGASTATE)pvUser;
3397 int rc;
3398 Assert(pData);
3399 Assert(GCPhys >= pData->GCPhysVRAM);
3400 rc = vgaLFBAccess(pVM, pData, GCPhys, 0);
3401 if (VBOX_SUCCESS(rc))
3402 return VINF_PGM_HANDLER_DO_DEFAULT;
3403 AssertMsg(rc <= VINF_SUCCESS, ("rc=%Vrc\n", rc));
3404 return rc;
3405}
3406#endif /* IN_RING3 */
3407
3408
3409/* -=-=-=-=-=- Ring 3 -=-=-=-=-=- */
3410
3411#ifdef IN_RING3
3412
3413# ifdef VBE_NEW_DYN_LIST
3414/**
3415 * Port I/O Handler for VBE Extra OUT operations.
3416 *
3417 * @returns VBox status code.
3418 *
3419 * @param pDevIns The device instance.
3420 * @param pvUser User argument - ignored.
3421 * @param Port Port number used for the IN operation.
3422 * @param u32 The value to output.
3423 * @param cb The value size in bytes.
3424 */
3425PDMBOTHCBDECL(int) vbeIOPortWriteVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3426{
3427 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
3428 NOREF(pvUser);
3429 NOREF(Port);
3430
3431 if (cb == 2)
3432 {
3433 Log(("vbeIOPortWriteVBEExtra: addr=%#RX32\n", u32));
3434 pData->u16VBEExtraAddress = u32;
3435 return VINF_SUCCESS;
3436 }
3437
3438 Log(("vbeIOPortWriteVBEExtra: Ignoring invalid cb=%d writes to the VBE Extra port!!!\n", cb));
3439 return VINF_SUCCESS;
3440}
3441
3442
3443/**
3444 * Port I/O Handler for VBE Extra IN operations.
3445 *
3446 * @returns VBox status code.
3447 *
3448 * @param pDevIns The device instance.
3449 * @param pvUser User argument - ignored.
3450 * @param Port Port number used for the IN operation.
3451 * @param pu32 Where to store the result.
3452 * @param cb Number of bytes read.
3453 */
3454PDMBOTHCBDECL(int) vbeIOPortReadVBEExtra(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3455{
3456 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
3457 NOREF(pvUser);
3458 NOREF(Port);
3459
3460 if (pData->u16VBEExtraAddress == 0xffff)
3461 {
3462 Log(("vbeIOPortReadVBEExtra: Requested number of 64k video banks\n"));
3463 *pu32 = pData->vram_size / _64K;
3464 return VINF_SUCCESS;
3465 }
3466
3467 if ( pData->u16VBEExtraAddress >= pData->cbVBEExtraData
3468 || pData->u16VBEExtraAddress + cb > pData->cbVBEExtraData)
3469 {
3470 *pu32 = 0;
3471 Log(("vbeIOPortReadVBEExtra: Requested address is out of VBE data!!! Address=%#x(%d) cbVBEExtraData=%#x(%d)\n",
3472 pData->u16VBEExtraAddress, pData->u16VBEExtraAddress, pData->cbVBEExtraData, pData->cbVBEExtraData));
3473 return VINF_SUCCESS;
3474 }
3475
3476 if (cb == 1)
3477 {
3478 *pu32 = pData->pu8VBEExtraData[pData->u16VBEExtraAddress] & 0xFF;
3479
3480 Log(("vbeIOPortReadVBEExtra: cb=%#x %.*Vhxs\n", cb, cb, pu32));
3481 return VINF_SUCCESS;
3482 }
3483
3484 if (cb == 2)
3485 {
3486 *pu32 = pData->pu8VBEExtraData[pData->u16VBEExtraAddress]
3487 | pData->pu8VBEExtraData[pData->u16VBEExtraAddress + 1] << 8;
3488
3489 Log(("vbeIOPortReadVBEExtra: cb=%#x %.*Vhxs\n", cb, cb, pu32));
3490 return VINF_SUCCESS;
3491 }
3492 Log(("vbeIOPortReadVBEExtra: Invalid cb=%d read from the VBE Extra port!!!\n", cb));
3493 return VERR_IOM_IOPORT_UNUSED;
3494}
3495# endif /* VBE_NEW_DYN_LIST */
3496
3497
3498
3499
3500/* -=-=-=-=-=- Ring 3: VGA BIOS I/Os -=-=-=-=-=- */
3501
3502/**
3503 * Port I/O Handler for VGA BIOS IN operations.
3504 *
3505 * @returns VBox status code.
3506 *
3507 * @param pDevIns The device instance.
3508 * @param pvUser User argument - ignored.
3509 * @param Port Port number used for the IN operation.
3510 * @param pu32 Where to store the result.
3511 * @param cb Number of bytes read.
3512 */
3513static DECLCALLBACK(int) vgaIOPortReadBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3514{
3515 NOREF(pDevIns);
3516 NOREF(pvUser);
3517 NOREF(Port);
3518 NOREF(pu32);
3519 NOREF(cb);
3520 return VERR_IOM_IOPORT_UNUSED;
3521}
3522
3523/**
3524 * Port I/O Handler for VGA BIOS OUT operations.
3525 *
3526 * @returns VBox status code.
3527 *
3528 * @param pDevIns The device instance.
3529 * @param pvUser User argument - ignored.
3530 * @param Port Port number used for the IN operation.
3531 * @param u32 The value to output.
3532 * @param cb The value size in bytes.
3533 */
3534static DECLCALLBACK(int) vgaIOPortWriteBIOS(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3535{
3536 static int lastWasNotNewline = 0; /* We are only called in a single-threaded way */
3537 /*
3538 * VGA BIOS char printing.
3539 */
3540 if ( cb == 1
3541 && Port == VBE_PRINTF_PORT)
3542 {
3543#if 0
3544 switch (u32)
3545 {
3546 case '\r': Log(("vgabios: <return>\n")); break;
3547 case '\n': Log(("vgabios: <newline>\n")); break;
3548 case '\t': Log(("vgabios: <tab>\n")); break;
3549 default:
3550 Log(("vgabios: %c\n", u32));
3551 }
3552#else
3553 if (lastWasNotNewline == 0)
3554 Log(("vgabios: "));
3555 if (u32 != '\r') /* return - is only sent in conjunction with '\n' */
3556 Log(("%c", u32));
3557 if (u32 == '\n')
3558 lastWasNotNewline = 0;
3559 else
3560 lastWasNotNewline = 1;
3561#endif
3562 return VINF_SUCCESS;
3563 }
3564
3565 /* not in use. */
3566 return VINF_SUCCESS;
3567}
3568
3569
3570/* -=-=-=-=-=- Ring 3: IBase -=-=-=-=-=- */
3571
3572/**
3573 * Queries an interface to the driver.
3574 *
3575 * @returns Pointer to interface.
3576 * @returns NULL if the interface was not supported by the driver.
3577 * @param pInterface Pointer to this interface structure.
3578 * @param enmInterface The requested interface identification.
3579 * @thread Any thread.
3580 */
3581static DECLCALLBACK(void *) vgaPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
3582{
3583 PVGASTATE pData = (PVGASTATE)((uintptr_t)pInterface - RT_OFFSETOF(VGASTATE, Base));
3584 switch (enmInterface)
3585 {
3586 case PDMINTERFACE_BASE:
3587 return &pData->Base;
3588 case PDMINTERFACE_DISPLAY_PORT:
3589 return &pData->Port;
3590 default:
3591 return NULL;
3592 }
3593}
3594
3595
3596/* -=-=-=-=-=- Ring 3: Dummy IDisplayConnector -=-=-=-=-=- */
3597
3598/**
3599 * Resize the display.
3600 * This is called when the resolution changes. This usually happens on
3601 * request from the guest os, but may also happen as the result of a reset.
3602 *
3603 * @param pInterface Pointer to this interface.
3604 * @param cx New display width.
3605 * @param cy New display height
3606 * @thread The emulation thread.
3607 */
3608static DECLCALLBACK(int) vgaDummyResize(PPDMIDISPLAYCONNECTOR pInterface, uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
3609{
3610 return VINF_SUCCESS;
3611}
3612
3613
3614/**
3615 * Update a rectangle of the display.
3616 * PDMIDISPLAYPORT::pfnUpdateDisplay is the caller.
3617 *
3618 * @param pInterface Pointer to this interface.
3619 * @param x The upper left corner x coordinate of the rectangle.
3620 * @param y The upper left corner y coordinate of the rectangle.
3621 * @param cx The width of the rectangle.
3622 * @param cy The height of the rectangle.
3623 * @thread The emulation thread.
3624 */
3625static DECLCALLBACK(void) vgaDummyUpdateRect(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
3626{
3627}
3628
3629
3630/**
3631 * Refresh the display.
3632 *
3633 * The interval between these calls is set by
3634 * PDMIDISPLAYPORT::pfnSetRefreshRate(). The driver should call
3635 * PDMIDISPLAYPORT::pfnUpdateDisplay() if it wishes to refresh the
3636 * display. PDMIDISPLAYPORT::pfnUpdateDisplay calls pfnUpdateRect with
3637 * the changed rectangles.
3638 *
3639 * @param pInterface Pointer to this interface.
3640 * @thread The emulation thread.
3641 */
3642static DECLCALLBACK(void) vgaDummyRefresh(PPDMIDISPLAYCONNECTOR pInterface)
3643{
3644}
3645
3646
3647/* -=-=-=-=-=- Ring 3: IDisplayPort -=-=-=-=-=- */
3648
3649/** Converts a display port interface pointer to a vga state pointer. */
3650#define IDISPLAYPORT_2_VGASTATE(pInterface) ( (PVGASTATE)((uintptr_t)pInterface - RT_OFFSETOF(VGASTATE, Port)) )
3651
3652
3653/**
3654 * Update the display with any changed regions.
3655 *
3656 * @param pInterface Pointer to this interface.
3657 * @see PDMIKEYBOARDPORT::pfnUpdateDisplay() for details.
3658 */
3659static DECLCALLBACK(int) vgaPortUpdateDisplay(PPDMIDISPLAYPORT pInterface)
3660{
3661 PVGASTATE pData = IDISPLAYPORT_2_VGASTATE(pInterface);
3662 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pData));
3663
3664#ifdef DEBUG_sunlover
3665 LogFlow(("vgaPortUpdateDisplay\n"));
3666#endif /* DEBUG_sunlover */
3667
3668 /* This should be called only in non VBVA mode. */
3669
3670 int rc = vga_update_display(pData);
3671 if (rc != VINF_SUCCESS)
3672 return rc;
3673
3674 if (pData->fHaveDirtyBits)
3675 {
3676 PPDMDEVINS pDevIns = pData->pDevInsHC;
3677 PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pData->GCPhysVRAM);
3678 pData->fHaveDirtyBits = false;
3679 }
3680
3681 return VINF_SUCCESS;
3682}
3683
3684
3685/**
3686 * Update the entire display.
3687 *
3688 * @param pInterface Pointer to this interface.
3689 * @see PDMIKEYBOARDPORT::pfnUpdateDisplayAll() for details.
3690 */
3691static DECLCALLBACK(int) vgaPortUpdateDisplayAll(PPDMIDISPLAYPORT pInterface)
3692{
3693 PVGASTATE pData = IDISPLAYPORT_2_VGASTATE(pInterface);
3694 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pData));
3695
3696 /* This is called both in VBVA mode and normal modes. */
3697
3698#ifdef DEBUG_sunlover
3699 LogFlow(("vgaPortUpdateDisplayAll\n"));
3700#endif /* DEBUG_sunlover */
3701
3702 pData->graphic_mode = -1; /* force full update */
3703 return vga_update_display(pData);
3704}
3705
3706
3707/**
3708 * Sets the refresh rate and restart the timer.
3709 *
3710 * @returns VBox status code.
3711 * @param pInterface Pointer to this interface.
3712 * @param cMilliesInterval Number of millies between two refreshes.
3713 * @see PDMIKEYBOARDPORT::pfnSetRefreshRate() for details.
3714 */
3715static DECLCALLBACK(int) vgaPortSetRefreshRate(PPDMIDISPLAYPORT pInterface, uint32_t cMilliesInterval)
3716{
3717 PVGASTATE pData = IDISPLAYPORT_2_VGASTATE(pInterface);
3718
3719 pData->cMilliesRefreshInterval = cMilliesInterval;
3720 if (cMilliesInterval)
3721 return TMTimerSetMillies(pData->RefreshTimer, cMilliesInterval);
3722 return TMTimerStop(pData->RefreshTimer);
3723}
3724
3725
3726/** @copydoc PDMIDISPLAYPORT::pfnQueryColorDepth */
3727static DECLCALLBACK(int) vgaPortQueryColorDepth(PPDMIDISPLAYPORT pInterface, uint32_t *pcBits)
3728{
3729 PVGASTATE pData = IDISPLAYPORT_2_VGASTATE(pInterface);
3730
3731 if (!pcBits)
3732 return VERR_INVALID_PARAMETER;
3733 *pcBits = vga_get_bpp(pData);
3734 return VINF_SUCCESS;
3735}
3736
3737/**
3738 * Create a 32-bbp snapshot of the display.
3739 *
3740 * @param pInterface Pointer to this interface.
3741 * @param pvData Pointer the buffer to copy the bits to.
3742 * @param cbData Size of the buffer.
3743 * @param pcx Where to store the width of the bitmap. (optional)
3744 * @param pcy Where to store the height of the bitmap. (optional)
3745 * @param pcbData Where to store the actual size of the bitmap. (optional)
3746 * @see PDMIKEYBOARDPORT::pfnSnapshot() for details.
3747 */
3748static DECLCALLBACK(int) vgaPortSnapshot(PPDMIDISPLAYPORT pInterface, void *pvData, size_t cbData, uint32_t *pcx, uint32_t *pcy, size_t *pcbData)
3749{
3750 /* @todo r=sunlover: replace the method with a direct VRAM rendering like in vgaPortUpdateDisplayRect. */
3751 PPDMIDISPLAYCONNECTOR pConnector;
3752 PDMIDISPLAYCONNECTOR Connector;
3753 int32_t graphic_mode;
3754 uint32_t fRenderVRAM;
3755 size_t cbRequired;
3756 PVGASTATE pData = IDISPLAYPORT_2_VGASTATE(pInterface);
3757 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pData));
3758 LogFlow(("vgaPortSnapshot: pvData=%p cbData=%d pcx=%p pcy=%p pcbData=%p\n", pvData, cbData, pcx, pcy, pcbData));
3759
3760 /*
3761 * Validate input.
3762 */
3763 if (!pvData)
3764 return VERR_INVALID_PARAMETER;
3765
3766 /*
3767 * Do a regular refresh first to resolve any pending resize issues.
3768 *
3769 * 20060317 It used to be pfnUpdateDisplay, but by VBVA design
3770 * only pfnUpdateDisplayAll is allowed to be called in VBVA mode.
3771 * Also since the goal here is to have updated display for screenshot,
3772 * the UpdateDisplayAll is even more logical to call. (sunlover)
3773 */
3774 pInterface->pfnUpdateDisplayAll(pInterface);
3775
3776 /*
3777 * Validate the buffer size.
3778 */
3779 cbRequired = RT_ALIGN_Z(pData->last_scr_width, 4) * pData->last_scr_height * 4;
3780 if (cbRequired > cbData)
3781 {
3782 Log(("vgaPortSnapshot: %d bytes are required, a buffer of %d bytes is profiled.\n", cbRequired, cbData));
3783 return VERR_BUFFER_OVERFLOW;
3784 }
3785
3786 /*
3787 * Temporarily replace the display connector interface with a fake one.
3788 */
3789 Connector.pu8Data = (uint8_t*)pvData;
3790 Connector.cBits = 32;
3791 Connector.cx = pData->pDrv->cx;
3792 Connector.cy = pData->pDrv->cy;
3793 Connector.cbScanline = RT_ALIGN_32(Connector.cx, 4) * 4;
3794 Connector.pfnRefresh = vgaDummyRefresh;
3795 Connector.pfnResize = vgaDummyResize;
3796 Connector.pfnUpdateRect = vgaDummyUpdateRect;
3797
3798 /* save & replace state data. */
3799 pConnector = pData->pDrv;
3800 pData->pDrv = &Connector;
3801 graphic_mode = pData->graphic_mode;
3802 pData->graphic_mode = -1; /* force a full refresh. */
3803 fRenderVRAM = pData->fRenderVRAM;
3804 pData->fRenderVRAM = 1; /* force the guest VRAM rendering to the given buffer. */
3805
3806 /* make the snapshot. */
3807 int rc = vga_update_display(pData);
3808
3809 /* restore */
3810 pData->pDrv = pConnector;
3811 pData->graphic_mode = graphic_mode;
3812 pData->fRenderVRAM = fRenderVRAM;
3813
3814 if (rc != VINF_SUCCESS)
3815 return rc;
3816
3817 /*
3818 * Return the result.
3819 */
3820 if (pcx)
3821 *pcx = Connector.cx;
3822 if (pcy)
3823 *pcy = Connector.cy;
3824 if (pcbData)
3825 *pcbData = cbRequired;
3826 LogFlow(("vgaPortSnapshot: returns VINF_SUCCESS (cx=%d cy=%d cbData=%d)\n", Connector.cx, Connector.cy, cbRequired));
3827 return VINF_SUCCESS;
3828}
3829
3830
3831/**
3832 * Copy bitmap to the display.
3833 *
3834 * @param pInterface Pointer to this interface.
3835 * @param pvData Pointer to the bitmap bits.
3836 * @param x The upper left corner x coordinate of the destination rectangle.
3837 * @param y The upper left corner y coordinate of the destination rectangle.
3838 * @param cx The width of the source and destination rectangles.
3839 * @param cy The height of the source and destination rectangles.
3840 * @see PDMIDISPLAYPORT::pfnDisplayBlt() for details.
3841 */
3842static DECLCALLBACK(int) vgaPortDisplayBlt(PPDMIDISPLAYPORT pInterface, const void *pvData, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
3843{
3844 PVGASTATE pData = IDISPLAYPORT_2_VGASTATE(pInterface);
3845 int rc = VINF_SUCCESS;
3846 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pData));
3847 LogFlow(("vgaPortDisplayBlt: pvData=%p x=%d y=%d cx=%d cy=%d\n", pvData, x, y, cx, cy));
3848
3849 /*
3850 * Validate input.
3851 */
3852 if ( pvData
3853 && x < pData->pDrv->cx
3854 && cx <= pData->pDrv->cx
3855 && cx + x <= pData->pDrv->cx
3856 && y < pData->pDrv->cy
3857 && cy <= pData->pDrv->cy
3858 && cy + y <= pData->pDrv->cy)
3859 {
3860 /*
3861 * Determin bytes per pixel in the destination buffer.
3862 */
3863 size_t cbPixelDst = 0;
3864 switch (pData->pDrv->cBits)
3865 {
3866 case 8:
3867 cbPixelDst = 1;
3868 break;
3869 case 15:
3870 case 16:
3871 cbPixelDst = 2;
3872 break;
3873 case 24:
3874 cbPixelDst = 3;
3875 break;
3876 case 32:
3877 cbPixelDst = 4;
3878 break;
3879 default:
3880 rc = VERR_INVALID_PARAMETER;
3881 break;
3882 }
3883 if (VBOX_SUCCESS(rc))
3884 {
3885 /*
3886 * The blitting loop.
3887 */
3888 size_t cbLineSrc = RT_ALIGN_Z(cx, 4) * 4;
3889 uint8_t *pu8Src = (uint8_t *)pvData;
3890 size_t cbLineDst = pData->pDrv->cbScanline;
3891 uint8_t *pu8Dst = pData->pDrv->pu8Data + y * cbLineDst + x * cbPixelDst;
3892 uint32_t cyLeft = cy;
3893 vga_draw_line_func *pfnVgaDrawLine = vga_draw_line_table[VGA_DRAW_LINE32 * 4 + get_depth_index(pData->pDrv->cBits)];
3894 Assert(pfnVgaDrawLine);
3895 while (cyLeft-- > 0)
3896 {
3897 pfnVgaDrawLine(pData, pu8Dst, pu8Src, cx);
3898 pu8Dst += cbLineDst;
3899 pu8Src += cbLineSrc;
3900 }
3901
3902 /*
3903 * Invalidate the area.
3904 */
3905 pData->pDrv->pfnUpdateRect(pData->pDrv, x, y, cx, cy);
3906 }
3907 }
3908 else
3909 rc = VERR_INVALID_PARAMETER;
3910
3911 LogFlow(("vgaPortDisplayBlt: returns %Vrc\n", rc));
3912 return rc;
3913}
3914
3915static DECLCALLBACK(void) vgaPortUpdateDisplayRect (PPDMIDISPLAYPORT pInterface, int32_t x, int32_t y, uint32_t w, uint32_t h)
3916{
3917 uint32_t v;
3918 vga_draw_line_func *vga_draw_line;
3919
3920 uint32_t cbPixelDst;
3921 uint32_t cbLineDst;
3922 uint8_t *pu8Dst;
3923
3924 uint32_t cbPixelSrc;
3925 uint32_t cbLineSrc;
3926 uint8_t *pu8Src;
3927
3928 uint32_t u32OffsetSrc, u32Dummy;
3929
3930 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
3931
3932#ifdef DEBUG_sunlover
3933 LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d\n", x, y, w, h));
3934#endif /* DEBUG_sunlover */
3935
3936 Assert(pInterface);
3937 Assert(s->pDrv);
3938 Assert(s->pDrv->pu8Data);
3939
3940 /* Check if there is something to do at all. */
3941 if (!s->fRenderVRAM)
3942 {
3943 /* The framebuffer uses the guest VRAM directly. */
3944#ifdef DEBUG_sunlover
3945 LogFlow(("vgaPortUpdateDisplayRect: nothing to do fRender is false.\n"));
3946#endif /* DEBUG_sunlover */
3947 return;
3948 }
3949
3950 /* Correct negative x and y coordinates. */
3951 if (x < 0)
3952 {
3953 x += w; /* Compute xRight which is also the new width. */
3954 w = (x < 0) ? 0 : x;
3955 x = 0;
3956 }
3957
3958 if (y < 0)
3959 {
3960 y += h; /* Compute yBottom, which is also the new height. */
3961 h = (y < 0) ? 0 : y;
3962 y = 0;
3963 }
3964
3965 /* Also check if coords are greater than the display resolution. */
3966 if (x + w > s->pDrv->cx)
3967 {
3968#ifndef VBOX
3969 w = s->pDrv->cx > x? s->pDrv->cx - x: 0;
3970#else
3971 // x < 0 is not possible here
3972 w = s->pDrv->cx > (uint32_t)x? s->pDrv->cx - x: 0;
3973#endif
3974 }
3975
3976 if (y + h > s->pDrv->cy)
3977 {
3978#ifndef VBOX
3979 h = s->pDrv->cy > y? s->pDrv->cy - y: 0;
3980#else
3981 // y < 0 is not possible here
3982 h = s->pDrv->cy > (uint32_t)y? s->pDrv->cy - y: 0;
3983#endif
3984 }
3985
3986#ifdef DEBUG_sunlover
3987 LogFlow(("vgaPortUpdateDisplayRect: %d,%d %dx%d (corrected coords)\n", x, y, w, h));
3988#endif /* DEBUG_sunlover */
3989
3990 /* Check if there is something to do at all. */
3991 if (w == 0 || h == 0)
3992 {
3993 /* Empty rectangle. */
3994#ifdef DEBUG_sunlover
3995 LogFlow(("vgaPortUpdateDisplayRect: nothing to do: %dx%d\n", w, h));
3996#endif /* DEBUG_sunlover */
3997 return;
3998 }
3999
4000 /** @todo This method should be made universal and not only for VBVA.
4001 * VGA_DRAW_LINE* must be selected and src/dst address calculation
4002 * changed.
4003 */
4004
4005 /* Choose the rendering function. */
4006 switch(s->get_bpp(s))
4007 {
4008 default:
4009 case 0:
4010 /* A LFB mode is already disabled, but the callback is still called
4011 * by Display because VBVA buffer is being flushed.
4012 * Nothing to do, just return.
4013 */
4014 return;
4015 case 8:
4016 v = VGA_DRAW_LINE8;
4017 break;
4018 case 15:
4019 v = VGA_DRAW_LINE15;
4020 break;
4021 case 16:
4022 v = VGA_DRAW_LINE16;
4023 break;
4024 case 24:
4025 v = VGA_DRAW_LINE24;
4026 break;
4027 case 32:
4028 v = VGA_DRAW_LINE32;
4029 break;
4030 }
4031
4032 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->pDrv->cBits)];
4033
4034 /* Compute source and destination addresses and pitches. */
4035 cbPixelDst = (s->pDrv->cBits + 7) / 8;
4036 cbLineDst = s->pDrv->cbScanline;
4037 pu8Dst = s->pDrv->pu8Data + y * cbLineDst + x * cbPixelDst;
4038
4039 cbPixelSrc = (s->get_bpp(s) + 7) / 8;
4040 s->get_offsets (s, &cbLineSrc, &u32OffsetSrc, &u32Dummy);
4041
4042 /* Assume that rendering is performed only on visible part of VRAM.
4043 * This is true because coordinates were verified.
4044 */
4045 pu8Src = s->vram_ptrHC;
4046 pu8Src += u32OffsetSrc + y * cbLineSrc + x * cbPixelSrc;
4047
4048 /* Render VRAM to framebuffer. */
4049
4050#ifdef DEBUG_sunlover
4051 LogFlow(("vgaPortUpdateDisplayRect: dst: %p, %d, %d. src: %p, %d, %d\n", pu8Dst, cbLineDst, cbPixelDst, pu8Src, cbLineSrc, cbPixelSrc));
4052#endif /* DEBUG_sunlover */
4053
4054 while (h-- > 0)
4055 {
4056 vga_draw_line (s, pu8Dst, pu8Src, w);
4057 pu8Dst += cbLineDst;
4058 pu8Src += cbLineSrc;
4059 }
4060
4061#ifdef DEBUG_sunlover
4062 LogFlow(("vgaPortUpdateDisplayRect: completed.\n"));
4063#endif /* DEBUG_sunlover */
4064}
4065
4066static DECLCALLBACK(void) vgaPortSetRenderVRAM(PPDMIDISPLAYPORT pInterface, bool fRender)
4067{
4068 PVGASTATE s = IDISPLAYPORT_2_VGASTATE(pInterface);
4069
4070 LogFlow(("vgaPortSetRenderVRAM: fRender = %d\n", fRender));
4071
4072 s->fRenderVRAM = fRender;
4073}
4074
4075
4076static DECLCALLBACK(void) vgaTimerRefresh(PPDMDEVINS pDevIns, PTMTIMER pTimer)
4077{
4078 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
4079 if (pData->pDrv)
4080 pData->pDrv->pfnRefresh(pData->pDrv);
4081 if (pData->cMilliesRefreshInterval)
4082 TMTimerSetMillies(pTimer, pData->cMilliesRefreshInterval);
4083}
4084
4085
4086/* -=-=-=-=-=- Ring 3: PCI Device -=-=-=-=-=- */
4087
4088/**
4089 * Callback function for mapping an PCI I/O region.
4090 *
4091 * @return VBox status code.
4092 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
4093 * @param iRegion The region number.
4094 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
4095 * I/O port, else it's a physical address.
4096 * This address is *NOT* relative to pci_mem_base like earlier!
4097 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
4098 */
4099static DECLCALLBACK(int) vgaR3IORegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
4100{
4101 int rc;
4102 PVGASTATE pData = PDMINS2DATA(pPciDev->pDevIns, PVGASTATE);
4103 LogFlow(("vgaR3IORegionMap: iRegion=%d GCPhysAddress=%VGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
4104
4105 /*
4106 * VRam mapping.
4107 */
4108 if (iRegion == 0 && enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH)
4109 {
4110 /*
4111 * Register and lock the VRAM.
4112 *
4113 * Windows usually re-initializes the PCI devices, so we have to check whether the memory was
4114 * already registered before trying to do that all over again.
4115 */
4116 PVM pVM = PDMDevHlpGetVM(pPciDev->pDevIns);
4117 if (pData->GCPhysVRAM)
4118 {
4119 AssertMsg(pData->GCPhysVRAM == GCPhysAddress,
4120 ("The Guest OS relocated our LFB! old GCPhysVRAM=%VGp new GCPhysAddress=%VGp\n",
4121 pData->GCPhysVRAM, GCPhysAddress));
4122 rc = VINF_SUCCESS;
4123 }
4124 else
4125 {
4126 /*
4127 * Register and lock the VRAM.
4128 */
4129 rc = MMR3PhysRegister(pVM, pData->vram_ptrHC, GCPhysAddress, pData->vram_size, MM_RAM_FLAGS_MMIO2, "VRam");
4130 if (VBOX_SUCCESS(rc))
4131 {
4132 if (!pData->GCPhysVRAM)
4133 rc = PGMR3HandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
4134 GCPhysAddress, GCPhysAddress + (pData->vram_size - 1),
4135 vgaR3LFBAccessHandler, pData,
4136 g_DeviceVga.szR0Mod, "vgaR0LFBAccessHandler", pData->pDevInsHC->pvInstanceDataR0,
4137 g_DeviceVga.szGCMod, "vgaGCLFBAccessHandler", pData->pDevInsHC->pvInstanceDataGC,
4138 "VGA LFB");
4139 if (VBOX_SUCCESS(rc))
4140 {
4141 /*
4142 * Map the first 256KB of the VRAM into GC for GC VGA support.
4143 */
4144 RTGCPTR GCPtr;
4145 rc = MMR3HyperMapGCPhys(pVM, GCPhysAddress, VGA_MAPPING_SIZE, "VGA VRam", &GCPtr);
4146 if (VBOX_SUCCESS(rc))
4147 {
4148 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
4149
4150 pData->vram_ptrGC = GCPtr;
4151 pData->GCPhysVRAM = GCPhysAddress;
4152 return VINF_SUCCESS;
4153 }
4154 AssertMsgFailed(("MMR3HyperMapGCPhys failed, rc=%Vrc\n", rc));
4155 }
4156 else
4157 AssertMsgFailed(("Failed to register write handler for VRAM! rc=%Vrc\n", rc));
4158 }
4159 else
4160 AssertReleaseMsgFailed(("Failed to register VRAM! rc=%Vra\n", rc));
4161 }
4162 return rc;
4163 }
4164 else
4165 AssertReleaseMsgFailed(("Huh!?! iRegion=%d enmType=%d\n", iRegion, enmType));
4166 return VERR_INTERNAL_ERROR;
4167}
4168
4169
4170/* -=-=-=-=-=- Ring3: Misc Wrappers -=-=-=-=-=- */
4171
4172/**
4173 * Saves a state of the VGA device.
4174 *
4175 * @returns VBox status code.
4176 * @param pDevIns The device instance.
4177 * @param pSSMHandle The handle to save the state to.
4178 */
4179static DECLCALLBACK(int) vgaR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
4180{
4181 vga_save(pSSMHandle, PDMINS2DATA(pDevIns, PVGASTATE));
4182 return VINF_SUCCESS;
4183}
4184
4185
4186/**
4187 * Loads a saved VGA device state.
4188 *
4189 * @returns VBox status code.
4190 * @param pDevIns The device instance.
4191 * @param pSSMHandle The handle to the saved state.
4192 * @param u32Version The data unit version number.
4193 */
4194static DECLCALLBACK(int) vgaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
4195{
4196 if (vga_load(pSSMHandle, PDMINS2DATA(pDevIns, PVGASTATE), u32Version))
4197 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4198 return VINF_SUCCESS;
4199}
4200
4201
4202/* -=-=-=-=-=- Ring 3: Device callbacks -=-=-=-=-=- */
4203
4204/**
4205 * Reset notification.
4206 *
4207 * @returns VBox status.
4208 * @param pDevIns The device instance data.
4209 */
4210static DECLCALLBACK(void) vgaR3Reset(PPDMDEVINS pDevIns)
4211{
4212 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
4213 char *pchStart;
4214 char *pchEnd;
4215 LogFlow(("vgaReset\n"));
4216
4217 /* Clear the VRAM ourselves. */
4218 if (pData->vram_ptrHC && pData->vram_size)
4219 {
4220#ifdef LOG_ENABLED /** @todo separate function. */
4221 /* First dump the textmode contents to the log; handy for capturing Windows blue screens. */
4222 uint8_t graphic_mode;
4223 VGAState *s = pData;
4224
4225 if (!(s->ar_index & 0x20)) {
4226 graphic_mode = GMODE_BLANK;
4227 } else {
4228 graphic_mode = s->gr[6] & 1;
4229 }
4230 switch(graphic_mode)
4231 case GMODE_TEXT:
4232 {
4233 int cw, height, width, cheight, cx_min, cx_max, cy, cx;
4234 int x_incr;
4235 uint8_t *s1, *src, ch, cattr;
4236 int line_offset;
4237 uint16_t ch_attr;
4238
4239 line_offset = s->line_offset;
4240 s1 = s->CTXSUFF(vram_ptr) + (s->start_addr * 4);
4241
4242 /* total width & height */
4243 cheight = (s->cr[9] & 0x1f) + 1;
4244 cw = 8;
4245 if (!(s->sr[1] & 0x01))
4246 cw = 9;
4247 if (s->sr[1] & 0x08)
4248 cw = 16; /* NOTE: no 18 pixel wide */
4249 x_incr = cw * ((s->pDrv->cBits + 7) >> 3);
4250 width = (s->cr[0x01] + 1);
4251 if (s->cr[0x06] == 100) {
4252 /* ugly hack for CGA 160x100x16 - explain me the logic */
4253 height = 100;
4254 } else {
4255 height = s->cr[0x12] |
4256 ((s->cr[0x07] & 0x02) << 7) |
4257 ((s->cr[0x07] & 0x40) << 3);
4258 height = (height + 1) / cheight;
4259 }
4260 if ((height * width) > CH_ATTR_SIZE) {
4261 /* better than nothing: exit if transient size is too big */
4262 break;
4263 }
4264 RTLogPrintf("VGA textmode BEGIN (%dx%d):\n\n", height, width);
4265 for(cy = 0; cy < height; cy++) {
4266 src = s1;
4267 cx_min = width;
4268 cx_max = -1;
4269 for(cx = 0; cx < width; cx++) {
4270 ch_attr = *(uint16_t *)src;
4271 if (cx < cx_min)
4272 cx_min = cx;
4273 if (cx > cx_max)
4274 cx_max = cx;
4275# ifdef WORDS_BIGENDIAN
4276 ch = ch_attr >> 8;
4277 cattr = ch_attr & 0xff;
4278# else
4279 ch = ch_attr & 0xff;
4280 cattr = ch_attr >> 8;
4281# endif
4282 RTLogPrintf("%c", ch);
4283
4284 src += 4;
4285 }
4286 if (cx_max != -1)
4287 RTLogPrintf("\n");
4288
4289 s1 += line_offset;
4290 }
4291 RTLogPrintf("VGA textmode END:\n\n");
4292 }
4293
4294#endif
4295 memset(pData->vram_ptrHC, 0, pData->vram_size);
4296 }
4297
4298 /*
4299 * Zero most of it.
4300 *
4301 * Unlike vga_reset we're leaving out a few members which believe must
4302 * remain unchanged....
4303 */
4304 /* 1st part. */
4305 pchStart = (char *)&pData->latch;
4306 pchEnd = (char *)&pData->invalidated_y_table;
4307 memset(pchStart, 0, pchEnd - pchStart);
4308
4309 /* 2nd part. */
4310 pchStart = (char *)&pData->last_palette;
4311 pchEnd = (char *)&pData->u32Marker;
4312 memset(pchStart, 0, pchEnd - pchStart);
4313
4314
4315 /*
4316 * Restore and re-init some bits.
4317 */
4318 pData->get_bpp = vga_get_bpp;
4319 pData->get_offsets = vga_get_offsets;
4320 pData->get_resolution = vga_get_resolution;
4321 pData->graphic_mode = -1; /* Force full update. */
4322#ifdef CONFIG_BOCHS_VBE
4323 pData->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
4324 pData->vbe_regs[VBE_DISPI_INDEX_VBOX_VIDEO] = 0;
4325 pData->vbe_bank_mask = ((pData->vram_size >> 16) - 1);
4326#endif /* CONFIG_BOCHS_VBE */
4327
4328 /*
4329 * Reset the LBF mapping.
4330 */
4331 pData->fLFBUpdated = false;
4332 if ( ( pData->fGCEnabled
4333 || pData->fR0Enabled)
4334 && pData->GCPhysVRAM)
4335 {
4336 int rc = PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pData->GCPhysVRAM);
4337 AssertRC(rc);
4338 }
4339
4340 /* notify port handler */
4341 if (pData->pDrv)
4342 pData->pDrv->pfnReset(pData->pDrv);
4343}
4344
4345
4346/**
4347 * Device relocation callback.
4348 *
4349 * @param pDevIns Pointer to the device instance.
4350 * @param offDelta The relocation delta relative to the old location.
4351 *
4352 * @see FNPDMDEVRELOCATE for details.
4353 */
4354static DECLCALLBACK(void) vgaR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
4355{
4356 if (offDelta)
4357 {
4358 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
4359 LogFlow(("vgaRelocate: offDelta = %08X\n", offDelta));
4360
4361 pData->GCPtrLFBHandler += offDelta;
4362 pData->vram_ptrGC += offDelta;
4363 }
4364}
4365
4366
4367/**
4368 * Attach command.
4369 *
4370 * This is called to let the device attach to a driver for a specified LUN
4371 * during runtime. This is not called during VM construction, the device
4372 * constructor have to attach to all the available drivers.
4373 *
4374 * This is like plugging in the monitor after turning on the PC.
4375 *
4376 * @returns VBox status code.
4377 * @param pDevIns The device instance.
4378 * @param iLUN The logical unit which is being detached.
4379 */
4380static DECLCALLBACK(int) vgaAttach(PPDMDEVINS pDevIns, unsigned iLUN)
4381{
4382 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
4383 switch (iLUN)
4384 {
4385 /* LUN #0: Display port. */
4386 case 0:
4387 {
4388 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pData->Base, &pData->pDrvBase, "Display Port");
4389 if (VBOX_SUCCESS(rc))
4390 {
4391 pData->pDrv = (PDMIDISPLAYCONNECTOR*)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_DISPLAY_CONNECTOR);
4392 if (pData->pDrv)
4393 {
4394 /* pData->pDrv->pu8Data can be NULL when there is no framebuffer. */
4395 if ( pData->pDrv->pfnRefresh
4396 && pData->pDrv->pfnResize
4397 && pData->pDrv->pfnUpdateRect)
4398 rc = VINF_SUCCESS;
4399 else
4400 {
4401 Assert(pData->pDrv->pfnRefresh);
4402 Assert(pData->pDrv->pfnResize);
4403 Assert(pData->pDrv->pfnUpdateRect);
4404 pData->pDrv = NULL;
4405 pData->pDrvBase = NULL;
4406 rc = VERR_INTERNAL_ERROR;
4407 }
4408 }
4409 else
4410 {
4411 AssertMsgFailed(("LUN #0 doesn't have a display connector interface! rc=%Vrc\n", rc));
4412 pData->pDrvBase = NULL;
4413 rc = VERR_PDM_MISSING_INTERFACE;
4414 }
4415 }
4416 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4417 {
4418 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
4419 rc = VINF_SUCCESS;
4420 }
4421 else
4422 AssertMsgFailed(("Failed to attach LUN #0! rc=%Vrc\n", rc));
4423 return rc;
4424 }
4425
4426 default:
4427 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
4428 return VERR_PDM_NO_SUCH_LUN;
4429 }
4430}
4431
4432
4433/**
4434 * Detach notification.
4435 *
4436 * This is called when a driver is detaching itself from a LUN of the device.
4437 * The device should adjust it's state to reflect this.
4438 *
4439 * This is like unplugging the monitor while the PC is still running.
4440 *
4441 * @param pDevIns The device instance.
4442 * @param iLUN The logical unit which is being detached.
4443 */
4444static DECLCALLBACK(void) vgaDetach(PPDMDEVINS pDevIns, unsigned iLUN)
4445{
4446 /*
4447 * Reset the interfaces and update the controller state.
4448 */
4449 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
4450 switch (iLUN)
4451 {
4452 /* LUN #0: Display port. */
4453 case 0:
4454 pData->pDrv = NULL;
4455 pData->pDrvBase = NULL;
4456 break;
4457
4458 default:
4459 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
4460 break;
4461 }
4462}
4463
4464
4465
4466/**
4467 * Construct a VGA device instance for a VM.
4468 *
4469 * @returns VBox status.
4470 * @param pDevIns The device instance data.
4471 * If the registration structure is needed, pDevIns->pDevReg points to it.
4472 * @param iInstance Instance number. Use this to figure out which registers and such to use.
4473 * The device number is also found in pDevIns->iInstance, but since it's
4474 * likely to be freqently used PDM passes it as parameter.
4475 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
4476 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
4477 * iInstance it's expected to be used a bit in this function.
4478 */
4479static DECLCALLBACK(int) vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
4480{
4481 static bool fExpandDone = false;
4482 bool f;
4483 int rc;
4484 unsigned i;
4485 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
4486 PVM pVM = PDMDevHlpGetVM(pDevIns);
4487#ifdef VBE_NEW_DYN_LIST
4488 uint32_t cCustomModes;
4489 uint32_t cyReduction;
4490 PVBEHEADER pVBEDataHdr;
4491 ModeInfoListItem *pCurMode;
4492 unsigned cb;
4493#endif
4494 Assert(iInstance == 0);
4495 Assert(pVM);
4496
4497 /*
4498 * Init static data.
4499 */
4500 if (!fExpandDone)
4501 {
4502 fExpandDone = true;
4503 vga_init_expand();
4504 }
4505
4506 /*
4507 * Validate configuration.
4508 */
4509 if (!CFGMR3AreValuesValid(pCfgHandle, "VRamSize\0"
4510 "GCEnabled\0"
4511 "R0Enabled\0"
4512 "CustomVideoModes\0"
4513 "HeightReduction\0"
4514 "CustomVideoMode1\0"
4515 "CustomVideoMode2\0"
4516 "CustomVideoMode3\0"
4517 "CustomVideoMode4\0"
4518 "CustomVideoMode5\0"
4519 "CustomVideoMode6\0"
4520 "CustomVideoMode7\0"
4521 "CustomVideoMode8\0"
4522 "CustomVideoMode9\0"
4523 "CustomVideoMode10\0"
4524 "CustomVideoMode11\0"
4525 "CustomVideoMode12\0"
4526 "CustomVideoMode13\0"
4527 "CustomVideoMode14\0"
4528 "CustomVideoMode15\0"
4529 "CustomVideoMode16\0"))
4530 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
4531 N_("Invalid configuration for vga device"));
4532
4533 /*
4534 * Init state data.
4535 */
4536 rc = CFGMR3QueryU32(pCfgHandle, "VRamSize", &pData->vram_size);
4537 if (VBOX_FAILURE(rc) || !pData->vram_size)
4538 pData->vram_size = VGA_VRAM_DEFAULT;
4539 else if (pData->vram_size > VGA_VRAM_MAX)
4540 {
4541 AssertMsgFailed(("vram_size=%d max=%d\n", pData->vram_size, VGA_VRAM_MAX));
4542 pData->vram_size = VGA_VRAM_MAX;
4543 }
4544 else if (pData->vram_size < VGA_VRAM_MIN)
4545 {
4546 AssertMsgFailed(("vram_size=%d min=%d\n", pData->vram_size, VGA_VRAM_MIN));
4547 pData->vram_size = RT_ALIGN_32(pData->vram_size, _1M);
4548 }
4549 Log(("VGA: VRamSize=%#x\n", pData->vram_size));
4550
4551 pData->fGCEnabled = true;
4552 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &f);
4553 if (VBOX_SUCCESS(rc) && !f)
4554 pData->fGCEnabled = false;
4555 Log(("VGA: fGCEnabled=%d\n", pData->fGCEnabled));
4556
4557 pData->fR0Enabled = true;
4558 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &f);
4559 if (VBOX_SUCCESS(rc) && !f)
4560 pData->fR0Enabled = false;
4561 Log(("VGA: fR0Enabled=%d\n", pData->fR0Enabled));
4562
4563 pData->pDevInsHC = pDevIns;
4564
4565 vgaR3Reset(pDevIns);
4566
4567 /* The PCI devices configuration. */
4568 pData->Dev.config[0x00] = 0xee; /* PCI vendor, just a free bogus value */
4569 pData->Dev.config[0x01] = 0x80;
4570
4571 pData->Dev.config[0x02] = 0xef; /* Device ID */
4572 pData->Dev.config[0x03] = 0xbe;
4573
4574 pData->Dev.config[0x0a] = 0x00; /* VGA controller */
4575 pData->Dev.config[0x0b] = 0x03;
4576 pData->Dev.config[0x0e] = 0x00; /* header_type */
4577
4578 /* The LBF access handler - error handling is better here than in the map function. */
4579 rc = PDMR3GetSymbolGCLazy(pVM, pDevIns->pDevReg->szGCMod, "vgaGCLFBAccessHandler", &pData->GCPtrLFBHandler);
4580 if (VBOX_FAILURE(rc))
4581 {
4582 AssertReleaseMsgFailed(("PDMR3GetSymbolGC(, %s, \"vgaGCLFBAccessHandler\",) -> %Vrc\n", pDevIns->pDevReg->szGCMod, rc));
4583 return rc;
4584 }
4585
4586 /* the interfaces. */
4587 pData->Base.pfnQueryInterface = vgaPortQueryInterface;
4588
4589 pData->Port.pfnUpdateDisplay = vgaPortUpdateDisplay;
4590 pData->Port.pfnUpdateDisplayAll = vgaPortUpdateDisplayAll;
4591 pData->Port.pfnQueryColorDepth = vgaPortQueryColorDepth;
4592 pData->Port.pfnSetRefreshRate = vgaPortSetRefreshRate;
4593 pData->Port.pfnSnapshot = vgaPortSnapshot;
4594 pData->Port.pfnDisplayBlt = vgaPortDisplayBlt;
4595 pData->Port.pfnUpdateDisplayRect = vgaPortUpdateDisplayRect;
4596 pData->Port.pfnSetRenderVRAM = vgaPortSetRenderVRAM;
4597
4598
4599 /*
4600 * Register I/O ports, ROM and save state.
4601 */
4602 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3c0, 16, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3c0");
4603 if (VBOX_FAILURE(rc))
4604 return rc;
4605 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3b4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3b4");
4606 if (VBOX_FAILURE(rc))
4607 return rc;
4608 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3ba, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3ba");
4609 if (VBOX_FAILURE(rc))
4610 return rc;
4611 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3d4, 2, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3d4");
4612 if (VBOX_FAILURE(rc))
4613 return rc;
4614 rc = PDMDevHlpIOPortRegister(pDevIns, 0x3da, 1, NULL, vgaIOPortWrite, vgaIOPortRead, NULL, NULL, "VGA - 3da");
4615 if (VBOX_FAILURE(rc))
4616 return rc;
4617
4618#ifdef CONFIG_BOCHS_VBE
4619 rc = PDMDevHlpIOPortRegister(pDevIns, 0x1ce, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, NULL, NULL, "VGA/VBE - Index");
4620 if (VBOX_FAILURE(rc))
4621 return rc;
4622 rc = PDMDevHlpIOPortRegister(pDevIns, 0x1cf, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, NULL, NULL, "VGA/VBE - Data");
4623 if (VBOX_FAILURE(rc))
4624 return rc;
4625#if 0
4626 /* This now causes conflicts with Win2k & XP; it is not aware this range is taken
4627 and tries to map other devices there */
4628 /* Old Bochs. */
4629 rc = PDMDevHlpIOPortRegister(pDevIns, 0xff80, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, "VGA/VBE - Index Old");
4630 if (VBOX_FAILURE(rc))
4631 return rc;
4632 rc = PDMDevHlpIOPortRegister(pDevIns, 0xff81, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, "VGA/VBE - Data Old");
4633 if (VBOX_FAILURE(rc))
4634 return rc;
4635#endif
4636#endif /* CONFIG_BOCHS_VBE */
4637
4638 /* guest context extension */
4639 if (pData->fGCEnabled)
4640 {
4641 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
4642 if (VBOX_FAILURE(rc))
4643 return rc;
4644 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
4645 if (VBOX_FAILURE(rc))
4646 return rc;
4647 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
4648 if (VBOX_FAILURE(rc))
4649 return rc;
4650 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
4651 if (VBOX_FAILURE(rc))
4652 return rc;
4653 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
4654 if (VBOX_FAILURE(rc))
4655 return rc;
4656#ifdef CONFIG_BOCHS_VBE
4657 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
4658 if (VBOX_FAILURE(rc))
4659 return rc;
4660 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
4661 if (VBOX_FAILURE(rc))
4662 return rc;
4663
4664#if 0
4665 /* This now causes conflicts with Win2k & XP; it is not aware this range is taken
4666 and tries to map other devices there */
4667 /* Old Bochs. */
4668 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0xff80, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", "VGA/VBE - Index Old (GC)");
4669 if (VBOX_FAILURE(rc))
4670 return rc;
4671 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0xff81, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", "VGA/VBE - Index Old (GC)");
4672 if (VBOX_FAILURE(rc))
4673 return rc;
4674#endif
4675
4676#endif /* CONFIG_BOCHS_VBE */
4677 }
4678
4679 /* R0 context extension */
4680 if (pData->fR0Enabled)
4681 {
4682 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3c0, 16, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3c0 (GC)");
4683 if (VBOX_FAILURE(rc))
4684 return rc;
4685 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3b4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3b4 (GC)");
4686 if (VBOX_FAILURE(rc))
4687 return rc;
4688 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3ba, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3ba (GC)");
4689 if (VBOX_FAILURE(rc))
4690 return rc;
4691 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3d4, 2, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3d4 (GC)");
4692 if (VBOX_FAILURE(rc))
4693 return rc;
4694 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x3da, 1, 0, "vgaIOPortWrite", "vgaIOPortRead", NULL, NULL, "VGA - 3da (GC)");
4695 if (VBOX_FAILURE(rc))
4696 return rc;
4697#ifdef CONFIG_BOCHS_VBE
4698 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1ce, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", NULL, NULL, "VGA/VBE - Index (GC)");
4699 if (VBOX_FAILURE(rc))
4700 return rc;
4701 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x1cf, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", NULL, NULL, "VGA/VBE - Data (GC)");
4702 if (VBOX_FAILURE(rc))
4703 return rc;
4704
4705#if 0
4706 /* This now causes conflicts with Win2k & XP; it is not aware this range is taken
4707 and tries to map other devices there */
4708 /* Old Bochs. */
4709 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0xff80, 1, 0, "vgaIOPortWriteVBEIndex", "vgaIOPortReadVBEIndex", "VGA/VBE - Index Old (GC)");
4710 if (VBOX_FAILURE(rc))
4711 return rc;
4712 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0xff81, 1, 0, "vgaIOPortWriteVBEData", "vgaIOPortReadVBEData", "VGA/VBE - Index Old (GC)");
4713 if (VBOX_FAILURE(rc))
4714 return rc;
4715#endif
4716
4717#endif /* CONFIG_BOCHS_VBE */
4718 }
4719
4720 /* vga mmio */
4721 rc = PDMDevHlpMMIORegister(pDevIns, 0x000a0000, 0x00020000, 0, vgaMMIOWrite, vgaMMIORead, vgaMMIOFill, "VGA - VGA Video Buffer");
4722 if (VBOX_FAILURE(rc))
4723 return rc;
4724 if (pData->fGCEnabled)
4725 {
4726 rc = PDMDevHlpMMIORegisterGC(pDevIns, 0x000a0000, 0x00020000, 0, "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill", "VGA - VGA Video Buffer");
4727 if (VBOX_FAILURE(rc))
4728 return rc;
4729 }
4730 if (pData->fR0Enabled)
4731 {
4732 rc = PDMDevHlpMMIORegisterR0(pDevIns, 0x000a0000, 0x00020000, 0, "vgaMMIOWrite", "vgaMMIORead", "vgaMMIOFill", "VGA - VGA Video Buffer");
4733 if (VBOX_FAILURE(rc))
4734 return rc;
4735 }
4736
4737 /* vga bios */
4738 rc = PDMDevHlpIOPortRegister(pDevIns, VBE_PRINTF_PORT, 1, NULL, vgaIOPortWriteBIOS, vgaIOPortReadBIOS, NULL, NULL, "VGA BIOS debug/panic");
4739 if (VBOX_FAILURE(rc))
4740 return rc;
4741 AssertReleaseMsg(g_cbVgaBiosBinary <= _64K && g_cbVgaBiosBinary >= 32*_1K, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
4742 AssertReleaseMsg(RT_ALIGN_Z(g_cbVgaBiosBinary, PAGE_SIZE) == g_cbVgaBiosBinary, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
4743 rc = PDMDevHlpROMRegister(pDevIns, 0x000c0000, g_cbVgaBiosBinary, &g_abVgaBiosBinary[0],
4744 false /* fShadow */, "VGA BIOS");
4745 if (VBOX_FAILURE(rc))
4746 return rc;
4747
4748 /* save */
4749 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, 1 /* version */, sizeof(*pData),
4750 NULL, vgaR3SaveExec, NULL,
4751 NULL, vgaR3LoadExec, NULL);
4752 if (VBOX_FAILURE(rc))
4753 return rc;
4754
4755 /* PCI */
4756 rc = PDMDevHlpPCIRegister(pDevIns, &pData->Dev);
4757 if (VBOX_FAILURE(rc))
4758 return rc;
4759 /*AssertMsg(pData->Dev.devfn == 16 || iInstance != 0, ("pData->Dev.devfn=%d\n", pData->Dev.devfn));*/
4760 if (pData->Dev.devfn != 16 && iInstance == 0)
4761 Log(("!!WARNING!!: pData->dev.devfn=%d (ignore if testcase or no started by Main)\n", pData->Dev.devfn));
4762 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, pData->vram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vgaR3IORegionMap);
4763 if (VBOX_FAILURE(rc))
4764 return rc;
4765
4766 /*
4767 * Create the refresh timer.
4768 */
4769 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, vgaTimerRefresh, "VGA Refresh Timer", &pData->RefreshTimer);
4770 if (VBOX_FAILURE(rc))
4771 return rc;
4772
4773 /*
4774 * Attach to the display.
4775 */
4776 rc = vgaAttach(pDevIns, 0 /* display LUN # */);
4777 if (VBOX_FAILURE(rc))
4778 return rc;
4779
4780 /*
4781 * Allocate the VRAM.
4782 */
4783 rc = SUPPageAlloc(pData->vram_size >> PAGE_SHIFT, (void **)&pData->vram_ptrHC);
4784 if (VBOX_FAILURE(rc))
4785 {
4786 AssertMsgFailed(("SUPPageAlloc(%#x,) -> %d\n", pData->vram_size, rc));
4787 return rc;
4788 }
4789
4790#ifdef VBE_NEW_DYN_LIST
4791 /*
4792 * Compute buffer size for the VBE BIOS Extra Data.
4793 */
4794 cb = sizeof(mode_info_list) + sizeof(ModeInfoListItem);
4795
4796 rc = CFGMR3QueryU32(pCfgHandle, "HeightReduction", &cyReduction);
4797 if (VBOX_SUCCESS(rc) && cyReduction)
4798 cb *= 2; /* Default mode list will be twice long */
4799 else
4800 cyReduction = 0;
4801
4802 rc = CFGMR3QueryU32(pCfgHandle, "CustomVideoModes", &cCustomModes);
4803 if (VBOX_SUCCESS(rc) && cCustomModes)
4804 cb += sizeof(ModeInfoListItem) * cCustomModes;
4805 else
4806 cCustomModes = 0;
4807
4808 /*
4809 * Allocate and initialize buffer for the VBE BIOS Extra Data.
4810 */
4811 pData->cbVBEExtraData = sizeof(VBEHEADER) + cb;
4812 pData->pu8VBEExtraData = (uint8_t *)PDMDevHlpMMHeapAllocZ(pDevIns, pData->cbVBEExtraData);
4813 if (!pData->pu8VBEExtraData)
4814 return VERR_NO_MEMORY;
4815
4816 pVBEDataHdr = (PVBEHEADER)pData->pu8VBEExtraData;
4817 pVBEDataHdr->u16Signature = VBEHEADER_MAGIC;
4818 pVBEDataHdr->cbData = cb;
4819
4820#ifndef VRAM_SIZE_FIX
4821 pCurMode = memcpy(pVBEDataHdr + 1, &mode_info_list, sizeof(mode_info_list));
4822 pCurMode = (ModeInfoListItem *)((uintptr_t)pCurMode + sizeof(mode_info_list));
4823#else /* VRAM_SIZE_FIX defined */
4824 pCurMode = (ModeInfoListItem *)(pVBEDataHdr + 1);
4825 for (i = 0; i < MODE_INFO_SIZE; i++)
4826 {
4827 uint32_t pixelWidth, reqSize;
4828 if (mode_info_list[i].info.MemoryModel == VBE_MEMORYMODEL_TEXT_MODE)
4829 pixelWidth = 2;
4830 else
4831 pixelWidth = mode_info_list[i].info.BitsPerPixel / 8;
4832 reqSize = mode_info_list[i].info.XResolution
4833 * mode_info_list[i].info.YResolution
4834 * pixelWidth;
4835 if (reqSize >= pData->vram_size)
4836 continue;
4837 *pCurMode = mode_info_list[i];
4838 pCurMode++;
4839 }
4840#endif /* VRAM_SIZE_FIX defined */
4841
4842 /*
4843 * Copy default modes with subtractred YResolution.
4844 */
4845 if (cyReduction)
4846 {
4847 ModeInfoListItem *pDefMode = mode_info_list;
4848 Log(("vgaR3Construct: cyReduction=%u\n", cyReduction));
4849#ifndef VRAM_SIZE_FIX
4850 for (i = 0; i < MODE_INFO_SIZE; i++, pCurMode++, pDefMode++)
4851 {
4852 *pCurMode = *pDefMode;
4853 pCurMode->mode += 0x30;
4854 pCurMode->info.YResolution -= cyReduction;
4855 }
4856#else /* VRAM_SIZE_FIX defined */
4857 for (i = 0; i < MODE_INFO_SIZE; i++, pDefMode++)
4858 {
4859 uint32_t pixelWidth, reqSize;
4860 if (pDefMode->info.MemoryModel == VBE_MEMORYMODEL_TEXT_MODE)
4861 pixelWidth = 2;
4862 else
4863 pixelWidth = pDefMode->info.BitsPerPixel / 8;
4864 reqSize = pDefMode->info.XResolution * pDefMode->info.YResolution * pixelWidth;
4865 if (reqSize >= pData->vram_size)
4866 continue;
4867 *pCurMode = *pDefMode;
4868 pCurMode->mode += 0x30;
4869 pCurMode->info.YResolution -= cyReduction;
4870 pCurMode++;
4871 }
4872#endif /* VRAM_SIZE_FIX defined */
4873 }
4874
4875
4876 /*
4877 * Add custom modes.
4878 */
4879 if (cCustomModes)
4880 {
4881 uint16_t u16CurMode = 0x160;
4882 for (i = 1; i <= cCustomModes; i++)
4883 {
4884 char szExtraDataKey[sizeof("CustomVideoModeXX")];
4885 char *pszExtraData = NULL;
4886
4887 /* query and decode the custom mode string. */
4888 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%d", i);
4889 rc = CFGMR3QueryStringAlloc(pCfgHandle, szExtraDataKey, &pszExtraData);
4890 if (VBOX_SUCCESS(rc))
4891 {
4892 ModeInfoListItem *pDefMode = mode_info_list;
4893 unsigned int cx, cy, cBits, cParams;
4894 uint16_t u16DefMode;
4895
4896 cParams = sscanf(pszExtraData, "%ux%ux%u", &cx, &cy, &cBits);
4897 if ( cParams != 3
4898 || (cBits != 16 && cBits != 24 && cBits != 32))
4899 {
4900 AssertMsgFailed(("Configuration error: Invalid mode data '%s' for '%s'! cBits=%d\n", pszExtraData, szExtraDataKey, cBits));
4901 return VERR_VGA_INVALID_CUSTOM_MODE;
4902 }
4903#ifdef VRAM_SIZE_FIX
4904 if (cx * cy * cBits / 8 >= pData->vram_size)
4905 {
4906 AssertMsgFailed(("Configuration error: custom video mode %dx%dx%dbits is too large for the virtual video memory of %dMb. Please increase the video memory size.\n",
4907 cx, cy, cBits, pData->vram_size / _1M));
4908 return VERR_VGA_INVALID_CUSTOM_MODE;
4909 }
4910#endif /* VRAM_SIZE_FIX defined */
4911 MMR3HeapFree(pszExtraData);
4912
4913 /* Use defaults from max@bpp mode. */
4914 switch (cBits)
4915 {
4916 case 16:
4917 u16DefMode = VBE_VESA_MODE_1024X768X565;
4918 break;
4919
4920 case 24:
4921 u16DefMode = VBE_VESA_MODE_1024X768X888;
4922 break;
4923
4924 case 32:
4925 u16DefMode = VBE_OWN_MODE_1024X768X8888;
4926 break;
4927
4928 default: /* gcc, shut up! */
4929 AssertMsgFailed(("gone postal!\n"));
4930 continue;
4931 }
4932
4933 while ( pDefMode->mode != u16DefMode
4934 && pDefMode->mode != VBE_VESA_MODE_END_OF_LIST)
4935 pDefMode++;
4936 Assert(pDefMode->mode != VBE_VESA_MODE_END_OF_LIST);
4937
4938 *pCurMode = *pDefMode;
4939 pCurMode->mode = u16CurMode++;
4940
4941 /* adjust defaults */
4942 pCurMode->info.XResolution = cx;
4943 pCurMode->info.YResolution = cy;
4944
4945 switch (cBits)
4946 {
4947 case 16:
4948 pCurMode->info.BytesPerScanLine = cx * 2;
4949 pCurMode->info.LinBytesPerScanLine = cx * 2;
4950 break;
4951
4952 case 24:
4953 pCurMode->info.BytesPerScanLine = cx * 3;
4954 pCurMode->info.LinBytesPerScanLine = cx * 3;
4955 break;
4956
4957 case 32:
4958 pCurMode->info.BytesPerScanLine = cx * 4;
4959 pCurMode->info.LinBytesPerScanLine = cx * 4;
4960 break;
4961 }
4962
4963 /* commit it */
4964 pCurMode++;
4965 }
4966 else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
4967 {
4968 AssertMsgFailed(("CFGMR3QueryStringAlloc(,'%s',) -> %Vrc\n", szExtraDataKey, rc));
4969 return rc;
4970 }
4971 } /* foreach custom mode key */
4972 }
4973
4974 /*
4975 * Add the "End of list" mode.
4976 */
4977 memset(pCurMode, 0, sizeof(*pCurMode));
4978 pCurMode->mode = VBE_VESA_MODE_END_OF_LIST;
4979
4980 /*
4981 * Register I/O Port for the VBE BIOS Extra Data.
4982 */
4983 rc = PDMDevHlpIOPortRegister(pDevIns, VBE_EXTRA_PORT, 1, NULL, vbeIOPortWriteVBEExtra, vbeIOPortReadVBEExtra, NULL, NULL, "VBE BIOS Extra Data");
4984 if (VBOX_FAILURE(rc))
4985 return rc;
4986#endif
4987
4988 /*
4989 * Statistics.
4990 */
4991 STAM_REG(pVM, &pData->StatGCMemoryRead, STAMTYPE_PROFILE, "/Devices/VGA/GC/Memory/Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryRead() body.");
4992 STAM_REG(pVM, &pData->StatGCMemoryWrite, STAMTYPE_PROFILE, "/Devices/VGA/GC/Memory/Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCMemoryWrite() body.");
4993 STAM_REG(pVM, &pData->StatGCIOPortRead, STAMTYPE_PROFILE, "/Devices/VGA/GC/IOPort/Read", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCIOPortRead() body.");
4994 STAM_REG(pVM, &pData->StatGCIOPortWrite, STAMTYPE_PROFILE, "/Devices/VGA/GC/IOPort/Write", STAMUNIT_TICKS_PER_CALL, "Profiling of the VGAGCIOPortWrite() body.");
4995
4996 return VINF_SUCCESS;
4997}
4998
4999
5000/**
5001 * Destruct a device instance.
5002 *
5003 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
5004 * resources can be freed correctly.
5005 *
5006 * @param pDevIns The device instance data.
5007 */
5008static DECLCALLBACK(int) vgaR3Destruct(PPDMDEVINS pDevIns)
5009{
5010#ifdef VBE_NEW_DYN_LIST
5011 PVGASTATE pData = PDMINS2DATA(pDevIns, PVGASTATE);
5012 LogFlow(("vgaR3Destruct:\n"));
5013
5014 /*
5015 * Free MM heap pointers.
5016 */
5017 if (pData->pu8VBEExtraData)
5018 {
5019 MMR3HeapFree(pData->pu8VBEExtraData);
5020 pData->pu8VBEExtraData = NULL;
5021 }
5022#endif
5023
5024#if 0 /** @todo r=bird: We can't free the buffer here because it's still locked.
5025 * (That's the reason why we didn't do it earlier.) */
5026 /*
5027 * Free the VRAM.
5028 */
5029 int rc = SUPPageFree(pData->vram_ptrHC, pData->vram_size >> PAGE_SHIFT);
5030 if (VBOX_FAILURE(rc))
5031 {
5032 AssertMsgFailed(("SUPPageFree(%p, %#x) -> %d\n", pData->vram_ptrHC, pData->vram_size, rc));
5033 return rc;
5034 }
5035 pData->vram_ptrHC = NULL;
5036#endif
5037
5038 return VINF_SUCCESS;
5039}
5040
5041
5042/**
5043 * The device registration structure.
5044 */
5045const PDMDEVREG g_DeviceVga =
5046{
5047 /* u32Version */
5048 PDM_DEVREG_VERSION,
5049 /* szDeviceName */
5050 "vga",
5051 /* szGCMod */
5052 "VBoxDDGC.gc",
5053 /* szR0Mod */
5054 "VBoxDDR0.r0",
5055 /* pszDescription */
5056 "VGA Adaptor with VESA extensions.",
5057 /* fFlags */
5058 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
5059 /* fClass */
5060 PDM_DEVREG_CLASS_GRAPHICS,
5061 /* cMaxInstances */
5062 1,
5063 /* cbInstance */
5064 sizeof(VGASTATE),
5065 /* pfnConstruct */
5066 vgaR3Construct,
5067 /* pfnDestruct */
5068 vgaR3Destruct,
5069 /* pfnRelocate */
5070 vgaR3Relocate,
5071 /* pfnIOCtl */
5072 NULL,
5073 /* pfnPowerOn */
5074 NULL,
5075 /* pfnReset */
5076 vgaR3Reset,
5077 /* pfnSuspend */
5078 NULL,
5079 /* pfnResume */
5080 NULL,
5081 /* pfnAttach */
5082 vgaAttach,
5083 /* pfnDetach */
5084 vgaDetach,
5085 /* pfnQueryInterface */
5086 NULL,
5087 /* pfnInitComplete */
5088 NULL
5089};
5090
5091#endif /* !IN_RING3 */
5092#endif /* VBOX */
5093#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
5094
5095/*
5096 * Local Variables:
5097 * nuke-trailing-whitespace-p:nil
5098 * End:
5099 */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette