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;
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__ */
#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 */
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
};
+
+static int render(struct vga_internal *vga)
+{
+ vga->updates_since_render++;
+
+ if (vga->updates_since_render<UPDATES_PER_RENDER) {
+ return 0;
+ }
+
+ // PrintError("vga: render UNIMPLEMENTED\n");
+
+ vga->updates_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) {
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<length;i++) {
+ char c= ((char*)src)[i];
+ PrintDebug("%c", (c>='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) {
// 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
// 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
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);
- }
-
/*
// 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<length;i++) {
+ char c= ((char*)dst)[i];
+ PrintDebug("%c", (c>='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) \
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,
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;
}
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;
}
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;
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;
}
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;
}
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;
}
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;
}
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);
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;
}
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;
}
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;
}
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);
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;
}
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;
}
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;
}
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);
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);
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;
}
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;
}
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
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;
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;
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;
}
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;
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;
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;
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;
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;
}
* Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
* All rights reserved.
*
- * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ * Authors: Jack Lange <jarusl@cs.northwestern.edu>
+ * Peter Dinda <pdinda@northwestern.edu> (full hook/string ops)
*
* This is free software. You are permitted to use,
* redistribute, and modify it as specified in the file "V3VEE_LICENSE".
/*
- 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
*/
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;
if (src_emulation_length<dst_emulation_length) {
emulation_length=src_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 if (src_emulation_length>dst_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
// 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;
}
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");
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");
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;
}
// 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);
}
}
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);
}
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");
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");
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;
+
+}
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 ;
}
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) {
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) {
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) {
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) {
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) {
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) {