X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fvga.c;h=f9c4e9022600a8c0f1c1ee74fda84e2cf1ecd574;hb=7ebb801201cc0c40f769db676e69b6e7394b08b5;hp=ce28940dd944a3f3b5e29b49a9802313fd8474ca;hpb=2e0992e07d6aebe06bab827f2534c074b9d7bb9e;p=palacios.releases.git diff --git a/palacios/src/devices/vga.c b/palacios/src/devices/vga.c index ce28940..f9c4e90 100644 --- a/palacios/src/devices/vga.c +++ b/palacios/src/devices/vga.c @@ -26,7 +26,7 @@ #include "vga_regs.h" -#ifndef CONFIG_DEBUG_VGA +#ifndef V3_CONFIG_DEBUG_VGA #undef PrintDebug #define PrintDebug(fmt, args...) #endif @@ -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;ytarget_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)); @@ -1194,7 +1265,7 @@ static int vga_write(struct guest_info * core, #endif // rotate data right if (ror) { - data = (data>>ror) | data<<(8-ror); + data = (data>>ror) | (data<<(8-ror)); } #if DEBUG_DEEP_MEM @@ -1384,7 +1455,7 @@ static int vga_write(struct guest_info * core, uint8_t data = ((uint8_t *)src)[i]; if (ror) { - data = (data>>ror) | data<<(8-ror); + data = (data>>ror) | (data<<(8-ror)); } uint8_t bm = vga->vga_graphics_controller.vga_bit_mask & data; @@ -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;imap[mapnum]+offset); + for (i=0;imap[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;imap[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); }