From: Jack Lange Date: Sun, 25 Jan 2009 21:12:26 +0000 (-0600) Subject: working instruction emulation X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=da0f0deecf22754656bad2a95640461ec3ac4f1d working instruction emulation --- diff --git a/palacios/build/Makefile b/palacios/build/Makefile index 6a17541..6d60c7e 100644 --- a/palacios/build/Makefile +++ b/palacios/build/Makefile @@ -399,11 +399,11 @@ CC_GENERAL_OPTS = \ $(EXTRA_C_OPTS) \ $(VMM_FLAGS) \ -I$(PROJECT_ROOT)/include \ - -fPIC \ -Werror \ -Wp,-MD,$(@D)/.$(@F).d \ -Wp,-MT,$@ \ +#-fPIC \ #-fvisibility=hidden diff --git a/palacios/include/palacios/vm_guest.h b/palacios/include/palacios/vm_guest.h index e1a9199..eb67f2b 100644 --- a/palacios/include/palacios/vm_guest.h +++ b/palacios/include/palacios/vm_guest.h @@ -144,12 +144,12 @@ struct guest_info { struct v3_dbg_regs dbg_regs; struct v3_segments segments; - struct emulation_state emulator; - v3_vm_operating_mode_t run_state; void * vmm_data; + void * decoder_state; + struct v3_msr guest_efer; /* TEMP */ diff --git a/palacios/include/palacios/vmm.h b/palacios/include/palacios/vmm.h index b164213..549ccb1 100644 --- a/palacios/include/palacios/vmm.h +++ b/palacios/include/palacios/vmm.h @@ -35,7 +35,7 @@ /* utility definitions */ -#ifdef VMM_DEBUG + #define PrintDebug(fmt, args...) \ do { \ extern struct v3_os_hooks * os_hooks; \ @@ -43,6 +43,8 @@ (os_hooks)->print_debug((fmt), ##args); \ } \ } while (0) + +#if 1 #else #define PrintDebug(fmt,args ...) #endif diff --git a/palacios/include/palacios/vmm_decoder.h b/palacios/include/palacios/vmm_decoder.h index cfe5ff7..ff70106 100644 --- a/palacios/include/palacios/vmm_decoder.h +++ b/palacios/include/palacios/vmm_decoder.h @@ -27,6 +27,16 @@ #include +typedef enum { V3_INVALID_OP, + V3_OP_MOVCR2, V3_OP_MOV2CR, V3_OP_SMSW, V3_OP_LMSW, V3_OP_CLTS, + V3_OP_ADC, V3_OP_ADD, V3_OP_AND, V3_OP_OR, V3_OP_XOR, V3_OP_SUB, + V3_OP_INC, V3_OP_DEC, V3_OP_NEG, V3_OP_MOV, V3_OP_NOT, V3_OP_XCHG, + V3_OP_SETB, V3_OP_SETBE, V3_OP_SETL, V3_OP_SETLE, V3_OP_SETNB, + V3_OP_SETNBE, V3_OP_SETNL, V3_OP_SETNLE, V3_OP_SETNO, V3_OP_SETNP, + V3_OP_SETNS, V3_OP_SETNZ, V3_OP_SETO, V3_OP_SETP, V3_OP_SETS, + V3_OP_SETZ, V3_OP_MOVS} v3_op_type_t; + + typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND, IMM_OPERAND} v3_operand_type_t; struct x86_operand { @@ -49,7 +59,7 @@ struct x86_prefixes { uint_t fs_override : 1; // 0x64 uint_t gs_override : 1; // 0x65 uint_t br_not_taken : 1; // 0x2E - uint_t br_takend : 1; // 0x3E + uint_t br_taken : 1; // 0x3E uint_t op_size : 1; // 0x66 uint_t addr_size : 1; // 0x67 }; @@ -58,11 +68,13 @@ struct x86_prefixes { struct x86_instr { struct x86_prefixes prefixes; uint_t instr_length; - addr_t opcode; // a pointer to the V3_OPCODE_[*] arrays defined below + v3_op_type_t op_type; uint_t num_operands; struct x86_operand dst_operand; struct x86_operand src_operand; struct x86_operand third_operand; + addr_t str_op_length; + addr_t is_str_op; void * decoder_data; }; @@ -119,7 +131,7 @@ int v3_basic_mem_decode(struct guest_info * info, addr_t instr_ptr, struct basic /* Removes a rep prefix in place */ void v3_strip_rep_prefix(uchar_t * instr, int length); - +void v3_get_prefixes(uchar_t * instr, struct x86_prefixes * prefixes); /* @@ -476,7 +488,7 @@ static inline v3_operand_type_t decode_operands32(struct v3_gprs * gprs, // inpu base_addr = gprs->rax; break; case 1: - base_addr = gprs->rcx; + base_addr = gprs->rcx; break; case 2: base_addr = gprs->rdx; diff --git a/palacios/include/palacios/vmm_emulator.h b/palacios/include/palacios/vmm_emulator.h index 45cfa44..86c85c8 100644 --- a/palacios/include/palacios/vmm_emulator.h +++ b/palacios/include/palacios/vmm_emulator.h @@ -22,68 +22,13 @@ #ifdef __V3VEE__ -#include #include #include - -struct emulated_page { - addr_t page_addr; - addr_t va; - pte32_t pte; - struct list_head page_list; -}; - -struct saved_page { - addr_t va; - pte32_t pte; - struct list_head page_list; -}; - - -struct write_region { - void * write_data; - - uint_t length; - int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data); - addr_t write_addr; - void * private_data; - - struct list_head write_list; -}; - - -struct emulation_state { - uint_t num_emulated_pages; - struct list_head emulated_pages; - - uint_t num_saved_pages; - struct list_head saved_pages; - - uint_t num_write_regions; - struct list_head write_regions; - - uint_t running : 1; - uint_t instr_length; - - uint_t tf_enabled : 1; -}; - - -int v3_init_emulator(struct guest_info * info); - - -int v3_emulation_exit_handler(struct guest_info * info); - -int v3_emulate_memory_write(struct guest_info * info, addr_t fault_gva, - int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data), - addr_t write_addr, void * private_data); -int v3_emulate_memory_read(struct guest_info * info, addr_t fault_gva, - int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data), - addr_t read_addr, void * private_data); +int v3_emulate_write_op(struct guest_info * info, addr_t fault_gva, addr_t write_gpa, addr_t * dst_addr); #endif // !__V3VEE__ diff --git a/palacios/include/palacios/vmm_instr_emulator.h b/palacios/include/palacios/vmm_instr_emulator.h new file mode 100644 index 0000000..190dcee --- /dev/null +++ b/palacios/include/palacios/vmm_instr_emulator.h @@ -0,0 +1,423 @@ +#include + + + +#define MAKE_1OP_8FLAGS_INST(iname) static inline void iname##8(addr_t * dst, addr_t * flags) { \ + uchar_t tmp_dst = *dst; \ + \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %2; " \ + "popf; " \ + #iname"b %0; " \ + "pushf; " \ + "pop %1; " \ + "popf; " \ + : "=q"(tmp_dst),"=q"(*flags) \ + : "q"(*flags), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + *flags |= flags_rsvd; \ + \ + } + +#define MAKE_1OP_16FLAGS_INST(iname) static inline void iname##16(addr_t * dst, addr_t * flags) { \ + ushort_t tmp_dst = *dst; \ + \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %2; " \ + "popf; " \ + #iname"w %0; " \ + "pushf; " \ + "pop %1; " \ + "popf; " \ + : "=q"(tmp_dst),"=q"(*flags) \ + : "q"(*flags), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + *flags |= flags_rsvd; \ + \ + } + +#define MAKE_1OP_32FLAGS_INST(iname) static inline void iname##32(addr_t * dst, addr_t * flags) { \ + uint_t tmp_dst = *dst; \ + \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %2; " \ + "popf; " \ + #iname"l %0; " \ + "pushf; " \ + "pop %1; " \ + "popf; " \ + : "=q"(tmp_dst),"=q"(*flags) \ + : "q"(*flags), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + *flags |= flags_rsvd; \ + \ + } + +#define MAKE_1OP_64FLAGS_INST(iname) static inline void iname##64(addr_t * dst, addr_t * flags) { \ + ullong_t tmp_dst = *dst; \ + \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushfq; " \ + "push %2; " \ + "popfq; " \ + #iname"q %0; " \ + "pushfq; " \ + "pop %1; " \ + "popfq; " \ + : "=q"(tmp_dst),"=q"(*flags) \ + : "q"(*flags), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + *flags |= flags_rsvd; \ + \ + } + + + +#define MAKE_1OP_8_INST(iname) static inline void iname##8(addr_t * dst) { \ + uchar_t tmp_dst = *dst; \ + \ + asm volatile ( \ + #iname"b %0; " \ + : "=q"(tmp_dst) \ + : "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + } + +#define MAKE_1OP_16_INST(iname) static inline void iname##16(addr_t * dst) { \ + ushort_t tmp_dst = *dst; \ + \ + asm volatile ( \ + #iname"w %0; " \ + : "=q"(tmp_dst) \ + : "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + } + +#define MAKE_1OP_32_INST(iname) static inline void iname##32(addr_t * dst) { \ + uint_t tmp_dst = *dst; \ + \ + asm volatile ( \ + #iname"l %0; " \ + : "=q"(tmp_dst) \ + : "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + } + +#define MAKE_1OP_64_INST(iname) static inline void iname##64(addr_t * dst) { \ + ullong_t tmp_dst = *dst; \ + \ + asm volatile ( \ + #iname"q %0; " \ + : "=q"(tmp_dst) \ + : "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + } + + +#define MAKE_2OP_64FLAGS_INST(iname) static inline void iname##64(addr_t * dst, addr_t * src, addr_t * flags) { \ + uint64_t tmp_dst = *dst, tmp_src = *src; \ + addr_t tmp_flags = *flags; \ + \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushfq\r\n" \ + "push %3\r\n" \ + "popfq\r\n" \ + #iname"q %2, %0\r\n" \ + "pushfq\r\n" \ + "pop %1\r\n" \ + "popfq\r\n" \ + : "=q"(tmp_dst),"=q"(tmp_flags) \ + : "q"(tmp_src),"q"(tmp_flags), "0"(tmp_dst) \ + ); \ + \ + *dst = tmp_dst; \ + *flags = tmp_flags; \ + *flags |= flags_rsvd; \ + \ + } + + + + +#define MAKE_2OP_32FLAGS_INST(iname) static inline void iname##32(addr_t * dst, addr_t * src, addr_t * flags) { \ + uint32_t tmp_dst = *dst, tmp_src = *src; \ + \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %3; " \ + "popf; " \ + #iname"l %2, %0; " \ + "pushf; " \ + "pop %1; " \ + "popf; " \ + : "=q"(tmp_dst),"=q"(*flags) \ + : "q"(tmp_src),"q"(*flags), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + *flags |= flags_rsvd; \ + \ + } + + +#define MAKE_2OP_16FLAGS_INST(iname) static inline void iname##16(addr_t * dst, addr_t * src, addr_t * flags) { \ + ushort_t tmp_dst = *dst, tmp_src = *src; \ + \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %3; " \ + "popf; " \ + #iname"w %2, %0; " \ + "pushf; " \ + "pop %1; " \ + "popf; " \ + : "=q"(tmp_dst),"=q"(*flags) \ + : "q"(tmp_src),"q"(*flags), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + *flags |= flags_rsvd; \ + \ + } + +#define MAKE_2OP_8FLAGS_INST(iname) static inline void iname##8(addr_t * dst, addr_t * src, addr_t * flags) { \ + uchar_t tmp_dst = *dst, tmp_src = *src; \ + \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %3; " \ + "popf; " \ + #iname"b %2, %0; " \ + "pushf; " \ + "pop %1; " \ + "popf; " \ + : "=q"(tmp_dst),"=q"(*flags) \ + : "q"(tmp_src),"q"(*flags), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + *flags |= flags_rsvd; \ + \ + } + + + + +#define MAKE_2OP_32STR_INST(iname) static inline void iname##32(addr_t * dst, \ + addr_t * src, \ + addr_t * ecx, addr_t * flags) { \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %4; " \ + "popf; " \ + "rep; " \ + #iname"l; " \ + "pushf; " \ + "pop %0; " \ + "popf; " \ + : "=b"(*flags) \ + : "D"(*dst),"S"(*src),"c"(*ecx),"b"(*flags) \ + ); \ + \ + /* : "=D"(*dst),"=S"(*src),"=c"(*ecx),"=q"(*flags)*/ \ + *flags |= flags_rsvd; \ + } + +#define MAKE_2OP_16STR_INST(iname) static inline void iname##16(addr_t * dst, \ + addr_t * src, \ + addr_t * ecx, addr_t * flags) { \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %4; " \ + "popf; " \ + "rep; " \ + #iname"w; " \ + "pushf; " \ + "pop %0; " \ + "popf; " \ + : "=b"(*flags) \ + : "D"(*dst),"S"(*src),"c"(*ecx),"b"(*flags) \ + ); \ + *flags |= flags_rsvd; \ + } + + + +#define MAKE_2OP_8STR_INST(iname) static inline void iname##8(addr_t * dst, \ + addr_t * src, \ + addr_t * ecx, addr_t * flags) { \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %4; " \ + "popf; " \ + "rep; " \ + #iname"b; " \ + "pushf; " \ + "pop %0; " \ + "popf; " \ + : "=b"(*flags) \ + : "D"(*dst),"S"(*src),"c"(*ecx),"b"(*flags) \ + ); \ + *flags |= flags_rsvd; \ + } + + + + +#define MAKE_2OP_32_INST(iname) static inline void iname##32(addr_t * dst, addr_t * src) { \ + uint32_t tmp_dst = *dst, tmp_src = *src; \ + \ + asm volatile ( \ + #iname"l %1, %0; " \ + : "=q"(tmp_dst) \ + : "q"(tmp_src), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + } + +#define MAKE_2OP_16_INST(iname) static inline void iname##16(addr_t * dst, addr_t * src) { \ + ushort_t tmp_dst = *dst, tmp_src = *src; \ + \ + asm volatile ( \ + #iname"w %1, %0; " \ + : "=q"(tmp_dst) \ + : "q"(tmp_src), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + } + +#define MAKE_2OP_8_INST(iname) static inline void iname##8(addr_t * dst, addr_t * src) { \ + uchar_t tmp_dst = *dst, tmp_src = *src; \ + \ + asm volatile ( \ + #iname"b %1, %0; " \ + : "=q"(tmp_dst) \ + : "q"(tmp_src), "0"(tmp_dst) \ + ); \ + *dst = tmp_dst; \ + } + + + + + + + +MAKE_2OP_8FLAGS_INST(adc); +MAKE_2OP_8FLAGS_INST(add); +MAKE_2OP_8FLAGS_INST(and); +MAKE_2OP_8FLAGS_INST(or); +MAKE_2OP_8FLAGS_INST(xor); +MAKE_2OP_8FLAGS_INST(sub); + + +MAKE_1OP_8FLAGS_INST(inc); +MAKE_1OP_8FLAGS_INST(dec); +MAKE_1OP_8FLAGS_INST(neg); +MAKE_1OP_8FLAGS_INST(setb); +MAKE_1OP_8FLAGS_INST(setbe); +MAKE_1OP_8FLAGS_INST(setl); +MAKE_1OP_8FLAGS_INST(setle); +MAKE_1OP_8FLAGS_INST(setnb); +MAKE_1OP_8FLAGS_INST(setnbe); +MAKE_1OP_8FLAGS_INST(setnl); +MAKE_1OP_8FLAGS_INST(setnle); +MAKE_1OP_8FLAGS_INST(setno); +MAKE_1OP_8FLAGS_INST(setnp); +MAKE_1OP_8FLAGS_INST(setns); +MAKE_1OP_8FLAGS_INST(setnz); +MAKE_1OP_8FLAGS_INST(seto); +MAKE_1OP_8FLAGS_INST(setp); +MAKE_1OP_8FLAGS_INST(sets); +MAKE_1OP_8FLAGS_INST(setz); + + +MAKE_1OP_8_INST(not); + +MAKE_2OP_8_INST(mov); +MAKE_2OP_8_INST(xchg); + + + +MAKE_2OP_16FLAGS_INST(adc); +MAKE_2OP_16FLAGS_INST(add); +MAKE_2OP_16FLAGS_INST(and); +MAKE_2OP_16FLAGS_INST(or); +MAKE_2OP_16FLAGS_INST(xor); +MAKE_2OP_16FLAGS_INST(sub); + + +MAKE_1OP_16FLAGS_INST(inc); +MAKE_1OP_16FLAGS_INST(dec); +MAKE_1OP_16FLAGS_INST(neg); + +MAKE_1OP_16_INST(not); + +MAKE_2OP_16_INST(mov); +MAKE_2OP_16_INST(xchg); + + + + + +MAKE_2OP_32FLAGS_INST(adc); +MAKE_2OP_32FLAGS_INST(add); +MAKE_2OP_32FLAGS_INST(and); +MAKE_2OP_32FLAGS_INST(or); +MAKE_2OP_32FLAGS_INST(xor); +MAKE_2OP_32FLAGS_INST(sub); + + +MAKE_1OP_32FLAGS_INST(inc); +MAKE_1OP_32FLAGS_INST(dec); +MAKE_1OP_32FLAGS_INST(neg); + +MAKE_1OP_32_INST(not); + +MAKE_2OP_32_INST(mov); +MAKE_2OP_32_INST(xchg); + +MAKE_2OP_8STR_INST(movs); +MAKE_2OP_16STR_INST(movs); +MAKE_2OP_32STR_INST(movs); diff --git a/palacios/include/palacios/vmm_mem.h b/palacios/include/palacios/vmm_mem.h index c21155b..e08e473 100644 --- a/palacios/include/palacios/vmm_mem.h +++ b/palacios/include/palacios/vmm_mem.h @@ -32,48 +32,36 @@ struct guest_info; -/* - - Guest Shadow Host - Virtual Physical Virtual Physical Virtual Physical - OK OK - OK NOK - NOK OK - NOK NOK - -*/ - -// These are the types of physical memory address regions -// from the perspective of the guest -typedef enum guest_region_type { - GUEST_REGION_NOTHING, - GUEST_REGION_PHYSICAL_MEMORY, - GUEST_REGION_MEMORY_MAPPED_DEVICE} guest_region_type_t; // These are the types of physical memory address regions // from the perspective of the HOST -typedef enum host_region_type { - HOST_REGION_INVALID, // This region is INVALID (this is a return type, to denote errors) - HOST_REGION_HOOK, // This region is mapped as not present (always generate page faults) - HOST_REGION_PHYSICAL_MEMORY, // Region is a section of host memory - HOST_REGION_MEMORY_MAPPED_DEVICE, // Region is allocated for DMA - HOST_REGION_UNALLOCATED, // Region is mapped on demand - HOST_REGION_REMOTE, // Region is located on a remote machine - HOST_REGION_SWAPPED, // Region is swapped -} host_region_type_t; +typedef enum shdw_region_type { + SHDW_REGION_INVALID, // This region is INVALID (this is a return type to denote errors) + SHDW_REGION_WRITE_HOOK, // This region is mapped as read-only (page faults on write) + SHDW_REGION_FULL_HOOK, // This region is mapped as not present (always generate page faults) + SHDW_REGION_ALLOCATED, // Region is a section of host memory + SHDW_REGION_UNALLOCATED, // Region is mapped on demand +} shdw_region_type_t; -#define shadow_mem_type_t host_region_type_t +struct vmm_mem_hook; struct shadow_region { - guest_region_type_t guest_type; addr_t guest_start; addr_t guest_end; - host_region_type_t host_type; - addr_t host_addr; // This either points to a host address mapping, - // or a structure holding the map info + shdw_region_type_t host_type; + + addr_t host_addr; // This either points to a host address mapping + + + // Called when data is read from a memory page + int (*read_hook)(addr_t guest_addr, void * dst, uint_t length, void * priv_data); + // Called when data is written to a memory page + int (*write_hook)(addr_t guest_addr, void * src, uint_t length, void * priv_data); + + void * priv_data; struct shadow_region *next, *prev; }; @@ -87,20 +75,12 @@ struct shadow_map { }; + void init_shadow_region(struct shadow_region * entry, - addr_t guest_addr_start, - addr_t guest_addr_end, - guest_region_type_t guest_region_type, - host_region_type_t host_region_type); + addr_t guest_addr_start, + addr_t guest_addr_end, + shdw_region_type_t shdw_region_type); -/* -void init_shadow_region_physical(struct shadow_region * entry, - addr_t guest_addr_start, - addr_t guest_addr_end, - guest_region_type_t guest_region_type, - addr_t host_addr_start, - host_region_type_t host_region_type); -*/ int add_shadow_region_passthrough(struct guest_info * guest_info, addr_t guest_addr_start, @@ -114,9 +94,9 @@ struct shadow_region * get_shadow_region_by_addr(struct shadow_map * map, addr_t struct shadow_region * get_shadow_region_by_index(struct shadow_map * map, uint_t index); -host_region_type_t lookup_shadow_map_addr(struct shadow_map * map, addr_t guest_addr, addr_t * host_addr); +shdw_region_type_t lookup_shadow_map_addr(struct shadow_map * map, addr_t guest_addr, addr_t * host_addr); -host_region_type_t get_shadow_addr_type(struct guest_info * info, addr_t guest_addr); +shdw_region_type_t get_shadow_addr_type(struct guest_info * info, addr_t guest_addr); addr_t get_shadow_addr(struct guest_info * info, addr_t guest_addr); // Semantics: @@ -127,40 +107,39 @@ int add_shadow_region(struct shadow_map * map, struct shadow_region * entry); // Semantics: // Deletions result in splitting int delete_shadow_region(struct shadow_map * map, - addr_t guest_start, - addr_t guest_end); + addr_t guest_start, + addr_t guest_end); void print_shadow_map(struct shadow_map * map); -struct vmm_mem_hook { - // Called when data is read from a memory page - int (*read)(addr_t guest_addr, void * dst, uint_t length, void * priv_data); - - // Called when data is written to a memory page - int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data); - - void * priv_data; - struct shadow_region * region; -}; +struct shadow_region * v3_get_shadow_region(struct guest_info * info, addr_t addr); +int v3_hook_full_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end, + int (*read)(addr_t guest_addr, void * dst, uint_t length, void * priv_data), + int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data), + void * priv_data); +int v3_hook_write_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end, + addr_t host_addr, + int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data), + void * priv_data); -struct vmm_mem_hook * get_mem_hook(struct guest_info * info, addr_t guest_addr); - -int hook_guest_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end, - int (*read)(addr_t guest_addr, void * dst, uint_t length, void * priv_data), - int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data), - void * priv_data); int unhook_guest_mem(struct guest_info * info, addr_t guest_addr); +const uchar_t * shdw_region_type_to_str(shdw_region_type_t type); + int handle_special_page_fault(struct guest_info * info, addr_t fault_addr, addr_t gp_addr, pf_error_t access_info); +int v3_handle_mem_wr_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, + struct shadow_region * reg, pf_error_t access_info); +int v3_handle_mem_full_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, + struct shadow_region * reg, pf_error_t access_info); #endif // ! __V3VEE__ diff --git a/palacios/include/palacios/vmm_rbtree.h b/palacios/include/palacios/vmm_rbtree.h index 8d5382e..44131fc 100644 --- a/palacios/include/palacios/vmm_rbtree.h +++ b/palacios/include/palacios/vmm_rbtree.h @@ -91,11 +91,17 @@ static inline struct page * rb_insert_page_cache(struct inode * inode, ----------------------------------------------------------------------- */ -#ifndef _LINUX_RBTREE_H -#define _LINUX_RBTREE_H +#ifndef _VMM_RBTREE_H +#define _VMM_RBTREE_H + +#ifdef __V3VEE__ + + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + -#include -#include struct rb_node { @@ -136,17 +142,17 @@ static inline void rb_set_color(struct rb_node *rb, int color) #define RB_EMPTY_NODE(node) (rb_parent(node) != node) #define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) -extern void rb_insert_color(struct rb_node *, struct rb_root *); -extern void rb_erase(struct rb_node *, struct rb_root *); +extern void v3_rb_insert_color(struct rb_node *, struct rb_root *); +extern void v3_rb_erase(struct rb_node *, struct rb_root *); /* Find logical next and previous nodes in a tree */ -extern struct rb_node *rb_next(struct rb_node *); -extern struct rb_node *rb_prev(struct rb_node *); -extern struct rb_node *rb_first(struct rb_root *); -extern struct rb_node *rb_last(struct rb_root *); +extern struct rb_node *v3_rb_next(struct rb_node *); +extern struct rb_node *v3_rb_prev(struct rb_node *); +extern struct rb_node *v3_rb_first(struct rb_root *); +extern struct rb_node *v3_rb_last(struct rb_root *); /* Fast replacement of a single node without remove/rebalance/add/rebalance */ -extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, +extern void v3_rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, @@ -158,4 +164,7 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, *rb_link = node; } + +#endif + #endif /* _LINUX_RBTREE_H */ diff --git a/palacios/include/palacios/vmm_xed.h b/palacios/include/palacios/vmm_xed.h index 4099d22..95e68ec 100644 --- a/palacios/include/palacios/vmm_xed.h +++ b/palacios/include/palacios/vmm_xed.h @@ -23,7 +23,6 @@ #ifdef __V3VEE__ - #endif // ! __V3VEE__ #endif diff --git a/palacios/src/palacios/svm_handler.c b/palacios/src/palacios/svm_handler.c index 8495a17..1f834a6 100644 --- a/palacios/src/palacios/svm_handler.c +++ b/palacios/src/palacios/svm_handler.c @@ -293,6 +293,9 @@ int v3_handle_svm_exit(struct guest_info * info) { } break; + +#if 0 + // Emulation handlers currently not used case VMEXIT_EXCP1: { #ifdef DEBUG_EMULATOR @@ -308,7 +311,7 @@ int v3_handle_svm_exit(struct guest_info * info) { } break; } - + case VMEXIT_VMMCALL: { @@ -340,7 +343,7 @@ int v3_handle_svm_exit(struct guest_info * info) { } break; } - +#endif case VMEXIT_WBINVD: diff --git a/palacios/src/palacios/vm_guest_mem.c b/palacios/src/palacios/vm_guest_mem.c index 876f0b3..78b4b7e 100644 --- a/palacios/src/palacios/vm_guest_mem.c +++ b/palacios/src/palacios/vm_guest_mem.c @@ -67,9 +67,11 @@ int host_pa_to_host_va(addr_t host_pa, addr_t * host_va) { int guest_pa_to_host_pa(struct guest_info * guest_info, addr_t guest_pa, addr_t * host_pa) { // we use the shadow map here... - host_region_type_t reg_type = lookup_shadow_map_addr(&(guest_info->mem_map), guest_pa, host_pa); + shdw_region_type_t reg_type = lookup_shadow_map_addr(&(guest_info->mem_map), guest_pa, host_pa); - if (reg_type != HOST_REGION_PHYSICAL_MEMORY) { + if ((reg_type == SHDW_REGION_INVALID) || + (reg_type == SHDW_REGION_UNALLOCATED) || + (reg_type == SHDW_REGION_FULL_HOOK)){ PrintError("In GPA->HPA: Could not find address in shadow map (addr=%p) (reg_type=%d)\n", (void *)guest_pa, reg_type); return -1; diff --git a/palacios/src/palacios/vmm.c b/palacios/src/palacios/vmm.c index 4502a80..6ef7fa1 100644 --- a/palacios/src/palacios/vmm.c +++ b/palacios/src/palacios/vmm.c @@ -23,7 +23,7 @@ #include #include #include -#include + v3_cpu_arch_t v3_cpu_type; struct v3_os_hooks * os_hooks = NULL; @@ -43,7 +43,7 @@ void Init_V3(struct v3_os_hooks * hooks, struct v3_ctrl_ops * vmm_ops) { v3_cpu_type = V3_INVALID_CPU; - v3_init_decoder(); + if (v3_is_svm_capable()) { diff --git a/palacios/src/palacios/vmm_config.c b/palacios/src/palacios/vmm_config.c index fd472dd..949b115 100644 --- a/palacios/src/palacios/vmm_config.c +++ b/palacios/src/palacios/vmm_config.c @@ -21,7 +21,7 @@ #include #include #include - +#include #include #include @@ -50,23 +50,14 @@ static struct vm_device * configure_generic(struct guest_info * info, struct v3 -static int mem_test_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) { - int foo = 20; - - memcpy(dst, &foo, length); +static int passthrough_mem_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) { - PrintDebug("Passthrough mem read returning: %p (length=%d)\n", (void *)(foo + (guest_addr & 0xfff)), length); return length; -} + // memcpy((void*)guest_addr, src, length); + PrintDebug("Write of %d bytes to %p\n", length, (void *)guest_addr); + PrintDebug("Write Value = %p\n", (void *)*(addr_t *)src); -static int passthrough_mem_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) { - memcpy(dst, (void*)guest_addr, length); - return length; -} - -static int passthrough_mem_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) { - memcpy((void*)guest_addr, src, length); return length; } @@ -81,9 +72,10 @@ int v3_config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) v3_init_msr_map(info); v3_init_interrupt_state(info); v3_init_dev_mgr(info); - v3_init_emulator(info); v3_init_host_events(info); + v3_init_decoder(info); + init_shadow_map(info); if (v3_cpu_type == V3_SVM_REV3_CPU) { @@ -160,10 +152,10 @@ static int setup_memory_map(struct guest_info * info, struct v3_vm_config * conf // add_shadow_region_passthrough(info, 0x0, 0xa0000, (addr_t)V3_AllocPages(160)); - if (1) { + if (0) { add_shadow_region_passthrough(info, 0xa0000, 0xc0000, 0xa0000); } else { - hook_guest_mem(info, 0xa0000, 0xc0000, passthrough_mem_read, passthrough_mem_write, NULL); + v3_hook_write_mem(info, 0xa0000, 0xc0000, 0xa0000, passthrough_mem_write, NULL); } // TEMP @@ -185,7 +177,7 @@ static int setup_memory_map(struct guest_info * info, struct v3_vm_config * conf } else { /* MEMORY HOOK TEST */ add_shadow_region_passthrough(info, 0x100000, 0xa00000, (addr_t)V3_AllocPages(2304)); - hook_guest_mem(info, 0xa00000, 0xa01000, mem_test_read, passthrough_mem_write, NULL); + v3_hook_write_mem(info, 0xa00000, 0xa01000, (addr_t)V3_AllocPages(1), passthrough_mem_write, NULL); add_shadow_region_passthrough(info, 0xa01000, 0x1000000, (addr_t)V3_AllocPages(1791)); } diff --git a/palacios/src/palacios/vmm_ctrl_regs.c b/palacios/src/palacios/vmm_ctrl_regs.c index cc11c04..7b637ed 100644 --- a/palacios/src/palacios/vmm_ctrl_regs.c +++ b/palacios/src/palacios/vmm_ctrl_regs.c @@ -62,19 +62,21 @@ int v3_handle_cr0_write(struct guest_info * info) { return -1; } - if (v3_opcode_cmp(V3_OPCODE_LMSW, (const uchar_t *)(dec_instr.opcode)) == 0) { + if (dec_instr.op_type == V3_OP_LMSW) { + // if (v3_opcode_cmp(V3_OPCODE_LMSW, (const uchar_t *)(dec_instr.opcode)) == 0) { if (handle_lmsw(info, &dec_instr) == -1) { return -1; } - } else if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) { - + // } else if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) { + } else if (dec_instr.op_type == V3_OP_MOV2CR) { if (handle_mov_to_cr0(info, &dec_instr) == -1) { return -1; } - } else if (v3_opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) { + // } else if (v3_opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) { + } else if (dec_instr.op_type == V3_OP_CLTS) { if (handle_clts(info, &dec_instr) == -1) { return -1; @@ -225,7 +227,8 @@ int v3_handle_cr0_read(struct guest_info * info) { return -1; } - if (v3_opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) { + // if (v3_opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) { + if (dec_instr.op_type == V3_OP_MOVCR2) { struct cr0_32 * dst_reg = (struct cr0_32 *)(dec_instr.dst_operand.operand); struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0); @@ -240,7 +243,8 @@ int v3_handle_cr0_read(struct guest_info * info) { PrintDebug("Shadow CR0: %x\n", *(uint_t*)shadow_cr0); PrintDebug("returned CR0: %x\n", *(uint_t*)dst_reg); - } else if (v3_opcode_cmp(V3_OPCODE_SMSW, (const uchar_t *)(dec_instr.opcode)) == 0) { + // } else if (v3_opcode_cmp(V3_OPCODE_SMSW, (const uchar_t *)(dec_instr.opcode)) == 0) { + } else if (dec_instr.op_type == V3_OP_SMSW) { struct cr0_real * shadow_cr0 = (struct cr0_real *)&(info->ctrl_regs.cr0); struct cr0_real * dst_reg = (struct cr0_real *)(dec_instr.dst_operand.operand); char cr0_val = *(char*)shadow_cr0 & 0x0f; @@ -283,7 +287,8 @@ int v3_handle_cr3_write(struct guest_info * info) { return -1; } - if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) { + // if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) { + if (dec_instr.op_type == V3_OP_MOV2CR) { PrintDebug("MOV2CR3 (cpu_mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode)); if (info->shdw_pg_mode == SHADOW_PAGING) { @@ -359,7 +364,8 @@ int v3_handle_cr3_read(struct guest_info * info) { return -1; } - if (v3_opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) { + // if (v3_opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) { + if (dec_instr.op_type == V3_OP_MOVCR2) { PrintDebug("MOVCR32 (mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode)); if (info->shdw_pg_mode == SHADOW_PAGING) { @@ -422,7 +428,8 @@ int v3_handle_cr4_write(struct guest_info * info) { return -1; } - if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) != 0) { + // if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) != 0) { + if (dec_instr.op_type != V3_OP_MOV2CR) { PrintError("Invalid opcode in write to CR4\n"); return -1; } diff --git a/palacios/src/palacios/vmm_decoder.c b/palacios/src/palacios/vmm_decoder.c index 593b038..54c77c4 100644 --- a/palacios/src/palacios/vmm_decoder.c +++ b/palacios/src/palacios/vmm_decoder.c @@ -30,6 +30,67 @@ int v3_opcode_cmp(const uchar_t * op1, const uchar_t * op2) { } +void v3_get_prefixes(uchar_t * instr, struct x86_prefixes * prefixes) { + while (1) { + switch (*instr) { + case 0xF0: // lock + prefixes->lock = 1; + break; + + case 0xF2: // REPNE/REPNZ + prefixes->repnz = 1; + prefixes->repne = 1; + break; + + case 0xF3: // REP or REPE/REPZ + prefixes->rep = 1; + prefixes->repe = 1; + prefixes->repz = 1; + break; + + case 0x2E: // CS override or Branch hint not taken (with Jcc instrs) + prefixes->cs_override = 1; + prefixes->br_not_taken = 1; + break; + + case 0x36: // SS override + prefixes->ss_override = 1; + break; + + case 0x3E: // DS override or Branch hint taken (with Jcc instrs) + prefixes->ds_override = 1; + prefixes->br_taken = 1; + break; + + case 0x26: // ES override + prefixes->es_override = 1; + break; + + case 0x64: // FS override + prefixes->fs_override = 1; + break; + + case 0x65: // GS override + prefixes->gs_override = 1; + break; + + case 0x66: // operand size override + prefixes->op_size = 1; + break; + + case 0x67: // address size override + prefixes->addr_size = 1; + break; + + default: + return; + } + + instr++; + } + +} + void v3_strip_rep_prefix(uchar_t * instr, int length) { int read_ctr = 0; int write_ctr = 0; diff --git a/palacios/src/palacios/vmm_emulator.c b/palacios/src/palacios/vmm_emulator.c index 97549eb..bb67a5f 100644 --- a/palacios/src/palacios/vmm_emulator.c +++ b/palacios/src/palacios/vmm_emulator.c @@ -21,11 +21,8 @@ #include #include #include -#include -#include -#include - -static const char VMMCALL[3] = {0x0f, 0x01, 0xd9}; +#include +#include #ifndef DEBUG_EMULATOR #undef PrintDebug @@ -33,120 +30,121 @@ static const char VMMCALL[3] = {0x0f, 0x01, 0xd9}; #endif -int v3_init_emulator(struct guest_info * info) { - struct emulation_state * emulator = &(info->emulator); - - emulator->num_emulated_pages = 0; - INIT_LIST_HEAD(&(emulator->emulated_pages)); - - emulator->num_saved_pages = 0; - INIT_LIST_HEAD(&(emulator->saved_pages)); - - emulator->num_write_regions = 0; - INIT_LIST_HEAD(&(emulator->write_regions)); - emulator->running = 0; - emulator->instr_length = 0; - emulator->tf_enabled = 0; - return 0; -} +// We emulate up to the next 4KB page boundry +static int emulate_string_write_op(struct guest_info * info, struct x86_instr * dec_instr, + addr_t write_gva, addr_t write_gpa, addr_t * dst_addr) { + uint_t emulation_length = 0; + addr_t tmp_rcx = 0; + addr_t src_addr = 0; -static addr_t get_new_page() { - void * page = V3_VAddr(V3_AllocPages(1)); - memset(page, 0, PAGE_SIZE); + if (dec_instr->op_type == V3_OP_MOVS) { + PrintDebug("MOVS emulation\n"); - return (addr_t)page; -} + if (dec_instr->dst_operand.operand != write_gva) { + PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n", + (void *)dec_instr->dst_operand.operand, (void *)write_gva); + return -1; + } -/* -static int setup_code_page(struct guest_info * info, char * instr, struct basic_instr_info * instr_info ) { - addr_t code_page_offset = PT32_PAGE_OFFSET(info->rip); - addr_t code_page = get_new_page(); - struct emulated_page * new_code_page = V3_Malloc(sizeof(struct emulated_page)); - struct saved_page * saved_code_page = V3_Malloc(sizeof(struct saved_page)); + emulation_length = ( (dec_instr->str_op_length < (0x1000 - PAGE_OFFSET_4KB(write_gva))) ? + dec_instr->str_op_length : + (0x1000 - PAGE_OFFSET_4KB(write_gva))); + /* ** Fix emulation length so that it doesn't overrun over the src page either ** */ - saved_code_page->va = PT32_PAGE_ADDR(info->rip); - - new_code_page->page_addr = code_page; - new_code_page->va = PT32_PAGE_ADDR(info->rip); - - new_code_page->pte.present = 1; - new_code_page->pte.writable = 0; - new_code_page->pte.user_page = 1; - new_code_page->pte.page_base_addr = PT32_BASE_ADDR(code_page); - - memcpy((void *)(code_page + code_page_offset), instr, instr_info->instr_length); - memcpy((void *)(code_page + code_page_offset + instr_info->instr_length), VMMCALL, 3); - -#ifdef DEBUG_EMULATOR - PrintDebug("New Instr Stream:\n"); - PrintTraceMemDump((void *)(code_page + code_page_offset), 32); - PrintDebug("rip =%x\n", info->rip); -#endif + PrintDebug("STR_OP_LEN: %d, Page Len: %d\n", + (uint_t)dec_instr->str_op_length, + (uint_t)(0x1000 - PAGE_OFFSET_4KB(write_gva))); + PrintDebug("Emulation length: %d\n", emulation_length); + tmp_rcx = emulation_length; + + if (guest_pa_to_host_va(info, write_gpa, dst_addr) == -1) { + PrintError("Could not translate write destination to host VA\n"); + return -1; + } + // figure out addresses here.... + if (info->mem_mode == PHYSICAL_MEM) { + if (guest_pa_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) { + PrintError("Could not translate write Source (Physical) to host VA\n"); + return -1; + } + } else { + if (guest_va_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) { + PrintError("Could not translate write Source (Virtual) to host VA\n"); + return -1; + } + } - v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte)); + PrintDebug("Dst Operand: %p (size=%d), Src Operand: %p\n", + (void *)dec_instr->dst_operand.operand, + dec_instr->dst_operand.size, + (void *)dec_instr->src_operand.operand); + PrintDebug("Dst Addr: %p, Src Addr: %p\n", (void *)(addr_t *)*dst_addr, (void *)src_addr); + //return -1; - list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages)); - info->emulator.num_emulated_pages++; - list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages)); - info->emulator.num_saved_pages++; + - return 0; -} -*/ + if (dec_instr->dst_operand.size == 1) { + movs8(dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + } else if (dec_instr->dst_operand.size == 2) { + movs16(dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + } else if (dec_instr->dst_operand.size == 4) { + movs32(dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + } else { + PrintError("Invalid operand length\n"); + return -1; + } -static int set_stepping(struct guest_info * info) { - vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); - ctrl_area->exceptions.db = 1; - info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf; - ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1; - return 0; -} + PrintDebug("RDI=%p, RSI=%p, RCX=%p\n", + (void *)*(addr_t *)&(info->vm_regs.rdi), + (void *)*(addr_t *)&(info->vm_regs.rsi), + (void *)*(addr_t *)&(info->vm_regs.rcx)); -static int unset_stepping(struct guest_info * info) { - vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); - ctrl_area->exceptions.db = 0; + info->vm_regs.rdi += emulation_length; + info->vm_regs.rsi += emulation_length; + info->vm_regs.rcx -= emulation_length; + + PrintDebug("RDI=%p, RSI=%p, RCX=%p\n", + (void *)*(addr_t *)&(info->vm_regs.rdi), + (void *)*(addr_t *)&(info->vm_regs.rsi), + (void *)*(addr_t *)&(info->vm_regs.rcx)); - ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled; + if (emulation_length == dec_instr->str_op_length) { + info->rip += dec_instr->instr_length; + } - if (info->emulator.tf_enabled) { - // Inject breakpoint exception into guest + return emulation_length; } - return 0; + + + return -1; } -// get the current instr -// check if rep + remove -// put into new page, vmexit after -// replace new page with current eip page -// -int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva, - int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data), - addr_t read_gpa, void * private_data) { - struct basic_instr_info instr_info; +int v3_emulate_write_op(struct guest_info * info, addr_t write_gva, addr_t write_gpa, addr_t * dst_addr) { + struct x86_instr dec_instr; uchar_t instr[15]; - int ret; - struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page)); - addr_t data_addr_offset = PAGE_OFFSET(read_gva); - pte32_t saved_pte; + int ret = 0; + addr_t src_addr = 0; + - PrintDebug("Emulating Read\n"); + PrintDebug("Emulating Write for instruction at %p\n", (void *)(addr_t)(info->rip)); + PrintDebug("GPA=%p, GVA=%p\n", (void *)write_gpa, (void *)write_gva); if (info->mem_mode == PHYSICAL_MEM) { ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr); @@ -155,233 +153,258 @@ int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva, } if (ret == -1) { - PrintError("Could not read guest memory\n"); return -1; } -#ifdef DEBUG_EMULATOR - PrintDebug("Instr (15 bytes) at %p:\n", (void *)(addr_t)instr); - PrintTraceMemDump(instr, 15); -#endif - - if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) { - PrintError("Could not do a basic memory instruction decode\n"); - V3_Free(data_page); + if (guest_pa_to_host_va(info, write_gpa, dst_addr) == -1) { + PrintError("Could not translate write destination to host VA\n"); return -1; } - /* - if (instr_info.has_rep == 1) { - PrintError("We currently don't handle rep* instructions\n"); - V3_Free(data_page); + if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) { + PrintError("Decoding Error\n"); + // Kick off single step emulator return -1; } - */ - - data_page->page_addr = get_new_page(); - data_page->va = PAGE_ADDR(read_gva); - data_page->pte.present = 1; - data_page->pte.writable = 0; - data_page->pte.user_page = 1; - data_page->pte.page_base_addr = PAGE_BASE_ADDR((addr_t)V3_PAddr((void *)(addr_t)(data_page->page_addr))); - - - // Read the data directly onto the emulated page - ret = read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data); - if ((ret == -1) || ((uint_t)ret != instr_info.op_size)) { - PrintError("Read error in emulator\n"); - V3_FreePage((void *)V3_PAddr((void *)(data_page->page_addr))); - V3_Free(data_page); - return -1; + + if (dec_instr.is_str_op) { + return emulate_string_write_op(info, &dec_instr, write_gva, write_gpa, dst_addr); } - v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte); - - - list_add(&(data_page->page_list), &(info->emulator.emulated_pages)); - info->emulator.num_emulated_pages++; - if (saved_pte.present == 1) { - struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page)); - saved_data_page->pte = saved_pte; - saved_data_page->va = PAGE_ADDR(read_gva); - - list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages)); - info->emulator.num_saved_pages++; + if ((dec_instr.dst_operand.type != MEM_OPERAND) || + (dec_instr.dst_operand.operand != write_gva)) { + PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n", + (void *)dec_instr.dst_operand.operand, (void *)write_gva); + return -1; } - // setup_code_page(info, instr, &instr_info); - set_stepping(info); - - info->emulator.running = 1; - info->run_state = VM_EMULATING; - info->emulator.instr_length = instr_info.instr_length; - - return 0; -} - - - -int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva, - int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data), - addr_t write_gpa, void * private_data) { - - struct basic_instr_info instr_info; - uchar_t instr[15]; - int ret; - struct write_region * write_op = V3_Malloc(sizeof(struct write_region )); - struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page)); - addr_t data_addr_offset = PAGE_OFFSET(write_gva); - pte32_t saved_pte; - int i; - - PrintDebug("Emulating Write for instruction at 0x%p\n", (void *)(addr_t)(info->rip)); - - if (info->mem_mode == PHYSICAL_MEM) { - ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr); - } else { - ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr); + if (dec_instr.src_operand.type == MEM_OPERAND) { + if (info->mem_mode == PHYSICAL_MEM) { + if (guest_pa_to_host_va(info, dec_instr.src_operand.operand, &src_addr) == -1) { + PrintError("Could not translate write Source (Physical) to host VA\n"); + return -1; + } + } else { + if (guest_va_to_host_va(info, dec_instr.src_operand.operand, &src_addr) == -1) { + PrintError("Could not translate write Source (Virtual) to host VA\n"); + return -1; + } + } + } else if (dec_instr.src_operand.type == REG_OPERAND) { + src_addr = dec_instr.src_operand.operand; + } else { + src_addr = (addr_t)&(dec_instr.src_operand.operand); } - PrintDebug("Instruction is"); - for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); } - PrintDebug("\n"); - - if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) { - PrintError("Could not do a basic memory instruction decode\n"); - V3_Free(write_op); - V3_Free(data_page); + PrintDebug("Dst_Addr Ptr = %p (val=%p), SRC operand = %p\n", + (void *)dst_addr, (void *)*dst_addr, (void *)src_addr); + + + if (dec_instr.dst_operand.size == 1) { + + switch (dec_instr.op_type) { + case V3_OP_ADC: + adc8((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_ADD: + add8((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_AND: + and8((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_OR: + or8((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_XOR: + xor8((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SUB: + sub8((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + + case V3_OP_MOV: + mov8((addr_t *)*dst_addr, (addr_t *)src_addr); + break; + case V3_OP_NOT: + not8((addr_t *)*dst_addr); + break; + case V3_OP_XCHG: + xchg8((addr_t *)*dst_addr, (addr_t *)src_addr); + break; + + + case V3_OP_INC: + inc8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_DEC: + dec8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_NEG: + neg8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETB: + setb8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETBE: + setbe8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETL: + setl8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETLE: + setle8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETNB: + setnb8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETNBE: + setnbe8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETNL: + setnl8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETNLE: + setnle8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETNO: + setno8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETNP: + setnp8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETNS: + setns8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETNZ: + setnz8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETO: + seto8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETP: + setp8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETS: + sets8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SETZ: + setz8((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + + default: + PrintError("Unknown 8 bit instruction\n"); + return -1; + } + + } else if (dec_instr.dst_operand.size == 2) { + + switch (dec_instr.op_type) { + case V3_OP_ADC: + adc16((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_ADD: + add16((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_AND: + and16((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_OR: + or16((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_XOR: + xor16((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SUB: + sub16((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + + + case V3_OP_INC: + inc16((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_DEC: + dec16((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_NEG: + neg16((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + + case V3_OP_MOV: + mov16((addr_t *)*dst_addr, (addr_t *)src_addr); + break; + case V3_OP_NOT: + not16((addr_t *)*dst_addr); + break; + case V3_OP_XCHG: + xchg16((addr_t *)*dst_addr, (addr_t *)src_addr); + break; + + default: + PrintError("Unknown 16 bit instruction\n"); + return -1; + } + + } else if (dec_instr.dst_operand.size == 4) { + + switch (dec_instr.op_type) { + case V3_OP_ADC: + adc32((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_ADD: + add32((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_AND: + and32((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_OR: + or32((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_XOR: + xor32((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_SUB: + sub32((addr_t *)*dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + + case V3_OP_INC: + inc32((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_DEC: + dec32((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + case V3_OP_NEG: + neg32((addr_t *)*dst_addr, (addr_t *)&(info->ctrl_regs.rflags)); + break; + + case V3_OP_MOV: + mov32((addr_t *)*dst_addr, (addr_t *)src_addr); + break; + case V3_OP_NOT: + not32((addr_t *)*dst_addr); + break; + case V3_OP_XCHG: + xchg32((addr_t *)*dst_addr, (addr_t *)src_addr); + break; + + default: + PrintError("Unknown 32 bit instruction\n"); + return -1; + } + + } else if (dec_instr.dst_operand.size == 8) { + PrintError("64 bit instructions not handled\n"); return -1; - } - - if (instr_info.has_rep==1) { - PrintDebug("Emulated instruction has rep\n"); - } - - /* - if (instr_info.has_rep == 1) { - PrintError("We currently don't handle rep* instructions\n"); - V3_Free(write_op); - V3_Free(data_page); + } else { + PrintError("Invalid Operation Size\n"); return -1; } - */ - data_page->page_addr = get_new_page(); - data_page->va = PAGE_ADDR(write_gva); - data_page->pte.present = 1; - data_page->pte.writable = 1; - data_page->pte.user_page = 1; - data_page->pte.page_base_addr = PAGE_BASE_ADDR((addr_t)V3_PAddr((void *)(addr_t)(data_page->page_addr))); + info->rip += dec_instr.instr_length; - - - write_op->write = write; - write_op->write_addr = write_gpa; - write_op->length = instr_info.op_size; - write_op->private_data = private_data; - - write_op->write_data = (void *)(data_page->page_addr + data_addr_offset); - - list_add(&(write_op->write_list), &(info->emulator.write_regions)); - info->emulator.num_write_regions--; - - v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte); - - - list_add(&(data_page->page_list), &(info->emulator.emulated_pages)); - info->emulator.num_emulated_pages++; - - if (saved_pte.present == 1) { - struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page)); - saved_data_page->pte = saved_pte; - saved_data_page->va = PAGE_ADDR(write_gva); - - list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages)); - info->emulator.num_saved_pages++; - } - - - if (info->emulator.running == 0) { - // setup_code_page(info, instr, &instr_info); - set_stepping(info); - info->emulator.running = 1; - info->run_state = VM_EMULATING; - info->emulator.instr_length = instr_info.instr_length; - } - - return 0; + return dec_instr.dst_operand.size; } - -// end emulation -int v3_emulation_exit_handler(struct guest_info * info) { - struct saved_page * svpg, * p_svpg; - struct emulated_page * empg, * p_empg; - struct write_region * wr_reg, * p_wr_reg; - pte32_t dummy_pte; - - // Complete the writes - // delete writes - // swap out emulated pages with blank dummies - // swap in saved pages - // increment rip - - PrintDebug("V3 Emulation Exit Handler\n"); - - list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) { - wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data); - PrintDebug("Writing \n"); - - list_del(&(wr_reg->write_list)); - V3_Free(wr_reg); - - } - info->emulator.num_write_regions = 0; - - - *(uint_t *)&dummy_pte = 0; - - list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) { - pte32_t empte32_t; - - PrintDebug("wiping page %p\n", (void *)(addr_t)(empg->va)); - - v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t); - V3_FreePage((void *)(V3_PAddr((void *)(empg->page_addr)))); - - list_del(&(empg->page_list)); - V3_Free(empg); - } - info->emulator.num_emulated_pages = 0; - - list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) { - - PrintDebug("Setting Saved page %p back\n", (void *)(addr_t)(svpg->va)); - v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte); - - list_del(&(svpg->page_list)); - V3_Free(svpg); - } - info->emulator.num_saved_pages = 0; - - info->run_state = VM_RUNNING; - info->emulator.running = 0; - //info->rip += info->emulator.instr_length; - - - PrintDebug("Returning to rip: 0x%p\n", (void *)(addr_t)(info->rip)); - - info->emulator.instr_length = 0; - - - unset_stepping(info); - - - PrintDebug("returning from emulation\n"); - - return 0; -} diff --git a/palacios/src/palacios/vmm_instr_emulator.c b/palacios/src/palacios/vmm_instr_emulator.c deleted file mode 100644 index f89d4e6..0000000 --- a/palacios/src/palacios/vmm_instr_emulator.c +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include - -#define addr_t unsigned long - - - - -void test() { - int a = 10; - int b; - - asm ("movl %1, %%eax\n\t" - "movl %%eax, %0\n\t" - :"=r"(b) /* output */ - :"r"(a) /* input */ - :"%eax" /* clobbered register */ - ); - -} - -void get_flags(addr_t * flags) { - addr_t tmp; - asm ("pushfq\n\t" - "pop %0\n\t" - :"=r"(tmp) - : - ); - - *flags = tmp; -} - -void adc64(int * dst, int * src, addr_t * flags) { - int tmp_dst = *dst, tmp_src = *src; - addr_t tmp_flags = *flags; - - char * inst = "adcl"; - - // Some of the flags values are not copied out in a pushf, we save them here - addr_t flags_rsvd = *flags & ~0xfffe7fff; - - asm volatile ( - "pushfq\r\n" - "push %3\r\n" - "popfq\r\n" - "adcl %2, %0\r\n" - "pushfq\r\n" - "pop %1\r\n" - "popfq\r\n" - : "=a"(tmp_dst),"=c"(tmp_flags) - : "b"(tmp_src),"c"(tmp_flags), "0"(tmp_dst) - ); - - *dst = tmp_dst; - *flags = tmp_flags; - *flags |= flags_rsvd; - -} - - -void adc32(int * dst, int * src, addr_t * flags) { - int tmp_dst = *dst, tmp_src = *src; - addr_t tmp_flags = *flags; - - - asm volatile ( - "pushfd\r\n" - "push %3\r\n" - "popfd\r\n" - "adcl %2, %0\r\n" - "pushfd\r\n" - "pop %1\r\n" - "popfd\r\n" - : "=a"(tmp_dst),"=c"(tmp_flags) - : "b"(tmp_src),"c"(tmp_flags), "0"(tmp_dst) - ); - - *dst = tmp_dst; - *flags = tmp_flags; - -} - - -int main(int argc, char ** argv) { - addr_t flags; - int dest = 4; - int src = 5; - - printf("sizeof ulong: %d\n", sizeof(unsigned long)); - - printf("Getting flags\n"); - get_flags(&flags); - flags = flags | 0x1; - - printf("Flags=0x%x\n", flags); - test(); - printf("Adding\n"); - adc64(&dest, &src, &flags); - printf("Result=%d\n", dest); - -} diff --git a/palacios/src/palacios/vmm_mem.c b/palacios/src/palacios/vmm_mem.c index 1b9f16d..fa17e97 100644 --- a/palacios/src/palacios/vmm_mem.c +++ b/palacios/src/palacios/vmm_mem.c @@ -27,15 +27,13 @@ void init_shadow_region(struct shadow_region * entry, addr_t guest_addr_start, addr_t guest_addr_end, - guest_region_type_t guest_region_type, - host_region_type_t host_region_type) + shdw_region_type_t shdw_region_type) { - entry->guest_type = guest_region_type; entry->guest_start = guest_addr_start; entry->guest_end = guest_addr_end; - entry->host_type = host_region_type; + entry->host_type = shdw_region_type; entry->host_addr = 0; - entry->next=entry->prev = NULL; + entry->next = entry->prev = NULL; } int add_shadow_region_passthrough( struct guest_info * guest_info, @@ -46,87 +44,65 @@ int add_shadow_region_passthrough( struct guest_info * guest_info, struct shadow_region * entry = (struct shadow_region *)V3_Malloc(sizeof(struct shadow_region)); init_shadow_region(entry, guest_addr_start, guest_addr_end, - GUEST_REGION_PHYSICAL_MEMORY, HOST_REGION_PHYSICAL_MEMORY); + SHDW_REGION_ALLOCATED); entry->host_addr = host_addr; return add_shadow_region(&(guest_info->mem_map), entry); } -int hook_guest_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end, - int (*read)(addr_t guest_addr, void * dst, uint_t length, void * priv_data), - int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data), - void * priv_data) { - - struct shadow_region * entry = (struct shadow_region *)V3_Malloc(sizeof(struct shadow_region)); - struct vmm_mem_hook * hook = (struct vmm_mem_hook *)V3_Malloc(sizeof(struct vmm_mem_hook)); - - memset(hook, 0, sizeof(struct vmm_mem_hook)); - - hook->read = read; - hook->write = write; - hook->region = entry; - hook->priv_data = priv_data; +int v3_hook_write_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end, + addr_t host_addr, + int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data), + void * priv_data) { + struct shadow_region * entry = (struct shadow_region *)V3_Malloc(sizeof(struct shadow_region)); init_shadow_region(entry, guest_addr_start, guest_addr_end, - GUEST_REGION_PHYSICAL_MEMORY, HOST_REGION_HOOK); + SHDW_REGION_WRITE_HOOK); - entry->host_addr = (addr_t)hook; + entry->write_hook = write; + entry->read_hook = NULL; + entry->host_addr = host_addr; + entry->priv_data = priv_data; - return add_shadow_region(&(info->mem_map), entry); + return add_shadow_region(&(info->mem_map), entry); } +int v3_hook_full_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end, + int (*read)(addr_t guest_addr, void * dst, uint_t length, void * priv_data), + int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data), + void * priv_data) { + + struct shadow_region * entry = (struct shadow_region *)V3_Malloc(sizeof(struct shadow_region)); -struct vmm_mem_hook * get_mem_hook(struct guest_info * info, addr_t guest_addr) { - struct shadow_region * region = get_shadow_region_by_addr(&(info->mem_map), guest_addr); - - if (region == NULL) { - PrintDebug("Could not find shadow region for addr: %p\n", (void *)guest_addr); - return NULL; - } - - return (struct vmm_mem_hook *)(region->host_addr); -} - + init_shadow_region(entry, guest_addr_start, guest_addr_end, + SHDW_REGION_FULL_HOOK); -/* mem_addr is the guest physical memory address */ -static int mem_hook_dispatch(struct guest_info * info, - addr_t fault_gva, addr_t fault_gpa, - pf_error_t access_info, struct vmm_mem_hook * hook) -{ + entry->write_hook = write; + entry->read_hook = read; + entry->priv_data = priv_data; - // emulate and then dispatch - // or dispatch and emulate + entry->host_addr = 0; + return add_shadow_region(&(info->mem_map), entry); +} - if (access_info.write == 1) { - if (v3_emulate_memory_write(info, fault_gva, hook->write, fault_gpa, hook->priv_data) == -1) { - PrintError("Memory write emulation failed\n"); - return -1; - } - - } else { - if (v3_emulate_memory_read(info, fault_gva, hook->read, fault_gpa, hook->priv_data) == -1) { - PrintError("Memory read emulation failed\n"); - return -1; - } - } - return 0; -} int handle_special_page_fault(struct guest_info * info, addr_t fault_gva, addr_t fault_gpa, pf_error_t access_info) { - struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), fault_gpa); + struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), fault_gpa); PrintDebug("Handling Special Page Fault\n"); switch (reg->host_type) { - case HOST_REGION_HOOK: - return mem_hook_dispatch(info, fault_gva, fault_gpa, access_info, (struct vmm_mem_hook *)(reg->host_addr)); + case SHDW_REGION_WRITE_HOOK: + return v3_handle_mem_wr_hook(info, fault_gva, fault_gpa, reg, access_info); + case SHDW_REGION_FULL_HOOK: + return v3_handle_mem_full_hook(info, fault_gva, fault_gpa, reg, access_info); default: return -1; } @@ -135,6 +111,48 @@ int handle_special_page_fault(struct guest_info * info, } +int v3_handle_mem_wr_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, + struct shadow_region * reg, pf_error_t access_info) { + + addr_t write_src_addr = 0; + + int write_len = v3_emulate_write_op(info, guest_va, guest_pa, &write_src_addr); + + if (write_len == -1) { + PrintError("Emulation failure in write hook\n"); + return -1; + } + + + if (reg->write_hook(guest_pa, (void *)write_src_addr, write_len, reg->priv_data) != write_len) { + PrintError("Memory write hook did not return correct value\n"); + return -1; + } + + return 0; +} + +int v3_handle_mem_full_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, + struct shadow_region * reg, pf_error_t access_info) { + return -1; +} + + + +struct shadow_region * v3_get_shadow_region(struct guest_info * info, addr_t addr) { + struct shadow_region * reg = info->mem_map.head; + + while (reg) { + if ((reg->guest_start <= addr) && (reg->guest_end > addr)) { + return reg; + } else if (reg->guest_start > addr) { + return NULL; + } else { + reg = reg->next; + } + } + return NULL; +} void init_shadow_map(struct guest_info * info) { @@ -259,11 +277,11 @@ struct shadow_region * get_shadow_region_by_addr(struct shadow_map * map, } -host_region_type_t get_shadow_addr_type(struct guest_info * info, addr_t guest_addr) { +shdw_region_type_t get_shadow_addr_type(struct guest_info * info, addr_t guest_addr) { struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), guest_addr); if (!reg) { - return HOST_REGION_INVALID; + return SHDW_REGION_INVALID; } else { return reg->host_type; } @@ -280,19 +298,20 @@ addr_t get_shadow_addr(struct guest_info * info, addr_t guest_addr) { } -host_region_type_t lookup_shadow_map_addr(struct shadow_map * map, addr_t guest_addr, addr_t * host_addr) { +shdw_region_type_t lookup_shadow_map_addr(struct shadow_map * map, addr_t guest_addr, addr_t * host_addr) { struct shadow_region * reg = get_shadow_region_by_addr(map, guest_addr); if (!reg) { // No mapping exists - return HOST_REGION_INVALID; + return SHDW_REGION_INVALID; } else { switch (reg->host_type) { - case HOST_REGION_PHYSICAL_MEMORY: + case SHDW_REGION_ALLOCATED: + case SHDW_REGION_WRITE_HOOK: *host_addr = (guest_addr - reg->guest_start) + reg->host_addr; return reg->host_type; - case HOST_REGION_MEMORY_MAPPED_DEVICE: - case HOST_REGION_UNALLOCATED: + case SHDW_REGION_UNALLOCATED: + case SHDW_REGION_FULL_HOOK: // ... default: *host_addr = 0; @@ -309,32 +328,43 @@ void print_shadow_map(struct shadow_map * map) { PrintDebug("Memory Layout (regions: %d) \n", map->num_regions); while (cur) { - PrintDebug("%d: 0x%p - 0x%p (%s) -> ", i, - (void *)cur->guest_start, (void *)(cur->guest_end - 1), - cur->guest_type == GUEST_REGION_PHYSICAL_MEMORY ? "GUEST_REGION_PHYSICAL_MEMORY" : - cur->guest_type == GUEST_REGION_NOTHING ? "GUEST_REGION_NOTHING" : - cur->guest_type == GUEST_REGION_MEMORY_MAPPED_DEVICE ? "GUEST_REGION_MEMORY_MAPPED_DEVICE" : - "UNKNOWN"); - if (cur->host_type == HOST_REGION_PHYSICAL_MEMORY || - cur->host_type == HOST_REGION_UNALLOCATED || - cur->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) { + PrintDebug("%d: 0x%p - 0x%p -> ", i, + (void *)cur->guest_start, (void *)(cur->guest_end - 1)); + if (cur->host_type == SHDW_REGION_ALLOCATED || + cur->host_type == SHDW_REGION_UNALLOCATED) { PrintDebug("0x%p", (void *)(cur->host_addr)); } - PrintDebug("(%s)\n", - cur->host_type == HOST_REGION_PHYSICAL_MEMORY ? "HOST_REGION_PHYSICAL_MEMORY" : - cur->host_type == HOST_REGION_UNALLOCATED ? "HOST_REGION_UNALLOACTED" : - cur->host_type == HOST_REGION_HOOK ? "HOST_REGION_HOOK" : - cur->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE ? "HOST_REGION_MEMORY_MAPPED_DEVICE" : - cur->host_type == HOST_REGION_REMOTE ? "HOST_REGION_REMOTE" : - cur->host_type == HOST_REGION_SWAPPED ? "HOST_REGION_SWAPPED" : - "UNKNOWN"); + PrintDebug("(%s)\n", shdw_region_type_to_str(cur->host_type)); cur = cur->next; i++; } } +static const uchar_t SHDW_REGION_INVALID_STR[] = "SHDW_REGION_INVALID"; +static const uchar_t SHDW_REGION_WRITE_HOOK_STR[] = "SHDW_REGION_WRITE_HOOK"; +static const uchar_t SHDW_REGION_FULL_HOOK_STR[] = "SHDW_REGION_FULL_HOOK"; +static const uchar_t SHDW_REGION_ALLOCATED_STR[] = "SHDW_REGION_ALLOCATED"; +static const uchar_t SHDW_REGION_UNALLOCATED_STR[] = "SHDW_REGION_UNALLOCATED"; + + +const uchar_t * shdw_region_type_to_str(shdw_region_type_t type) { + switch (type) { + case SHDW_REGION_INVALID: + return SHDW_REGION_INVALID_STR; + case SHDW_REGION_WRITE_HOOK: + return SHDW_REGION_WRITE_HOOK_STR; + case SHDW_REGION_FULL_HOOK: + return SHDW_REGION_FULL_HOOK_STR; + case SHDW_REGION_ALLOCATED: + return SHDW_REGION_ALLOCATED_STR; + case SHDW_REGION_UNALLOCATED: + return SHDW_REGION_UNALLOCATED_STR; + default: + return SHDW_REGION_INVALID_STR; + } +} diff --git a/palacios/src/palacios/vmm_paging.c b/palacios/src/palacios/vmm_paging.c index a5ef2df..12163f8 100644 --- a/palacios/src/palacios/vmm_paging.c +++ b/palacios/src/palacios/vmm_paging.c @@ -677,11 +677,8 @@ pde32_t * create_passthrough_pts_32(struct guest_info * guest_info) { struct shadow_region * region = get_shadow_region_by_addr(map, current_page_addr); if (!region || - (region->host_type == HOST_REGION_HOOK) || - (region->host_type == HOST_REGION_UNALLOCATED) || - (region->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) || - (region->host_type == HOST_REGION_REMOTE) || - (region->host_type == HOST_REGION_SWAPPED)) { + (region->host_type == SHDW_REGION_FULL_HOOK) || + (region->host_type == SHDW_REGION_UNALLOCATED)) { pte[j].present = 0; pte[j].writable = 0; pte[j].user_page = 0; @@ -696,7 +693,14 @@ pde32_t * create_passthrough_pts_32(struct guest_info * guest_info) { } else { addr_t host_addr; pte[j].present = 1; - pte[j].writable = 1; + + if (region->host_type == SHDW_REGION_WRITE_HOOK) { + pte[j].writable = 0; + PrintDebug("Marking Write hook host_addr %p as RO\n", (void *)current_page_addr); + } else { + pte[j].writable = 1; + } + pte[j].user_page = 1; pte[j].write_through = 0; pte[j].cache_disable = 0; @@ -781,11 +785,8 @@ pdpe32pae_t * create_passthrough_pts_32PAE(struct guest_info * guest_info) { struct shadow_region * region = get_shadow_region_by_addr(map, current_page_addr); if (!region || - (region->host_type == HOST_REGION_HOOK) || - (region->host_type == HOST_REGION_UNALLOCATED) || - (region->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) || - (region->host_type == HOST_REGION_REMOTE) || - (region->host_type == HOST_REGION_SWAPPED)) { + (region->host_type == SHDW_REGION_FULL_HOOK) || + (region->host_type == SHDW_REGION_UNALLOCATED)) { pte[k].present = 0; pte[k].writable = 0; pte[k].user_page = 0; @@ -801,7 +802,13 @@ pdpe32pae_t * create_passthrough_pts_32PAE(struct guest_info * guest_info) { } else { addr_t host_addr; pte[k].present = 1; - pte[k].writable = 1; + + if (region->host_type == SHDW_REGION_WRITE_HOOK) { + pte[k].writable = 0; + } else { + pte[k].writable = 1; + } + pte[k].user_page = 1; pte[k].write_through = 0; pte[k].cache_disable = 0; @@ -923,11 +930,8 @@ pml4e64_t * create_passthrough_pts_64(struct guest_info * info) { if (!region || - (region->host_type == HOST_REGION_HOOK) || - (region->host_type == HOST_REGION_UNALLOCATED) || - (region->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) || - (region->host_type == HOST_REGION_REMOTE) || - (region->host_type == HOST_REGION_SWAPPED)) { + (region->host_type == SHDW_REGION_FULL_HOOK) || + (region->host_type == SHDW_REGION_UNALLOCATED)) { pte[m].present = 0; pte[m].writable = 0; pte[m].user_page = 0; @@ -942,7 +946,13 @@ pml4e64_t * create_passthrough_pts_64(struct guest_info * info) { } else { addr_t host_addr; pte[m].present = 1; - pte[m].writable = 1; + + if (region->host_type == SHDW_REGION_WRITE_HOOK) { + pte[m].writable = 0; + } else { + pte[m].writable = 1; + } + pte[m].user_page = 1; pte[m].write_through = 0; pte[m].cache_disable = 0; diff --git a/palacios/src/palacios/vmm_rbtree.c b/palacios/src/palacios/vmm_rbtree.c index 1e55ba1..520e227 100644 --- a/palacios/src/palacios/vmm_rbtree.c +++ b/palacios/src/palacios/vmm_rbtree.c @@ -20,8 +20,8 @@ linux/lib/rbtree.c */ -#include -#include +#include + static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) { @@ -69,7 +69,7 @@ static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) rb_set_parent(node, left); } -void rb_insert_color(struct rb_node *node, struct rb_root *root) +void v3_rb_insert_color(struct rb_node *node, struct rb_root *root) { struct rb_node *parent, *gparent; @@ -133,7 +133,7 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root) rb_set_black(root->rb_node); } -EXPORT_SYMBOL(rb_insert_color); + static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, struct rb_root *root) @@ -221,7 +221,7 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, rb_set_black(node); } -void rb_erase(struct rb_node *node, struct rb_root *root) +void v3_rb_erase(struct rb_node *node, struct rb_root *root) { struct rb_node *child, *parent; int color; @@ -287,12 +287,12 @@ void rb_erase(struct rb_node *node, struct rb_root *root) if (color == RB_BLACK) __rb_erase_color(child, parent, root); } -EXPORT_SYMBOL(rb_erase); + /* * This function returns the first node (in sort order) of the tree. */ -struct rb_node *rb_first(struct rb_root *root) +struct rb_node *v3_rb_first(struct rb_root *root) { struct rb_node *n; @@ -303,9 +303,9 @@ struct rb_node *rb_first(struct rb_root *root) n = n->rb_left; return n; } -EXPORT_SYMBOL(rb_first); -struct rb_node *rb_last(struct rb_root *root) + +struct rb_node *v3_rb_last(struct rb_root *root) { struct rb_node *n; @@ -316,9 +316,9 @@ struct rb_node *rb_last(struct rb_root *root) n = n->rb_right; return n; } -EXPORT_SYMBOL(rb_last); -struct rb_node *rb_next(struct rb_node *node) + +struct rb_node *v3_rb_next(struct rb_node *node) { struct rb_node *parent; @@ -342,9 +342,9 @@ struct rb_node *rb_next(struct rb_node *node) return parent; } -EXPORT_SYMBOL(rb_next); -struct rb_node *rb_prev(struct rb_node *node) + +struct rb_node *v3_rb_prev(struct rb_node *node) { struct rb_node *parent; @@ -364,9 +364,9 @@ struct rb_node *rb_prev(struct rb_node *node) return parent; } -EXPORT_SYMBOL(rb_prev); -void rb_replace_node(struct rb_node *victim, struct rb_node *new, + +void v3_rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root) { struct rb_node *parent = rb_parent(victim); @@ -388,4 +388,4 @@ void rb_replace_node(struct rb_node *victim, struct rb_node *new, /* Copy the pointers/colour from the victim to the replacement */ *new = *victim; } -EXPORT_SYMBOL(rb_replace_node); + diff --git a/palacios/src/palacios/vmm_shadow_paging.c b/palacios/src/palacios/vmm_shadow_paging.c index a427b13..0690f66 100644 --- a/palacios/src/palacios/vmm_shadow_paging.c +++ b/palacios/src/palacios/vmm_shadow_paging.c @@ -623,7 +623,8 @@ static int handle_large_pagefault_32(struct guest_info * info, { pt_access_status_t shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code); pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]); - + addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr); + if (shadow_pte_access == PT_ACCESS_OK) { // Inconsistent state... // Guest Re-Entry will flush tables and everything should now workd @@ -634,18 +635,18 @@ static int handle_large_pagefault_32(struct guest_info * info, if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) { // Get the guest physical address of the fault - addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr); - host_region_type_t host_page_type = get_shadow_addr_type(info, guest_fault_pa); + shdw_region_type_t host_page_type = get_shadow_addr_type(info, guest_fault_pa); - if (host_page_type == HOST_REGION_INVALID) { + if (host_page_type == SHDW_REGION_INVALID) { // Inject a machine check in the guest PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa); v3_raise_exception(info, MC_EXCEPTION); return 0; } - if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) { + if ((host_page_type == SHDW_REGION_ALLOCATED) || + (host_page_type == SHDW_REGION_WRITE_HOOK)) { struct shadow_page_state * state = &(info->shdw_pg_state); addr_t shadow_pa = get_shadow_addr(info, guest_fault_pa); @@ -665,11 +666,12 @@ static int handle_large_pagefault_32(struct guest_info * info, PrintDebug("Marking page as Guest Page Table (large page)\n"); shadow_pte->vmm_info = PT32_GUEST_PT; shadow_pte->writable = 0; + } else if (host_page_type == SHDW_REGION_WRITE_HOOK) { + shadow_pte->writable = 0; } else { shadow_pte->writable = 1; } - //set according to VMM policy shadow_pte->write_through = 0; shadow_pte->cache_disable = 0; @@ -678,18 +680,30 @@ static int handle_large_pagefault_32(struct guest_info * info, } else { // Handle hooked pages as well as other special pages - if (handle_special_page_fault(info, fault_addr, guest_fault_pa, error_code) == -1) { + // if (handle_special_page_fault(info, fault_addr, guest_fault_pa, error_code) == -1) { + struct shadow_region * reg = v3_get_shadow_region(info, guest_fault_pa); + + if (v3_handle_mem_full_hook(info, fault_addr, guest_fault_pa, reg, error_code) == -1) { PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr); return -1; } } - } else if ((shadow_pte_access == PT_ACCESS_WRITE_ERROR) && - (shadow_pte->vmm_info == PT32_GUEST_PT)) { + } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) { + shdw_region_type_t host_page_type = get_shadow_addr_type(info, guest_fault_pa); + + if (host_page_type == SHDW_REGION_WRITE_HOOK) { + struct shadow_region * reg = v3_get_shadow_region(info, guest_fault_pa); - struct shadow_page_state * state = &(info->shdw_pg_state); - PrintDebug("Write operation on Guest PAge Table Page (large page)\n"); - state->cached_cr3 = 0; - shadow_pte->writable = 1; + if (v3_handle_mem_wr_hook(info, fault_addr, guest_fault_pa, reg, error_code) == -1) { + PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr); + return -1; + } + } else if (shadow_pte->vmm_info == PT32_GUEST_PT) { + struct shadow_page_state * state = &(info->shdw_pg_state); + PrintDebug("Write operation on Guest PAge Table Page (large page)\n"); + state->cached_cr3 = 0; + shadow_pte->writable = 1; + } } else { PrintError("Error in large page fault handler...\n"); @@ -717,6 +731,7 @@ static int handle_shadow_pte32_fault(struct guest_info * info, pt_access_status_t shadow_pte_access; pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);; pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]); + addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) + PAGE_OFFSET(fault_addr); // Check the guest page permissions @@ -751,14 +766,13 @@ static int handle_shadow_pte32_fault(struct guest_info * info, if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) { - addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) + PAGE_OFFSET(fault_addr); // Page Table Entry Not Present PrintDebug("guest_pa =%p\n", (void *)guest_pa); - host_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa); + shdw_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa); - if (host_page_type == HOST_REGION_INVALID) { + if (host_page_type == SHDW_REGION_INVALID) { // Inject a machine check in the guest PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa); v3_raise_exception(info, MC_EXCEPTION); @@ -767,7 +781,8 @@ static int handle_shadow_pte32_fault(struct guest_info * info, // else... - if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) { + if ((host_page_type == SHDW_REGION_ALLOCATED) || + (host_page_type == SHDW_REGION_WRITE_HOOK)) { struct shadow_page_state * state = &(info->shdw_pg_state); addr_t shadow_pa = get_shadow_addr(info, guest_pa); @@ -790,7 +805,9 @@ static int handle_shadow_pte32_fault(struct guest_info * info, shadow_pte->vmm_info = PT32_GUEST_PT; } - if (guest_pte->dirty == 1) { + if (host_page_type == SHDW_REGION_WRITE_HOOK) { + shadow_pte->writable = 0; + } else if (guest_pte->dirty == 1) { shadow_pte->writable = guest_pte->writable; } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) { shadow_pte->writable = guest_pte->writable; @@ -807,29 +824,42 @@ static int handle_shadow_pte32_fault(struct guest_info * info, shadow_pte->writable = 0; } - - } else { // Page fault handled by hook functions - if (handle_special_page_fault(info, fault_addr, guest_pa, error_code) == -1) { + struct shadow_region * reg = v3_get_shadow_region(info, guest_pa); + + if (v3_handle_mem_full_hook(info, fault_addr, guest_pa, reg, error_code) == -1) { PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr); return -1; } } - + /* } else if ((shadow_pte_access == PT_ACCESS_WRITE_ERROR) && (guest_pte->dirty == 0)) { - - PrintDebug("Shadow PTE Write Error\n"); + */ + } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) { guest_pte->dirty = 1; - shadow_pte->writable = guest_pte->writable; + + shdw_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa); + + if (host_page_type == SHDW_REGION_WRITE_HOOK) { + struct shadow_region * reg = v3_get_shadow_region(info, guest_pa); + + if (v3_handle_mem_wr_hook(info, fault_addr, guest_pa, reg, error_code) == -1) { + PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr); + return -1; + } + } else { + PrintDebug("Shadow PTE Write Error\n"); + shadow_pte->writable = guest_pte->writable; + } if (shadow_pte->vmm_info == PT32_GUEST_PT) { struct shadow_page_state * state = &(info->shdw_pg_state); PrintDebug("Write operation on Guest PAge Table Page\n"); state->cached_cr3 = 0; } - + return 0; } else { diff --git a/palacios/src/palacios/vmm_xed.c b/palacios/src/palacios/vmm_xed.c index 9b16078..f34408b 100644 --- a/palacios/src/palacios/vmm_xed.c +++ b/palacios/src/palacios/vmm_xed.c @@ -23,14 +23,14 @@ #include #include "vm_guest.h" #include "test.h" + #else + #include #include #include #include #include - - #endif @@ -42,7 +42,9 @@ -static xed_state_t decoder_state; + +static uint_t tables_inited = 0; + #define GPR_REGISTER 0 #define SEGMENT_REGISTER 1 @@ -88,8 +90,8 @@ struct memory_operand { -// This returns a pointer to a V3_OPCODE_[*] array defined in vmm_decoder.h -static int get_opcode(xed_iform_enum_t iform, addr_t * opcode); + +static v3_op_type_t get_opcode(xed_iform_enum_t iform); static int xed_reg_to_v3_reg(struct guest_info * info, xed_reg_enum_t xed_reg, addr_t * v3_reg, uint_t * reg_len); static int get_memory_operand(struct guest_info * info, xed_decoded_inst_t * xed_instr, uint_t index, struct x86_operand * operand); @@ -139,9 +141,18 @@ static int is_flags_reg(xed_reg_enum_t xed_reg) { -int v3_init_decoder() { - xed_tables_init(); - xed_state_zero(&decoder_state); +int v3_init_decoder(struct guest_info * info) { + // Global library initialization, only do it once + if (tables_inited == 0) { + xed_tables_init(); + tables_inited = 1; + } + + xed_state_t * decoder_state = (xed_state_t *)V3_Malloc(sizeof(xed_state_t)); + xed_state_zero(decoder_state); + + info->decoder_state = decoder_state; + return 0; } @@ -152,13 +163,13 @@ int v3_basic_mem_decode(struct guest_info * info, addr_t instr_ptr, struct basic xed_error_enum_t xed_error; - if (set_decoder_mode(info, &decoder_state) == -1) { + if (set_decoder_mode(info, info->decoder_state) == -1) { PrintError("Could not set decoder mode\n"); return -1; } - xed_decoded_inst_zero_set_mode(&xed_instr, &decoder_state); + xed_decoded_inst_zero_set_mode(&xed_instr, info->decoder_state); xed_error = xed_decode(&xed_instr, REINTERPRET_CAST(const xed_uint8_t *, instr_ptr), @@ -198,21 +209,55 @@ int v3_basic_mem_decode(struct guest_info * info, addr_t instr_ptr, struct basic } +static int decode_string_op(struct guest_info * info, + xed_decoded_inst_t * xed_instr, const xed_inst_t * xi, + struct x86_instr * instr) { + + PrintDebug("String operation\n"); + + if (instr->op_type == V3_OP_MOVS) { + instr->num_operands = 2; + + if (get_memory_operand(info, xed_instr, 0, &(instr->dst_operand)) == -1) { + PrintError("Could not get Destination memory operand\n"); + return -1; + } + + if (get_memory_operand(info, xed_instr, 1, &(instr->src_operand)) == -1) { + PrintError("Could not get Source memory operand\n"); + return -1; + } + + if (instr->prefixes.rep == 1) { + addr_t reg_addr = 0; + uint_t reg_length = 0; + + xed_reg_to_v3_reg(info, xed_decoded_inst_get_reg(xed_instr, XED_OPERAND_REG0), ®_addr, ®_length); + instr->str_op_length = MASK(*(addr_t *)reg_addr, reg_length); + } else { + instr->str_op_length = 1; + } + + } + + return 0; +} + + int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * instr) { xed_decoded_inst_t xed_instr; xed_error_enum_t xed_error; + v3_get_prefixes((uchar_t *)instr_ptr, &(instr->prefixes)); - if (set_decoder_mode(info, &decoder_state) == -1) { + if (set_decoder_mode(info, info->decoder_state) == -1) { PrintError("Could not set decoder mode\n"); return -1; } - - - xed_decoded_inst_zero_set_mode(&xed_instr, &decoder_state); + xed_decoded_inst_zero_set_mode(&xed_instr, info->decoder_state); xed_error = xed_decode(&xed_instr, REINTERPRET_CAST(const xed_uint8_t *, instr_ptr), @@ -227,14 +272,35 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins const xed_inst_t * xi = xed_decoded_inst_inst(&xed_instr); instr->instr_length = xed_decoded_inst_get_length(&xed_instr); - instr->num_operands = xed_decoded_inst_noperands(&xed_instr); + xed_iform_enum_t iform = xed_decoded_inst_get_iform_enum(&xed_instr); +#ifdef DEBUG_XED + xed_iclass_enum_t iclass = xed_decoded_inst_get_iclass(&xed_instr); - PrintDebug("iform=%s\n", xed_iform_enum_t2str(iform)); + PrintDebug("iform=%s, iclass=%s\n", xed_iform_enum_t2str(iform), xed_iclass_enum_t2str(iclass)); +#endif + if ((instr->op_type = get_opcode(iform)) == V3_INVALID_OP) { + PrintError("Could not get opcode. (iform=%s)\n", xed_iform_enum_t2str(iform)); + return -1; + } + + + // We special case the string operations... + if (xed_decoded_inst_get_category(&xed_instr) == XED_CATEGORY_STRINGOP) { + instr->is_str_op = 1; + return decode_string_op(info, &xed_instr, xi, instr); + } else { + instr->is_str_op = 0; + instr->str_op_length = 0; + } + + + instr->num_operands = xed_decoded_inst_noperands(&xed_instr); + if (instr->num_operands > 3) { PrintDebug("Special Case Not Handled\n"); return -1; @@ -253,16 +319,6 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins - - - if (get_opcode(iform, &(instr->opcode)) == -1) { - PrintError("Could not get opcode. (iform=%s)\n", xed_iform_enum_t2str(iform)); - return -1; - } - - - - //PrintDebug("Number of operands: %d\n", instr->num_operands); //PrintDebug("INSTR length: %d\n", instr->instr_length); @@ -286,7 +342,7 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins xed_reg, &(v3_op->operand), &(v3_op->size)); - + if (v3_reg_type == -1) { PrintError("First operand is an Unhandled Operand: %s\n", xed_reg_enum_t2str(xed_reg)); v3_op->type = INVALID_OPERAND; @@ -303,16 +359,6 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins case XED_OPERAND_MEM0: { - /* - struct x86_operand * operand = &(instr->dst_operand); - - if (xed_decoded_inst_mem_read(&xed_instr, 0)) { - operand = &(instr->src_operand); - } else if (xed_decoded_inst_mem_written(&xed_instr, 0)) { - operand = &(instr->dst_operand); - } - */ - if (get_memory_operand(info, &xed_instr, 0, v3_op) == -1) { PrintError("Could not get first memory operand\n"); return -1; @@ -379,15 +425,6 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins case XED_OPERAND_MEM0: { - - /* - if (xed_decoded_inst_mem_read(&xed_instr, 0)) { - v3_op = &(instr->src_operand); - } else if (xed_decoded_inst_mem_written(&xed_instr, 0)) { - v3_op = &(instr->dst_operand); - } - */ - if (get_memory_operand(info, &xed_instr, 0, v3_op) == -1) { PrintError("Could not get first memory operand\n"); return -1; @@ -535,9 +572,8 @@ static int get_memory_operand(struct guest_info * info, xed_decoded_inst_t * xe if (disp_bits) { xed_int64_t xed_disp = xed_decoded_inst_get_memory_displacement(xed_instr, op_index); - mem_op.displacement_size = disp_bits / 8; + mem_op.displacement_size = disp_bits; mem_op.displacement = xed_disp; - } operand->type = MEM_OPERAND; @@ -545,9 +581,12 @@ static int get_memory_operand(struct guest_info * info, xed_decoded_inst_t * xe - PrintDebug("Struct: Seg=%x, base=%x, index=%x, scale=%x, displacement=%x\n", - mem_op.segment, mem_op.base, mem_op.index, mem_op.scale, mem_op.displacement); + PrintDebug("Struct: Seg=%p, base=%p, index=%p, scale=%p, displacement=%p\n", + (void *)mem_op.segment, (void*)mem_op.base, (void *)mem_op.index, + (void *)mem_op.scale, (void *)(addr_t)mem_op.displacement); + + PrintDebug("operand size: %d\n", operand->size); seg = mem_op.segment; base = MASK(mem_op.base, mem_op.base_size); @@ -555,7 +594,8 @@ static int get_memory_operand(struct guest_info * info, xed_decoded_inst_t * xe scale = mem_op.scale; displacement = MASK(mem_op.displacement, mem_op.displacement_size); - PrintDebug("Seg=%x, base=%x, index=%x, scale=%x, displacement=%x\n", seg, base, index, scale, displacement); + PrintDebug("Seg=%p, base=%p, index=%p, scale=%p, displacement=%p\n", + (void *)seg, (void *)base, (void *)index, (void *)scale, (void *)(addr_t)displacement); operand->operand = seg + base + (scale * index) + displacement; return 0; @@ -773,7 +813,7 @@ static int xed_reg_to_v3_reg(struct guest_info * info, xed_reg_enum_t xed_reg, a return CTRL_REGISTER; case XED_REG_CR4: *v3_reg = (addr_t)&(info->ctrl_regs.cr4); - *reg_len = 4; + *reg_len = 4; return CTRL_REGISTER; case XED_REG_CR8: *v3_reg = (addr_t)&(info->ctrl_regs.cr8); @@ -974,37 +1014,144 @@ static int xed_reg_to_v3_reg(struct guest_info * info, xed_reg_enum_t xed_reg, a -static int get_opcode(xed_iform_enum_t iform, addr_t * opcode) { +static v3_op_type_t get_opcode(xed_iform_enum_t iform) { switch (iform) { case XED_IFORM_MOV_CR_GPR64_CR: case XED_IFORM_MOV_CR_GPR32_CR: - *opcode = (addr_t)&V3_OPCODE_MOVCR2; - break; + return V3_OP_MOVCR2; case XED_IFORM_MOV_CR_CR_GPR64: case XED_IFORM_MOV_CR_CR_GPR32: - *opcode = (addr_t)&V3_OPCODE_MOV2CR; - break; + return V3_OP_MOV2CR; case XED_IFORM_SMSW_GPRv: - *opcode = (addr_t)&V3_OPCODE_SMSW; - break; + return V3_OP_SMSW; case XED_IFORM_LMSW_GPR16: - *opcode = (addr_t)&V3_OPCODE_LMSW; - break; + return V3_OP_LMSW; case XED_IFORM_CLTS: - *opcode = (addr_t)&V3_OPCODE_CLTS; - break; + return V3_OP_CLTS; + + case XED_IFORM_ADC_MEMv_GPRv: + case XED_IFORM_ADC_MEMv_IMM: + case XED_IFORM_ADC_MEMb_GPR8: + case XED_IFORM_ADC_MEMb_IMM: + return V3_OP_ADC; + + case XED_IFORM_ADD_MEMv_GPRv: + case XED_IFORM_ADD_MEMb_IMM: + case XED_IFORM_ADD_MEMb_GPR8: + case XED_IFORM_ADD_MEMv_IMM: + return V3_OP_ADD; + + case XED_IFORM_AND_MEMv_IMM: + case XED_IFORM_AND_MEMb_GPR8: + case XED_IFORM_AND_MEMv_GPRv: + case XED_IFORM_AND_MEMb_IMM: + return V3_OP_AND; + + case XED_IFORM_SUB_MEMv_IMM: + case XED_IFORM_SUB_MEMb_GPR8: + case XED_IFORM_SUB_MEMb_IMM: + case XED_IFORM_SUB_MEMv_GPRv: + return V3_OP_SUB; + + case XED_IFORM_MOV_MEMv_GPRv: + case XED_IFORM_MOV_MEMb_GPR8: + case XED_IFORM_MOV_MEMb_AL: + case XED_IFORM_MOV_MEMv_IMM: + case XED_IFORM_MOV_MEMb_IMM: + return V3_OP_MOV; + + case XED_IFORM_DEC_MEMv: + case XED_IFORM_DEC_MEMb: + return V3_OP_DEC; + + case XED_IFORM_INC_MEMb: + case XED_IFORM_INC_MEMv: + return V3_OP_INC; + + case XED_IFORM_OR_MEMv_IMM: + case XED_IFORM_OR_MEMb_IMM: + case XED_IFORM_OR_MEMv_GPRv: + case XED_IFORM_OR_MEMb_GPR8: + return V3_OP_OR; + + case XED_IFORM_XOR_MEMv_GPRv: + case XED_IFORM_XOR_MEMb_IMM: + case XED_IFORM_XOR_MEMb_GPR8: + case XED_IFORM_XOR_MEMv_IMM: + return V3_OP_XOR; + + case XED_IFORM_NEG_MEMb: + case XED_IFORM_NEG_MEMv: + return V3_OP_NEG; + + case XED_IFORM_NOT_MEMv: + case XED_IFORM_NOT_MEMb: + return V3_OP_NOT; + + case XED_IFORM_XCHG_MEMv_GPRv: + case XED_IFORM_XCHG_MEMb_GPR8: + return V3_OP_XCHG; + + case XED_IFORM_SETB_MEMb: + return V3_OP_SETB; + + case XED_IFORM_SETBE_MEMb: + return V3_OP_SETBE; + + case XED_IFORM_SETL_MEMb: + return V3_OP_SETL; + + case XED_IFORM_SETLE_MEMb: + return V3_OP_SETLE; + + case XED_IFORM_SETNB_MEMb: + return V3_OP_SETNB; + + case XED_IFORM_SETNBE_MEMb: + return V3_OP_SETNBE; + + case XED_IFORM_SETNL_MEMb: + return V3_OP_SETNL; + + case XED_IFORM_SETNLE_MEMb: + return V3_OP_SETNLE; + + case XED_IFORM_SETNO_MEMb: + return V3_OP_SETNO; + + case XED_IFORM_SETNP_MEMb: + return V3_OP_SETNP; + + case XED_IFORM_SETNS_MEMb: + return V3_OP_SETNS; + + case XED_IFORM_SETNZ_MEMb: + return V3_OP_SETNZ; + + case XED_IFORM_SETO_MEMb: + return V3_OP_SETO; + + case XED_IFORM_SETP_MEMb: + return V3_OP_SETP; + case XED_IFORM_SETS_MEMb: + return V3_OP_SETS; + case XED_IFORM_SETZ_MEMb: + return V3_OP_SETZ; + + case XED_IFORM_MOVSB: + case XED_IFORM_MOVSW: + case XED_IFORM_MOVSD: + case XED_IFORM_MOVSQ: + return V3_OP_MOVS; default: - *opcode = 0; - return -1; + return V3_INVALID_OP; } - - return 0; }