VirtualBox

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

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

64-bit alignment. HCPTRTYPE -> R3PTRTYPE. And an question for Frank.

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