X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Finclude%2Fgeekos%2Fvmm_emulate.h;h=6a6c14428f86136f8edc25e1a31fc6bacc7d86d3;hb=89d5928385ff776aaaf9c0957734a611c9f9880c;hp=e82777c2c426797384554273b09bd2d72e649445;hpb=9be2a31f574121ab4aa0289b7714eefe070b0db0;p=palacios.git diff --git a/palacios/include/geekos/vmm_emulate.h b/palacios/include/geekos/vmm_emulate.h index e82777c..6a6c144 100644 --- a/palacios/include/geekos/vmm_emulate.h +++ b/palacios/include/geekos/vmm_emulate.h @@ -46,7 +46,7 @@ #define MODRM_MOD(x) ((x >> 6) & 0x3) #define MODRM_REG(x) ((x >> 3) & 0x7) -#define MODRM_RM(x) (x & 0x07) +#define MODRM_RM(x) (x & 0x7) struct modrm_byte { uint_t rm : 3 PACKED; @@ -55,6 +55,10 @@ struct modrm_byte { }; +#define SIB_BASE(x) ((x >> 6) & 0x3) +#define SIB_INDEX(x) ((x >> 3) & 0x7) +#define SIB_SCALE(x) (x & 0x7) + struct sib_byte { uint_t base : 3 PACKED; uint_t index : 3 PACKED; @@ -127,168 +131,305 @@ static inline int is_prefix_byte(char byte) { } } -typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_addr_type_t; +typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t; typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t; -typedef enum {INVALID_OPERAND_TYPE, REG_TO_REG, REG_TO_MEM, MEM_TO_REG} operand_type_t; +typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND} operand_type_t; struct guest_gprs; +static inline addr_t decode_register(struct guest_gprs * gprs, char reg_code, reg_size_t reg_size) { + addr_t reg_addr; -static inline int decode_operands16(struct guest_gprs * gprs, - char * modrm_instr, - addr_t * first_operand, - addr_t * second_operand, - reg_size_t reg_size) { + switch (reg_code) { + case 0: + reg_addr = (addr_t)&(gprs->rax); + break; + case 1: + reg_addr = (addr_t)&(gprs->rcx); + break; + case 2: + reg_addr = (addr_t)&(gprs->rdx); + break; + case 3: + reg_addr = (addr_t)&(gprs->rbx); + break; + case 4: + if (reg_size == REG8) { + reg_addr = (addr_t)&(gprs->rax) + 1; + } else { + reg_addr = (addr_t)&(gprs->rsp); + } + break; + case 5: + if (reg_size == REG8) { + reg_addr = (addr_t)&(gprs->rcx) + 1; + } else { + reg_addr = (addr_t)&(gprs->rbp); + } + break; + case 6: + if (reg_size == REG8) { + reg_addr = (addr_t)&(gprs->rdx) + 1; + } else { + reg_addr = (addr_t)&(gprs->rsi); + } + break; + case 7: + if (reg_size == REG8) { + reg_addr = (addr_t)&(gprs->rbx) + 1; + } else { + reg_addr = (addr_t)&(gprs->rdi); + } + break; + default: + reg_addr = 0; + break; + } + + return reg_addr; +} + + + +static inline operand_type_t decode_operands16(struct guest_gprs * gprs, + char * modrm_instr, + addr_t * first_operand, + addr_t * second_operand, + reg_size_t reg_size) { - struct modrm_byte * modrm = (struct modrm_byte*)modrm_instr; + struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr; addr_t base_addr = 0; - modrm_addr_type_t mod_type = 0; + modrm_mode_t mod_mode = 0; + operand_type_t addr_type = INVALID_OPERAND; PrintDebug("ModRM mod=%d\n", modrm->mod); if (modrm->mod == 3) { - mod_type = REG; - + mod_mode = REG; + addr_type = REG_OPERAND; PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); - switch (modrm->rm) { - case 0: - PrintDebug("EAX Operand\n"); - *first_operand = (addr_t)&(gprs->rax); - break; - case 1: - *first_operand = (addr_t)&(gprs->rcx); - break; - case 2: - *first_operand = (addr_t)&(gprs->rdx); - break; - case 3: - *first_operand = (addr_t)&(gprs->rbx); - break; - case 4: - if (reg_size == REG8) { - *first_operand = (addr_t)(&(gprs->rax) + 1); - } else { - *first_operand = (addr_t)&(gprs->rsp); - } - break; - case 5: - if (reg_size == REG8) { - *first_operand = (addr_t)(&(gprs->rcx) + 1); - } else { - *first_operand = (addr_t)&(gprs->rbp); - } - break; - case 6: - if (reg_size == REG8) { - *first_operand = (addr_t)(&(gprs->rdx) + 1); - } else { - *first_operand = (addr_t)&(gprs->rsi); - } - break; - case 7: - if (reg_size == REG8) { - *first_operand = (addr_t)(&(gprs->rbx) + 1); - } else { - *first_operand = (addr_t)&(gprs->rdi); - } - break; - } + *first_operand = decode_register(gprs, modrm->rm, reg_size); } else { + + addr_type = MEM_OPERAND; + if (modrm->mod == 0) { - mod_type = DISP0; + mod_mode = DISP0; } else if (modrm->mod == 1) { - mod_type = DISP8; + mod_mode = DISP8; } else if (modrm->mod == 2) { - mod_type = DISP16; + mod_mode = DISP16; } switch (modrm->rm) { case 0: base_addr = gprs->rbx + gprs->rsi; + break; case 1: base_addr = gprs->rbx + gprs->rdi; + break; case 2: base_addr = gprs->rbp + gprs->rsi; + break; case 3: base_addr = gprs->rbp + gprs->rdi; + break; case 4: base_addr = gprs->rsi; + break; case 5: base_addr = gprs->rdi; + break; case 6: if (modrm->mod == 0) { base_addr = 0; - mod_type = DISP16; + mod_mode = DISP16; } else { base_addr = gprs->rbp; } + break; case 7: base_addr = gprs->rbx; + break; } - if (mod_type == DISP8) { + if (mod_mode == DISP8) { base_addr += (uchar_t)*(modrm_instr + 1); - } else if (mod_type == DISP16) { + } else if (mod_mode == DISP16) { base_addr += (ushort_t)*(modrm_instr + 1); } - *first_operand = base_addr; } + *second_operand = decode_register(gprs, modrm->reg, reg_size); + + return addr_type; +} + - switch (modrm->reg) { +static inline operand_type_t decode_operands32(struct guest_gprs * gprs, + char * modrm_instr, + addr_t * first_operand, + addr_t * second_operand, + reg_size_t reg_size) { + + char * instr_cursor = modrm_instr; + struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr; + addr_t base_addr = 0; + modrm_mode_t mod_mode = 0; + uint_t has_sib_byte = 0; + operand_type_t addr_type = INVALID_OPERAND; + + if (modrm->mod == 3) { + mod_mode = REG; + addr_type = REG_OPERAND; + + PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); + + *first_operand = decode_register(gprs, modrm->rm, reg_size); + + } else { + + addr_type = MEM_OPERAND; + + if (modrm->mod == 0) { + mod_mode = DISP0; + } else if (modrm->mod == 1) { + mod_mode = DISP8; + } else if (modrm->mod == 2) { + mod_mode = DISP32; + } + + switch (modrm->rm) { case 0: - *second_operand = (addr_t)&(gprs->rax); + base_addr = gprs->rax; break; case 1: - *second_operand = (addr_t)&(gprs->rcx); + base_addr = gprs->rcx; break; case 2: - *second_operand = (addr_t)&(gprs->rdx); + base_addr = gprs->rdx; break; case 3: - *second_operand = (addr_t)&(gprs->rbx); + base_addr = gprs->rbx; break; case 4: - if (reg_size == REG8) { - *second_operand = (addr_t)&(gprs->rax) + 1; - } else { - *second_operand = (addr_t)&(gprs->rsp); - } + has_sib_byte = 1; break; case 5: - if (reg_size == REG8) { - *second_operand = (addr_t)&(gprs->rcx) + 1; + if (modrm->mod == 0) { + base_addr = 0; + mod_mode = DISP32; } else { - *second_operand = (addr_t)&(gprs->rbp); + base_addr = gprs->rbp; } break; case 6: - if (reg_size == REG8) { - *second_operand = (addr_t)&(gprs->rdx) + 1; - } else { - *second_operand = (addr_t)&(gprs->rsi); - } + base_addr = gprs->rsi; break; case 7: - if (reg_size == REG8) { - *second_operand = (addr_t)&(gprs->rbx) + 1; - } else { - *second_operand = (addr_t)&(gprs->rdi); - } + base_addr = gprs->rdi; break; + } + + if (has_sib_byte) { + instr_cursor += 1; + struct sib_byte * sib = (struct sib_byte *)(instr_cursor); + int scale = 1; + + + if (sib->scale == 1) { + scale = 2; + } else if (sib->scale == 2) { + scale = 4; + } else if (sib->scale == 3) { + scale = 8; + } + + + switch (sib->index) { + case 0: + base_addr = gprs->rax; + break; + case 1: + base_addr = gprs->rcx; + break; + case 2: + base_addr = gprs->rdx; + break; + case 3: + base_addr = gprs->rbx; + break; + case 4: + base_addr = 0; + break; + case 5: + base_addr = gprs->rbp; + break; + case 6: + base_addr = gprs->rsi; + break; + case 7: + base_addr = gprs->rdi; + break; + } + + base_addr *= scale; + + + switch (sib->base) { + case 0: + base_addr += gprs->rax; + break; + case 1: + base_addr += gprs->rcx; + break; + case 2: + base_addr += gprs->rdx; + break; + case 3: + base_addr += gprs->rbx; + break; + case 4: + base_addr += gprs->rsp; + break; + case 5: + if (modrm->mod != 0) { + base_addr += gprs->rbp; + } + break; + case 6: + base_addr += gprs->rsi; + break; + case 7: + base_addr += gprs->rdi; + break; + } + + } + + instr_cursor += 1; + + if (mod_mode == DISP8) { + base_addr += (uchar_t)*(instr_cursor); + } else if (mod_mode == DISP32) { + base_addr += (uint_t)*(instr_cursor); + } + + + *first_operand = base_addr; } - return 0; + *second_operand = decode_register(gprs, modrm->reg, reg_size); + return addr_type; } - #endif