2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm_types.h>
23 /* .... Giant fucking switch tables */
138 static int get_addr_width(struct guest_info * info, struct x86_instr * instr) {
140 switch (v3_get_vm_cpu_mode(info)) {
142 return (instr->prefixes.addr_size) ? 4 : 2;
148 if (info->segments.cs.db) {
149 return (instr->prefixes.addr_size) ? 2 : 4;
151 return (instr->prefixes.addr_size) ? 4 : 2;
154 PrintError("Unsupported CPU mode: %d\n", info->cpu_mode);
159 static int get_operand_width(struct guest_info * info, struct x86_instr * instr,
259 switch (v3_get_vm_cpu_mode(info)) {
261 return (instr->prefixes.op_size) ? 4 : 2;
263 if (instr->prefixes.rex.op_size) {
269 if (info->segments.cs.db) {
271 return (instr->prefixes.op_size) ? 2 : 4;
273 return (instr->prefixes.op_size) ? 4 : 2;
276 PrintError("Unsupported CPU mode: %d\n", info->cpu_mode);
281 switch (v3_get_vm_cpu_mode(info)) {
283 PrintError("Invalid instruction given operating mode (%d)\n", form);
293 PrintError("Unsupported CPU mode: %d\n", info->cpu_mode);
299 switch (v3_get_vm_cpu_mode(info)) {
309 PrintError("Unsupported CPU mode: %d\n", info->cpu_mode);
317 switch (v3_get_vm_cpu_mode(info)) {
327 PrintError("Unsupported CPU mode: %d\n", info->cpu_mode);
334 PrintError("Unsupported instruction form %d\n", form);
343 typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t;
344 typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t;
351 } __attribute__((packed));
358 } __attribute__((packed));
365 static inline int decode_gpr(struct guest_info * core,
367 struct x86_operand * reg) {
369 struct v3_gprs * gprs = &(core->vm_regs);
373 reg->operand = (addr_t)&(gprs->rax);
376 reg->operand = (addr_t)&(gprs->rcx);
379 reg->operand = (addr_t)&(gprs->rdx);
382 reg->operand = (addr_t)&(gprs->rbx);
385 if (reg->size == 1) {
386 reg->operand = (addr_t)&(gprs->rax) + 1;
388 reg->operand = (addr_t)&(gprs->rsp);
392 if (reg->size == 1) {
393 reg->operand = (addr_t)&(gprs->rcx) + 1;
395 reg->operand = (addr_t)&(gprs->rbp);
399 if (reg->size == 1) {
400 reg->operand = (addr_t)&(gprs->rdx) + 1;
402 reg->operand = (addr_t)&(gprs->rsi);
406 if (reg->size == 1) {
407 reg->operand = (addr_t)&(gprs->rbx) + 1;
409 reg->operand = (addr_t)&(gprs->rdi);
413 PrintError("Invalid Reg Code (%d)\n", reg_code);
424 static inline int decode_cr(struct guest_info * core,
426 struct x86_operand * reg) {
428 struct v3_ctrl_regs * crs = &(core->ctrl_regs);
430 PrintDebug("\t Ctrl regs %d\n", reg_code);
434 reg->operand = (addr_t)&(crs->cr0);
437 reg->operand = (addr_t)&(crs->cr2);
440 reg->operand = (addr_t)&(crs->cr3);
443 reg->operand = (addr_t)&(crs->cr4);
447 PrintError("Invalid Reg Code (%d)\n", reg_code);
454 // This converts the displacement into the appropriate masked value
456 QUESTION: Are the register Values signed ?????
458 #define MASK_DISPLACEMENT(reg, mode) ({ \
460 if (mode == DISP8) { \
461 val = (sint8_t)(reg & 0xff); \
462 } else if (mode == DISP16) { \
463 val = (sint16_t)(reg & 0xffff); \
464 } else if (mode == DISP32) { \
465 val = (sint32_t)(reg & 0xffffffff); \
467 PrintError("Error invalid displacement size (%d)\n", mode); \
474 #define ADDR_MASK(val, length) ({ \
475 ullong_t mask = 0x0LL; \
478 mask = 0x00000000000fffffLL; \
481 mask = 0x00000000ffffffffLL; \
484 mask = 0xffffffffffffffffLL; \
492 static int decode_rm_operand16(struct guest_info * core,
493 uint8_t * modrm_instr,
494 struct x86_instr * instr,
495 struct x86_operand * operand,
496 uint8_t * reg_code) {
498 struct v3_gprs * gprs = &(core->vm_regs);
499 struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
500 addr_t base_addr = 0;
501 modrm_mode_t mod_mode = 0;
502 uint8_t * instr_cursor = modrm_instr;
504 // PrintDebug("ModRM mod=%d\n", modrm->mod);
506 *reg_code = modrm->reg;
510 if (modrm->mod == 3) {
511 //PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
512 operand->type = REG_OPERAND;
514 decode_gpr(core, modrm->rm, operand);
517 struct v3_segment * seg = NULL;
519 operand->type = MEM_OPERAND;
521 if (modrm->mod == 0) {
523 } else if (modrm->mod == 1) {
525 } else if (modrm->mod == 2) {
531 base_addr = gprs->rbx + MASK_DISPLACEMENT(gprs->rsi, mod_mode);
534 base_addr = gprs->rbx + MASK_DISPLACEMENT(gprs->rdi, mod_mode);
537 base_addr = gprs->rbp + MASK_DISPLACEMENT(gprs->rsi, mod_mode);
540 base_addr = gprs->rbp + MASK_DISPLACEMENT(gprs->rdi, mod_mode);
543 base_addr = gprs->rsi;
546 base_addr = gprs->rdi;
549 if (modrm->mod == 0) {
553 base_addr = gprs->rbp;
557 base_addr = gprs->rbx;
563 if (mod_mode == DISP8) {
564 base_addr += *(sint8_t *)instr_cursor;
566 } else if (mod_mode == DISP16) {
567 base_addr += *(sint16_t *)instr_cursor;
572 // get appropriate segment
573 if (instr->prefixes.cs_override) {
574 seg = &(core->segments.cs);
575 } else if (instr->prefixes.es_override) {
576 seg = &(core->segments.es);
577 } else if (instr->prefixes.ss_override) {
578 seg = &(core->segments.ss);
579 } else if (instr->prefixes.fs_override) {
580 seg = &(core->segments.fs);
581 } else if (instr->prefixes.gs_override) {
582 seg = &(core->segments.gs);
584 seg = &(core->segments.ds);
587 operand->operand = ADDR_MASK(get_addr_linear(core, base_addr, seg),
588 get_addr_width(core, instr));
592 return (instr_cursor - modrm_instr);
596 // returns num_bytes parsed
597 static int decode_rm_operand32(struct guest_info * core,
598 uint8_t * modrm_instr,
599 struct x86_instr * instr,
600 struct x86_operand * operand,
601 uint8_t * reg_code) {
603 struct v3_gprs * gprs = &(core->vm_regs);
604 uint8_t * instr_cursor = modrm_instr;
605 struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
606 addr_t base_addr = 0;
607 modrm_mode_t mod_mode = 0;
608 uint_t has_sib_byte = 0;
611 *reg_code = modrm->reg;
615 if (modrm->mod == 3) {
616 operand->type = REG_OPERAND;
617 // PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
619 decode_gpr(core, modrm->rm, operand);
622 struct v3_segment * seg = NULL;
624 operand->type = MEM_OPERAND;
626 if (modrm->mod == 0) {
628 } else if (modrm->mod == 1) {
630 } else if (modrm->mod == 2) {
636 base_addr = gprs->rax;
639 base_addr = gprs->rcx;
642 base_addr = gprs->rdx;
645 base_addr = gprs->rbx;
651 if (modrm->mod == 0) {
655 base_addr = gprs->rbp;
659 base_addr = gprs->rsi;
662 base_addr = gprs->rdi;
668 struct sib_byte * sib = (struct sib_byte *)(instr_cursor);
669 int scale = 0x1 << sib->scale;
673 switch (sib->index) {
675 base_addr = gprs->rax;
678 base_addr = gprs->rcx;
681 base_addr = gprs->rdx;
684 base_addr = gprs->rbx;
690 base_addr = gprs->rbp;
693 base_addr = gprs->rsi;
696 base_addr = gprs->rdi;
705 base_addr += MASK_DISPLACEMENT(gprs->rax, mod_mode);
708 base_addr += MASK_DISPLACEMENT(gprs->rcx, mod_mode);
711 base_addr += MASK_DISPLACEMENT(gprs->rdx, mod_mode);
714 base_addr += MASK_DISPLACEMENT(gprs->rbx, mod_mode);
717 base_addr += MASK_DISPLACEMENT(gprs->rsp, mod_mode);
720 if (modrm->mod != 0) {
721 base_addr += MASK_DISPLACEMENT(gprs->rbp, mod_mode);
725 base_addr += MASK_DISPLACEMENT(gprs->rsi, mod_mode);
728 base_addr += MASK_DISPLACEMENT(gprs->rdi, mod_mode);
735 if (mod_mode == DISP8) {
736 base_addr += *(sint8_t *)instr_cursor;
738 } else if (mod_mode == DISP32) {
739 base_addr += *(sint32_t *)instr_cursor;
743 // get appropriate segment
744 if (instr->prefixes.cs_override) {
745 seg = &(core->segments.cs);
746 } else if (instr->prefixes.es_override) {
747 seg = &(core->segments.es);
748 } else if (instr->prefixes.ss_override) {
749 seg = &(core->segments.ss);
750 } else if (instr->prefixes.fs_override) {
751 seg = &(core->segments.fs);
752 } else if (instr->prefixes.gs_override) {
753 seg = &(core->segments.gs);
755 seg = &(core->segments.ds);
758 operand->operand = ADDR_MASK(get_addr_linear(core, base_addr, seg),
759 get_addr_width(core, instr));
763 return (instr_cursor - modrm_instr);
767 int decode_rm_operand64(struct guest_info * core, uint8_t * instr_ptr,
768 struct x86_instr * instr, struct x86_operand * operand,
769 uint8_t * reg_code) {
776 static int decode_rm_operand(struct guest_info * core,
777 uint8_t * instr_ptr, // input
778 struct x86_instr * instr,
779 struct x86_operand * operand,
780 uint8_t * reg_code) {
782 v3_cpu_mode_t mode = v3_get_vm_cpu_mode(core);
785 return decode_rm_operand16(core, instr_ptr, instr, operand, reg_code);
786 } else if ((mode == PROTECTED) || (mode == PROTECTED_PAE) || (mode == LONG_32_COMPAT)) {
787 return decode_rm_operand32(core, instr_ptr, instr, operand, reg_code);
788 } else if (mode == LONG) {
789 return decode_rm_operand64(core, instr_ptr, instr, operand, reg_code);
791 PrintError("Invalid CPU_MODE (%d)\n", mode);
798 static inline op_form_t op_code_to_form_0f(uint8_t * instr, int * length) {
803 struct modrm_byte * modrm = (struct modrm_byte *)&(instr[2]);
805 switch (modrm->reg) {
813 return INVALID_INSTR;
874 return INVALID_INSTR;
879 static op_form_t op_code_to_form(uint8_t * instr, int * length) {
903 return op_code_to_form_0f(instr, length);
943 struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
945 switch (modrm->reg) {
959 return INVALID_INSTR;
963 struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
965 switch (modrm->reg) {
979 return INVALID_INSTR;
983 struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
985 switch (modrm->reg) {
999 return INVALID_INSTR;
1028 return MOV_MEM2AL_8;
1032 return MOV_AL2MEM_8;
1056 struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
1058 switch (modrm->reg) {
1064 return INVALID_INSTR;
1068 struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
1070 switch (modrm->reg) {
1076 return INVALID_INSTR;
1082 struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
1084 switch (modrm->reg) {
1090 return INVALID_INSTR;
1095 struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
1097 switch (modrm->reg) {
1103 return INVALID_INSTR;
1108 return INVALID_INSTR;
1114 static char * op_form_to_str(op_form_t form) {
1117 case LMSW: return "LMSW";
1118 case SMSW: return "SMSW";
1119 case CLTS: return "CLTS";
1120 case INVLPG: return "INVLPG";
1121 case MOV_CR2: return "MOV_CR2";
1122 case MOV_2CR: return "MOV_2CR";
1123 case MOV_DR2: return "MOV_DR2";
1124 case MOV_2DR: return "MOV_2DR";
1125 case MOV_SR2: return "MOV_SR2";
1126 case MOV_2SR: return "MOV_2SR";
1127 case MOV_MEM2_8: return "MOV_MEM2_8";
1128 case MOV_MEM2: return "MOV_MEM2";
1129 case MOV_2MEM_8: return "MOV_2MEM_8";
1130 case MOV_2MEM: return "MOV_2MEM";
1131 case MOV_MEM2AL_8: return "MOV_MEM2AL_8";
1132 case MOV_MEM2AX: return "MOV_MEM2AX";
1133 case MOV_AL2MEM_8: return "MOV_AL2MEM_8";
1134 case MOV_AX2MEM: return "MOV_AX2MEM";
1135 case MOV_IMM2_8: return "MOV_IMM2_8";
1136 case MOV_IMM2: return "MOV_IMM2";
1137 case MOVS_8: return "MOVS_8";
1138 case MOVS: return "MOVS";
1139 case MOVSX_8: return "MOVSX_8";
1140 case MOVSX: return "MOVSX";
1141 case MOVZX_8: return "MOVZX_8";
1142 case MOVZX: return "MOVZX";
1143 case HLT: return "HLT";
1144 case PUSHF: return "PUSHF";
1145 case POPF: return "POPF";
1146 case ADC_2MEM_8: return "ADC_2MEM_8";
1147 case ADC_2MEM: return "ADC_2MEM";
1148 case ADC_MEM2_8: return "ADC_MEM2_8";
1149 case ADC_MEM2: return "ADC_MEM2";
1150 case ADC_IMM2_8: return "ADC_IMM2_8";
1151 case ADC_IMM2: return "ADC_IMM2";
1152 case ADC_IMM2SX_8: return "ADC_IMM2SX_8";
1153 case ADD_IMM2_8: return "ADD_IMM2_8";
1154 case ADD_IMM2: return "ADD_IMM2";
1155 case ADD_IMM2SX_8: return "ADD_IMM2SX_8";
1156 case ADD_2MEM_8: return "ADD_2MEM_8";
1157 case ADD_2MEM: return "ADD_2MEM";
1158 case ADD_MEM2_8: return "ADD_MEM2_8";
1159 case ADD_MEM2: return "ADD_MEM2";
1160 case AND_MEM2_8: return "AND_MEM2_8";
1161 case AND_MEM2: return "AND_MEM2";
1162 case AND_2MEM_8: return "AND_2MEM_8";
1163 case AND_2MEM: return "AND_2MEM";
1164 case AND_IMM2_8: return "AND_IMM2_8";
1165 case AND_IMM2: return "AND_IMM2";
1166 case AND_IMM2SX_8: return "AND_IMM2SX_8";
1167 case OR_2MEM_8: return "OR_2MEM_8";
1168 case OR_2MEM: return "OR_2MEM";
1169 case OR_MEM2_8: return "OR_MEM2_8";
1170 case OR_MEM2: return "OR_MEM2";
1171 case OR_IMM2_8: return "OR_IMM2_8";
1172 case OR_IMM2: return "OR_IMM2";
1173 case OR_IMM2SX_8: return "OR_IMM2SX_8";
1174 case SUB_2MEM_8: return "SUB_2MEM_8";
1175 case SUB_2MEM: return "SUB_2MEM";
1176 case SUB_MEM2_8: return "SUB_MEM2_8";
1177 case SUB_MEM2: return "SUB_MEM2";
1178 case SUB_IMM2_8: return "SUB_IMM2_8";
1179 case SUB_IMM2: return "SUB_IMM2";
1180 case SUB_IMM2SX_8: return "SUB_IMM2SX_8";
1181 case XOR_2MEM_8: return "XOR_2MEM_8";
1182 case XOR_2MEM: return "XOR_2MEM";
1183 case XOR_MEM2_8: return "XOR_MEM2_8";
1184 case XOR_MEM2: return "XOR_MEM2";
1185 case XOR_IMM2_8: return "XOR_IMM2_8";
1186 case XOR_IMM2: return "XOR_IMM2";
1187 case XOR_IMM2SX_8: return "XOR_IMM2SX_8";
1188 case INC_8: return "INC_8";
1189 case INC: return "INC";
1190 case DEC_8: return "DEC_8";
1191 case DEC: return "DEC";
1192 case NEG_8: return "NEG_8";
1193 case NEG: return "NEG";
1194 case NOT_8: return "NOT_8";
1195 case NOT: return "NOT";
1196 case XCHG_8: return "XCHG_8";
1197 case XCHG: return "XCHG";
1198 case SETB: return "SETB";
1199 case SETBE: return "SETBE";
1200 case SETL: return "SETL";
1201 case SETLE: return "SETLE";
1202 case SETNB: return "SETNB";
1203 case SETNBE: return "SETNBE";
1204 case SETNL: return "SETNL";
1205 case SETNLE: return "SETNLE";
1206 case SETNO: return "SETNO";
1207 case SETNP: return "SETNP";
1208 case SETNS: return "SETNS";
1209 case SETNZ: return "SETNZ";
1210 case SETP: return "SETP";
1211 case SETS: return "SETS";
1212 case SETZ: return "SETZ";
1213 case SETO: return "SETO";
1214 case STOS_8: return "STOS_8";
1215 case STOS: return "STOS";
1219 return "INVALID_INSTR";