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.


Lots of pedantic error checking in Palacios proper, especially for memory
[palacios.git] / palacios / src / devices / vga.c
index 6e5687c..f9c4e90 100644 (file)
@@ -43,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
 
@@ -96,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;
@@ -283,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;
 
@@ -819,7 +831,7 @@ static void render_text(struct vga_internal *vga, void *fb)
     rtw = tw < fw/cw ? tw : fw/cw;
     rth = th < fh/ch ? th : fh/ch;
 
-    
+    PrintDebug("\n");
 
     // Now let's scan by char across the whole thing
     for (y=0;y<th;y++) { 
@@ -830,6 +842,8 @@ static void render_text(struct vga_internal *vga, void *fb)
                ca = *attr;  
                a.val = ca;
 
+               PrintDebug("%c",ct);
+
                // find the character's font bitmap (one byte per row)
                find_text_font_start(vga,(void**)&font,
                                     extended_fontset(vga) ? a.foreground_intensity_or_font_select : 0 ); 
@@ -974,7 +988,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;
@@ -996,46 +1010,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_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);
+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) { 
@@ -1070,10 +1136,11 @@ static uint64_t find_offset_write(struct vga_internal *vga, addr_t guest_addr)
     size=(mem_end-mem_start > 65536 ? 65536 : (mem_end-mem_start)); 
 
     if (vga->vga_sequencer.vga_mem_mode.odd_even) { 
-       return (guest_addr-mem_start) % size;
+      // NOT odd/even mode
+      return (guest_addr-mem_start) % size;
     } else {
        // odd/even mode
-       return ((guest_addr-mem_start) >> 1 ) % size;
+      return ((guest_addr-mem_start) >> 1 ) % size;
     }
 }
 
@@ -1090,23 +1157,26 @@ static uint8_t find_map_write(struct vga_internal *vga, addr_t guest_addr)
     uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
 
     if (vga->vga_sequencer.vga_mem_mode.odd_even) { 
-       return mm;
+      // NOT odd/even mode
+      return mm;
     } else {
-       if (guest_addr & 0x1) { 
-           return mm & 0xa;  // 0x1010
-       } else {
-           return mm & 0x5;  // 0x0101
-       }
+      // odd/even mode
+      if (guest_addr & 0x1) { 
+       return mm & 0xa;  // 0x1010
+      } else {
+       return mm & 0x5;  // 0x0101
+      }
     }
 }
 
 static uint8_t find_increment_write(struct vga_internal *vga, addr_t new_guest_addr)
 {
-    if (vga->vga_sequencer.vga_mem_mode.odd_even) { 
-       return 1;
-    } else {
-       return !(new_guest_addr & 0x1);
-    }
+  if (vga->vga_sequencer.vga_mem_mode.odd_even) { 
+    // NOT odd/even mode
+    return 1;
+  } else {
+    return !(new_guest_addr & 0x1);
+  }
 }
 
 
@@ -1120,7 +1190,8 @@ static int vga_write(struct guest_info * core,
     struct vm_device *dev = (struct vm_device *)priv_data;
     struct vga_internal *vga = (struct vga_internal *) dev->private_data;
 
-    PrintDebug("vga: memory write: guest_addr=0x%p len=%u\n",(void*)guest_addr, length);
+    PrintDebug("vga: memory write: guest_addr=0x%p len=%u write_mode=%d\n",(void*)guest_addr, length,
+              vga->vga_graphics_controller.vga_graphics_mode.write_mode);
 
     if (vga->passthrough) { 
        PrintDebug("vga: passthrough write to 0x%p\n", V3_VAddr((void*)guest_addr));
@@ -1435,22 +1506,61 @@ static uint64_t find_offset_read(struct vga_internal *vga, addr_t guest_addr)
     
     size=(mem_end-mem_start > 65536 ? 65536 : (mem_end-mem_start)); 
 
-    if (!vga->vga_sequencer.vga_mem_mode.chain4) { 
-       return (guest_addr-mem_start) % size;
-    } else {
-       // chain4 mode
-       return ((guest_addr - mem_start) >> 2) % size;
+    if (!vga->vga_sequencer.vga_mem_mode.odd_even) { 
+      // odd/even mode takes priority
+      return ((guest_addr-mem_start) >> 1 ) % size;
+    } 
+
+    if (vga->vga_sequencer.vga_mem_mode.chain4) {
+      // otherwise chain4 if it's on
+      return ((guest_addr - mem_start) >> 2) % size;
     }
+
+    // and what you would expect if neither are on
+    return (guest_addr-mem_start) % size;
 }
 
-static uint8_t find_increment_read(struct vga_internal *vga, addr_t new_guest_addr)
+// Given this address
+// which specific map should we write into?
+// Note that unlike with find_map_write, here we are looking
+// for a single map number, not a bit vector of maps to be selected
+static uint8_t find_map_read(struct vga_internal *vga, addr_t guest_addr)
 {
+    uint64_t mem_start, mem_end;
+    
+    mem_start=mem_end=0;
+    
+    get_mem_region(vga, &mem_start, &mem_end);
+    
+    if (!vga->vga_sequencer.vga_mem_mode.odd_even) { 
+      // odd-even mode
+      // last bit tells us map 0 or 1
+      return (guest_addr-mem_start) & 0x1; 
+    } 
 
-    if (vga->vga_sequencer.vga_mem_mode.chain4) { 
-       return !(new_guest_addr & 0x3);
-    } else {
-       return 1;
+    if (vga->vga_sequencer.vga_mem_mode.chain4) {
+      // otherwise chain4 if it's on
+      // last two bits
+      return (guest_addr - mem_start) & 0x3;
     }
+
+    // and what you would expect if neither are on
+    // note that it's not the same as a write!
+    return vga->vga_graphics_controller.vga_read_map_select.map_select;
+}
+
+static uint8_t find_increment_read(struct vga_internal *vga, addr_t new_guest_addr)
+{
+
+  if (!vga->vga_sequencer.vga_mem_mode.odd_even) { 
+    // odd-even mode
+    return !(new_guest_addr & 0x1); 
+  } 
+
+  if (vga->vga_sequencer.vga_mem_mode.chain4) { 
+    return !(new_guest_addr & 0x3);
+  } 
+  return 1;
 }
 
 
@@ -1464,7 +1574,8 @@ static int vga_read(struct guest_info * core,
     struct vga_internal *vga = (struct vga_internal *) dev->private_data;
     
 
-    PrintDebug("vga: memory read: guest_addr=0x%p len=%u\n",(void*)guest_addr, length);
+    PrintDebug("vga: memory read: guest_addr=0x%p len=%u read_mode=%d\n",(void*)guest_addr, length,
+              vga->vga_graphics_controller.vga_graphics_mode.read_mode);
 
         
    
@@ -1474,46 +1585,29 @@ static int vga_read(struct guest_info * core,
     switch (vga->vga_graphics_controller.vga_graphics_mode.read_mode) { 
        case 0: {
            /*      0 - a byte from ONE of the 4 planes is returned; 
-                   which plane is determined by Read Map Select (Read Map Select Register (Index 04h)) */
+                   which plane is determined by Read Map Select (Read Map Select Register (Index 04h))
+                   OR by odd/even chaining OR by chain4 chaining
+           */
            uint8_t  mapnum;
            uint64_t offset;
+           uint32_t i;
 
-
-           if (vga->vga_sequencer.vga_mem_mode.chain4) { 
-               uint32_t i;
-               offset = find_offset_read(vga,guest_addr);
-               // address bytes select the map
-               for (i=0;i<length;i++,offset+=find_increment_read(vga,guest_addr+i)) { 
-                   mapnum = (guest_addr+i) % 4;
+           offset = find_offset_read(vga,guest_addr);
+           
 #if DEBUG_DEEP_MEM
-                   PrintDebug("vga: mode 0 read, chain4, offset=0x%llx, mapnum=%u\n",offset,mapnum);
+           PrintDebug("vga: mode 0 read, offset=0x%llx\n",offset);
 #endif
-                   ((uint8_t*)dst)[i] = *(vga->map[mapnum]+offset);
+           for (i=0;i<length;i++,offset+=find_increment_read(vga,guest_addr+i)) { 
+
+             mapnum = find_map_read(vga,guest_addr+i);
+
+             ((uint8_t*)dst)[i] = *(vga->map[mapnum]+offset);
+             
+             vga->latch[mapnum] = *(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;
-               offset = find_offset_read(vga,guest_addr);
-               
-               if (offset>=65536) { 
-                   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
-               for (mapnum=0;mapnum<4;mapnum++) { 
-                   vga->latch[mapnum] = vga->map[mapnum][offset+length-1];
-               }
            }
+
        
        }
            break;
@@ -2581,9 +2675,10 @@ static int dac_pixel_mask_write(struct guest_info *core,
 
 static int init_vga(struct vga_internal *vga)
 {
-    // TODO: startup spec of register contents, if any
-    PrintError("vga: init_vga is UNIMPLEMTED\n");
-    return 0;
+  // TODO: startup spec of register contents, if any
+  vga->vga_misc.vga_input_stat1.val = 0x1;  // display enable, not in retrace
+
+  return 0;
 }
 
 static int free_vga(struct vga_internal *vga) 
@@ -2680,6 +2775,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;
@@ -2718,7 +2816,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");
@@ -2731,12 +2845,17 @@ static int vga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     // Now allocate the maps
     for (i=0;i<MAP_NUM;i++) { 
-       vga->map[i] = (vga_map) V3_VAddr((void*)V3_AllocPages(MAP_SIZE/4096));
-       if (!(vga->map[i])) {
+       void *temp;
+
+       temp = (void*)V3_AllocPages(MAP_SIZE/4096);
+       if (!temp) { 
            PrintError("vga: cannot allocate maps\n");
            free_vga(vga);
            return -1;
        }
+
+       vga->map[i] = (vga_map) V3_VAddr(temp);
+
        memset(vga->map[i],0,MAP_SIZE);
     }