Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


VGA support for host-driven rendering
[palacios.releases.git] / palacios / src / devices / vga.c
index de6bc66..a99faae 100644 (file)
 
 #include "vga_regs.h"
 
+#ifndef V3_CONFIG_DEBUG_VGA
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+#define DEBUG_MEM_DATA    0
+#define DEBUG_DEEP_MEM    0
+#define DEBUG_DEEP_RENDER 0
+
+
 #define MEM_REGION_START 0xa0000
 #define MEM_REGION_END   0xc0000
 #define MEM_REGION_NUM_PAGES (((MEM_REGION_END)-(MEM_REGION_START))/4096)
@@ -33,7 +43,6 @@
 #define MAP_SIZE 65536
 #define MAP_NUM  4
 
-#define UPDATES_PER_RENDER 100
 
 typedef uint8_t *vga_map; // points to MAP_SIZE data
 
@@ -86,6 +95,18 @@ typedef uint8_t *vga_map; // points to MAP_SIZE data
 #define VGA_FONT_WIDTH      8
 #define VGA_MAX_FONT_HEIGHT 32
 
+struct vga_render_model {
+  uint32_t   model;  // composite the following
+
+#define VGA_DRIVEN_PERIODIC_RENDERING 0x1  // render after n GPU updates
+#define CONSOLE_ADVISORY_RENDERING    0x2  // ask console if we should render following an update
+#define CONSOLE_DRIVEN_RENDERING      0x4  // have console tell us when to render
+
+  uint32_t   updates_before_render;   // defaults to the following
+
+#define DEFAULT_UPDATES_BEFORE_RENDER   1000
+};
+
 struct vga_misc_regs {
     /* Read: 0x3cc; Write: 0x3c2 */
     struct vga_misc_out_reg        vga_misc_out;
@@ -273,12 +294,13 @@ struct vga_dac_regs {
 
 struct vga_internal {
     struct vm_device *dev; 
-    
+
     bool passthrough;
     bool skip_next_passthrough_out; // for word access 
 
     struct v3_frame_buffer_spec  target_spec;
     v3_graphics_console_t host_cons;
+    struct vga_render_model render_model;
 
     uint32_t updates_since_render;
 
@@ -365,6 +387,7 @@ static void find_text_data_start(struct vga_internal *vga, void **data)
 
 }
 
+
 static void find_text_attr_start(struct vga_internal *vga, void **data)
 {
     uint32_t offset;
@@ -446,6 +469,29 @@ static int blinking(struct vga_internal *vga)
 }
 
 
+static void find_graphics_data_starting_offset(struct vga_internal *vga, uint32_t *offset)
+{
+
+    *offset = vga->vga_crt_controller.vga_start_address_high;
+    *offset <<= 8;
+    *offset += vga->vga_crt_controller.vga_start_address_low;
+}
+
+
+static void find_shift_mode(struct vga_internal *vga, shift_mode_t *mode)
+{
+    if (vga->vga_graphics_controller.vga_graphics_mode.c256) { 
+       *mode=C256_SHIFT;
+    } else {
+       if (vga->vga_graphics_controller.vga_graphics_mode.shift_reg_mode) {
+           *mode=PACKED_SHIFT;
+       } else {
+           *mode=PLANAR_SHIFT;
+       }
+    }
+}
+
+
 static void find_graphics_res(struct vga_internal *vga, uint32_t *width, uint32_t *height)
 {
     uint32_t vert_lsb, vert_msb;
@@ -460,6 +506,31 @@ static void find_graphics_res(struct vga_internal *vga, uint32_t *width, uint32_
        + (vga->vga_crt_controller.vga_overflow.vertical_disp_enable_end8);
               
     *height  = ( (vert_msb << 8) + vert_lsb + 1) ; // pixels high (scanlines)
+
+    // At this point we have the resolution in dot clocks across and scanlines top-to-bottom
+    // This is usually the resolution in pixels, but it can be monkeyed with
+    // at least in the following ways
+
+    // vga sequencer dot clock divide by two 
+    if (vga->vga_sequencer.vga_clocking_mode.dot_clock) { 
+       *width/=2;
+       *height/=2;
+    }
+
+    // crt_controller.max_row_scan.double_scan => each row twice for 200=>400
+    if (vga->vga_crt_controller.vga_max_row_scan.double_scan) { 
+       *height/=2;
+    }
+    
+    // crt_controller.crt_mode_control.count_by_two => pixels twice as wide as normal
+    if (vga->vga_crt_controller.vga_crt_mode_control.count_by_two) { 
+       *width /= 2;
+    }
+
+    // crt_controller.crt_mode_control.horizontal_retrace_select => pixels twice as tall as normal
+    if (vga->vga_crt_controller.vga_crt_mode_control.horizontal_retrace_select) { 
+       *height /= 2;
+    }
     
 }
 
@@ -471,19 +542,6 @@ static void find_graphics_cursor_pos(struct vga_internal *vga, uint32_t *x, uint
 }
 
 
-static void find_shift_mode(struct vga_internal *vga, shift_mode_t *mode)
-{
-    if (vga->vga_graphics_controller.vga_graphics_mode.c256) { 
-       *mode=C256_SHIFT;
-    } else {
-       if (vga->vga_graphics_controller.vga_graphics_mode.shift_reg_mode) {
-           *mode=PACKED_SHIFT;
-       } else {
-           *mode=PLANAR_SHIFT;
-       }
-    }
-}
-
 static void dac_lookup_24bit_color(struct vga_internal *vga,
                                   uint8_t entry,
                                   uint8_t *red,
@@ -589,26 +647,28 @@ static void render_graphics(struct vga_internal *vga, void *fb)
 
     find_graphics_cursor_pos(vga,&cur_x,&cur_y);
 
+    find_graphics_data_starting_offset(vga,&offset);
+
     fw = spec->width;
     fh = spec->height;
 
 
     PrintDebug("vga: attempting graphics render (%s): graphics_res=(%u,%u), fb_res=(%u,%u), "
-               "fb=0x%p (16 color mode)\n",
+               "fb=0x%p offset=0x%x\n",
               sm == PLANAR_SHIFT ? "planar shift" : 
               sm == PACKED_SHIFT ? "packed shift" : 
               sm == C256_SHIFT ? "color256 shift" : "UNKNOWN",
-              gw,gh,fw,fh, fb);
+              gw,gh,fw,fh,fb,offset);
 
     // First we need to clip to what we can actually show
     rgw = gw < fw ? gw : fw;
-    rgh = gh < fh ? gh : gw;
+    rgh = gh < fh ? gh : fh;
 
     if (gw%8) { 
        PrintError("vga: warning: graphics width is not a multiple of 8\n");
     }
 
-    offset=0;  // do we always start at zero in the map?
+
 
     // Now we scan across by row
     for (fy=0;fy<gh;fy++) { 
@@ -616,7 +676,7 @@ static void render_graphics(struct vga_internal *vga, void *fb)
        for (fx=0;fx<gw;
             fx += (sm==C256_SHIFT ? 4 : 8) , offset++ ) { 
 
-           // if any of these pixels are in the renger region
+           // if any of these pixels are in the rendger region
            if (fy < rgh && fx < rgw) {
                // assemble all 4 or 8 pixels
                
@@ -630,10 +690,10 @@ static void render_graphics(struct vga_internal *vga, void *fb)
                    case PLANAR_SHIFT:
                        for (p=0;p<8;p++) { 
                            pb[p]= 
-                               ( db[0] >> 7)  |
-                               ( db[1] >> 6)  |
-                               ( db[2] >> 5)  |
-                               ( db[3] >> 4) ;
+                               (( db[0] >> 7) & 0x1) |
+                               (( db[1] >> 6) & 0x2) |
+                               (( db[2] >> 5) & 0x4) |
+                               (( db[3] >> 4) & 0x8) ;
                            
                            for (m=0;m<4;m++) { 
                                db[m] <<= 1;
@@ -645,8 +705,8 @@ static void render_graphics(struct vga_internal *vga, void *fb)
                        // first 4 pixels use planes 0 and 2
                        for (p=0;p<4;p++) { 
                            pb[p] = 
-                               ( db[2] >> 4) |
-                               ( db[0] >> 6) ;
+                               ((db[2] >> 4) & 0xc) |
+                               ((db[0] >> 6) & 0x3) ;
                            db[2] <<= 2;
                            db[0] <<= 2;
                        }
@@ -655,8 +715,8 @@ static void render_graphics(struct vga_internal *vga, void *fb)
                        // next 4 pixels use planes 1 and 3
                        for (p=4;p<8;p++) { 
                            pb[p] = 
-                               ( db[3] >> 4) |
-                               ( db[1] >> 6) ;
+                               ((db[3] >> 4) & 0xc) |
+                               ((db[1] >> 6) & 0x3) ;
                            db[3] <<= 2;
                            db[1] <<= 2;
                        }
@@ -674,7 +734,7 @@ static void render_graphics(struct vga_internal *vga, void *fb)
                for (p=0;p< (sm==C256_SHIFT ? 4 : 8);p++) { 
                    
                    // find its color
-                   find_24bit_color(vga,db[p],&r,&g,&b);
+                   find_24bit_color(vga,pb[p],&r,&g,&b);
                
                    // find its position in the framebuffer;
                    pixel =  fb + (((fx + p) + (fy*spec->width)) * spec->bytes_per_pixel);
@@ -909,6 +969,15 @@ static void render_test(struct vga_internal *vga, void *fb)
     }
 }
 
+static void render_black(struct vga_internal *vga, void *fb)
+{
+    struct v3_frame_buffer_spec *s;
+
+    s=&(vga->target_spec);
+
+    memset(fb,0,s->height*s->width*s->bytes_per_pixel);
+}
+
 static void render_maps(struct vga_internal *vga, void *fb)
 {
 
@@ -917,7 +986,7 @@ static void render_maps(struct vga_internal *vga, void *fb)
 
     s=&(vga->target_spec);
 
-    if (fb && s->height>=768 && s->width>=1024 && !(vga->updates_since_render % 100)) { 
+    if (fb && s->height>=768 && s->width>=1024 ) { 
        // we draw the maps next, each being a 256x256 block appearing 32 pixels below the display block
        uint8_t m;
        uint32_t x,y;
@@ -939,41 +1008,98 @@ static void render_maps(struct vga_internal *vga, void *fb)
     }
 }
 
+static int render_core(struct vga_internal *vga)
+{
+  void *fb;
+
+  PrintDebug("vga: render on update %u\n",vga->updates_since_render);
+  
+  fb = v3_graphics_console_get_frame_buffer_data_rw(vga->host_cons,&(vga->target_spec));
+  
+  if (!(vga->vga_sequencer.vga_clocking_mode.screen_off)) {
+    if (vga->vga_attribute_controller.vga_attribute_mode_control.graphics) { 
+      render_graphics(vga,fb);
+    } else {
+         render_text(vga,fb);
+         render_text_cursor(vga,fb);
+       }
+  } else {
+    render_black(vga,fb);
+  }
+  
+  if (0) { render_test(vga,fb); }
+  
+  // always render maps for now 
+  render_maps(vga,fb);
+  
+  v3_graphics_console_release_frame_buffer_data_rw(vga->host_cons);
+  
+  vga->updates_since_render=0;
+  
+  return 0;
+
+}
+    
 
 static int render(struct vga_internal *vga)
 {
-    void *fb;
-
 
     vga->updates_since_render++;
 
-    if (vga->updates_since_render%100) { 
-       // skip render
+
+    if (vga->host_cons) { 
+      int do_render=0;
+      
+      if ((vga->render_model.model & VGA_DRIVEN_PERIODIC_RENDERING)
+         &&
+         (vga->updates_since_render > vga->render_model.updates_before_render)) {
+       PrintDebug("vga: render due to periodic\n");
+       
+       do_render = 1;
+      }
+      
+      if ((vga->render_model.model & CONSOLE_ADVISORY_RENDERING) 
+         &&
+         (v3_graphics_console_inform_update(vga->host_cons) > 0) ) { 
+
+        PrintDebug("vga: render due to advisory\n");
+
+       do_render = 1;
+      }
+
+      // note that CONSOLE_DRIVEN_RENDERING is handled via the render_callback() function
+      
+      if (do_render) { 
+       return render_core(vga);
+      } else {
        return 0;
+      }
     }
+    return 0;
+    
+}
 
-    if (vga->host_cons && v3_graphics_console_inform_update(vga->host_cons)>0) { 
-
-       fb = v3_graphics_console_get_frame_buffer_data_rw(vga->host_cons,&(vga->target_spec));
-
-       if (vga->vga_graphics_controller.vga_misc.graphics_mode) { 
-           render_graphics(vga,fb);
-       } else {
-           render_text(vga,fb);
-           render_text_cursor(vga,fb);
-       }
-
-       if (0) { render_test(vga,fb); }
 
-       render_maps(vga,fb);
+static int render_callback(v3_graphics_console_t cons,
+                          void *priv)
+{
+  struct vga_internal *vga = (struct vga_internal *) priv;
+  
+  PrintDebug("vga: render due to callback\n");
 
-       v3_graphics_console_release_frame_buffer_data_rw(vga->host_cons);
-    }
+  return render_core(vga);
+}
 
-    return 0;
+static int update_callback(v3_graphics_console_t cons,
+                          void *priv)
+{
+  struct vga_internal *vga = (struct vga_internal *) priv;
+  
+  return vga->updates_since_render>0;
 }
 
 
+
 static void get_mem_region(struct vga_internal *vga, uint64_t *mem_start, uint64_t *mem_end) 
 {
     switch (vga->vga_graphics_controller.vga_misc.memory_map) { 
@@ -1065,7 +1191,7 @@ static int vga_write(struct guest_info * core,
        memcpy(V3_VAddr((void*)guest_addr),src,length);
     }
     
-#if 0
+#if DEBUG_MEM_DATA
     int i;
     PrintDebug("vga: data written was 0x");
     for (i=0;i<length;i++) {
@@ -1107,7 +1233,9 @@ static int vga_write(struct guest_info * core,
            
            offset = find_offset_write(vga, guest_addr);
 
+#if DEBUG_DEEP_MEM
            PrintDebug("vga: mode 0 write, offset=0x%llx, ror=%u, func=%u\n", offset,ror,func);
+#endif
 
            for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) { 
                // now for each map
@@ -1116,21 +1244,36 @@ static int vga_write(struct guest_info * core,
                uint8_t bm = vga->vga_graphics_controller.vga_bit_mask;
                uint8_t mm = find_map_write(vga,guest_addr+i);
 
-               //PrintDebug("vga: write i=%u, mm=0x%x, offset=0x%x\n",i,(unsigned int)mm,(unsigned int)offset);
+#if DEBUG_DEEP_MEM
+               PrintDebug("vga: write i=%u, mm=0x%x, bm=0x%x sr=0x%x esr=0x%x offset=0x%x\n",i,(unsigned int)mm,(unsigned int)bm, (unsigned int)sr, (unsigned int)esr,(unsigned int)offset);
+#endif
 
-               for (mapnum=0;mapnum<4;mapnum++, sr>>=1, esr>>=1, bm>>=1, mm>>=1) { 
+               for (mapnum=0;mapnum<4;mapnum++, sr>>=1, esr>>=1, mm>>=1) { 
                    vga_map map = vga->map[mapnum];
                    uint8_t data = ((uint8_t *)src)[i];
                    uint8_t latchval = vga->latch[mapnum];
-                       
+                   
+#if DEBUG_DEEP_MEM
+                   PrintDebug("vga: raw data=0x%x\n",data);
+#endif
                    // rotate data right
-                   data = (data>>ror) | data<<(8-ror);
-
+                   if (ror) { 
+                       data = (data>>ror) | (data<<(8-ror));
+                   }
+                   
+#if DEBUG_DEEP_MEM
+                   PrintDebug("vga: data after ror=0x%x\n",data);
+#endif
                    // use SR bit if ESR is on for this map
-                   if (esr & 0x1) { 
-                       data = (uint8_t)((((sint8_t)(sr&0x1))<<7)>>7);  // expand sr bit
+                   if (esr & 0x1) {
+                       data = (sr&0x1) * -1;
+                       
                    }
                    
+#if DEBUG_DEEP_MEM
+                   PrintDebug("vga: data after esrr=0x%x\n",data);
+#endif
+                   
                    // Apply function
                    switch (func) { 
                        case 0: // NOP
@@ -1145,19 +1288,26 @@ static int vga_write(struct guest_info * core,
                            data ^= latchval;
                            break;
                    }
-                           
-                   // mux between latch and alu output
-                   if (bm & 0x1) { 
-                       // use alu output, which is in data
-                   } else {
-                       // use latch value
-                       data=latchval;
-                   }
+                   
+#if DEBUG_DEEP_MEM
+                   PrintDebug("vga: data after func=0x%x\n",data);
+#endif
+                   
+                   // mux between the data byte and the latch byte on
+                   // a per-bit basis
+                   data = (bm & data) | ((~bm) & latchval);
+                   
+
+#if DEBUG_DEEP_MEM
+                   PrintDebug("vga: data after bm mux=0x%x\n",data);
+#endif
                    
                    // selective write
                    if (mm & 0x1) { 
                        // write to this map
-                       //PrintDebug("vga: write map %u offset 0x%p map=0x%p pointer=0x%p\n",mapnum,(void*)offset,map,&(map[offset]));
+#if DEBUG_DEEP_MEM
+                       PrintDebug("vga: write map %u offset 0x%p map=0x%p pointer=0x%p\n",mapnum,(void*)offset,map,&(map[offset]));
+#endif
                        map[offset] = data;
                    } else {
                        // skip this map
@@ -1180,7 +1330,9 @@ static int vga_write(struct guest_info * core,
 
            uint64_t offset = find_offset_write(vga,guest_addr);
 
+#if DEBUG_DEEP_MEM
            PrintDebug("vga: mode 1 write, offset=0x%llx\n", offset);
+#endif
 
            for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) { 
 
@@ -1221,7 +1373,9 @@ static int vga_write(struct guest_info * core,
            
            offset = find_offset_write(vga, guest_addr);
 
+#if DEBUG_DEEP_MEM
            PrintDebug("vga: mode 2 write, offset=0x%llx, func=%u\n", offset,func);
+#endif
 
            for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) { 
                // now for each map
@@ -1234,9 +1388,9 @@ static int vga_write(struct guest_info * core,
                    uint8_t latchval = vga->latch[mapnum];
                        
                    // expand relevant bit to 8 bit
-                   // it's basically esr=1, sr=bit from write
-                   data = (uint8_t)(((sint8_t)(((data>>mapnum)&0x1)<<7))>>7);
-                   
+                   // it's basically esr=1, sr=bit from mode 0 write
+                   data = ((data>>mapnum)&0x1) * -1;
+                       
                    // Apply function
                    switch (func) { 
                        case 0: // NOP
@@ -1251,14 +1405,9 @@ static int vga_write(struct guest_info * core,
                            data ^= latchval;
                            break;
                    }
-                           
+
                    // mux between latch and alu output
-                   if (bm & 0x1) { 
-                       // use alu output, which is in data
-                   } else {
-                       // use latch value
-                       data=latchval;
-                   }
+                   data = (bm & data) | ((~bm) & latchval);
                    
                    // selective write
                    if (mm & 0x1) { 
@@ -1298,7 +1447,9 @@ static int vga_write(struct guest_info * core,
                // now for each map
                uint8_t data = ((uint8_t *)src)[i];
 
-               data = (data>>ror) | data<<(8-ror);
+               if (ror) {
+                   data = (data>>ror) | (data<<(8-ror));
+               }
 
                uint8_t bm = vga->vga_graphics_controller.vga_bit_mask & data;
                uint8_t sr = vga->vga_graphics_controller.vga_set_reset.val & 0xf;
@@ -1308,16 +1459,11 @@ static int vga_write(struct guest_info * core,
                    vga_map map = vga->map[mapnum];
                    uint8_t latchval = vga->latch[mapnum];
                        
-                   data = (uint8_t)((((sint8_t)(sr&0x1))<<7)>>7);  // expand sr bit
-                   
-                   
+                   // expand SR bit
+                   data = (sr&0x1) * -1;
+
                    // mux between latch and alu output
-                   if (bm & 0x1) { 
-                       // use alu output, which is in data
-                   } else {
-                       // use latch value
-                       data=latchval;
-                   }
+                   data = (bm & data) | ((~bm) & latchval);
                    
                    // selective write
                    if (mm & 0x1) { 
@@ -1403,7 +1549,15 @@ static int vga_read(struct guest_info * core,
                // address bytes select the map
                for (i=0;i<length;i++,offset+=find_increment_read(vga,guest_addr+i)) { 
                    mapnum = (guest_addr+i) % 4;
-                   ((uint8_t*)dst)[i] = vga->latch[mapnum] = *(vga->map[mapnum]+offset);
+#if DEBUG_DEEP_MEM
+                   PrintDebug("vga: mode 0 read, chain4, offset=0x%llx, mapnum=%u\n",offset,mapnum);
+#endif
+                   ((uint8_t*)dst)[i] = *(vga->map[mapnum]+offset);
+
+                   // presumably all the latches are to be reloaded, not just the selected one?
+                   for (mapnum=0;mapnum<4;mapnum++) { 
+                       vga->latch[mapnum] = *(vga->map[mapnum]+offset);
+                   }
                }
            } else {
                mapnum = vga->vga_graphics_controller.vga_read_map_select.map_select;
@@ -1413,6 +1567,10 @@ static int vga_read(struct guest_info * core,
                    PrintError("vga: read to offset=%llu map=%u (%u bytes)\n",offset,mapnum,length);
                }
                
+#if DEBUG_DEEP_MEM
+               PrintDebug("vga: mode 0 read, not-chain4, offset=0x%llx, mapnum=%u\n",offset,mapnum);
+#endif
+
                memcpy(dst,(vga->map[mapnum])+offset,length);
                
                // load the latches with the last item read
@@ -1443,6 +1601,11 @@ static int vga_read(struct guest_info * core,
            uint8_t  bits;
            
            offset = find_offset_read(vga,guest_addr);
+
+#if DEBUG_DEEP_MEM
+           PrintDebug("vga: mode 1 read, offset=0x%llx, cc=0x%x, dc-0x%x\n",offset,cc,dc);
+#endif
+               
            
            for (i=0;i<length;i++,offset++) { 
                vga_map map;
@@ -1480,7 +1643,7 @@ static int vga_read(struct guest_info * core,
     }
 
 
-#if 0
+#if DEBUG_MEM_DATA
     int i;
     PrintDebug("vga: data read is 0x");
     for (i=0;i<length;i++) {
@@ -2581,6 +2744,9 @@ static int vga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     memset(vga, 0, sizeof(struct vga_internal));
 
+    vga->render_model.model = CONSOLE_DRIVEN_RENDERING | VGA_DRIVEN_PERIODIC_RENDERING;
+    vga->render_model.updates_before_render = DEFAULT_UPDATES_BEFORE_RENDER;
+
     if (passthrough && strcasecmp(passthrough,"enable")==0) {
        PrintDebug("vga: enabling passthrough\n");
        vga->passthrough=true;
@@ -2619,7 +2785,23 @@ static int vga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
            PrintDebug("vga: response: %u by %u by %u with %u bpc and r,g,b at %u, %u, %u\n", vga->target_spec.width, vga->target_spec.height, vga->target_spec.bytes_per_pixel, vga->target_spec.bits_per_channel, vga->target_spec.red_offset, vga->target_spec.green_offset, vga->target_spec.blue_offset);
 
        }
-    }
+
+       if (vga->render_model.model & CONSOLE_DRIVEN_RENDERING) { 
+         V3_Print("vga: enabling console-driven rendering\n");
+         if (v3_graphics_console_register_render_request(vga->host_cons, render_callback, vga)!=0) { 
+           PrintError("vga: cannot enable console-driven rendering\n");
+           free_vga(vga);
+           return -1;
+         }
+       }
+       
+       V3_Print("vga: enabling console inquiry for updates\n");
+       if (v3_graphics_console_register_update_inquire(vga->host_cons, update_callback, vga)!=0) { 
+         PrintError("vga: cannot enable console inquiry for updates\n");
+         free_vga(vga);
+         return -1;
+       }
+   }
 
     if (!vga->passthrough && !vga->host_cons) { 
        V3_Print("vga: neither passthrough nor host console are enabled - no way to display anything!\n");