From: Peter Dinda Date: Tue, 29 Mar 2011 22:28:24 +0000 (-0500) Subject: Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio... X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=a79fa3206e688095687133457c891aa102b303bf;hp=5f98ee52fd6643118ce394acfb9f8537ab51b592;p=palacios-OLD.git Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacios into devel --- diff --git a/palacios/include/palacios/vmm_mem.h b/palacios/include/palacios/vmm_mem.h index 99a53fc..6974344 100644 --- a/palacios/include/palacios/vmm_mem.h +++ b/palacios/include/palacios/vmm_mem.h @@ -44,6 +44,9 @@ typedef struct { union { uint16_t value; struct { + // These reflect the VMM's intent for the shadow or nested pts + // that will implement the region. The guest's intent is in + // its own page tables. uint8_t read : 1; uint8_t write : 1; uint8_t exec : 1; diff --git a/palacios/include/palacios/vmm_mem_hook.h b/palacios/include/palacios/vmm_mem_hook.h index 7184c68..cd87518 100644 --- a/palacios/include/palacios/vmm_mem_hook.h +++ b/palacios/include/palacios/vmm_mem_hook.h @@ -50,7 +50,12 @@ int v3_hook_write_mem(struct v3_vm_info * vm, uint16_t core_id, int v3_unhook_mem(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr_start); - +int v3_find_mem_hook(struct v3_vm_info *vm, uint16_t core_id, addr_t guest_addr, + int (**read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data), + void **read_priv_data, + int (**write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data), + void **write_priv_data); + #endif /* ! __V3VEE__ */ diff --git a/palacios/src/devices/vga.c b/palacios/src/devices/vga.c index 0aa991e..b5258cd 100644 --- a/palacios/src/devices/vga.c +++ b/palacios/src/devices/vga.c @@ -32,6 +32,8 @@ #define MAP_SIZE 65536 #define MAP_NUM 4 +#define UPDATES_PER_RENDER 100 + typedef uint8_t *vga_map; // points to MAP_SIZE data /* HACK HACK HACK */ @@ -284,6 +286,8 @@ struct vga_internal { bool passthrough; + uint32_t updates_since_render; + struct frame_buf *framebuf; // we render to this // void *mem_store; // This is the region where the memory hooks will go @@ -322,6 +326,30 @@ struct vga_internal { }; + +static int render(struct vga_internal *vga) +{ + vga->updates_since_render++; + + if (vga->updates_since_renderupdates_since_render=0; + + if (!palacios_linux_fb_hack_pointer) { + return 0; + } + + + + + return 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) { @@ -365,15 +393,24 @@ static int vga_write(struct guest_info * core, uint_t length, void * priv_data) { + int i; 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); if (vga->passthrough) { + PrintDebug("vga: passthrough write to 0x%p\n", V3_VAddr((void*)guest_addr)); memcpy(V3_VAddr((void*)guest_addr),src,length); } + PrintDebug("vga: data written was \""); + for (i=0;i='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') ? c : '.'); + } + PrintDebug("\"\n"); + /* Write mode determine by Graphics Mode Register (Index 05h).writemode */ switch (vga->vga_graphics_controller.vga_graphics_mode.write_mode) { @@ -448,7 +485,7 @@ static int vga_write(struct guest_info * core, // 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])); + //PrintDebug("vga: write map %u offset 0x%p map=0x%p pointer=0x%p\n",mapnum,(void*)offset,map,&(map[offset])); map[offset] = data; } else { // skip this map @@ -625,14 +662,15 @@ static int vga_write(struct guest_info * core, // There is no default } + + render(vga); return length; } - // PrintError("vga: vga_write UNIMPLEMENTED\n"); /* -up to 256K mapped through a window of 128K +up to 256K mapped through a window of 32 to 128K most cards support linear mode as well @@ -677,16 +715,14 @@ static int vga_read(struct guest_info * core, uint_t length, void * priv_data) { + int i; struct vm_device *dev = (struct vm_device *)priv_data; 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); - if (vga->passthrough) { - memcpy(dst,V3_VAddr((void*)guest_addr),length); - } - /* @@ -767,24 +803,25 @@ static int vga_read(struct guest_info * core, // there is no default } - return length; - -} + if (vga->passthrough) { + PrintDebug("vga: passthrough read from 0x%p\n",V3_VAddr((void*)guest_addr)); + memcpy(dst,V3_VAddr((void*)guest_addr),length); + } + PrintDebug("vga: data read is \""); + for (i=0;i='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') ? c : '.'); + } + PrintDebug("\"\n"); -static int render(struct vga_internal *vga) -{ - PrintError("vga: render UNIMPLEMENTED\n"); + return length; - if (!palacios_linux_fb_hack_pointer) { - return 0; - } +} - return 0; -} #define ERR_WRONG_SIZE(op,reg,len,min,max) \ @@ -832,9 +869,10 @@ static inline void passthrough_io_out(uint16_t port, const void * src, uint_t le do { if ((vga)->passthrough) { passthrough_io_in(port,dest,len); } } while (0) #define PASSTHROUGH_IO_OUT(vga,port,src,len) \ - do { if ((vga)->passthrough) { passthrough_io_in(port,src,len); } } while (0) + do { if ((vga)->passthrough) { passthrough_io_out(port,src,len); } } while (0) - +#define PASSTHROUGH_READ_CHECK(vga,inter,pass) \ + do { if ((vga)->passthrough) { if ((inter)!=(pass)) { PrintError("vga: passthrough error: passthrough value read is 0x%x, but internal value read is 0x%x\n",(pass),(inter)); } } } while (0) static int misc_out_read(struct guest_info *core, uint16_t port, @@ -847,10 +885,12 @@ static int misc_out_read(struct guest_info *core, PrintDebug("vga: misc out read data=0x%x\n", vga->vga_misc.vga_misc_out.val); ERR_WRONG_SIZE("read","misc out",len,1,1); - + + *((uint8_t*)dest) = vga->vga_misc.vga_misc_out.val; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = vga->vga_misc.vga_misc_out.val; + PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_misc_out.val,*((uint8_t*)dest)); return len; } @@ -890,9 +930,11 @@ static int input_stat0_read(struct guest_info *core, ERR_WRONG_SIZE("read","input stat0",len,1,1); + *((uint8_t*)dest) = vga->vga_misc.vga_input_stat0.val; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = vga->vga_misc.vga_input_stat0.val; + PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_input_stat0.val,*(uint8_t*)dest); return len; } @@ -912,7 +954,6 @@ static int input_stat1_read(struct guest_info *core, ERR_WRONG_SIZE("read","input stat1",len,1,1); - PASSTHROUGH_IO_IN(vga,port,dest,len); *((uint8_t*)dest) = vga->vga_misc.vga_input_stat1.val; @@ -922,6 +963,10 @@ static int input_stat1_read(struct guest_info *core, vga->vga_attribute_controller.state=ATTR_ADDR; + PASSTHROUGH_IO_IN(vga,port,dest,len); + + PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_input_stat1.val,*(uint8_t*)dest); + return len; } @@ -939,10 +984,13 @@ static int feature_control_read(struct guest_info *core, ERR_WRONG_SIZE("read","feature control",len,1,1); - PASSTHROUGH_IO_IN(vga,port,dest,len); *((uint8_t*)dest) = vga->vga_misc.vga_feature_control.val; + PASSTHROUGH_IO_IN(vga,port,dest,len); + + PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_feature_control.val,*(uint8_t*)dest); + return len; } @@ -983,9 +1031,11 @@ static int video_subsys_enable_read(struct guest_info *core, ERR_WRONG_SIZE("read","video subsys enable",len,1,1); + *((uint8_t*)dest) = vga->vga_misc.vga_video_subsys_enable.val; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = vga->vga_misc.vga_video_subsys_enable.val; + PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_video_subsys_enable.val,*(uint8_t*)dest); return len; } @@ -1024,9 +1074,11 @@ static int sequencer_address_read(struct guest_info *core, ERR_WRONG_SIZE("read","vga sequencer addr",len,1,1); + *((uint8_t*)dest) = vga->vga_sequencer.vga_sequencer_addr.val; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = vga->vga_sequencer.vga_sequencer_addr.val; + PASSTHROUGH_READ_CHECK(vga,vga->vga_sequencer.vga_sequencer_addr.val,*(uint8_t*)dest); return len; } @@ -1051,7 +1103,12 @@ static int sequencer_data_write(struct guest_info *core, PASSTHROUGH_IO_OUT(vga,port,src,len); - vga->vga_sequencer.vga_sequencer_regs[index] = data; + + if (index>=VGA_SEQUENCER_NUM) { + PrintError("vga: sequencer data write is for invalid index %d, ignoring\n",index); + } else { + vga->vga_sequencer.vga_sequencer_regs[index] = data; + } render(vga); @@ -1069,28 +1126,22 @@ static int sequencer_address_write(struct guest_info *core, new_addr=*((uint8_t*)src); - PrintDebug("vga: sequencer address write data=0x%x len=%u\n", new_addr,len); + PrintDebug("vga: sequencer address write data=0x%x len=%u\n", len==1 ? *((uint8_t*)src) : len==2 ? *((uint16_t*)src) : *((uint32_t*)src), len); ERR_WRONG_SIZE("write","vga sequencer addr",len,1,2); PASSTHROUGH_IO_OUT(vga,port,src,1); - if (new_addr>VGA_SEQUENCER_NUM) { - PrintError("vga: ignoring change of sequencer address to %u (>%u)\n", - new_addr, VGA_SEQUENCER_NUM); - //return -1; - } else { - vga->vga_sequencer.vga_sequencer_addr.val = *((uint8_t*)src) ; - if (len==2) { - // second byte is the data - if (sequencer_data_write(core,port,src+1,1,vga)!=1) { - PrintError("vga: write of data failed\n"); - return -1; - } + vga->vga_sequencer.vga_sequencer_addr.val = *((uint8_t*)src) ; + + if (len==2) { + // second byte is the data + if (sequencer_data_write(core,port,src+1,1,vga)!=1) { + PrintError("vga: write of data failed\n"); + return -1; } } - return len; } @@ -1105,16 +1156,24 @@ static int sequencer_data_read(struct guest_info *core, uint8_t data; index=vga->vga_sequencer.vga_sequencer_addr.val; // should mask probably - data=vga->vga_sequencer.vga_sequencer_regs[index]; - + + if (index>=VGA_SEQUENCER_NUM) { + data=0; + PrintError("vga: sequencer data read at invalid index %d, returning zero\n",index); + } else { + data=vga->vga_sequencer.vga_sequencer_regs[index]; + } + PrintDebug("vga: sequencer data read data (index=%d) = 0x%x\n", - index, data); + index, data); + + ERR_WRONG_SIZE("read","vga sequencer data",len,1,1); - ERR_WRONG_SIZE("read","vga sequenver data",len,1,1); + *((uint8_t*)dest) = data; PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = data; + PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest); return len; } @@ -1137,9 +1196,11 @@ static int crt_controller_address_read(struct guest_info *core, ERR_WRONG_SIZE("read","vga crt controller addr",len,1,1); + *((uint8_t*)dest) = vga->vga_crt_controller.vga_crt_addr.val; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = vga->vga_crt_controller.vga_crt_addr.val; + PASSTHROUGH_READ_CHECK(vga,vga->vga_crt_controller.vga_crt_addr.val,*(uint8_t*)dest); return len; } @@ -1166,7 +1227,11 @@ static int crt_controller_data_write(struct guest_info *core, PASSTHROUGH_IO_OUT(vga,port,src,len); - vga->vga_crt_controller.vga_crt_controller_regs[index] = data; + if (index>=VGA_CRT_CONTROLLER_NUM) { + PrintError("vga; crt controller write is for illegal index %d, ignoring\n",index); + } else { + vga->vga_crt_controller.vga_crt_controller_regs[index] = data; + } render(vga); @@ -1186,28 +1251,22 @@ static int crt_controller_address_write(struct guest_info *core, PrintDebug("vga: crt controller (%s) address write data=0x%x len=%u\n", port==0x3b4 ? "mono" : "color", - new_addr,len); + len==1 ? *((uint8_t*)src) : len==2 ? *((uint16_t*)src) : *((uint32_t*)src), len); ERR_WRONG_SIZE("write","vga crt controller addr",len,1,2); PASSTHROUGH_IO_OUT(vga,port,src,1); - if (new_addr>VGA_CRT_CONTROLLER_NUM) { - PrintError("vga: ignoring change of crt controller address to %u (>%u)\n", - new_addr, VGA_CRT_CONTROLLER_NUM); - //return -1; - } else { - vga->vga_crt_controller.vga_crt_addr.val = *((uint8_t*)src) ; - if (len==2) { - // second byte is the data - if (crt_controller_data_write(core,port,src+1,1,vga)!=1) { - PrintError("vga: write of data failed\n"); - return -1; - } + vga->vga_crt_controller.vga_crt_addr.val = *((uint8_t*)src) ; + + if (len==2) { + // second byte is the data + if (crt_controller_data_write(core,port,src+1,1,vga)!=1) { + PrintError("vga: write of data failed\n"); + return -1; } - } - + return len; } @@ -1222,17 +1281,23 @@ static int crt_controller_data_read(struct guest_info *core, uint8_t data; index=vga->vga_crt_controller.vga_crt_addr.val; // should mask probably - data=vga->vga_crt_controller.vga_crt_controller_regs[index]; - PrintDebug("vga: crt controller data (%s) read data (index=%d) = 0x%x\n", - port==0x3b5 ? "mono" : "color", - index, data); + if (index>=VGA_CRT_CONTROLLER_NUM) { + data=0; + PrintError("vga: crt controller data read for illegal index %d, returning zero\n",index); + } else { + data=vga->vga_crt_controller.vga_crt_controller_regs[index]; + } + PrintDebug("vga: crt controller data (index=%d) = 0x%x\n",index,data); + ERR_WRONG_SIZE("read","vga crt controller data",len,1,1); + *((uint8_t*)dest) = data; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = data; + PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t *)dest); return len; } @@ -1252,9 +1317,11 @@ static int graphics_controller_address_read(struct guest_info *core, ERR_WRONG_SIZE("read","vga graphics controller addr",len,1,1); + *((uint8_t*)dest) = vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; + PASSTHROUGH_READ_CHECK(vga,vga->vga_graphics_controller.vga_graphics_ctrl_addr.val,*(uint8_t*)dest); return len; } @@ -1272,6 +1339,7 @@ static int graphics_controller_data_write(struct guest_info *core, data=*((uint8_t*)src); index=vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; // should mask probably + PrintDebug("vga: graphics_controller write data (index=%d) with 0x%x\n", index, data); @@ -1279,7 +1347,11 @@ static int graphics_controller_data_write(struct guest_info *core, PASSTHROUGH_IO_OUT(vga,port,src,len); - vga->vga_graphics_controller.vga_graphics_controller_regs[index] = data; + if (index>=VGA_GRAPHICS_CONTROLLER_NUM) { + PrintError("vga: graphics controller write for illegal index %d ignored\n",index); + } else { + vga->vga_graphics_controller.vga_graphics_controller_regs[index] = data; + } render(vga); @@ -1297,26 +1369,23 @@ static int graphics_controller_address_write(struct guest_info *core, new_addr=*((uint8_t*)src); - PrintDebug("vga: graphics controller address write data=0x%x len=%u\n", new_addr,len); + PrintDebug("vga: graphics controller address write data=0x%x len=%u\n", + len==1 ? *((uint8_t*)src) : len==2 ? *((uint16_t*)src) : *((uint32_t*)src), len); ERR_WRONG_SIZE("write","vga graphics controller addr",len,1,2); PASSTHROUGH_IO_OUT(vga,port,src,1); - if (new_addr>VGA_GRAPHICS_CONTROLLER_NUM) { - PrintError("vga: ignoring change of graphics controller address to %u (>%u)\n", - new_addr, VGA_GRAPHICS_CONTROLLER_NUM); - //return -1; - } else { - vga->vga_graphics_controller.vga_graphics_ctrl_addr.val = *((uint8_t*)src) ; - if (len==2) { - // second byte is the data - if (graphics_controller_data_write(core,port,src+1,1,vga)!=1) { - PrintError("vga: write of data failed\n"); - return -1; - } + vga->vga_graphics_controller.vga_graphics_ctrl_addr.val = *((uint8_t*)src) ; + + if (len==2) { + // second byte is the data + if (graphics_controller_data_write(core,port,src+1,1,vga)!=1) { + PrintError("vga: write of data failed\n"); + return -1; } } + return len; } @@ -1331,17 +1400,26 @@ static int graphics_controller_data_read(struct guest_info *core, uint8_t data; index=vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; // should mask probably - data=vga->vga_graphics_controller.vga_graphics_controller_regs[index]; + + + if (index>=VGA_GRAPHICS_CONTROLLER_NUM) { + data=0; + PrintError("vga: graphics controller data read from illegal index %d, returning zero\n",index); + } else { + data=vga->vga_graphics_controller.vga_graphics_controller_regs[index]; + } PrintDebug("vga: graphics controller data read data (index=%d) = 0x%x\n", index, data); ERR_WRONG_SIZE("read","vga graphics controller data",len,1,1); - PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = data; + PASSTHROUGH_IO_IN(vga,port,dest,len); + + PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest); + return len; } @@ -1363,9 +1441,11 @@ static int attribute_controller_address_read(struct guest_info *core, ERR_WRONG_SIZE("read","vga attribute controller addr",len,1,1); + *((uint8_t*)dest) = vga->vga_attribute_controller.vga_attribute_controller_addr.val; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = vga->vga_attribute_controller.vga_attribute_controller_addr.val; + PASSTHROUGH_READ_CHECK(vga,vga->vga_attribute_controller.vga_attribute_controller_addr.val,*(uint8_t*)dest); // Reading the attribute controller does not change the state @@ -1391,13 +1471,8 @@ static int attribute_controller_address_and_data_write(struct guest_info *core, PASSTHROUGH_IO_OUT(vga,port,src,len); - if (new_addr>VGA_ATTRIBUTE_CONTROLLER_NUM) { - PrintError("vga: ignoring change of attribute controller address to %u (>%u)\n", - new_addr, VGA_ATTRIBUTE_CONTROLLER_NUM); - //return -1; - } else { - vga->vga_attribute_controller.vga_attribute_controller_addr.val = *((uint8_t*)src) ; - } + vga->vga_attribute_controller.vga_attribute_controller_addr.val = new_addr; + vga->vga_attribute_controller.state=ATTR_DATA; return len; @@ -1412,7 +1487,11 @@ static int attribute_controller_address_and_data_write(struct guest_info *core, PASSTHROUGH_IO_OUT(vga,port,src,len); - vga->vga_attribute_controller.vga_attribute_controller_regs[index] = data; + if (index>=VGA_ATTRIBUTE_CONTROLLER_NUM) { + PrintError("vga: attribute controller write to illegal index %d ignored\n",index); + } else { + vga->vga_attribute_controller.vga_attribute_controller_regs[index] = data; + } vga->vga_attribute_controller.state=ATTR_ADDR; @@ -1434,16 +1513,24 @@ static int attribute_controller_data_read(struct guest_info *core, uint8_t data; index=vga->vga_attribute_controller.vga_attribute_controller_addr.val; // should mask probably - data=vga->vga_attribute_controller.vga_attribute_controller_regs[index]; + + if (index>=VGA_ATTRIBUTE_CONTROLLER_NUM) { + data=0; + PrintError("vga: attribute controller read of illegal index %d, returning zero\n",index); + } else { + data=vga->vga_attribute_controller.vga_attribute_controller_regs[index]; + } PrintDebug("vga: attribute controller data read data (index=%d) = 0x%x\n", index, data); ERR_WRONG_SIZE("read","vga attribute controller data",len,1,1); + *((uint8_t*)dest) = data; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = data; + PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest); return len; } @@ -1467,10 +1554,13 @@ static int dac_write_address_read(struct guest_info *core, ERR_WRONG_SIZE("read","vga dac write addr",len,1,1); - PASSTHROUGH_IO_IN(vga,port,dest,len); *((uint8_t*)dest) = vga->vga_dac.vga_dac_write_addr; + PASSTHROUGH_IO_IN(vga,port,dest,len); + + PASSTHROUGH_READ_CHECK(vga,vga->vga_dac.vga_dac_write_addr,*(uint8_t*)dest); + // This read does not reset the state machine return len; @@ -1519,10 +1609,12 @@ static int dac_read_address_read(struct guest_info *core, ERR_WRONG_SIZE("read","vga dac read addr",len,1,1); - PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = vga->vga_dac.vga_dac_read_addr; + PASSTHROUGH_IO_IN(vga,port,dest,len); + + PASSTHROUGH_READ_CHECK(vga,vga->vga_dac.vga_dac_read_addr,*(uint8_t*)dest); + // This read does not reset the state machine return len; @@ -1576,8 +1668,6 @@ static int dac_data_read(struct guest_info *core, ERR_WRONG_SIZE("read","vga dac read data",len,1,1); - PASSTHROUGH_IO_IN(vga,port,dest,len); - curreg = vga->vga_dac.vga_dac_read_addr; curchannel = vga->vga_dac.channel; data = (vga->vga_dac.vga_dac_palette[curreg] >> curchannel*8) & 0x3f; @@ -1589,6 +1679,10 @@ static int dac_data_read(struct guest_info *core, data); *((uint8_t*)dest) = data; + + PASSTHROUGH_IO_IN(vga,port,dest,len); + + PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest); curchannel = (curchannel+1)%3; vga->vga_dac.channel=curchannel; @@ -1670,9 +1764,11 @@ static int dac_pixel_mask_read(struct guest_info *core, ERR_WRONG_SIZE("read","vga pixel mask",len,1,1); + *((uint8_t*)dest) = vga->vga_dac.vga_pixel_mask; + PASSTHROUGH_IO_IN(vga,port,dest,len); - *((uint8_t*)dest) = vga->vga_dac.vga_pixel_mask; + PASSTHROUGH_READ_CHECK(vga,vga->vga_dac.vga_pixel_mask,*(uint8_t*)dest); return len; } diff --git a/palacios/src/palacios/vmm_emulator.c b/palacios/src/palacios/vmm_emulator.c index 1a0e868..f371356 100644 --- a/palacios/src/palacios/vmm_emulator.c +++ b/palacios/src/palacios/vmm_emulator.c @@ -11,7 +11,8 @@ * Copyright (c) 2008, The V3VEE Project * All rights reserved. * - * Author: Jack Lange + * Authors: Jack Lange + * Peter Dinda (full hook/string ops) * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "V3VEE_LICENSE". @@ -150,8 +151,11 @@ static int emulate_string_write_op(struct guest_info * info, struct x86_instr * /* - This function is intended to handle pure read hooks, pure write hook, and full hooks, - with and without backing memory for writes + This function is intended to handle pure read hooks, pure write hooks, and full hooks, + with and without backing memory for reads and writes + + A MAXIMUM OF ONE PAGE IS TRANSFERED BUT REGISTERS ARE UPDATED SO THAT + THE INSTRUCTION CAN BE RESTARTED read_fn == NULL orig_src_addr == NULL => data at read_gpa is read @@ -168,29 +172,38 @@ static int emulate_string_write_op(struct guest_info * info, struct x86_instr * */ static int emulate_string_op(struct guest_info * info, struct x86_instr * dec_instr, - addr_t read_gva, addr_t read_gpa, addr_t orig_src_addr, - addr_t write_gva, addr_t write_gpa, addr_t orig_dst_addr, + addr_t read_gva, addr_t read_gpa, addr_t read_hva, + addr_t write_gva, addr_t write_gpa, addr_t write_hva, int (*read_fn)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data), - int (*write_fn)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data), - void * priv_data) + void * read_priv_data, + int (*write_fn)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data), + void * write_priv_data) { uint_t src_emulation_length = 0; uint_t dst_emulation_length = 0; uint_t emulation_length = 0; uint_t emulation_iter_cnt = 0; addr_t tmp_rcx = 0; - addr_t src_addr, dst_addr; + addr_t src_hva, dst_hva; + + PrintDebug("emulate_string_op: read_gva=0x%p, read_gpa=0x%p, read_hva=0x%p, write_gva=0x%p, write_gpa=0x%p, write_hva=0x%p, read_fn=0x%p, read_priv_data=0x%p, write_fn=0x%p, write_priv_data=0x%p, len=0x%p\n", + (void*)read_gva,(void*)read_gpa,(void*)read_hva, (void*)write_gva,(void*)write_gpa,(void*)write_hva, + (void*)read_fn, (void*)read_priv_data, (void*)write_fn, (void*)write_priv_data, (void*)(dec_instr->str_op_length)); + + // v3_print_instr(dec_instr); // Sanity check the decoded instruction if (info->shdw_pg_mode == SHADOW_PAGING) { - if (!read_fn && (dec_instr->src_operand.operand != read_gva)) { + // If we're reading, we better have a sane gva + if ((read_hva || read_fn) && (dec_instr->src_operand.operand != read_gva)) { PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p (Read)\n", (void *)dec_instr->src_operand.operand, (void *)read_gva); return -1; } - if (!write_fn && (dec_instr->dst_operand.operand != write_gva)) { + // if we're writing, we better have a sane gva + if ((write_hva || write_fn) && (dec_instr->dst_operand.operand != write_gva)) { PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p (Write)\n", (void *)dec_instr->dst_operand.operand, (void *)write_gva); return -1; @@ -230,9 +243,11 @@ static int emulate_string_op(struct guest_info * info, struct x86_instr * dec_in if (src_emulation_lengthdst_emulation_length) { emulation_length=dst_emulation_length; + // Note that this error is what is to be expected if you're coping to a different offset on a page PrintError("Warning: emulate_string_op has src length %u but dst length %u\n", src_emulation_length, dst_emulation_length); } else { // equal @@ -243,60 +258,74 @@ static int emulate_string_op(struct guest_info * info, struct x86_instr * dec_in // Fetch the data if (read_fn) { - src_addr = (addr_t) V3_Malloc(emulation_length); // hideous - should reuse memory - if (!src_addr) { + // This is a full hook - full hooks never have backing memory + // This should use the scratch page allocated for the hook, but + // we do not know where that is at this point + src_hva = (addr_t) V3_Malloc(emulation_length); // hideous - should reuse memory + if (!src_hva) { PrintError("Unable to allocate space for read operation in emulate_string_read_op\n"); return -1; } - if (read_fn(info, read_gpa, (void *)src_addr, emulation_length, priv_data) != emulation_length) { + if (read_fn(info, read_gpa, (void *)src_hva, emulation_length, read_priv_data) != emulation_length) { PrintError("Did not fully read hooked data in emulate_string_op\n"); return -1; } } else { - if (orig_src_addr) { - src_addr=orig_src_addr; + // This is ordinary memory + if (read_hva) { + // The caller told us where to read from + src_hva=read_hva; } else { + // We need to figure out where to read from if (info->mem_mode == PHYSICAL_MEM) { - if (v3_gpa_to_hva(info, dec_instr->src_operand.operand, &src_addr) == -1) { + if (v3_gpa_to_hva(info, dec_instr->src_operand.operand, &src_hva) == -1) { PrintError("Could not translate write Source (Physical) to host VA\n"); return -1; } } else { - if (v3_gva_to_hva(info, dec_instr->src_operand.operand, &src_addr) == -1) { + if (v3_gva_to_hva(info, dec_instr->src_operand.operand, &src_hva) == -1) { PrintError("Could not translate write Source (Virtual) to host VA\n"); return -1; - } + } } } } - // Now src_addr points to the fetched data in HVA + // Now src_hva points to the fetched data or to the in-VM data // Allocate space for the write, in case we need to copy out later if (write_fn) { - if (orig_dst_addr) { - dst_addr=orig_dst_addr; + // This is a full hook or a write hook + if (write_hva) { + // This is a write hook with backing memory + // The caller already told us where that memory is + dst_hva = write_hva; } else { - dst_addr = (addr_t) V3_Malloc(emulation_length); // yuck - if (!dst_addr) { + // This is a full hook without backing memory + // Again, should use the scratch memory + dst_hva = (addr_t) V3_Malloc(emulation_length); // yuck + if (!dst_hva) { PrintError("Unable to allocate space for write operation in emulate_string_op\n"); if (read_fn) { - V3_Free((void*)src_addr); + V3_Free((void*)src_hva); } return -1; } } } else { - if (orig_dst_addr) { - dst_addr=orig_dst_addr; + // This is ordinary memory + if (write_hva) { + // The caller told us where to write + dst_hva=write_hva; } else { + // We need to figure out where to write if (info->mem_mode == PHYSICAL_MEM) { - if (v3_gpa_to_hva(info, dec_instr->dst_operand.operand, &dst_addr) == -1) { + if (v3_gpa_to_hva(info, dec_instr->dst_operand.operand, &dst_hva) == -1) { PrintError("Could not translate write Dest (Physical) to host VA\n"); return -1; } } else { - if (v3_gva_to_hva(info, dec_instr->dst_operand.operand, &dst_addr) == -1) { + if (v3_gva_to_hva(info, dec_instr->dst_operand.operand, &dst_hva) == -1) { PrintError("Could not translate write Dest (Virtual) to host VA\n"); return -1; } @@ -311,19 +340,24 @@ static int emulate_string_op(struct guest_info * info, struct x86_instr * dec_in tmp_rcx = emulation_iter_cnt; + // Do the actual emulation + // The instruction implementation operates from data at src_hva to data at dest_hva + // Furthemore, it must operate for emulation_length steps + // And update tmp_rcx + // And the real rcx if we do have a rep prefix switch (dec_instr->op_type) { case V3_OP_MOVS: { if (dec_instr->dst_operand.size == 1) { - movs8((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + movs8((addr_t *)&dst_hva, &src_hva, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); } else if (dec_instr->dst_operand.size == 2) { - movs16((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + movs16((addr_t *)&dst_hva, &src_hva, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); } else if (dec_instr->dst_operand.size == 4) { - movs32((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + movs32((addr_t *)&dst_hva, &src_hva, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); #ifdef __V3_64BIT__ } else if (dec_instr->dst_operand.size == 8) { - movs64((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + movs64((addr_t *)&dst_hva, &src_hva, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); #endif } else { PrintError("Invalid operand length\n"); @@ -346,14 +380,14 @@ static int emulate_string_op(struct guest_info * info, struct x86_instr * dec_in case V3_OP_STOS: { if (dec_instr->dst_operand.size == 1) { - stos8((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + stos8((addr_t *)&dst_hva, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); } else if (dec_instr->dst_operand.size == 2) { - stos16((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + stos16((addr_t *)&dst_hva, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); } else if (dec_instr->dst_operand.size == 4) { - stos32((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + stos32((addr_t *)&dst_hva, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); #ifdef __V3_64BIT__ } else if (dec_instr->dst_operand.size == 8) { - stos64((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + stos64((addr_t *)&dst_hva, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); #endif } else { PrintError("Invalid operand length\n"); @@ -377,16 +411,19 @@ static int emulate_string_op(struct guest_info * info, struct x86_instr * dec_in break; } - // At this point, the data has been written over dst_addr, which - // is either our temporary buffer, or it's the requested target in orig_dst_addr + // At this point, the data has been written over dst_hva, which + // is either our temporary buffer, or it's the requested target in write_hva if (write_fn) { - if (write_fn(info, write_gpa, (void *)dst_addr, emulation_length, priv_data) != emulation_length) { + if (write_fn(info, write_gpa, (void *)dst_hva, emulation_length, write_priv_data) != emulation_length) { PrintError("Did not fully write hooked data\n"); return -1; } } + // We only goto the next instruction if we have finished operating on all the data. + // If we haven't we'll restart the same instruction, but with rdi/rsi/rcx updated + // This is also how we handle going over a page boundary if (emulation_length == dec_instr->str_op_length) { info->rip += dec_instr->instr_length; } @@ -394,10 +431,10 @@ static int emulate_string_op(struct guest_info * info, struct x86_instr * dec_in // Delete temporary buffers if (read_fn) { - V3_Free((void*)src_addr); + V3_Free((void*)src_hva); } - if (write_fn && !orig_dst_addr) { - V3_Free((void*)dst_addr); + if (write_fn && !write_hva) { + V3_Free((void*)dst_hva); } @@ -679,11 +716,102 @@ int v3_emulate_read_op(struct guest_info * info, addr_t read_gva, addr_t read_gp } if (dec_instr.is_str_op) { + // We got here due to a read fault due to a full memory hook on the + // region being READ. Thus our current write_fn is also for that region + // We need the region that will be WRITTEN, which we need to look up + // That region could be write or full hooked, in which case we need + // the associated write function for that region. If it's not + // hooked, then we need the relevant hva + // + // This all assumes that emulate_string_op() will handle at most + // a single page. Therefore we can consider only the starting pages + // for the read and write sides. We will restart the instruction on + // the next page, if needed. + addr_t write_gpa=0; + addr_t write_gva=0; + addr_t write_hva=0; + int (*dest_write_fn)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data)=0; + void *dest_write_priv_data; + struct v3_mem_region *dest_reg; + + if (dec_instr.dst_operand.type != MEM_OPERAND) { + write_gpa=0; + write_gva=0; + write_hva=0; // should calc target here and continue + dest_write_fn=0; + dest_write_priv_data=0; + PrintError("Emulation of string ops with non-memory destinations currently unsupported\n"); + v3_print_instr(&dec_instr); + return -1; + } else { + if (info->mem_mode == PHYSICAL_MEM) { + write_gpa = dec_instr.dst_operand.operand; + write_gva = write_gpa; + } else { + write_gva = dec_instr.dst_operand.operand; + if (v3_gva_to_gpa(info, dec_instr.dst_operand.operand, &write_gpa) == -1) { + // We are going to inject "Not Present" here to try to force + // the guest to build a PTE we can use. + // This needs to be fixed to inject the appropraite page fault + // given access permissions + struct pf_error_code c; + c.present=0; + c.write=0; + c.user=0; + c.rsvd_access=0; + c.ifetch=0; + c.rsvd=0; + v3_inject_guest_pf(info,write_gva,c); + return 0; + } + } + + // First we need to find the region to determine if we will need to write + // back to it and to check access + if (!(dest_reg=v3_get_mem_region(info->vm_info,info->cpu_id,write_gpa))) { + PrintError("Could not look up region for destination of string op\n"); + v3_print_instr(&dec_instr); + return -1; + } + + + if (dest_reg->flags.alloced) { + // We will need to write back to memory in addition to any hook function + if (v3_gpa_to_hva(info, write_gpa, &write_hva) == -1) { + PrintError("Unable to convert gpa to hva in emulation of string op write\n"); + v3_print_instr(&dec_instr); + return -1; + } + } else { + write_hva=0; // no actual writeback - hook function only + } + + // Now that we have the write_gpa, we need to find out whether it's a hooked region + // or just plain memory + + if (v3_find_mem_hook(info->vm_info, info->cpu_id, write_gpa, + 0, 0, // don't want the read function/data even if they exist + &dest_write_fn,&dest_write_priv_data) == -1) { + PrintError("Finding write destination memory hook failed\n"); + v3_print_instr(&dec_instr); + return -1; + } + + // We must have either or both of a write_hva and a dest_write_fn + if (!dest_write_fn && !write_hva) { + PrintError("Destination of string write has neither physical memory nor write hook!\n"); + v3_print_instr(&dec_instr); + return -1; + } + } + + return emulate_string_op(info,&dec_instr, - read_gva,read_gpa,0, - 0, 0, 0, - read_fn,write_fn, - priv_data); + read_gva,read_gpa, 0, // 0=> read hook has no backing memory + write_gva, write_gpa, write_hva, + read_fn, priv_data, // This is from the original call + dest_write_fn, dest_write_priv_data); // This is from our lookup + } else if (dec_instr.op_type == V3_OP_XCHG) { return emulate_xchg_read_op(info, &dec_instr, read_gva, read_gpa, src_addr, read_fn, write_fn, priv_data); } @@ -720,8 +848,8 @@ int v3_emulate_read_op(struct guest_info * info, addr_t read_gva, addr_t read_gp src_op_len = dec_instr.src_operand.size; dst_op_len = dec_instr.dst_operand.size; - PrintDebug("Dst_Addr = %p, SRC Addr = %p\n", - (void *)dst_addr, (void *)src_addr); + PrintDebug("Dst_Addr = %p, SRC Addr = %p\n", + (void *)dst_addr, (void *)src_addr); if (read_fn(info, read_gpa, (void *)src_addr, src_op_len, priv_data) != src_op_len) { PrintError("Did not fully read hooked data\n"); diff --git a/palacios/src/palacios/vmm_mem_hook.c b/palacios/src/palacios/vmm_mem_hook.c index 46c84cc..0b6c6b0 100644 --- a/palacios/src/palacios/vmm_mem_hook.c +++ b/palacios/src/palacios/vmm_mem_hook.c @@ -106,7 +106,7 @@ static int handle_mem_hook(struct guest_info * info, addr_t guest_va, addr_t gue return -1; } } else { - // Read Operation + // Read Operation or a read->write (e.g., string ops) if (reg->flags.read == 1) { PrintError("Tried to emulate read for a guest Readable page\n"); @@ -226,5 +226,43 @@ int v3_unhook_mem(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr_st return 0; } +// Return the read and/or write hook functions of the region associated +// with the address, if any. +// +int v3_find_mem_hook(struct v3_vm_info *vm, uint16_t core_id, addr_t guest_addr, + int (**read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data), + void **read_priv_data, + int (**write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data), + void **write_priv_data) +{ + struct v3_mem_region * reg = v3_get_mem_region(vm, core_id, guest_addr); + + if (!reg) { + return -1; + } + + // Should probably sanity-check the region smarter than the following + + struct mem_hook * hook = reg->priv_data; + + if (!hook) { + // This must be a simple memory region without hooks + if (read) { *read=0;} + if (read_priv_data) { *read_priv_data=0;} + if (write) { *write=0;} + if (write_priv_data) { *write_priv_data=0;} + return 0; + } + + // There is some form of hook here - copy it out for the caller + + if (read) { *read=hook->read;} + if (read_priv_data) { *read_priv_data=hook->priv_data;} + if (write) { *write=hook->write;} + if (write_priv_data) { *write_priv_data=hook->priv_data;} + + return 0; + +} diff --git a/palacios/src/palacios/vmm_paging.c b/palacios/src/palacios/vmm_paging.c index 05d1025..ec91056 100644 --- a/palacios/src/palacios/vmm_paging.c +++ b/palacios/src/palacios/vmm_paging.c @@ -971,9 +971,7 @@ int v3_drill_guest_pt_32(struct guest_info * info, v3_reg_t guest_cr3, addr_t va addr_t large_page_va = 0; if (v3_gpa_to_hva(info, large_page_pa, &large_page_va) == -1) { - PrintError("Could not get virtual address of Guest Page 4MB (PA=%p)\n", - (void *)large_page_va); - return -1; + large_page_va = 0 ; } @@ -1003,9 +1001,7 @@ int v3_drill_guest_pt_32(struct guest_info * info, v3_reg_t guest_cr3, addr_t va addr_t page_va; if (v3_gpa_to_hva(info, page_pa, &page_va) == -1) { - PrintError("Could not get virtual address of Guest Page 4KB (PA=%p)\n", - (void *)page_pa); - return -1; + page_va = 0; } if ((ret = callback(info, PAGE_4KB, vaddr, page_va, page_pa, private_data)) != 0) { @@ -1070,9 +1066,7 @@ int v3_drill_guest_pt_32pae(struct guest_info * info, v3_reg_t guest_cr3, addr_t addr_t large_page_va = 0; if (v3_gpa_to_hva(info, large_page_pa, &large_page_va) == -1) { - PrintDebug("Could not get virtual address of Guest Page 2MB (PA=%p)\n", - (void *)large_page_va); - + large_page_va = 0; } if ((ret == callback(info, PAGE_2MB, vaddr, large_page_va, large_page_pa, private_data)) != 0) { @@ -1101,9 +1095,7 @@ int v3_drill_guest_pt_32pae(struct guest_info * info, v3_reg_t guest_cr3, addr_t addr_t page_va; if (v3_gpa_to_hva(info, page_pa, &page_va) == -1) { - PrintError("Could not get virtual address of Guest Page 4KB (PA=%p)\n", - (void *)page_pa); - return -1; + page_va = 0; } if ((ret = callback(info, PAGE_4KB, vaddr, page_va, page_pa, private_data)) != 0) { @@ -1169,9 +1161,7 @@ int v3_drill_guest_pt_64(struct guest_info * info, v3_reg_t guest_cr3, addr_t va addr_t large_page_va = 0; if (v3_gpa_to_hva(info, large_page_pa, &large_page_va) == -1) { - PrintDebug("Could not get virtual address of Guest Page 1GB (PA=%p)\n", - (void *)large_page_va); - + large_page_va = 0; } if ((ret == callback(info, PAGE_1GB, vaddr, large_page_va, large_page_pa, private_data)) != 0) { @@ -1204,9 +1194,7 @@ int v3_drill_guest_pt_64(struct guest_info * info, v3_reg_t guest_cr3, addr_t va addr_t large_page_va = 0; if (v3_gpa_to_hva(info, large_page_pa, &large_page_va) == -1) { - PrintDebug("Could not get virtual address of Guest Page 2MB (PA=%p)\n", - (void *)large_page_va); - + large_page_va = 0; } if ((ret == callback(info, PAGE_2MB, vaddr, large_page_va, large_page_pa, private_data)) != 0) { @@ -1235,9 +1223,7 @@ int v3_drill_guest_pt_64(struct guest_info * info, v3_reg_t guest_cr3, addr_t va addr_t page_va; if (v3_gpa_to_hva(info, page_pa, &page_va) == -1) { - PrintError("Could not get virtual address of Guest Page 4KB (PA=%p)\n", - (void *)page_pa); - return -1; + page_va = 0; } if ((ret = callback(info, PAGE_4KB, vaddr, page_va, page_pa, private_data)) != 0) {