VirtualBox

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

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

In DevVGA the line width in bytes was incorrectly calculated for non 32 bit video modes.

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