VirtualBox

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

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

the string of valid CFG options in CFGMR3AreValuesValid() should be terminated with \0

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