1 /////////////////////////////////////////////////////////////////////////
2 // $Id: vga.cc 14286 2021-06-20 07:30:29Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 //  Copyright (C) 2002-2021  The Bochs Project
6 //  PCI VGA dummy adapter Copyright (C) 2002,2003  Mike Nordell
7 //
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 //  You should have received a copy of the GNU Lesser General Public
19 //  License along with this library; if not, write to the Free Software
20 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
21 //
22 /////////////////////////////////////////////////////////////////////////
23 
24 // Standard VGA emulation + Bochs VBE support + PCI VGA interface
25 
26 // NOTE from the original pcivga code:
27 // This "driver" was created for the SOLE PURPOSE of getting BeOS
28 // to boot. It currently does NOTHING more than presenting a generic VGA
29 // device on the PCI bus. ALL gfx in/out-put is still handled by the VGA code.
30 // Furthermore, almost all of the PCI registers are currently acting like RAM.
31 
32 // Define BX_PLUGGABLE in files that can be compiled into plugins.  For
33 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
34 // is used to know when we are exporting symbols and when we are importing.
35 #define BX_PLUGGABLE
36 
37 #include "iodev.h"
38 #include "vgacore.h"
39 #include "ddc.h"
40 #include "vga.h"
41 #include "virt_timer.h"
42 
43 #define LOG_THIS theVga->
44 
45 bx_vga_c *theVga = NULL;
46 
PLUGIN_ENTRY_FOR_MODULE(vga)47 PLUGIN_ENTRY_FOR_MODULE(vga)
48 {
49   if (mode == PLUGIN_INIT) {
50     theVga = new bx_vga_c();
51     bx_devices.pluginVgaDevice = theVga;
52     BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theVga, BX_PLUGIN_VGA);
53   } else if (mode == PLUGIN_FINI) {
54     delete theVga;
55   } else if (mode == PLUGIN_PROBE) {
56     return (int)PLUGTYPE_VGA;
57   } else if (mode == PLUGIN_FLAGS) {
58     return PLUGFLAG_PCI;
59   }
60   return 0; // Success
61 }
62 
bx_vga_c()63 bx_vga_c::bx_vga_c() : bx_vgacore_c()
64 {
65   put("VGA");
66 }
67 
~bx_vga_c()68 bx_vga_c::~bx_vga_c()
69 {
70   SIM->get_bochs_root()->remove("vga");
71   BX_DEBUG(("Exit"));
72 }
73 
init_vga_extension(void)74 bool bx_vga_c::init_vga_extension(void)
75 {
76   unsigned addr;
77   bool ret = 0;
78 
79   BX_VGA_THIS init_iohandlers(read_handler, write_handler);
80   BX_VGA_THIS pci_enabled = SIM->is_pci_device("pcivga");
81 
82   // The following is for the VBE display extension
83   BX_VGA_THIS vbe_present = 0;
84   BX_VGA_THIS vbe.enabled = 0;
85   BX_VGA_THIS vbe.dac_8bit = 0;
86   BX_VGA_THIS vbe.ddc_enabled = 0;
87   BX_VGA_THIS vbe.base_address = 0x0000;
88   if (!strcmp(BX_VGA_THIS vga_ext->get_selected(), "vbe")) {
89     BX_VGA_THIS put("BXVGA");
90     for (addr=VBE_DISPI_IOPORT_INDEX; addr<=VBE_DISPI_IOPORT_DATA; addr++) {
91       DEV_register_ioread_handler(this, vbe_read_handler, addr, "vga video", 7);
92       DEV_register_iowrite_handler(this, vbe_write_handler, addr, "vga video", 7);
93     }
94     if (!BX_VGA_THIS pci_enabled) {
95       BX_VGA_THIS vbe.base_address = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
96       DEV_register_memory_handlers(theVga, mem_read_handler, mem_write_handler,
97                                    BX_VGA_THIS vbe.base_address,
98                                    BX_VGA_THIS vbe.base_address + VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES - 1);
99     }
100     if (BX_VGA_THIS s.memory == NULL)
101       BX_VGA_THIS s.memory = new Bit8u[VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES];
102     memset(BX_VGA_THIS s.memory, 0, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES);
103     BX_VGA_THIS s.memsize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
104     BX_VGA_THIS vbe.cur_dispi=VBE_DISPI_ID0;
105     BX_VGA_THIS vbe.xres=640;
106     BX_VGA_THIS vbe.yres=480;
107     BX_VGA_THIS vbe.bpp=8;
108     BX_VGA_THIS vbe.bank[0] = 0;
109     BX_VGA_THIS vbe.bank[1] = 0;
110     BX_VGA_THIS vbe.bank_granularity_kb=64;
111     BX_VGA_THIS vbe.curindex=0;
112     BX_VGA_THIS vbe.offset_x=0;
113     BX_VGA_THIS vbe.offset_y=0;
114     BX_VGA_THIS vbe.virtual_xres=640;
115     BX_VGA_THIS vbe.virtual_yres=480;
116     BX_VGA_THIS vbe.bpp_multiplier=1;
117     BX_VGA_THIS vbe.virtual_start=0;
118     BX_VGA_THIS vbe.get_capabilities=0;
119     BX_VGA_THIS vbe.max_xres=VBE_DISPI_MAX_XRES;
120     BX_VGA_THIS vbe.max_yres=VBE_DISPI_MAX_YRES;
121     BX_VGA_THIS vbe.max_bpp=VBE_DISPI_MAX_BPP;
122     BX_VGA_THIS s.max_xres = BX_VGA_THIS vbe.max_xres;
123     BX_VGA_THIS s.max_yres = BX_VGA_THIS vbe.max_yres;
124     BX_VGA_THIS vbe_present = 1;
125     ret = 1;
126 
127     BX_INFO(("VBE Bochs Display Extension Enabled"));
128   }
129 #if BX_SUPPORT_PCI
130   Bit8u devfunc = 0x00;
131 
132   if (BX_VGA_THIS pci_enabled) {
133     DEV_register_pci_handlers(this, &devfunc, "pcivga", "Experimental PCI VGA");
134 
135     // initialize readonly registers
136     // Note that the values for vendor and device id are selected at random!
137     // There might actually be "real" values for "experimental" vendor and
138     // device that should be used!
139     init_pci_conf(0x1234, 0x1111, 0x00, 0x030000, 0x00, 0);
140 
141     if (BX_VGA_THIS vbe_present) {
142       BX_VGA_THIS pci_conf[0x10] = 0x08;
143       BX_VGA_THIS init_bar_mem(0, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES,
144                                mem_read_handler, mem_write_handler);
145     }
146     BX_VGA_THIS pci_rom_address = 0;
147     BX_VGA_THIS pci_rom_read_handler = mem_read_handler;
148     BX_VGA_THIS load_pci_rom(SIM->get_param_string(BXPN_VGA_ROM_PATH)->getptr());
149   }
150 #endif
151 #if BX_DEBUGGER
152   // register device for the 'info device' command (calls debug_dump())
153   bx_dbg_register_debug_info("vga", this);
154 #endif
155   return ret;
156 }
157 
reset(unsigned type)158 void bx_vga_c::reset(unsigned type)
159 {
160 #if BX_SUPPORT_PCI
161   if (BX_VGA_THIS pci_enabled) {
162     static const struct reset_vals_t {
163       unsigned      addr;
164       unsigned char val;
165     } reset_vals[] = {
166         { 0x04, 0x03 }, { 0x05, 0x00 }, // command_io + command_mem
167         { 0x06, 0x00 }, { 0x07, 0x02 }  // status_devsel_medium
168     };
169     for (unsigned i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
170       BX_VGA_THIS pci_conf[reset_vals[i].addr] = reset_vals[i].val;
171     }
172   }
173 #endif
174 }
175 
register_state(void)176 void bx_vga_c::register_state(void)
177 {
178   bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "vga", "VGA Adapter State");
179   BX_VGA_THIS vgacore_register_state(list);
180 #if BX_SUPPORT_PCI
181   if (BX_VGA_THIS pci_enabled) {
182     register_pci_state(list);
183   }
184 #endif
185   // register state for Bochs VBE
186   if (BX_VGA_THIS vbe_present) {
187     bx_list_c *vbe = new bx_list_c(list, "vbe");
188     new bx_shadow_num_c(vbe, "cur_dispi", &BX_VGA_THIS vbe.cur_dispi, BASE_HEX);
189     new bx_shadow_num_c(vbe, "xres", &BX_VGA_THIS vbe.xres);
190     new bx_shadow_num_c(vbe, "yres", &BX_VGA_THIS vbe.yres);
191     new bx_shadow_num_c(vbe, "bpp", &BX_VGA_THIS vbe.bpp);
192     new bx_shadow_num_c(vbe, "bank0", &BX_VGA_THIS vbe.bank[0]);
193     new bx_shadow_num_c(vbe, "bank1", &BX_VGA_THIS vbe.bank[1]);
194     new bx_shadow_num_c(vbe, "bank_granularity_kb", &BX_VGA_THIS vbe.bank_granularity_kb);
195     BXRS_PARAM_BOOL(vbe, enabled, BX_VGA_THIS vbe.enabled);
196     new bx_shadow_num_c(vbe, "curindex", &BX_VGA_THIS vbe.curindex);
197     new bx_shadow_num_c(vbe, "visible_screen_size", &BX_VGA_THIS vbe.visible_screen_size);
198     new bx_shadow_num_c(vbe, "offset_x", &BX_VGA_THIS vbe.offset_x);
199     new bx_shadow_num_c(vbe, "offset_y", &BX_VGA_THIS vbe.offset_y);
200     new bx_shadow_num_c(vbe, "virtual_xres", &BX_VGA_THIS vbe.virtual_xres);
201     new bx_shadow_num_c(vbe, "virtual_yres", &BX_VGA_THIS vbe.virtual_yres);
202     new bx_shadow_num_c(vbe, "virtual_start", &BX_VGA_THIS vbe.virtual_start);
203     new bx_shadow_num_c(vbe, "bpp_multiplier", &BX_VGA_THIS vbe.bpp_multiplier);
204     BXRS_PARAM_BOOL(vbe, get_capabilities, BX_VGA_THIS vbe.get_capabilities);
205     BXRS_PARAM_BOOL(vbe, dac_8bit, BX_VGA_THIS vbe.dac_8bit);
206     BXRS_PARAM_BOOL(vbe, ddc_enabled, BX_VGA_THIS vbe.ddc_enabled);
207   }
208 }
209 
after_restore_state(void)210 void bx_vga_c::after_restore_state(void)
211 {
212   bx_vgacore_c::after_restore_state();
213 #if BX_SUPPORT_PCI
214   if (BX_VGA_THIS pci_enabled) {
215     bx_pci_device_c::after_restore_pci_state(mem_read_handler);
216   }
217 #endif
218   if (BX_VGA_THIS vbe.enabled) {
219     bx_gui->dimension_update(BX_VGA_THIS vbe.xres, BX_VGA_THIS vbe.yres, 0, 0,
220                              BX_VGA_THIS vbe.bpp);
221   }
222 }
223 
224 // static IO port write callback handler
225 // redirects to non-static class handler to avoid virtual functions
226 
write_handler(void * this_ptr,Bit32u address,Bit32u value,unsigned io_len)227 void bx_vga_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
228 {
229 #if BX_USE_VGA_SMF == 0
230   bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
231   class_ptr->write(address, value, io_len, 0);
232 #else
233   UNUSED(this_ptr);
234   theVga->write(address, value, io_len, 0);
235 #endif
236 }
237 
238 #if BX_USE_VGA_SMF
write_handler_no_log(void * this_ptr,Bit32u address,Bit32u value,unsigned io_len)239 void bx_vga_c::write_handler_no_log(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
240 {
241   UNUSED(this_ptr);
242   theVga->write(address, value, io_len, 1);
243 }
244 #endif
245 
write(Bit32u address,Bit32u value,unsigned io_len,bool no_log)246 void bx_vga_c::write(Bit32u address, Bit32u value, unsigned io_len, bool no_log)
247 {
248   if (io_len == 2) {
249 #if BX_USE_VGA_SMF
250     bx_vga_c::write_handler_no_log(0, address, value & 0xff, 1);
251     bx_vga_c::write_handler_no_log(0, address+1, (value >> 8) & 0xff, 1);
252 #else
253     bx_vga_c::write(address, value & 0xff, 1, 1);
254     bx_vga_c::write(address+1, (value >> 8) & 0xff, 1, 1);
255 #endif
256     return;
257   }
258 
259   if ((address >= 0x03b0) && (address <= 0x03bf) &&
260       (BX_VGA_THIS s.misc_output.color_emulation))
261     return;
262   if ((address >= 0x03d0) && (address <= 0x03df) &&
263       (BX_VGA_THIS s.misc_output.color_emulation==0))
264     return;
265 
266   switch (address) {
267     case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
268     case 0x03d5: /* CRTC Registers (color emulation modes) */
269       if (BX_VGA_THIS s.CRTC.address > 0x18) {
270         BX_DEBUG(("write: invalid CRTC register 0x%02x ignored",
271           (unsigned) BX_VGA_THIS s.CRTC.address));
272         return;
273       }
274       if (value != BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]) {
275         switch (BX_VGA_THIS s.CRTC.address) {
276           case 0x13:
277           case 0x14:
278           case 0x17:
279             if (!BX_VGA_THIS vbe.enabled || (BX_VGA_THIS vbe.bpp == VBE_DISPI_BPP_4)) {
280               // Line offset change
281               bx_vgacore_c::write(address, value, io_len, no_log);
282             } else {
283               BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] = value;
284             }
285             break;
286           default:
287             bx_vgacore_c::write(address, value, io_len, no_log);
288         }
289       }
290       break;
291     default:
292       bx_vgacore_c::write(address, value, io_len, no_log);
293   }
294 }
295 
update(void)296 void bx_vga_c::update(void)
297 {
298   unsigned iHeight, iWidth;
299 
300   if (BX_VGA_THIS vbe.enabled) {
301     /* no screen update necessary */
302     if ((BX_VGA_THIS s.vga_mem_updated==0) && BX_VGA_THIS s.graphics_ctrl.graphics_alpha)
303       return;
304 
305     /* skip screen update when vga/video is disabled or the sequencer is in reset mode */
306     if (!BX_VGA_THIS s.vga_enabled || !BX_VGA_THIS s.attribute_ctrl.video_enabled
307         || !BX_VGA_THIS s.sequencer.reset2 || !BX_VGA_THIS s.sequencer.reset1
308         || (BX_VGA_THIS s.sequencer.reg1 & 0x20))
309       return;
310 
311     /* skip screen update if the vertical retrace is in progress
312        (using 72 Hz vertical frequency) */
313     if ((bx_virt_timer.time_usec(BX_VGA_THIS vsync_realtime) % 13888) < 70)
314       return;
315 
316     if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
317       // specific VBE code display update code
318       unsigned pitch;
319       unsigned xc, yc, xti, yti;
320       unsigned r, c, w, h;
321       int i;
322       unsigned long red, green, blue, colour;
323       Bit8u * vid_ptr, * vid_ptr2;
324       Bit8u * tile_ptr, * tile_ptr2;
325       bx_svga_tileinfo_t info;
326       Bit8u dac_size = BX_VGA_THIS vbe.dac_8bit ? 8 : 6;
327 
328       iWidth=BX_VGA_THIS vbe.xres;
329       iHeight=BX_VGA_THIS vbe.yres;
330       pitch = BX_VGA_THIS s.line_offset;
331       Bit8u *disp_ptr = &BX_VGA_THIS s.memory[BX_VGA_THIS vbe.virtual_start];
332 
333       if (bx_gui->graphics_tile_info_common(&info)) {
334         if (info.snapshot_mode) {
335           vid_ptr = disp_ptr;
336           tile_ptr = bx_gui->get_snapshot_buffer();
337           if (tile_ptr != NULL) {
338             for (yc = 0; yc < iHeight; yc++) {
339               memcpy(tile_ptr, vid_ptr, info.pitch);
340               vid_ptr += pitch;
341               tile_ptr += info.pitch;
342             }
343           }
344         } else if (info.is_indexed) {
345           switch (BX_VGA_THIS vbe.bpp) {
346             case 4:
347             case 15:
348             case 16:
349             case 24:
350             case 32:
351               BX_ERROR(("current guest pixel format is unsupported on indexed colour host displays"));
352               break;
353             case 8:
354               for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
355                 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
356                   if (GET_TILE_UPDATED (xti, yti)) {
357                     vid_ptr = disp_ptr + (yc * pitch + xc);
358                     tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
359                     for (r=0; r<h; r++) {
360                       vid_ptr2  = vid_ptr;
361                       tile_ptr2 = tile_ptr;
362                       for (c=0; c<w; c++) {
363                         colour = 0;
364                         for (i=0; i<(int)BX_VGA_THIS vbe.bpp; i+=8) {
365                           colour |= *(vid_ptr2++) << i;
366                         }
367                         if (info.is_little_endian) {
368                           for (i=0; i<info.bpp; i+=8) {
369                             *(tile_ptr2++) = (Bit8u)(colour >> i);
370                           }
371                         } else {
372                           for (i=info.bpp-8; i>-8; i-=8) {
373                             *(tile_ptr2++) = (Bit8u)(colour >> i);
374                           }
375                         }
376                       }
377                       vid_ptr  += pitch;
378                       tile_ptr += info.pitch;
379                     }
380                     bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
381                     SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
382                   }
383                 }
384               }
385               break;
386           }
387         } else {
388           switch (BX_VGA_THIS vbe.bpp) {
389             case 4:
390               BX_ERROR(("cannot draw 4bpp SVGA"));
391               break;
392             case 8:
393               for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
394                 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
395                   if (GET_TILE_UPDATED (xti, yti)) {
396                     vid_ptr = disp_ptr + (yc * pitch + xc);
397                     tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
398                     for (r=0; r<h; r++) {
399                       vid_ptr2  = vid_ptr;
400                       tile_ptr2 = tile_ptr;
401                       for (c=0; c<w; c++) {
402                         colour = *(vid_ptr2++);
403                         colour = MAKE_COLOUR(
404                           BX_VGA_THIS s.pel.data[colour].red, dac_size, info.red_shift, info.red_mask,
405                           BX_VGA_THIS s.pel.data[colour].green, dac_size, info.green_shift, info.green_mask,
406                           BX_VGA_THIS s.pel.data[colour].blue, dac_size, info.blue_shift, info.blue_mask);
407                         if (info.is_little_endian) {
408                           for (i=0; i<info.bpp; i+=8) {
409                             *(tile_ptr2++) = (Bit8u)(colour >> i);
410                           }
411                         } else {
412                           for (i=info.bpp-8; i>-8; i-=8) {
413                             *(tile_ptr2++) = (Bit8u)(colour >> i);
414                           }
415                         }
416                       }
417                       vid_ptr  += pitch;
418                       tile_ptr += info.pitch;
419                     }
420                     bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
421                     SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
422                   }
423                 }
424               }
425               break;
426             case 15:
427               for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
428                 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
429                   if (GET_TILE_UPDATED (xti, yti)) {
430                     vid_ptr = disp_ptr + (yc * pitch + (xc<<1));
431                     tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
432                     for (r=0; r<h; r++) {
433                       vid_ptr2  = vid_ptr;
434                       tile_ptr2 = tile_ptr;
435                       for (c=0; c<w; c++) {
436                         colour = *(vid_ptr2++);
437                         colour |= *(vid_ptr2++) << 8;
438                         colour = MAKE_COLOUR(
439                           colour & 0x001f, 5, info.blue_shift, info.blue_mask,
440                           colour & 0x03e0, 10, info.green_shift, info.green_mask,
441                           colour & 0x7c00, 15, info.red_shift, info.red_mask);
442                         if (info.is_little_endian) {
443                           for (i=0; i<info.bpp; i+=8) {
444                             *(tile_ptr2++) = (Bit8u)(colour >> i);
445                           }
446                         } else {
447                           for (i=info.bpp-8; i>-8; i-=8) {
448                             *(tile_ptr2++) = (Bit8u)(colour >> i);
449                           }
450                         }
451                       }
452                       vid_ptr  += pitch;
453                       tile_ptr += info.pitch;
454                     }
455                     bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
456                     SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
457                   }
458                 }
459               }
460               break;
461             case 16:
462               for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
463                 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
464                   if (GET_TILE_UPDATED (xti, yti)) {
465                     vid_ptr = disp_ptr + (yc * pitch + (xc<<1));
466                     tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
467                     for (r=0; r<h; r++) {
468                       vid_ptr2  = vid_ptr;
469                       tile_ptr2 = tile_ptr;
470                       for (c=0; c<w; c++) {
471                         colour = *(vid_ptr2++);
472                         colour |= *(vid_ptr2++) << 8;
473                         colour = MAKE_COLOUR(
474                           colour & 0x001f, 5, info.blue_shift, info.blue_mask,
475                           colour & 0x07e0, 11, info.green_shift, info.green_mask,
476                           colour & 0xf800, 16, info.red_shift, info.red_mask);
477                         if (info.is_little_endian) {
478                           for (i=0; i<info.bpp; i+=8) {
479                             *(tile_ptr2++) = (Bit8u)(colour >> i);
480                           }
481                         } else {
482                           for (i=info.bpp-8; i>-8; i-=8) {
483                             *(tile_ptr2++) = (Bit8u)(colour >> i);
484                           }
485                         }
486                       }
487                       vid_ptr  += pitch;
488                       tile_ptr += info.pitch;
489                     }
490                     bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
491                     SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
492                   }
493                 }
494               }
495               break;
496             case 24:
497               for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
498                 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
499                   if (GET_TILE_UPDATED (xti, yti)) {
500                     vid_ptr = disp_ptr + (yc * pitch + 3*xc);
501                     tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
502                     for (r=0; r<h; r++) {
503                       vid_ptr2  = vid_ptr;
504                       tile_ptr2 = tile_ptr;
505                       for (c=0; c<w; c++) {
506                         blue = *(vid_ptr2++);
507                         green = *(vid_ptr2++);
508                         red = *(vid_ptr2++);
509                         colour = MAKE_COLOUR(
510                           red, 8, info.red_shift, info.red_mask,
511                           green, 8, info.green_shift, info.green_mask,
512                           blue, 8, info.blue_shift, info.blue_mask);
513                         if (info.is_little_endian) {
514                           for (i=0; i<info.bpp; i+=8) {
515                             *(tile_ptr2++) = (Bit8u)(colour >> i);
516                           }
517                         } else {
518                           for (i=info.bpp-8; i>-8; i-=8) {
519                             *(tile_ptr2++) = (Bit8u)(colour >> i);
520                           }
521                         }
522                       }
523                       vid_ptr  += pitch;
524                       tile_ptr += info.pitch;
525                     }
526                     bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
527                     SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
528                   }
529                 }
530               }
531               break;
532             case 32:
533               for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
534                 for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++) {
535                   if (GET_TILE_UPDATED (xti, yti)) {
536                     vid_ptr = disp_ptr + (yc * pitch + (xc<<2));
537                     tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h);
538                     for (r=0; r<h; r++) {
539                       vid_ptr2  = vid_ptr;
540                       tile_ptr2 = tile_ptr;
541                       for (c=0; c<w; c++) {
542                         blue = *(vid_ptr2++);
543                         green = *(vid_ptr2++);
544                         red = *(vid_ptr2++);
545                         vid_ptr2++;
546                         colour = MAKE_COLOUR(
547                           red, 8, info.red_shift, info.red_mask,
548                           green, 8, info.green_shift, info.green_mask,
549                           blue, 8, info.blue_shift, info.blue_mask);
550                         if (info.is_little_endian) {
551                           for (i=0; i<info.bpp; i+=8) {
552                             *(tile_ptr2++) = (Bit8u)(colour >> i);
553                           }
554                         } else {
555                           for (i=info.bpp-8; i>-8; i-=8) {
556                             *(tile_ptr2++) = (Bit8u)(colour >> i);
557                           }
558                         }
559                       }
560                       vid_ptr  += pitch;
561                       tile_ptr += info.pitch;
562                     }
563                     bx_gui->graphics_tile_update_in_place(xc, yc, w, h);
564                     SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
565                   }
566                 }
567               }
568               break;
569           }
570         }
571         BX_VGA_THIS s.last_xres = iWidth;
572         BX_VGA_THIS s.last_yres = iHeight;
573         BX_VGA_THIS s.vga_mem_updated = 0;
574       } else {
575         BX_PANIC(("cannot get svga tile info"));
576       }
577     } else {
578       unsigned r, c, x, y;
579       unsigned xc, yc, xti, yti;
580       Bit8u *plane[4];
581 
582       BX_VGA_THIS determine_screen_dimensions(&iHeight, &iWidth);
583       if ((iWidth != BX_VGA_THIS s.last_xres) || (iHeight != BX_VGA_THIS s.last_yres) ||
584            (BX_VGA_THIS s.last_bpp > 8)) {
585         bx_gui->dimension_update(iWidth, iHeight);
586         BX_VGA_THIS s.last_xres = iWidth;
587         BX_VGA_THIS s.last_yres = iHeight;
588         BX_VGA_THIS s.last_bpp = 8;
589       }
590 
591       plane[0] = &BX_VGA_THIS s.memory[0<<VBE_DISPI_4BPP_PLANE_SHIFT];
592       plane[1] = &BX_VGA_THIS s.memory[1<<VBE_DISPI_4BPP_PLANE_SHIFT];
593       plane[2] = &BX_VGA_THIS s.memory[2<<VBE_DISPI_4BPP_PLANE_SHIFT];
594       plane[3] = &BX_VGA_THIS s.memory[3<<VBE_DISPI_4BPP_PLANE_SHIFT];
595 
596       for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
597         for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
598           if (GET_TILE_UPDATED (xti, yti)) {
599             for (r=0; r<Y_TILESIZE; r++) {
600               y = yc + r;
601               if (BX_VGA_THIS s.y_doublescan) y >>= 1;
602               for (c=0; c<X_TILESIZE; c++) {
603                 x = xc + c;
604                 BX_VGA_THIS s.tile[r*X_TILESIZE + c] =
605                   BX_VGA_THIS get_vga_pixel(x, y, BX_VGA_THIS vbe.virtual_start, 0xffff, 0, plane);
606               }
607             }
608             SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 0);
609             bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc);
610           }
611         }
612       }
613     }
614   } else {
615     BX_VGA_THIS bx_vgacore_c::update();
616   }
617 }
618 
mem_read_handler(bx_phy_address addr,unsigned len,void * data,void * param)619 bool bx_vga_c::mem_read_handler(bx_phy_address addr, unsigned len, void *data, void *param)
620 {
621   Bit8u *data_ptr;
622 #ifdef BX_LITTLE_ENDIAN
623   data_ptr = (Bit8u *) data;
624 #else // BX_BIG_ENDIAN
625   data_ptr = (Bit8u *) data + (len - 1);
626 #endif
627   for (unsigned i = 0; i < len; i++) {
628     *data_ptr = theVga->mem_read(addr);
629     addr++;
630 #ifdef BX_LITTLE_ENDIAN
631     data_ptr++;
632 #else // BX_BIG_ENDIAN
633     data_ptr--;
634 #endif
635   }
636   return 1;
637 }
638 
mem_read(bx_phy_address addr)639 Bit8u bx_vga_c::mem_read(bx_phy_address addr)
640 {
641 #if BX_SUPPORT_PCI
642   if ((BX_VGA_THIS pci_enabled) && (BX_VGA_THIS pci_rom_size > 0)) {
643     Bit32u mask = (BX_VGA_THIS pci_rom_size - 1);
644     if (((Bit32u)addr & ~mask) == BX_VGA_THIS pci_rom_address) {
645       if (BX_VGA_THIS pci_conf[0x30] & 0x01) {
646         return BX_VGA_THIS pci_rom[addr & mask];
647       } else {
648         return 0xff;
649       }
650     }
651   }
652 #endif
653   // if in a vbe enabled mode, read from the vbe_memory
654   if ((BX_VGA_THIS vbe.enabled) && (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4)) {
655     return vbe_mem_read(addr);
656   } else if ((BX_VGA_THIS vbe.base_address != 0) && (addr >= BX_VGA_THIS vbe.base_address)) {
657     return 0xff;
658   }
659 
660   return bx_vgacore_c::mem_read(addr);
661 }
662 
mem_write_handler(bx_phy_address addr,unsigned len,void * data,void * param)663 bool bx_vga_c::mem_write_handler(bx_phy_address addr, unsigned len, void *data, void *param)
664 {
665   Bit8u *data_ptr;
666 #ifdef BX_LITTLE_ENDIAN
667   data_ptr = (Bit8u *) data;
668 #else // BX_BIG_ENDIAN
669   data_ptr = (Bit8u *) data + (len - 1);
670 #endif
671   for (unsigned i = 0; i < len; i++) {
672     theVga->mem_write(addr, *data_ptr);
673     addr++;
674 #ifdef BX_LITTLE_ENDIAN
675     data_ptr++;
676 #else // BX_BIG_ENDIAN
677     data_ptr--;
678 #endif
679   }
680   return 1;
681 }
682 
mem_write(bx_phy_address addr,Bit8u value)683 void bx_vga_c::mem_write(bx_phy_address addr, Bit8u value)
684 {
685   // if in a vbe enabled mode, write to the vbe_memory
686   if ((BX_VGA_THIS vbe.enabled) && (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4)) {
687     vbe_mem_write(addr, value);
688     return;
689   } else if ((BX_VGA_THIS vbe.base_address != 0) && (addr >= BX_VGA_THIS vbe.base_address)) {
690     return;
691   }
692 
693   bx_vgacore_c::mem_write(addr, value);
694 }
695 
redraw_area(unsigned x0,unsigned y0,unsigned width,unsigned height)696 void bx_vga_c::redraw_area(unsigned x0, unsigned y0, unsigned width,
697                            unsigned height)
698 {
699   unsigned xti, yti, xt0, xt1, yt0, yt1, xmax, ymax;
700 
701   if (BX_VGA_THIS vbe.enabled) {
702     BX_VGA_THIS s.vga_mem_updated = 1;
703     xmax = BX_VGA_THIS vbe.xres;
704     ymax = BX_VGA_THIS vbe.yres;
705     xt0 = x0 / X_TILESIZE;
706     yt0 = y0 / Y_TILESIZE;
707     if (x0 < xmax) {
708       xt1 = (x0 + width  - 1) / X_TILESIZE;
709     } else {
710       xt1 = (xmax - 1) / X_TILESIZE;
711     }
712     if (y0 < ymax) {
713       yt1 = (y0 + height - 1) / Y_TILESIZE;
714     } else {
715       yt1 = (ymax - 1) / Y_TILESIZE;
716     }
717     for (yti=yt0; yti<=yt1; yti++) {
718       for (xti=xt0; xti<=xt1; xti++) {
719         SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 1);
720       }
721     }
722 
723   } else {
724     bx_vgacore_c::redraw_area(x0, y0, width, height);
725   }
726 }
727 
728 #if BX_SUPPORT_PCI
pci_bar_change_notify(void)729 void bx_vga_c::pci_bar_change_notify(void)
730 {
731   BX_VGA_THIS vbe.base_address = pci_bar[0].addr;
732 }
733 #endif
734 
735   Bit8u  BX_CPP_AttrRegparmN(1)
vbe_mem_read(bx_phy_address addr)736 bx_vga_c::vbe_mem_read(bx_phy_address addr)
737 {
738   Bit32u offset;
739 
740   if (addr >= BX_VGA_THIS vbe.base_address) {
741     // LFB read
742     offset = (Bit32u)(addr - BX_VGA_THIS vbe.base_address);
743   } else if (addr < 0xB0000) {
744     // banked mode read
745     offset = (Bit32u)(BX_VGA_THIS vbe.bank[1] * (BX_VGA_THIS vbe.bank_granularity_kb << 10) +
746              (addr & 0xffff));
747   } else {
748     // out of bounds read
749     return 0;
750   }
751 
752   // check for out of memory read
753   if (offset > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
754     return 0;
755 
756   return (BX_VGA_THIS s.memory[offset]);
757 }
758 
759   void BX_CPP_AttrRegparmN(2)
vbe_mem_write(bx_phy_address addr,Bit8u value)760 bx_vga_c::vbe_mem_write(bx_phy_address addr, Bit8u value)
761 {
762   Bit32u offset;
763   unsigned x_tileno, y_tileno;
764 
765   if (addr >= BX_VGA_THIS vbe.base_address) {
766     // LFB write
767     offset = (Bit32u)(addr - BX_VGA_THIS vbe.base_address);
768   } else if (addr < 0xB0000) {
769     // banked mode write
770     offset = (Bit32u)(BX_VGA_THIS vbe.bank[0] * (BX_VGA_THIS vbe.bank_granularity_kb << 10) +
771              (addr & 0xffff));
772   } else {
773     // ignore out of bounds write
774     return;
775   }
776 
777   // check for out of memory write
778   if (offset < VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES) {
779     BX_VGA_THIS s.memory[offset] = value;
780   } else {
781     // make sure we don't flood the logfile
782     static int count=0;
783     if (count<100) {
784       count ++;
785       BX_INFO(("VBE_mem_write out of video memory write at %x",offset));
786     }
787   }
788 
789   offset -= BX_VGA_THIS vbe.virtual_start;
790 
791   // only update the UI when writing 'onscreen'
792   if (offset < BX_VGA_THIS vbe.visible_screen_size) {
793     y_tileno = ((offset / BX_VGA_THIS vbe.bpp_multiplier) / BX_VGA_THIS vbe.virtual_xres) / Y_TILESIZE;
794     x_tileno = ((offset / BX_VGA_THIS vbe.bpp_multiplier) % BX_VGA_THIS vbe.virtual_xres) / X_TILESIZE;
795 
796     if ((y_tileno < BX_VGA_THIS s.num_y_tiles) && (x_tileno < BX_VGA_THIS s.num_x_tiles))
797     {
798       BX_VGA_THIS s.vga_mem_updated = 1;
799       SET_TILE_UPDATED(BX_VGA_THIS, x_tileno, y_tileno, 1);
800     }
801   }
802 }
803 
vbe_read_handler(void * this_ptr,Bit32u address,unsigned io_len)804 Bit32u bx_vga_c::vbe_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
805 {
806 #if BX_USE_VGA_SMF == 0
807   bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
808   return class_ptr->vbe_read(address, io_len);
809 }
810 
vbe_read(Bit32u address,unsigned io_len)811 Bit32u bx_vga_c::vbe_read(Bit32u address, unsigned io_len)
812 {
813 #else
814   UNUSED(this_ptr);
815 #endif  // BX_USE_VGA_SMF == 0
816   Bit16u retval = 0;
817 
818 //  BX_INFO(("VBE_read %x (len %x)", address, io_len));
819 
820   if (address==VBE_DISPI_IOPORT_INDEX)
821   {
822     // index register
823     return (Bit32u) BX_VGA_THIS vbe.curindex;
824   }
825   else
826   {
827     // data register read
828 
829     switch (BX_VGA_THIS vbe.curindex)
830     {
831       case VBE_DISPI_INDEX_ID: // Display Interface ID check
832         return BX_VGA_THIS vbe.cur_dispi;
833 
834       case VBE_DISPI_INDEX_XRES: // x resolution
835         if (BX_VGA_THIS vbe.get_capabilities) {
836           return BX_VGA_THIS vbe.max_xres;
837         } else {
838           return BX_VGA_THIS vbe.xres;
839         }
840 
841       case VBE_DISPI_INDEX_YRES: // y resolution
842         if (BX_VGA_THIS vbe.get_capabilities) {
843           return BX_VGA_THIS vbe.max_yres;
844         } else {
845           return BX_VGA_THIS vbe.yres;
846         }
847 
848       case VBE_DISPI_INDEX_BPP: // bpp
849         if (BX_VGA_THIS vbe.get_capabilities) {
850           return BX_VGA_THIS vbe.max_bpp;
851         } else {
852           return BX_VGA_THIS vbe.bpp;
853         }
854 
855       case VBE_DISPI_INDEX_ENABLE: // vbe enabled
856         retval = BX_VGA_THIS vbe.enabled;
857         if (BX_VGA_THIS vbe.get_capabilities)
858           retval |= VBE_DISPI_GETCAPS;
859         if (BX_VGA_THIS vbe.dac_8bit)
860           retval |= VBE_DISPI_8BIT_DAC;
861         if (BX_VGA_THIS vbe.bank_granularity_kb == 32)
862           retval |= VBE_DISPI_BANK_GRANULARITY_32K;
863         return retval;
864 
865       case VBE_DISPI_INDEX_BANK: // current bank
866         if (BX_VGA_THIS vbe.get_capabilities) {
867           return (VBE_DISPI_BANK_GRANULARITY_32K << 8);
868         } else {
869           return BX_VGA_THIS vbe.bank[0];
870         }
871 
872       case VBE_DISPI_INDEX_X_OFFSET:
873         return BX_VGA_THIS vbe.offset_x;
874 
875       case VBE_DISPI_INDEX_Y_OFFSET:
876         return BX_VGA_THIS vbe.offset_y;
877 
878       case VBE_DISPI_INDEX_VIRT_WIDTH:
879         return BX_VGA_THIS vbe.virtual_xres;
880 
881       case VBE_DISPI_INDEX_VIRT_HEIGHT:
882         return BX_VGA_THIS vbe.virtual_yres;
883 
884       case VBE_DISPI_INDEX_VIDEO_MEMORY_64K:
885         return (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB >> 6);
886 
887       case VBE_DISPI_INDEX_DDC:
888         if (BX_VGA_THIS vbe.ddc_enabled) {
889           retval = (1 << 7) | BX_VGA_THIS ddc.read();
890         } else {
891           retval = 0x000f;
892         }
893         break;
894 
895       default:
896         BX_ERROR(("VBE unknown data read index 0x%x",BX_VGA_THIS vbe.curindex));
897         break;
898     }
899   }
900   return retval;
901 }
902 
vbe_write_handler(void * this_ptr,Bit32u address,Bit32u value,unsigned io_len)903 void bx_vga_c::vbe_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
904 {
905 #if BX_USE_VGA_SMF == 0
906   bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
907   class_ptr->vbe_write(address, value, io_len);
908 }
909 
vbe_write(Bit32u address,Bit32u value,unsigned io_len)910 Bit32u bx_vga_c::vbe_write(Bit32u address, Bit32u value, unsigned io_len)
911 {
912 #else
913   UNUSED(this_ptr);
914 #endif
915   Bit16u max_xres, max_yres, max_bpp, new_bank_gran;
916   bool new_vbe_8bit_dac;
917   bool needs_update = 0;
918   unsigned i;
919 
920 //  BX_INFO(("VBE_write %x = %x (len %x)", address, value, io_len));
921 
922   switch(address)
923   {
924     // index register
925     case VBE_DISPI_IOPORT_INDEX:
926 
927       BX_VGA_THIS vbe.curindex = (Bit16u) value;
928       break;
929 
930     // data register
931     // FIXME: maybe do some 'sanity' checks on received data?
932     case VBE_DISPI_IOPORT_DATA:
933       switch (BX_VGA_THIS vbe.curindex)
934       {
935         case VBE_DISPI_INDEX_ID: // Display Interface ID check
936         {
937           if ((value == VBE_DISPI_ID0) ||
938               (value == VBE_DISPI_ID1) ||
939               (value == VBE_DISPI_ID2) ||
940               (value == VBE_DISPI_ID3) ||
941               (value == VBE_DISPI_ID4) ||
942               (value == VBE_DISPI_ID5))
943           {
944             // allow backwards compatible with previous dispi bioses
945             BX_VGA_THIS vbe.cur_dispi=value;
946           }
947           else
948           {
949             BX_PANIC(("VBE unknown Display Interface %x", value));
950           }
951 
952           // make sure we don't flood the logfile
953           static int count=0;
954           if (count < 100)
955           {
956             count++;
957             BX_INFO(("VBE known Display Interface %x", value));
958           }
959         } break;
960 
961         case VBE_DISPI_INDEX_XRES: // set xres
962         {
963           // check that we don't set xres during vbe enabled
964           if (!BX_VGA_THIS vbe.enabled)
965           {
966             // check for within max xres range
967             if (value <= BX_VGA_THIS vbe.max_xres)
968             {
969               BX_VGA_THIS vbe.xres=(Bit16u) value;
970               BX_INFO(("VBE set xres (%d)", value));
971             }
972             else
973             {
974               BX_INFO(("VBE set xres more then max xres (%d)", value));
975             }
976           }
977           else
978           {
979             BX_ERROR(("VBE set xres during vbe enabled!"));
980           }
981         } break;
982 
983         case VBE_DISPI_INDEX_YRES: // set yres
984         {
985           // check that we don't set yres during vbe enabled
986           if (!BX_VGA_THIS vbe.enabled)
987           {
988             // check for within max yres range
989             if (value <= BX_VGA_THIS vbe.max_yres)
990             {
991               BX_VGA_THIS vbe.yres=(Bit16u) value;
992               BX_INFO(("VBE set yres (%d)", value));
993             }
994             else
995             {
996               BX_INFO(("VBE set yres more then max yres (%d)", value));
997             }
998           }
999           else
1000           {
1001             BX_ERROR(("VBE set yres during vbe enabled!"));
1002           }
1003         } break;
1004 
1005         case VBE_DISPI_INDEX_BPP: // set bpp
1006         {
1007           // check that we don't set bpp during vbe enabled
1008           if (!BX_VGA_THIS vbe.enabled)
1009           {
1010             // for backward compatiblity
1011             if (value == 0) value = VBE_DISPI_BPP_8;
1012             // check for correct bpp range
1013             if ((value == VBE_DISPI_BPP_4) || (value == VBE_DISPI_BPP_8) || (value == VBE_DISPI_BPP_15) ||
1014                 (value == VBE_DISPI_BPP_16) || (value == VBE_DISPI_BPP_24) || (value == VBE_DISPI_BPP_32))
1015             {
1016               BX_VGA_THIS vbe.bpp=(Bit16u) value;
1017               BX_INFO(("VBE set bpp (%d)", value));
1018             }
1019             else
1020             {
1021               BX_ERROR(("VBE set bpp with unknown bpp (%d)", value));
1022             }
1023           }
1024           else
1025           {
1026             BX_ERROR(("VBE set bpp during vbe enabled!"));
1027           }
1028         } break;
1029 
1030         case VBE_DISPI_INDEX_BANK: // set bank
1031         {
1032           Bit16u num_banks = (Bit16u)(VBE_DISPI_TOTAL_VIDEO_MEMORY_KB / BX_VGA_THIS vbe.bank_granularity_kb);
1033           Bit16u rw_mode = VBE_DISPI_BANK_RW; // compatibility mode
1034           if (BX_VGA_THIS vbe.bpp == VBE_DISPI_BPP_4) num_banks >>= 2;
1035           if ((value & VBE_DISPI_BANK_RW) != 0) {
1036             rw_mode = (value & VBE_DISPI_BANK_RW);
1037           }
1038           value &= 0x1ff;
1039           // check for max bank nr
1040           if (value < num_banks) {
1041             BX_DEBUG(("VBE set bank to %d", value));
1042             if ((rw_mode & VBE_DISPI_BANK_WR) != 0) {
1043               BX_VGA_THIS vbe.bank[0] = value;
1044             }
1045             if ((rw_mode & VBE_DISPI_BANK_RD) != 0) {
1046               BX_VGA_THIS vbe.bank[1] = value;
1047             }
1048             if (BX_VGA_THIS vbe.bank_granularity_kb == 64) {
1049               BX_VGA_THIS s.ext_offset = (BX_VGA_THIS vbe.bank[0] << 16);
1050             } else {
1051               BX_VGA_THIS s.ext_offset = (BX_VGA_THIS vbe.bank[0] << 15);
1052             }
1053           } else {
1054             BX_ERROR(("VBE set invalid bank (%d)", value));
1055           }
1056         } break;
1057 
1058         case VBE_DISPI_INDEX_ENABLE: // enable video
1059         {
1060           if ((value & VBE_DISPI_ENABLED) && !BX_VGA_THIS vbe.enabled)
1061           {
1062             unsigned depth=0;
1063 
1064             // setup virtual resolution to be the same as current reso
1065             BX_VGA_THIS vbe.virtual_yres=BX_VGA_THIS vbe.yres;
1066             BX_VGA_THIS vbe.virtual_xres=BX_VGA_THIS vbe.xres;
1067 
1068             // reset offset
1069             BX_VGA_THIS vbe.offset_x=0;
1070             BX_VGA_THIS vbe.offset_y=0;
1071             BX_VGA_THIS vbe.virtual_start=0;
1072 
1073             switch((BX_VGA_THIS vbe.bpp))
1074             {
1075               // Default pixel sizes
1076               case VBE_DISPI_BPP_8:
1077                 BX_VGA_THIS vbe.bpp_multiplier = 1;
1078                 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres;
1079                 depth=8;
1080                 break;
1081 
1082               case VBE_DISPI_BPP_4:
1083                 BX_VGA_THIS vbe.bpp_multiplier = 1;
1084                 BX_VGA_THIS s.line_offset = (BX_VGA_THIS vbe.virtual_xres >> 3);
1085                 depth=4;
1086                 break;
1087 
1088               case VBE_DISPI_BPP_15:
1089                 BX_VGA_THIS vbe.bpp_multiplier = 2;
1090                 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * 2;
1091                 depth=15;
1092                 break;
1093 
1094               case VBE_DISPI_BPP_16:
1095                 BX_VGA_THIS vbe.bpp_multiplier = 2;
1096                 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * 2;
1097                 depth=16;
1098                 break;
1099 
1100               case VBE_DISPI_BPP_24:
1101                 BX_VGA_THIS vbe.bpp_multiplier = 3;
1102                 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * 3;
1103                 depth=24;
1104                 break;
1105 
1106               case VBE_DISPI_BPP_32:
1107                 BX_VGA_THIS vbe.bpp_multiplier = 4;
1108                 BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres << 2;
1109                 depth=32;
1110                 break;
1111             }
1112             BX_VGA_THIS vbe.visible_screen_size = BX_VGA_THIS s.line_offset * BX_VGA_THIS vbe.yres;
1113 
1114             BX_INFO(("VBE enabling x %d, y %d, bpp %d, %u bytes visible", BX_VGA_THIS vbe.xres, BX_VGA_THIS vbe.yres, BX_VGA_THIS vbe.bpp, BX_VGA_THIS vbe.visible_screen_size));
1115 
1116             if ((value & VBE_DISPI_NOCLEARMEM) == 0) {
1117               memset(BX_VGA_THIS s.memory, 0, VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES);
1118             }
1119             if (depth > 4) {
1120               bx_gui->dimension_update(BX_VGA_THIS vbe.xres, BX_VGA_THIS vbe.yres, 0, 0, depth);
1121               BX_VGA_THIS s.last_bpp = depth;
1122               BX_VGA_THIS s.last_fh = 0;
1123             } else {
1124               BX_VGA_THIS s.plane_shift = VBE_DISPI_4BPP_PLANE_SHIFT;
1125               BX_VGA_THIS s.ext_offset = (BX_VGA_THIS vbe.bank[0] << 16);
1126             }
1127           } else if (((value & VBE_DISPI_ENABLED) == 0) && BX_VGA_THIS vbe.enabled) {
1128             BX_INFO(("VBE disabling"));
1129             BX_VGA_THIS s.plane_shift = 16;
1130             BX_VGA_THIS s.ext_offset = 0;
1131           }
1132           BX_VGA_THIS vbe.enabled = ((value & VBE_DISPI_ENABLED) != 0);
1133           BX_VGA_THIS vbe.get_capabilities = ((value & VBE_DISPI_GETCAPS) != 0);
1134           if (BX_VGA_THIS vbe.get_capabilities) {
1135             bx_gui->get_capabilities(&max_xres, &max_yres, &max_bpp);
1136             if (max_xres < BX_VGA_THIS vbe.max_xres) {
1137               BX_VGA_THIS vbe.max_xres = max_xres;
1138             }
1139             if (max_yres < BX_VGA_THIS vbe.max_yres) {
1140               BX_VGA_THIS vbe.max_yres = max_yres;
1141             }
1142             if (max_bpp < BX_VGA_THIS vbe.max_bpp) {
1143               BX_VGA_THIS vbe.max_bpp = max_bpp;
1144             }
1145           }
1146           if ((value & VBE_DISPI_BANK_GRANULARITY_32K) != 0) {
1147             new_bank_gran = 32;
1148           } else {
1149             new_bank_gran = 64;
1150           }
1151           if (new_bank_gran != BX_VGA_THIS vbe.bank_granularity_kb) {
1152             BX_VGA_THIS vbe.bank_granularity_kb = new_bank_gran;
1153             BX_VGA_THIS vbe.bank[0] = 0;
1154             BX_VGA_THIS vbe.bank[1] = 0;
1155             BX_VGA_THIS s.ext_offset = 0;
1156           }
1157           new_vbe_8bit_dac = ((value & VBE_DISPI_8BIT_DAC) != 0);
1158           if (new_vbe_8bit_dac != BX_VGA_THIS vbe.dac_8bit) {
1159             if (new_vbe_8bit_dac) {
1160               for (i=0; i<256; i++) {
1161                 BX_VGA_THIS s.pel.data[i].red <<= 2;
1162                 BX_VGA_THIS s.pel.data[i].green <<= 2;
1163                 BX_VGA_THIS s.pel.data[i].blue <<= 2;
1164               }
1165               BX_INFO(("DAC in 8 bit mode"));
1166             } else {
1167               for (i=0; i<256; i++) {
1168                 BX_VGA_THIS s.pel.data[i].red >>= 2;
1169                 BX_VGA_THIS s.pel.data[i].green >>= 2;
1170                 BX_VGA_THIS s.pel.data[i].blue >>= 2;
1171               }
1172               BX_INFO(("DAC in standard mode"));
1173             }
1174             BX_VGA_THIS vbe.dac_8bit = new_vbe_8bit_dac;
1175             BX_VGA_THIS s.dac_shift = new_vbe_8bit_dac ? 0 : 2;
1176             needs_update = 1;
1177           }
1178         } break;
1179 
1180         case VBE_DISPI_INDEX_X_OFFSET:
1181         {
1182           BX_DEBUG(("VBE offset x %d", value));
1183           BX_VGA_THIS vbe.offset_x=(Bit16u)value;
1184 
1185           BX_VGA_THIS vbe.virtual_start = BX_VGA_THIS vbe.offset_y * BX_VGA_THIS s.line_offset;
1186           if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1187             BX_VGA_THIS vbe.virtual_start += (BX_VGA_THIS vbe.offset_x * BX_VGA_THIS vbe.bpp_multiplier);
1188           } else {
1189             BX_VGA_THIS vbe.virtual_start += (BX_VGA_THIS vbe.offset_x >> 3);
1190           }
1191           needs_update = 1;
1192         } break;
1193 
1194         case VBE_DISPI_INDEX_Y_OFFSET:
1195         {
1196           BX_DEBUG(("VBE offset y %d", value));
1197 
1198           Bit32u new_screen_start = value * BX_VGA_THIS s.line_offset;
1199           if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1200             if ((new_screen_start + BX_VGA_THIS vbe.visible_screen_size) > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
1201             {
1202               BX_PANIC(("VBE offset y %d out of bounds", value));
1203               break;
1204             }
1205             new_screen_start += (BX_VGA_THIS vbe.offset_x * BX_VGA_THIS vbe.bpp_multiplier);
1206           } else {
1207             if ((new_screen_start + BX_VGA_THIS vbe.visible_screen_size) > (VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / 4))
1208             {
1209               BX_PANIC(("VBE offset y %d out of bounds", value));
1210               break;
1211             }
1212             new_screen_start += (BX_VGA_THIS vbe.offset_x >> 3);
1213           }
1214           BX_VGA_THIS vbe.virtual_start = new_screen_start;
1215           BX_VGA_THIS vbe.offset_y = (Bit16u)value;
1216           needs_update = 1;
1217         } break;
1218 
1219         case VBE_DISPI_INDEX_VIRT_WIDTH:
1220         {
1221           BX_INFO(("VBE requested virtual width %d", value));
1222 
1223           // calculate virtual width & height dimensions
1224           // req:
1225           //   virt_width > xres
1226           //   virt_height >=yres
1227           //   virt_width*virt_height < MAX_VIDEO_MEMORY
1228 
1229           // basically 2 situations
1230 
1231           // situation 1:
1232           //   MAX_VIDEO_MEMORY / virt_width >= yres
1233           //        adjust result height
1234           //   else
1235           //        adjust result width based upon virt_height=yres
1236           Bit16u new_width=value;
1237           Bit16u new_height;
1238           if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1239             new_height=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / BX_VGA_THIS vbe.bpp_multiplier) / new_width;
1240           } else {
1241             new_height=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES * 2) / new_width;
1242           }
1243           if (new_height >=BX_VGA_THIS vbe.yres)
1244           {
1245             // we have a decent virtual width & new_height
1246             BX_INFO(("VBE decent virtual height %d",new_height));
1247           }
1248           else
1249           {
1250             // no decent virtual height: adjust width & height
1251             new_height=BX_VGA_THIS vbe.yres;
1252             if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1253               new_width=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES / BX_VGA_THIS vbe.bpp_multiplier) / new_height;
1254             } else {
1255               new_width=(VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES * 2) / new_height;
1256             }
1257 
1258             BX_INFO(("VBE recalc virtual width %d height %d",new_width, new_height));
1259           }
1260 
1261           BX_VGA_THIS vbe.virtual_xres=new_width;
1262           BX_VGA_THIS vbe.virtual_yres=new_height;
1263           if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {
1264             BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres * BX_VGA_THIS vbe.bpp_multiplier;
1265           } else {
1266             BX_VGA_THIS s.line_offset = BX_VGA_THIS vbe.virtual_xres >> 3;
1267           }
1268           BX_VGA_THIS vbe.visible_screen_size = BX_VGA_THIS s.line_offset * BX_VGA_THIS vbe.yres;
1269 
1270         } break;
1271         case VBE_DISPI_INDEX_VIRT_HEIGHT:
1272           BX_ERROR(("VBE: write to virtual height register ignored"));
1273           break;
1274         case VBE_DISPI_INDEX_DDC:
1275           if ((value >> 7) & 1) {
1276             BX_VGA_THIS vbe.ddc_enabled = 1;
1277             BX_VGA_THIS ddc.write(value & 1, (value >> 1) & 1);
1278           } else {
1279             BX_VGA_THIS vbe.ddc_enabled = 0;
1280           }
1281           break;
1282         default:
1283           BX_ERROR(("VBE: write unsupported register at index 0x%x",BX_VGA_THIS vbe.curindex));
1284           break;
1285       }
1286       if (needs_update) {
1287         BX_VGA_THIS s.vga_mem_updated = 1;
1288         for (unsigned xti = 0; xti < BX_VGA_THIS s.num_x_tiles; xti++) {
1289           for (unsigned yti = 0; yti < BX_VGA_THIS s.num_y_tiles; yti++) {
1290             SET_TILE_UPDATED(BX_VGA_THIS, xti, yti, 1);
1291           }
1292         }
1293       }
1294       break;
1295 
1296   } // end switch address
1297 }
1298 
1299 #if BX_SUPPORT_PCI
1300 // static pci configuration space write callback handler
pci_write_handler(Bit8u address,Bit32u value,unsigned io_len)1301 void bx_vga_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
1302 {
1303   if ((address >= 0x14) && (address < 0x30))
1304     return;
1305 
1306   BX_DEBUG_PCI_WRITE(address, value, io_len);
1307   for (unsigned i = 0; i < io_len; i++) {
1308     unsigned write_addr = address + i;
1309 //  Bit8u old_value = BX_VGA_THIS pci_conf[write_addr];
1310     Bit8u new_value = (Bit8u)(value & 0xff);
1311     switch (write_addr) {
1312       case 0x04: // disallowing write to command
1313       case 0x06: // disallowing write to status lo-byte (is that expected?)
1314         break;
1315       default:
1316         BX_VGA_THIS pci_conf[write_addr] = new_value;
1317     }
1318     value >>= 8;
1319   }
1320 
1321 }
1322 #endif
1323 
1324 #if BX_DEBUGGER
debug_dump(int argc,char ** argv)1325 void bx_vga_c::debug_dump(int argc, char **argv)
1326 {
1327   if (BX_VGA_THIS vbe.enabled) {
1328     dbg_printf("Bochs VGA/VBE adapter\n\n");
1329     dbg_printf("current mode : %u x %u x %u\n", BX_VGA_THIS vbe.xres,
1330                BX_VGA_THIS vbe.yres, BX_VGA_THIS vbe.bpp);
1331     if (argc > 0) {
1332       dbg_printf("\nAdditional options not supported\n");
1333     }
1334   } else {
1335     bx_vgacore_c::debug_dump(argc, argv);
1336   }
1337 }
1338 #endif
1339