VirtualBox

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

Last change on this file since 473 was 473, checked in by vboxsync, 18 years ago

several small fixes merged from upstream

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