static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) { int b, prefixes, aflag, dflag; int shift, ot; int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; target_ulong next_eip, tval; int rex_w, rex_r; if (unlikely(loglevel & CPU_LOG_TB_OP)) tcg_gen_debug_insn_start(pc_start); s->pc = pc_start; prefixes = 0; aflag = s->code32; dflag = s->code32; s->override = -1; rex_w = -1; rex_r = 0; #ifdef TARGET_X86_64 s->rex_x = 0; s->rex_b = 0; x86_64_hregs = 0; #endif s->rip_offset = 0; /* for relative ip address */ next_byte: b = ldub_code(s->pc); s->pc++; /* check prefixes */ #ifdef TARGET_X86_64 if (CODE64(s)) { switch (b) { case 0xf3: prefixes |= PREFIX_REPZ; goto next_byte; case 0xf2: prefixes |= PREFIX_REPNZ; goto next_byte; case 0xf0: prefixes |= PREFIX_LOCK; goto next_byte; case 0x2e: s->override = R_CS; goto next_byte; case 0x36: s->override = R_SS; goto next_byte; case 0x3e: s->override = R_DS; goto next_byte; case 0x26: s->override = R_ES; goto next_byte; case 0x64: s->override = R_FS; goto next_byte; case 0x65: s->override = R_GS; goto next_byte; case 0x66: prefixes |= PREFIX_DATA; goto next_byte; case 0x67: prefixes |= PREFIX_ADR; goto next_byte; case 0x40 ... 0x4f: /* REX prefix */ rex_w = (b >> 3) & 1; rex_r = (b & 0x4) << 1; s->rex_x = (b & 0x2) << 2; REX_B(s) = (b & 0x1) << 3; x86_64_hregs = 1; /* select uniform byte register addressing */ goto next_byte; } if (rex_w == 1) { /* 0x66 is ignored if rex.w is set */ dflag = 2; } else { if (prefixes & PREFIX_DATA) dflag ^= 1; } if (!(prefixes & PREFIX_ADR)) aflag = 2; } else #endif { switch (b) { case 0xf3: prefixes |= PREFIX_REPZ; goto next_byte; case 0xf2: prefixes |= PREFIX_REPNZ; goto next_byte; case 0xf0: prefixes |= PREFIX_LOCK; goto next_byte; case 0x2e: s->override = R_CS; goto next_byte; case 0x36: s->override = R_SS; goto next_byte; case 0x3e: s->override = R_DS; goto next_byte; case 0x26: s->override = R_ES; goto next_byte; case 0x64: s->override = R_FS; goto next_byte; case 0x65: s->override = R_GS; goto next_byte; case 0x66: prefixes |= PREFIX_DATA; goto next_byte; case 0x67: prefixes |= PREFIX_ADR; goto next_byte; } if (prefixes & PREFIX_DATA) dflag ^= 1; if (prefixes & PREFIX_ADR) aflag ^= 1; } s->prefix = prefixes; s->aflag = aflag; s->dflag = dflag; /* lock generation */ if (prefixes & PREFIX_LOCK) gen_helper_lock(); /* now check op code */ reswitch: switch(b) { case 0x0f: /**************************/ /* extended op code */ b = ldub_code(s->pc++) | 0x100; goto reswitch; /**************************/ /* arith & logic */ case 0x00 ... 0x05: case 0x08 ... 0x0d: case 0x10 ... 0x15: case 0x18 ... 0x1d: case 0x20 ... 0x25: case 0x28 ... 0x2d: case 0x30 ... 0x35: case 0x38 ... 0x3d: { int op, f, val; op = (b >> 3) & 7; f = (b >> 1) & 3; if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; switch(f) { case 0: /* OP Ev, Gv */ modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); if (mod != 3) { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); opreg = OR_TMP0; } else if (op == OP_XORL && rm == reg) { xor_zero: /* xor reg, reg optimisation */ gen_op_movl_T0_0(); s->cc_op = CC_OP_LOGICB + ot; gen_op_mov_reg_T0(ot, reg); gen_op_update1_cc(); break; } else { opreg = rm; } gen_op_mov_TN_reg(ot, 1, reg); gen_op(s, op, ot, opreg); break; case 1: /* OP Gv, Ev */ modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; reg = ((modrm >> 3) & 7) | rex_r; rm = (modrm & 7) | REX_B(s); if (mod != 3) { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_op_ld_T1_A0(ot + s->mem_index); } else if (op == OP_XORL && rm == reg) { goto xor_zero; } else { gen_op_mov_TN_reg(ot, 1, rm); } gen_op(s, op, ot, reg); break; case 2: /* OP A, Iv */ val = insn_get(s, ot); gen_op_movl_T1_im(val); gen_op(s, op, ot, OR_EAX); break; } } break; case 0x82: if (CODE64(s)) goto illegal_op; case 0x80: /* GRP1 */ case 0x81: case 0x83: { int val; if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); op = (modrm >> 3) & 7; if (mod != 3) { if (b == 0x83) s->rip_offset = 1; else s->rip_offset = insn_const_size(ot); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); opreg = OR_TMP0; } else { opreg = rm; } switch(b) { default: case 0x80: case 0x81: case 0x82: val = insn_get(s, ot); break; case 0x83: val = (int8_t)insn_get(s, OT_BYTE); break; } gen_op_movl_T1_im(val); gen_op(s, op, ot, opreg); } break; /**************************/ /* inc, dec, and other misc arith */ case 0x40 ... 0x47: /* inc Gv */ ot = dflag ? OT_LONG : OT_WORD; gen_inc(s, ot, OR_EAX + (b & 7), 1); break; case 0x48 ... 0x4f: /* dec Gv */ ot = dflag ? OT_LONG : OT_WORD; gen_inc(s, ot, OR_EAX + (b & 7), -1); break; case 0xf6: /* GRP3 */ case 0xf7: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); op = (modrm >> 3) & 7; if (mod != 3) { if (op == 0) s->rip_offset = insn_const_size(ot); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_op_ld_T0_A0(ot + s->mem_index); } else { gen_op_mov_TN_reg(ot, 0, rm); } switch(op) { case 0: /* test */ val = insn_get(s, ot); gen_op_movl_T1_im(val); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; case 2: /* not */ tcg_gen_not_tl(cpu_T[0], cpu_T[0]); if (mod != 3) { gen_op_st_T0_A0(ot + s->mem_index); } else { gen_op_mov_reg_T0(ot, rm); } break; case 3: /* neg */ tcg_gen_neg_tl(cpu_T[0], cpu_T[0]); if (mod != 3) { gen_op_st_T0_A0(ot + s->mem_index); } else { gen_op_mov_reg_T0(ot, rm); } gen_op_update_neg_cc(); s->cc_op = CC_OP_SUBB + ot; break; case 4: /* mul */ switch(ot) { case OT_BYTE: gen_op_mov_TN_reg(OT_BYTE, 1, R_EAX); tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]); tcg_gen_ext8u_tl(cpu_T[1], cpu_T[1]); /* XXX: use 32 bit mul which could be faster */ tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); gen_op_mov_reg_T0(OT_WORD, R_EAX); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_andi_tl(cpu_cc_src, cpu_T[0], 0xff00); s->cc_op = CC_OP_MULB; break; case OT_WORD: gen_op_mov_TN_reg(OT_WORD, 1, R_EAX); tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]); tcg_gen_ext16u_tl(cpu_T[1], cpu_T[1]); /* XXX: use 32 bit mul which could be faster */ tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); gen_op_mov_reg_T0(OT_WORD, R_EAX); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16); gen_op_mov_reg_T0(OT_WORD, R_EDX); tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); s->cc_op = CC_OP_MULW; break; default: case OT_LONG: #ifdef TARGET_X86_64 gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]); tcg_gen_ext32u_tl(cpu_T[1], cpu_T[1]); tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); gen_op_mov_reg_T0(OT_LONG, R_EAX); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32); gen_op_mov_reg_T0(OT_LONG, R_EDX); tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); #else { TCGv_i64 t0, t1; t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); tcg_gen_extu_i32_i64(t0, cpu_T[0]); tcg_gen_extu_i32_i64(t1, cpu_T[1]); tcg_gen_mul_i64(t0, t0, t1); tcg_gen_trunc_i64_i32(cpu_T[0], t0); gen_op_mov_reg_T0(OT_LONG, R_EAX); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_trunc_i64_i32(cpu_T[0], t0); gen_op_mov_reg_T0(OT_LONG, R_EDX); tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); } #endif s->cc_op = CC_OP_MULL; break; #ifdef TARGET_X86_64 case OT_QUAD: gen_helper_mulq_EAX_T0(cpu_T[0]); s->cc_op = CC_OP_MULQ; break; #endif } break; case 5: /* imul */ switch(ot) { case OT_BYTE: gen_op_mov_TN_reg(OT_BYTE, 1, R_EAX); tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]); tcg_gen_ext8s_tl(cpu_T[1], cpu_T[1]); /* XXX: use 32 bit mul which could be faster */ tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); gen_op_mov_reg_T0(OT_WORD, R_EAX); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_ext8s_tl(cpu_tmp0, cpu_T[0]); tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); s->cc_op = CC_OP_MULB; break; case OT_WORD: gen_op_mov_TN_reg(OT_WORD, 1, R_EAX); tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]); /* XXX: use 32 bit mul which could be faster */ tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); gen_op_mov_reg_T0(OT_WORD, R_EAX); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]); tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16); gen_op_mov_reg_T0(OT_WORD, R_EDX); s->cc_op = CC_OP_MULW; break; default: case OT_LONG: #ifdef TARGET_X86_64 gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]); tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); gen_op_mov_reg_T0(OT_LONG, R_EAX); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]); tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32); gen_op_mov_reg_T0(OT_LONG, R_EDX); #else { TCGv_i64 t0, t1; t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); tcg_gen_ext_i32_i64(t0, cpu_T[0]); tcg_gen_ext_i32_i64(t1, cpu_T[1]); tcg_gen_mul_i64(t0, t0, t1); tcg_gen_trunc_i64_i32(cpu_T[0], t0); gen_op_mov_reg_T0(OT_LONG, R_EAX); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_trunc_i64_i32(cpu_T[0], t0); gen_op_mov_reg_T0(OT_LONG, R_EDX); tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); } #endif s->cc_op = CC_OP_MULL; break; #ifdef TARGET_X86_64 case OT_QUAD: gen_helper_imulq_EAX_T0(cpu_T[0]); s->cc_op = CC_OP_MULQ; break; #endif } break; case 6: /* div */ switch(ot) { case OT_BYTE: gen_jmp_im(pc_start - s->cs_base); gen_helper_divb_AL(cpu_T[0]); break; case OT_WORD: gen_jmp_im(pc_start - s->cs_base); gen_helper_divw_AX(cpu_T[0]); break; default: case OT_LONG: gen_jmp_im(pc_start - s->cs_base); gen_helper_divl_EAX(cpu_T[0]); break; #ifdef TARGET_X86_64 case OT_QUAD: gen_jmp_im(pc_start - s->cs_base); gen_helper_divq_EAX(cpu_T[0]); break; #endif } break; case 7: /* idiv */ switch(ot) { case OT_BYTE: gen_jmp_im(pc_start - s->cs_base); gen_helper_idivb_AL(cpu_T[0]); break; case OT_WORD: gen_jmp_im(pc_start - s->cs_base); gen_helper_idivw_AX(cpu_T[0]); break; default: case OT_LONG: gen_jmp_im(pc_start - s->cs_base); gen_helper_idivl_EAX(cpu_T[0]); break; #ifdef TARGET_X86_64 case OT_QUAD: gen_jmp_im(pc_start - s->cs_base); gen_helper_idivq_EAX(cpu_T[0]); break; #endif } break; default: goto illegal_op; } break; case 0xfe: /* GRP4 */ case 0xff: /* GRP5 */ if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); op = (modrm >> 3) & 7; if (op >= 2 && b == 0xfe) { goto illegal_op; } if (CODE64(s)) { if (op == 2 || op == 4) { /* operand size for jumps is 64 bit */ ot = OT_QUAD; } else if (op == 3 || op == 5) { /* for call calls, the operand is 16 or 32 bit, even in long mode */ ot = dflag ? OT_LONG : OT_WORD; } else if (op == 6) { /* default push size is 64 bit */ ot = dflag ? OT_QUAD : OT_WORD; } } if (mod != 3) { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); if (op >= 2 && op != 3 && op != 5) gen_op_ld_T0_A0(ot + s->mem_index); } else { gen_op_mov_TN_reg(ot, 0, rm); } switch(op) { case 0: /* inc Ev */ if (mod != 3) opreg = OR_TMP0; else opreg = rm; gen_inc(s, ot, opreg, 1); break; case 1: /* dec Ev */ if (mod != 3) opreg = OR_TMP0; else opreg = rm; gen_inc(s, ot, opreg, -1); break; case 2: /* call Ev */ /* XXX: optimize if memory (no 'and' is necessary) */ if (s->dflag == 0) gen_op_andl_T0_ffff(); next_eip = s->pc - s->cs_base; gen_movtl_T1_im(next_eip); gen_push_T1(s); gen_op_jmp_T0(); gen_eob(s); break; case 3: /* lcall Ev */ gen_op_ld_T1_A0(ot + s->mem_index); gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); gen_op_ldu_T0_A0(OT_WORD + s->mem_index); do_lcall: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_lcall_protected(cpu_tmp2_i32, cpu_T[1], tcg_const_i32(dflag), tcg_const_i32(s->pc - pc_start)); } else { tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_lcall_real(cpu_tmp2_i32, cpu_T[1], tcg_const_i32(dflag), tcg_const_i32(s->pc - s->cs_base)); } gen_eob(s); break; case 4: /* jmp Ev */ if (s->dflag == 0) gen_op_andl_T0_ffff(); gen_op_jmp_T0(); gen_eob(s); break; case 5: /* ljmp Ev */ gen_op_ld_T1_A0(ot + s->mem_index); gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); gen_op_ldu_T0_A0(OT_WORD + s->mem_index); do_ljmp: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_ljmp_protected(cpu_tmp2_i32, cpu_T[1], tcg_const_i32(s->pc - pc_start)); } else { gen_op_movl_seg_T0_vm(R_CS); gen_op_movl_T0_T1(); gen_op_jmp_T0(); } gen_eob(s); break; case 6: /* push Ev */ gen_push_T0(s); break; default: goto illegal_op; } break; case 0x84: /* test Ev, Gv */ case 0x85: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_TN_reg(ot, 1, reg); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; case 0xa8: /* test eAX, Iv */ case 0xa9: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; val = insn_get(s, ot); gen_op_mov_TN_reg(ot, 0, OR_EAX); gen_op_movl_T1_im(val); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; case 0x98: /* CWDE/CBW */ #ifdef TARGET_X86_64 if (dflag == 2) { gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(OT_QUAD, R_EAX); } else #endif if (dflag == 1) { gen_op_mov_TN_reg(OT_WORD, 0, R_EAX); tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(OT_LONG, R_EAX); } else { gen_op_mov_TN_reg(OT_BYTE, 0, R_EAX); tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(OT_WORD, R_EAX); } break; case 0x99: /* CDQ/CWD */ #ifdef TARGET_X86_64 if (dflag == 2) { gen_op_mov_TN_reg(OT_QUAD, 0, R_EAX); tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 63); gen_op_mov_reg_T0(OT_QUAD, R_EDX); } else #endif if (dflag == 1) { gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 31); gen_op_mov_reg_T0(OT_LONG, R_EDX); } else { gen_op_mov_TN_reg(OT_WORD, 0, R_EAX); tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 15); gen_op_mov_reg_T0(OT_WORD, R_EDX); } break; case 0x1af: /* imul Gv, Ev */ case 0x69: /* imul Gv, Ev, I */ case 0x6b: ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; if (b == 0x69) s->rip_offset = insn_const_size(ot); else if (b == 0x6b) s->rip_offset = 1; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); if (b == 0x69) { val = insn_get(s, ot); gen_op_movl_T1_im(val); } else if (b == 0x6b) { val = (int8_t)insn_get(s, OT_BYTE); gen_op_movl_T1_im(val); } else { gen_op_mov_TN_reg(ot, 1, reg); } #ifdef TARGET_X86_64 if (ot == OT_QUAD) { gen_helper_imulq_T0_T1(cpu_T[0], cpu_T[0], cpu_T[1]); } else #endif if (ot == OT_LONG) { #ifdef TARGET_X86_64 tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]); tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]); tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); #else { TCGv_i64 t0, t1; t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); tcg_gen_ext_i32_i64(t0, cpu_T[0]); tcg_gen_ext_i32_i64(t1, cpu_T[1]); tcg_gen_mul_i64(t0, t0, t1); tcg_gen_trunc_i64_i32(cpu_T[0], t0); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_trunc_i64_i32(cpu_T[1], t0); tcg_gen_sub_tl(cpu_cc_src, cpu_T[1], cpu_tmp0); } #endif } else { tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]); /* XXX: use 32 bit mul which could be faster */ tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]); tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); } gen_op_mov_reg_T0(ot, reg); s->cc_op = CC_OP_MULB + ot; break; case 0x1c0: case 0x1c1: /* xadd Ev, Gv */ if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; if (mod == 3) { rm = (modrm & 7) | REX_B(s); gen_op_mov_TN_reg(ot, 0, reg); gen_op_mov_TN_reg(ot, 1, rm); gen_op_addl_T0_T1(); gen_op_mov_reg_T1(ot, reg); gen_op_mov_reg_T0(ot, rm); } else { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_op_mov_TN_reg(ot, 0, reg); gen_op_ld_T1_A0(ot + s->mem_index); gen_op_addl_T0_T1(); gen_op_st_T0_A0(ot + s->mem_index); gen_op_mov_reg_T1(ot, reg); } gen_op_update2_cc(); s->cc_op = CC_OP_ADDB + ot; break; case 0x1b0: case 0x1b1: /* cmpxchg Ev, Gv */ { int label1, label2; TCGv t0, t1, t2, a0; if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; t0 = tcg_temp_local_new(); t1 = tcg_temp_local_new(); t2 = tcg_temp_local_new(); a0 = tcg_temp_local_new(); gen_op_mov_v_reg(ot, t1, reg); if (mod == 3) { rm = (modrm & 7) | REX_B(s); gen_op_mov_v_reg(ot, t0, rm); } else { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); tcg_gen_mov_tl(a0, cpu_A0); gen_op_ld_v(ot + s->mem_index, t0, a0); rm = 0; /* avoid warning */ } label1 = gen_new_label(); tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUState, regs[R_EAX])); tcg_gen_sub_tl(t2, t2, t0); gen_extu(ot, t2); tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1); if (mod == 3) { label2 = gen_new_label(); gen_op_mov_reg_v(ot, R_EAX, t0); tcg_gen_br(label2); gen_set_label(label1); gen_op_mov_reg_v(ot, rm, t1); gen_set_label(label2); } else { tcg_gen_mov_tl(t1, t0); gen_op_mov_reg_v(ot, R_EAX, t0); gen_set_label(label1); /* always store */ gen_op_st_v(ot + s->mem_index, t1, a0); } tcg_gen_mov_tl(cpu_cc_src, t0); tcg_gen_mov_tl(cpu_cc_dst, t2); s->cc_op = CC_OP_SUBB + ot; tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free(t2); tcg_temp_free(a0); } break; case 0x1c7: /* cmpxchg8b */ modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; if ((mod == 3) || ((modrm & 0x38) != 0x8)) goto illegal_op; #ifdef TARGET_X86_64 if (dflag == 2) { if (!(s->cpuid_ext_features & CPUID_EXT_CX16)) goto illegal_op; gen_jmp_im(pc_start - s->cs_base); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_helper_cmpxchg16b(cpu_A0); } else #endif { if (!(s->cpuid_features & CPUID_CX8)) goto illegal_op; gen_jmp_im(pc_start - s->cs_base); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_helper_cmpxchg8b(cpu_A0); } s->cc_op = CC_OP_EFLAGS; break; /**************************/ /* push/pop */ case 0x50 ... 0x57: /* push */ gen_op_mov_TN_reg(OT_LONG, 0, (b & 7) | REX_B(s)); gen_push_T0(s); break; case 0x58 ... 0x5f: /* pop */ if (CODE64(s)) { ot = dflag ? OT_QUAD : OT_WORD; } else { ot = dflag + OT_WORD; } gen_pop_T0(s); /* NOTE: order is important for pop %sp */ gen_pop_update(s); gen_op_mov_reg_T0(ot, (b & 7) | REX_B(s)); break; case 0x60: /* pusha */ if (CODE64(s)) goto illegal_op; gen_pusha(s); break; case 0x61: /* popa */ if (CODE64(s)) goto illegal_op; gen_popa(s); break; case 0x68: /* push Iv */ case 0x6a: if (CODE64(s)) { ot = dflag ? OT_QUAD : OT_WORD; } else { ot = dflag + OT_WORD; } if (b == 0x68) val = insn_get(s, ot); else val = (int8_t)insn_get(s, OT_BYTE); gen_op_movl_T0_im(val); gen_push_T0(s); break; case 0x8f: /* pop Ev */ if (CODE64(s)) { ot = dflag ? OT_QUAD : OT_WORD; } else { ot = dflag + OT_WORD; } modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; gen_pop_T0(s); if (mod == 3) { /* NOTE: order is important for pop %sp */ gen_pop_update(s); rm = (modrm & 7) | REX_B(s); gen_op_mov_reg_T0(ot, rm); } else { /* NOTE: order is important too for MMU exceptions */ s->popl_esp_hack = 1 << ot; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); s->popl_esp_hack = 0; gen_pop_update(s); } break; case 0xc8: /* enter */ { int level; val = lduw_code(s->pc); s->pc += 2; level = ldub_code(s->pc++); gen_enter(s, val, level); } break; case 0xc9: /* leave */ /* XXX: exception not precise (ESP is updated before potential exception) */ if (CODE64(s)) { gen_op_mov_TN_reg(OT_QUAD, 0, R_EBP); gen_op_mov_reg_T0(OT_QUAD, R_ESP); } else if (s->ss32) { gen_op_mov_TN_reg(OT_LONG, 0, R_EBP); gen_op_mov_reg_T0(OT_LONG, R_ESP); } else { gen_op_mov_TN_reg(OT_WORD, 0, R_EBP); gen_op_mov_reg_T0(OT_WORD, R_ESP); } gen_pop_T0(s); if (CODE64(s)) { ot = dflag ? OT_QUAD : OT_WORD; } else { ot = dflag + OT_WORD; } gen_op_mov_reg_T0(ot, R_EBP); gen_pop_update(s); break; case 0x06: /* push es */ case 0x0e: /* push cs */ case 0x16: /* push ss */ case 0x1e: /* push ds */ if (CODE64(s)) goto illegal_op; gen_op_movl_T0_seg(b >> 3); gen_push_T0(s); break; case 0x1a0: /* push fs */ case 0x1a8: /* push gs */ gen_op_movl_T0_seg((b >> 3) & 7); gen_push_T0(s); break; case 0x07: /* pop es */ case 0x17: /* pop ss */ case 0x1f: /* pop ds */ if (CODE64(s)) goto illegal_op; reg = b >> 3; gen_pop_T0(s); gen_movl_seg_T0(s, reg, pc_start - s->cs_base); gen_pop_update(s); if (reg == R_SS) { /* if reg == SS, inhibit interrupts/trace. */ /* If several instructions disable interrupts, only the _first_ does it */ if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) gen_helper_set_inhibit_irq(); s->tf = 0; } if (s->is_jmp) { gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; case 0x1a1: /* pop fs */ case 0x1a9: /* pop gs */ gen_pop_T0(s); gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); gen_pop_update(s); if (s->is_jmp) { gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; /**************************/ /* mov */ case 0x88: case 0x89: /* mov Gv, Ev */ if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; /* generate a generic store */ gen_ldst_modrm(s, modrm, ot, reg, 1); break; case 0xc6: case 0xc7: /* mov Ev, Iv */ if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; if (mod != 3) { s->rip_offset = insn_const_size(ot); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); } val = insn_get(s, ot); gen_op_movl_T0_im(val); if (mod != 3) gen_op_st_T0_A0(ot + s->mem_index); else gen_op_mov_reg_T0(ot, (modrm & 7) | REX_B(s)); break; case 0x8a: case 0x8b: /* mov Ev, Gv */ if ((b & 1) == 0) ot = OT_BYTE; else ot = OT_WORD + dflag; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_reg_T0(ot, reg); break; case 0x8e: /* mov seg, Gv */ modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; if (reg >= 6 || reg == R_CS) goto illegal_op; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_movl_seg_T0(s, reg, pc_start - s->cs_base); if (reg == R_SS) { /* if reg == SS, inhibit interrupts/trace */ /* If several instructions disable interrupts, only the _first_ does it */ if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) gen_helper_set_inhibit_irq(); s->tf = 0; } if (s->is_jmp) { gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; case 0x8c: /* mov Gv, seg */ modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; if (reg >= 6) goto illegal_op; gen_op_movl_T0_seg(reg); if (mod == 3) ot = OT_WORD + dflag; else ot = OT_WORD; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); break; case 0x1b6: /* movzbS Gv, Eb */ case 0x1b7: /* movzwS Gv, Eb */ case 0x1be: /* movsbS Gv, Eb */ case 0x1bf: /* movswS Gv, Eb */ { int d_ot; /* d_ot is the size of destination */ d_ot = dflag + OT_WORD; /* ot is the size of source */ ot = (b & 1) + OT_BYTE; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); if (mod == 3) { gen_op_mov_TN_reg(ot, 0, rm); switch(ot | (b & 8)) { case OT_BYTE: tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]); break; case OT_BYTE | 8: tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]); break; case OT_WORD: tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]); break; default: case OT_WORD | 8: tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); break; } gen_op_mov_reg_T0(d_ot, reg); } else { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); if (b & 8) { gen_op_lds_T0_A0(ot + s->mem_index); } else { gen_op_ldu_T0_A0(ot + s->mem_index); } gen_op_mov_reg_T0(d_ot, reg); } } break; case 0x8d: /* lea */ ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; reg = ((modrm >> 3) & 7) | rex_r; /* we must ensure that no segment is added */ s->override = -1; val = s->addseg; s->addseg = 0; gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); s->addseg = val; gen_op_mov_reg_A0(ot - OT_WORD, reg); break; case 0xa0: /* mov EAX, Ov */ case 0xa1: case 0xa2: /* mov Ov, EAX */ case 0xa3: { target_ulong offset_addr; if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; #ifdef TARGET_X86_64 if (s->aflag == 2) { offset_addr = ldq_code(s->pc); s->pc += 8; gen_op_movq_A0_im(offset_addr); } else #endif { if (s->aflag) { offset_addr = insn_get(s, OT_LONG); } else { offset_addr = insn_get(s, OT_WORD); } gen_op_movl_A0_im(offset_addr); } gen_add_A0_ds_seg(s); if ((b & 2) == 0) { gen_op_ld_T0_A0(ot + s->mem_index); gen_op_mov_reg_T0(ot, R_EAX); } else { gen_op_mov_TN_reg(ot, 0, R_EAX); gen_op_st_T0_A0(ot + s->mem_index); } } break; case 0xd7: /* xlat */ #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_movq_A0_reg(R_EBX); gen_op_mov_TN_reg(OT_QUAD, 0, R_EAX); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xff); tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_T[0]); } else #endif { gen_op_movl_A0_reg(R_EBX); gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xff); tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_T[0]); if (s->aflag == 0) gen_op_andl_A0_ffff(); else tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); } gen_add_A0_ds_seg(s); gen_op_ldu_T0_A0(OT_BYTE + s->mem_index); gen_op_mov_reg_T0(OT_BYTE, R_EAX); break; case 0xb0 ... 0xb7: /* mov R, Ib */ val = insn_get(s, OT_BYTE); gen_op_movl_T0_im(val); gen_op_mov_reg_T0(OT_BYTE, (b & 7) | REX_B(s)); break; case 0xb8 ... 0xbf: /* mov R, Iv */ #ifdef TARGET_X86_64 if (dflag == 2) { uint64_t tmp; /* 64 bit case */ tmp = ldq_code(s->pc); s->pc += 8; reg = (b & 7) | REX_B(s); gen_movtl_T0_im(tmp); gen_op_mov_reg_T0(OT_QUAD, reg); } else #endif { ot = dflag ? OT_LONG : OT_WORD; val = insn_get(s, ot); reg = (b & 7) | REX_B(s); gen_op_movl_T0_im(val); gen_op_mov_reg_T0(ot, reg); } break; case 0x91 ... 0x97: /* xchg R, EAX */ ot = dflag + OT_WORD; reg = (b & 7) | REX_B(s); rm = R_EAX; goto do_xchg_reg; case 0x86: case 0x87: /* xchg Ev, Gv */ if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; if (mod == 3) { rm = (modrm & 7) | REX_B(s); do_xchg_reg: gen_op_mov_TN_reg(ot, 0, reg); gen_op_mov_TN_reg(ot, 1, rm); gen_op_mov_reg_T0(ot, rm); gen_op_mov_reg_T1(ot, reg); } else { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_op_mov_TN_reg(ot, 0, reg); /* for xchg, lock is implicit */ if (!(prefixes & PREFIX_LOCK)) gen_helper_lock(); gen_op_ld_T1_A0(ot + s->mem_index); gen_op_st_T0_A0(ot + s->mem_index); if (!(prefixes & PREFIX_LOCK)) gen_helper_unlock(); gen_op_mov_reg_T1(ot, reg); } break; case 0xc4: /* les Gv */ if (CODE64(s)) goto illegal_op; op = R_ES; goto do_lxx; case 0xc5: /* lds Gv */ if (CODE64(s)) goto illegal_op; op = R_DS; goto do_lxx; case 0x1b2: /* lss Gv */ op = R_SS; goto do_lxx; case 0x1b4: /* lfs Gv */ op = R_FS; goto do_lxx; case 0x1b5: /* lgs Gv */ op = R_GS; do_lxx: ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_op_ld_T1_A0(ot + s->mem_index); gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ gen_op_ldu_T0_A0(OT_WORD + s->mem_index); gen_movl_seg_T0(s, op, pc_start - s->cs_base); /* then put the data */ gen_op_mov_reg_T1(ot, reg); if (s->is_jmp) { gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; /************************/ /* shifts */ case 0xc0: case 0xc1: /* shift Ev,Ib */ shift = 2; grp2: { if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; if (mod != 3) { if (shift == 2) { s->rip_offset = 1; } gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); opreg = OR_TMP0; } else { opreg = (modrm & 7) | REX_B(s); } /* simpler op */ if (shift == 0) { gen_shift(s, op, ot, opreg, OR_ECX); } else { if (shift == 2) { shift = ldub_code(s->pc++); } gen_shifti(s, op, ot, opreg, shift); } } break; case 0xd0: case 0xd1: /* shift Ev,1 */ shift = 1; goto grp2; case 0xd2: case 0xd3: /* shift Ev,cl */ shift = 0; goto grp2; case 0x1a4: /* shld imm */ op = 0; shift = 1; goto do_shiftd; case 0x1a5: /* shld cl */ op = 0; shift = 0; goto do_shiftd; case 0x1ac: /* shrd imm */ op = 1; shift = 1; goto do_shiftd; case 0x1ad: /* shrd cl */ op = 1; shift = 0; do_shiftd: ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; if (mod != 3) { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); opreg = OR_TMP0; } else { opreg = rm; } gen_op_mov_TN_reg(ot, 1, reg); if (shift) { val = ldub_code(s->pc++); tcg_gen_movi_tl(cpu_T3, val); } else { tcg_gen_ld_tl(cpu_T3, cpu_env, offsetof(CPUState, regs[R_ECX])); } gen_shiftd_rm_T1_T3(s, ot, opreg, op); break; /************************/ /* floats */ case 0xd8 ... 0xdf: if (s->flags & (HF_EM_MASK | HF_TS_MASK)) { /* if CR0.EM or CR0.TS are set, generate an FPU exception */ /* XXX: what to do if illegal op ? */ gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; op = ((b & 7) << 3) | ((modrm >> 3) & 7); if (mod != 3) { /* memory op */ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); switch(op) { case 0x00 ... 0x07: /* fxxxs */ case 0x10 ... 0x17: /* fixxxl */ case 0x20 ... 0x27: /* fxxxl */ case 0x30 ... 0x37: /* fixxx */ { int op1; op1 = op & 7; switch(op >> 4) { case 0: gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_flds_FT0(cpu_tmp2_i32); break; case 1: gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_fildl_FT0(cpu_tmp2_i32); break; case 2: tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); gen_helper_fldl_FT0(cpu_tmp1_i64); break; case 3: default: gen_op_lds_T0_A0(OT_WORD + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_fildl_FT0(cpu_tmp2_i32); break; } gen_helper_fp_arith_ST0_FT0(op1); if (op1 == 3) { /* fcomp needs pop */ gen_helper_fpop(); } } break; case 0x08: /* flds */ case 0x0a: /* fsts */ case 0x0b: /* fstps */ case 0x18 ... 0x1b: /* fildl, fisttpl, fistl, fistpl */ case 0x28 ... 0x2b: /* fldl, fisttpll, fstl, fstpl */ case 0x38 ... 0x3b: /* filds, fisttps, fists, fistps */ switch(op & 7) { case 0: switch(op >> 4) { case 0: gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_flds_ST0(cpu_tmp2_i32); break; case 1: gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_fildl_ST0(cpu_tmp2_i32); break; case 2: tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); gen_helper_fldl_ST0(cpu_tmp1_i64); break; case 3: default: gen_op_lds_T0_A0(OT_WORD + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_fildl_ST0(cpu_tmp2_i32); break; } break; case 1: /* XXX: the corresponding CPUID bit must be tested ! */ switch(op >> 4) { case 1: gen_helper_fisttl_ST0(cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 2: gen_helper_fisttll_ST0(cpu_tmp1_i64); tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); break; case 3: default: gen_helper_fistt_ST0(cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); break; } gen_helper_fpop(); break; default: switch(op >> 4) { case 0: gen_helper_fsts_ST0(cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 1: gen_helper_fistl_ST0(cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 2: gen_helper_fstl_ST0(cpu_tmp1_i64); tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); break; case 3: default: gen_helper_fist_ST0(cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); break; } if ((op & 7) == 3) gen_helper_fpop(); break; } break; case 0x0c: /* fldenv mem */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fldenv( cpu_A0, tcg_const_i32(s->dflag)); break; case 0x0d: /* fldcw mem */ gen_op_ld_T0_A0(OT_WORD + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_fldcw(cpu_tmp2_i32); break; case 0x0e: /* fnstenv mem */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fstenv(cpu_A0, tcg_const_i32(s->dflag)); break; case 0x0f: /* fnstcw mem */ gen_helper_fnstcw(cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x1d: /* fldt mem */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fldt_ST0(cpu_A0); break; case 0x1f: /* fstpt mem */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fstt_ST0(cpu_A0); gen_helper_fpop(); break; case 0x2c: /* frstor mem */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_frstor(cpu_A0, tcg_const_i32(s->dflag)); break; case 0x2e: /* fnsave mem */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fsave(cpu_A0, tcg_const_i32(s->dflag)); break; case 0x2f: /* fnstsw mem */ gen_helper_fnstsw(cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x3c: /* fbld */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fbld_ST0(cpu_A0); break; case 0x3e: /* fbstp */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fbst_ST0(cpu_A0); gen_helper_fpop(); break; case 0x3d: /* fildll */ tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); gen_helper_fildll_ST0(cpu_tmp1_i64); break; case 0x3f: /* fistpll */ gen_helper_fistll_ST0(cpu_tmp1_i64); tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); gen_helper_fpop(); break; default: goto illegal_op; } } else { /* register float ops */ opreg = rm; switch(op) { case 0x08: /* fld sti */ gen_helper_fpush(); gen_helper_fmov_ST0_STN(tcg_const_i32((opreg + 1) & 7)); break; case 0x09: /* fxchg sti */ case 0x29: /* fxchg4 sti, undocumented op */ case 0x39: /* fxchg7 sti, undocumented op */ gen_helper_fxchg_ST0_STN(tcg_const_i32(opreg)); break; case 0x0a: /* grp d9/2 */ switch(rm) { case 0: /* fnop */ /* check exceptions (FreeBSD FPU probe) */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fwait(); break; default: goto illegal_op; } break; case 0x0c: /* grp d9/4 */ switch(rm) { case 0: /* fchs */ gen_helper_fchs_ST0(); break; case 1: /* fabs */ gen_helper_fabs_ST0(); break; case 4: /* ftst */ gen_helper_fldz_FT0(); gen_helper_fcom_ST0_FT0(); break; case 5: /* fxam */ gen_helper_fxam_ST0(); break; default: goto illegal_op; } break; case 0x0d: /* grp d9/5 */ { switch(rm) { case 0: gen_helper_fpush(); gen_helper_fld1_ST0(); break; case 1: gen_helper_fpush(); gen_helper_fldl2t_ST0(); break; case 2: gen_helper_fpush(); gen_helper_fldl2e_ST0(); break; case 3: gen_helper_fpush(); gen_helper_fldpi_ST0(); break; case 4: gen_helper_fpush(); gen_helper_fldlg2_ST0(); break; case 5: gen_helper_fpush(); gen_helper_fldln2_ST0(); break; case 6: gen_helper_fpush(); gen_helper_fldz_ST0(); break; default: goto illegal_op; } } break; case 0x0e: /* grp d9/6 */ switch(rm) { case 0: /* f2xm1 */ gen_helper_f2xm1(); break; case 1: /* fyl2x */ gen_helper_fyl2x(); break; case 2: /* fptan */ gen_helper_fptan(); break; case 3: /* fpatan */ gen_helper_fpatan(); break; case 4: /* fxtract */ gen_helper_fxtract(); break; case 5: /* fprem1 */ gen_helper_fprem1(); break; case 6: /* fdecstp */ gen_helper_fdecstp(); break; default: case 7: /* fincstp */ gen_helper_fincstp(); break; } break; case 0x0f: /* grp d9/7 */ switch(rm) { case 0: /* fprem */ gen_helper_fprem(); break; case 1: /* fyl2xp1 */ gen_helper_fyl2xp1(); break; case 2: /* fsqrt */ gen_helper_fsqrt(); break; case 3: /* fsincos */ gen_helper_fsincos(); break; case 5: /* fscale */ gen_helper_fscale(); break; case 4: /* frndint */ gen_helper_frndint(); break; case 6: /* fsin */ gen_helper_fsin(); break; default: case 7: /* fcos */ gen_helper_fcos(); break; } break; case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ { int op1; op1 = op & 7; if (op >= 0x20) { gen_helper_fp_arith_STN_ST0(op1, opreg); if (op >= 0x30) gen_helper_fpop(); } else { gen_helper_fmov_FT0_STN(tcg_const_i32(opreg)); gen_helper_fp_arith_ST0_FT0(op1); } } break; case 0x02: /* fcom */ case 0x22: /* fcom2, undocumented op */ gen_helper_fmov_FT0_STN(tcg_const_i32(opreg)); gen_helper_fcom_ST0_FT0(); break; case 0x03: /* fcomp */ case 0x23: /* fcomp3, undocumented op */ case 0x32: /* fcomp5, undocumented op */ gen_helper_fmov_FT0_STN(tcg_const_i32(opreg)); gen_helper_fcom_ST0_FT0(); gen_helper_fpop(); break; case 0x15: /* da/5 */ switch(rm) { case 1: /* fucompp */ gen_helper_fmov_FT0_STN(tcg_const_i32(1)); gen_helper_fucom_ST0_FT0(); gen_helper_fpop(); gen_helper_fpop(); break; default: goto illegal_op; } break; case 0x1c: switch(rm) { case 0: /* feni (287 only, just do nop here) */ break; case 1: /* fdisi (287 only, just do nop here) */ break; case 2: /* fclex */ gen_helper_fclex(); break; case 3: /* fninit */ gen_helper_fninit(); break; case 4: /* fsetpm (287 only, just do nop here) */ break; default: goto illegal_op; } break; case 0x1d: /* fucomi */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_fmov_FT0_STN(tcg_const_i32(opreg)); gen_helper_fucomi_ST0_FT0(); s->cc_op = CC_OP_EFLAGS; break; case 0x1e: /* fcomi */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_fmov_FT0_STN(tcg_const_i32(opreg)); gen_helper_fcomi_ST0_FT0(); s->cc_op = CC_OP_EFLAGS; break; case 0x28: /* ffree sti */ gen_helper_ffree_STN(tcg_const_i32(opreg)); break; case 0x2a: /* fst sti */ gen_helper_fmov_STN_ST0(tcg_const_i32(opreg)); break; case 0x2b: /* fstp sti */ case 0x0b: /* fstp1 sti, undocumented op */ case 0x3a: /* fstp8 sti, undocumented op */ case 0x3b: /* fstp9 sti, undocumented op */ gen_helper_fmov_STN_ST0(tcg_const_i32(opreg)); gen_helper_fpop(); break; case 0x2c: /* fucom st(i) */ gen_helper_fmov_FT0_STN(tcg_const_i32(opreg)); gen_helper_fucom_ST0_FT0(); break; case 0x2d: /* fucomp st(i) */ gen_helper_fmov_FT0_STN(tcg_const_i32(opreg)); gen_helper_fucom_ST0_FT0(); gen_helper_fpop(); break; case 0x33: /* de/3 */ switch(rm) { case 1: /* fcompp */ gen_helper_fmov_FT0_STN(tcg_const_i32(1)); gen_helper_fcom_ST0_FT0(); gen_helper_fpop(); gen_helper_fpop(); break; default: goto illegal_op; } break; case 0x38: /* ffreep sti, undocumented op */ gen_helper_ffree_STN(tcg_const_i32(opreg)); gen_helper_fpop(); break; case 0x3c: /* df/4 */ switch(rm) { case 0: gen_helper_fnstsw(cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_mov_reg_T0(OT_WORD, R_EAX); break; default: goto illegal_op; } break; case 0x3d: /* fucomip */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_fmov_FT0_STN(tcg_const_i32(opreg)); gen_helper_fucomi_ST0_FT0(); gen_helper_fpop(); s->cc_op = CC_OP_EFLAGS; break; case 0x3e: /* fcomip */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_fmov_FT0_STN(tcg_const_i32(opreg)); gen_helper_fcomi_ST0_FT0(); gen_helper_fpop(); s->cc_op = CC_OP_EFLAGS; break; case 0x10 ... 0x13: /* fcmovxx */ case 0x18 ... 0x1b: { int op1, l1; static const uint8_t fcmov_cc[8] = { (JCC_B << 1), (JCC_Z << 1), (JCC_BE << 1), (JCC_P << 1), }; op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1); l1 = gen_new_label(); gen_jcc1(s, s->cc_op, op1, l1); gen_helper_fmov_ST0_STN(tcg_const_i32(opreg)); gen_set_label(l1); } break; default: goto illegal_op; } } break; /************************/ /* string ops */ case 0xa4: /* movsS */ case 0xa5: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { gen_movs(s, ot); } break; case 0xaa: /* stosS */ case 0xab: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { gen_stos(s, ot); } break; case 0xac: /* lodsS */ case 0xad: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { gen_lods(s, ot); } break; case 0xae: /* scasS */ case 0xaf: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; if (prefixes & PREFIX_REPNZ) { gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); } else if (prefixes & PREFIX_REPZ) { gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); } else { gen_scas(s, ot); s->cc_op = CC_OP_SUBB + ot; } break; case 0xa6: /* cmpsS */ case 0xa7: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag + OT_WORD; if (prefixes & PREFIX_REPNZ) { gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); } else if (prefixes & PREFIX_REPZ) { gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); } else { gen_cmps(s, ot); s->cc_op = CC_OP_SUBB + ot; } break; case 0x6c: /* insS */ case 0x6d: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); gen_check_io(s, ot, pc_start - s->cs_base, SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4); if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { gen_ins(s, ot); if (use_icount) { gen_jmp(s, s->pc - s->cs_base); } } break; case 0x6e: /* outsS */ case 0x6f: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); gen_check_io(s, ot, pc_start - s->cs_base, svm_is_rep(prefixes) | 4); if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { gen_outs(s, ot); if (use_icount) { gen_jmp(s, s->pc - s->cs_base); } } break; /************************/ /* port I/O */ case 0xe4: case 0xe5: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; val = ldub_code(s->pc++); gen_op_movl_T0_im(val); gen_check_io(s, ot, pc_start - s->cs_base, SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); if (use_icount) gen_io_start(); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_in_func(ot, cpu_T[1], cpu_tmp2_i32); gen_op_mov_reg_T1(ot, R_EAX); if (use_icount) { gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; case 0xe6: case 0xe7: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; val = ldub_code(s->pc++); gen_op_movl_T0_im(val); gen_check_io(s, ot, pc_start - s->cs_base, svm_is_rep(prefixes)); gen_op_mov_TN_reg(ot, 1, R_EAX); if (use_icount) gen_io_start(); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32); if (use_icount) { gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; case 0xec: case 0xed: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); gen_check_io(s, ot, pc_start - s->cs_base, SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); if (use_icount) gen_io_start(); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_in_func(ot, cpu_T[1], cpu_tmp2_i32); gen_op_mov_reg_T1(ot, R_EAX); if (use_icount) { gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; case 0xee: case 0xef: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); gen_check_io(s, ot, pc_start - s->cs_base, svm_is_rep(prefixes)); gen_op_mov_TN_reg(ot, 1, R_EAX); if (use_icount) gen_io_start(); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32); if (use_icount) { gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; /************************/ /* control */ case 0xc2: /* ret im */ val = ldsw_code(s->pc); s->pc += 2; gen_pop_T0(s); if (CODE64(s) && s->dflag) s->dflag = 2; gen_stack_update(s, val + (2 << s->dflag)); if (s->dflag == 0) gen_op_andl_T0_ffff(); gen_op_jmp_T0(); gen_eob(s); break; case 0xc3: /* ret */ gen_pop_T0(s); gen_pop_update(s); if (s->dflag == 0) gen_op_andl_T0_ffff(); gen_op_jmp_T0(); gen_eob(s); break; case 0xca: /* lret im */ val = ldsw_code(s->pc); s->pc += 2; do_lret: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_lret_protected(tcg_const_i32(s->dflag), tcg_const_i32(val)); } else { gen_stack_A0(s); /* pop offset */ gen_op_ld_T0_A0(1 + s->dflag + s->mem_index); if (s->dflag == 0) gen_op_andl_T0_ffff(); /* NOTE: keeping EIP updated is not a problem in case of exception */ gen_op_jmp_T0(); /* pop selector */ gen_op_addl_A0_im(2 << s->dflag); gen_op_ld_T0_A0(1 + s->dflag + s->mem_index); gen_op_movl_seg_T0_vm(R_CS); /* add stack offset */ gen_stack_update(s, val + (4 << s->dflag)); } gen_eob(s); break; case 0xcb: /* lret */ val = 0; goto do_lret; case 0xcf: /* iret */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET); if (!s->pe) { /* real mode */ gen_helper_iret_real(tcg_const_i32(s->dflag)); s->cc_op = CC_OP_EFLAGS; } else if (s->vm86) { if (s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_helper_iret_real(tcg_const_i32(s->dflag)); s->cc_op = CC_OP_EFLAGS; } } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_iret_protected(tcg_const_i32(s->dflag), tcg_const_i32(s->pc - s->cs_base)); s->cc_op = CC_OP_EFLAGS; } gen_eob(s); break; case 0xe8: /* call im */ { if (dflag) tval = (int32_t)insn_get(s, OT_LONG); else tval = (int16_t)insn_get(s, OT_WORD); next_eip = s->pc - s->cs_base; tval += next_eip; if (s->dflag == 0) tval &= 0xffff; gen_movtl_T0_im(next_eip); gen_push_T0(s); gen_jmp(s, tval); } break; case 0x9a: /* lcall im */ { unsigned int selector, offset; if (CODE64(s)) goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); gen_op_movl_T0_im(selector); gen_op_movl_T1_imu(offset); } goto do_lcall; case 0xe9: /* jmp im */ if (dflag) tval = (int32_t)insn_get(s, OT_LONG); else tval = (int16_t)insn_get(s, OT_WORD); tval += s->pc - s->cs_base; if (s->dflag == 0) tval &= 0xffff; gen_jmp(s, tval); break; case 0xea: /* ljmp im */ { unsigned int selector, offset; if (CODE64(s)) goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); gen_op_movl_T0_im(selector); gen_op_movl_T1_imu(offset); } goto do_ljmp; case 0xeb: /* jmp Jb */ tval = (int8_t)insn_get(s, OT_BYTE); tval += s->pc - s->cs_base; if (s->dflag == 0) tval &= 0xffff; gen_jmp(s, tval); break; case 0x70 ... 0x7f: /* jcc Jb */ tval = (int8_t)insn_get(s, OT_BYTE); goto do_jcc; case 0x180 ... 0x18f: /* jcc Jv */ if (dflag) { tval = (int32_t)insn_get(s, OT_LONG); } else { tval = (int16_t)insn_get(s, OT_WORD); } do_jcc: next_eip = s->pc - s->cs_base; tval += next_eip; if (s->dflag == 0) tval &= 0xffff; gen_jcc(s, b, tval, next_eip); break; case 0x190 ... 0x19f: /* setcc Gv */ modrm = ldub_code(s->pc++); gen_setcc(s, b); gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); break; case 0x140 ... 0x14f: /* cmov Gv, Ev */ { int l1; TCGv t0; ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; t0 = tcg_temp_local_new(); if (mod != 3) { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); } else { rm = (modrm & 7) | REX_B(s); gen_op_mov_v_reg(ot, t0, rm); } #ifdef TARGET_X86_64 if (ot == OT_LONG) { /* XXX: specific Intel behaviour ? */ l1 = gen_new_label(); gen_jcc1(s, s->cc_op, b ^ 1, l1); tcg_gen_st32_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET); gen_set_label(l1); tcg_gen_movi_tl(cpu_tmp0, 0); tcg_gen_st32_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_LH_OFFSET); } else #endif { l1 = gen_new_label(); gen_jcc1(s, s->cc_op, b ^ 1, l1); gen_op_mov_reg_v(ot, reg, t0); gen_set_label(l1); } tcg_temp_free(t0); } break; /************************/ /* flags */ case 0x9c: /* pushf */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF); if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_read_eflags(cpu_T[0]); gen_push_T0(s); } break; case 0x9d: /* popf */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF); if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_pop_T0(s); if (s->cpl == 0) { if (s->dflag) { gen_helper_write_eflags(cpu_T[0], tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK))); } else { gen_helper_write_eflags(cpu_T[0], tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK) & 0xffff)); } } else { if (s->cpl <= s->iopl) { if (s->dflag) { gen_helper_write_eflags(cpu_T[0], tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK))); } else { gen_helper_write_eflags(cpu_T[0], tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK) & 0xffff)); } } else { if (s->dflag) { gen_helper_write_eflags(cpu_T[0], tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK))); } else { gen_helper_write_eflags(cpu_T[0], tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff)); } } } gen_pop_update(s); s->cc_op = CC_OP_EFLAGS; /* abort translation because TF flag may change */ gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; case 0x9e: /* sahf */ if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) goto illegal_op; gen_op_mov_TN_reg(OT_BYTE, 0, R_AH); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_compute_eflags(cpu_cc_src); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], CC_S | CC_Z | CC_A | CC_P | CC_C); tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_T[0]); s->cc_op = CC_OP_EFLAGS; break; case 0x9f: /* lahf */ if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_compute_eflags(cpu_T[0]); /* Note: gen_compute_eflags() only gives the condition codes */ tcg_gen_ori_tl(cpu_T[0], cpu_T[0], 0x02); gen_op_mov_reg_T0(OT_BYTE, R_AH); break; case 0xf5: /* cmc */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_compute_eflags(cpu_cc_src); tcg_gen_xori_tl(cpu_cc_src, cpu_cc_src, CC_C); s->cc_op = CC_OP_EFLAGS; break; case 0xf8: /* clc */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_compute_eflags(cpu_cc_src); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_C); s->cc_op = CC_OP_EFLAGS; break; case 0xf9: /* stc */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_compute_eflags(cpu_cc_src); tcg_gen_ori_tl(cpu_cc_src, cpu_cc_src, CC_C); s->cc_op = CC_OP_EFLAGS; break; case 0xfc: /* cld */ tcg_gen_movi_i32(cpu_tmp2_i32, 1); tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, df)); break; case 0xfd: /* std */ tcg_gen_movi_i32(cpu_tmp2_i32, -1); tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, df)); break; /************************/ /* bit operations */ case 0x1ba: /* bt/bts/btr/btc Gv, im */ ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); op = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); if (mod != 3) { s->rip_offset = 1; gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_op_ld_T0_A0(ot + s->mem_index); } else { gen_op_mov_TN_reg(ot, 0, rm); } /* load shift */ val = ldub_code(s->pc++); gen_op_movl_T1_im(val); if (op < 4) goto illegal_op; op -= 4; goto bt_op; case 0x1a3: /* bt Gv, Ev */ op = 0; goto do_btx; case 0x1ab: /* bts */ op = 1; goto do_btx; case 0x1b3: /* btr */ op = 2; goto do_btx; case 0x1bb: /* btc */ op = 3; do_btx: ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); gen_op_mov_TN_reg(OT_LONG, 1, reg); if (mod != 3) { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); /* specific case: we need to add a displacement */ gen_exts(ot, cpu_T[1]); tcg_gen_sari_tl(cpu_tmp0, cpu_T[1], 3 + ot); tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, ot); tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); gen_op_ld_T0_A0(ot + s->mem_index); } else { gen_op_mov_TN_reg(ot, 0, rm); } bt_op: tcg_gen_andi_tl(cpu_T[1], cpu_T[1], (1 << (3 + ot)) - 1); switch(op) { case 0: tcg_gen_shr_tl(cpu_cc_src, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_cc_dst, 0); break; case 1: tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_tmp0, 1); tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; case 2: tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_tmp0, 1); tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); tcg_gen_not_tl(cpu_tmp0, cpu_tmp0); tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; default: case 3: tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_tmp0, 1); tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; } s->cc_op = CC_OP_SARB + ot; if (op != 0) { if (mod != 3) gen_op_st_T0_A0(ot + s->mem_index); else gen_op_mov_reg_T0(ot, rm); tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4); tcg_gen_movi_tl(cpu_cc_dst, 0); } break; case 0x1bc: /* bsf */ case 0x1bd: /* bsr */ { int label1; TCGv t0; ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_extu(ot, cpu_T[0]); label1 = gen_new_label(); tcg_gen_movi_tl(cpu_cc_dst, 0); t0 = tcg_temp_local_new(); tcg_gen_mov_tl(t0, cpu_T[0]); tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, label1); if (b & 1) { gen_helper_bsr(cpu_T[0], t0); } else { gen_helper_bsf(cpu_T[0], t0); } gen_op_mov_reg_T0(ot, reg); tcg_gen_movi_tl(cpu_cc_dst, 1); gen_set_label(label1); tcg_gen_discard_tl(cpu_cc_src); s->cc_op = CC_OP_LOGICB + ot; tcg_temp_free(t0); } break; /************************/ /* bcd */ case 0x27: /* daa */ if (CODE64(s)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_daa(); s->cc_op = CC_OP_EFLAGS; break; case 0x2f: /* das */ if (CODE64(s)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_das(); s->cc_op = CC_OP_EFLAGS; break; case 0x37: /* aaa */ if (CODE64(s)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_aaa(); s->cc_op = CC_OP_EFLAGS; break; case 0x3f: /* aas */ if (CODE64(s)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_aas(); s->cc_op = CC_OP_EFLAGS; break; case 0xd4: /* aam */ if (CODE64(s)) goto illegal_op; val = ldub_code(s->pc++); if (val == 0) { gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base); } else { gen_helper_aam(tcg_const_i32(val)); s->cc_op = CC_OP_LOGICB; } break; case 0xd5: /* aad */ if (CODE64(s)) goto illegal_op; val = ldub_code(s->pc++); gen_helper_aad(tcg_const_i32(val)); s->cc_op = CC_OP_LOGICB; break; /************************/ /* misc */ case 0x90: /* nop */ /* XXX: xchg + rex handling */ /* XXX: correct lock test for all insn */ if (prefixes & PREFIX_LOCK) goto illegal_op; if (prefixes & PREFIX_REPZ) { gen_svm_check_intercept(s, pc_start, SVM_EXIT_PAUSE); } break; case 0x9b: /* fwait */ if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == (HF_MP_MASK | HF_TS_MASK)) { gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fwait(); } break; case 0xcc: /* int3 */ gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); break; case 0xcd: /* int N */ val = ldub_code(s->pc++); if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); } break; case 0xce: /* into */ if (CODE64(s)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_into(tcg_const_i32(s->pc - pc_start)); break; #ifdef WANT_ICEBP case 0xf1: /* icebp (undocumented, exits to external debugger) */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP); #if 1 gen_debug(s, pc_start - s->cs_base); #else /* start debug */ tb_flush(cpu_single_env); cpu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM); #endif break; #endif case 0xfa: /* cli */ if (!s->vm86) { if (s->cpl <= s->iopl) { gen_helper_cli(); } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } else { if (s->iopl == 3) { gen_helper_cli(); } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } break; case 0xfb: /* sti */ if (!s->vm86) { if (s->cpl <= s->iopl) { gen_sti: gen_helper_sti(); /* interruptions are enabled only the first insn after sti */ /* If several instructions disable interrupts, only the _first_ does it */ if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) gen_helper_set_inhibit_irq(); /* give a chance to handle pending irqs */ gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } else { if (s->iopl == 3) { goto gen_sti; } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } break; case 0x62: /* bound */ if (CODE64(s)) goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; gen_op_mov_TN_reg(ot, 0, reg); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_jmp_im(pc_start - s->cs_base); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); if (ot == OT_WORD) gen_helper_boundw(cpu_A0, cpu_tmp2_i32); else gen_helper_boundl(cpu_A0, cpu_tmp2_i32); break; case 0x1c8 ... 0x1cf: /* bswap reg */ reg = (b & 7) | REX_B(s); #ifdef TARGET_X86_64 if (dflag == 2) { gen_op_mov_TN_reg(OT_QUAD, 0, reg); tcg_gen_bswap_i64(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(OT_QUAD, reg); } else { TCGv_i32 tmp0; gen_op_mov_TN_reg(OT_LONG, 0, reg); tmp0 = tcg_temp_new_i32(); tcg_gen_trunc_i64_i32(tmp0, cpu_T[0]); tcg_gen_bswap_i32(tmp0, tmp0); tcg_gen_extu_i32_i64(cpu_T[0], tmp0); gen_op_mov_reg_T0(OT_LONG, reg); } #else { gen_op_mov_TN_reg(OT_LONG, 0, reg); tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(OT_LONG, reg); } #endif break; case 0xd6: /* salc */ if (CODE64(s)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_compute_eflags_c(cpu_T[0]); tcg_gen_neg_tl(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(OT_BYTE, R_EAX); break; case 0xe0: /* loopnz */ case 0xe1: /* loopz */ case 0xe2: /* loop */ case 0xe3: /* jecxz */ { int l1, l2, l3; tval = (int8_t)insn_get(s, OT_BYTE); next_eip = s->pc - s->cs_base; tval += next_eip; if (s->dflag == 0) tval &= 0xffff; l1 = gen_new_label(); l2 = gen_new_label(); l3 = gen_new_label(); b &= 3; switch(b) { case 0: /* loopnz */ case 1: /* loopz */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_add_reg_im(s->aflag, R_ECX, -1); gen_op_jz_ecx(s->aflag, l3); gen_compute_eflags(cpu_tmp0); tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_Z); if (b == 0) { tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1); } else { tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, l1); } break; case 2: /* loop */ gen_op_add_reg_im(s->aflag, R_ECX, -1); gen_op_jnz_ecx(s->aflag, l1); break; default: case 3: /* jcxz */ gen_op_jz_ecx(s->aflag, l1); break; } gen_set_label(l3); gen_jmp_im(next_eip); tcg_gen_br(l2); gen_set_label(l1); gen_jmp_im(tval); gen_set_label(l2); gen_eob(s); } break; case 0x130: /* wrmsr */ case 0x132: /* rdmsr */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); if (b & 2) { gen_helper_rdmsr(); } else { gen_helper_wrmsr(); } } break; case 0x131: /* rdtsc */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); if (use_icount) gen_io_start(); gen_helper_rdtsc(); if (use_icount) { gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; case 0x133: /* rdpmc */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_rdpmc(); break; case 0x134: /* sysenter */ /* For Intel SYSENTER is valid on 64-bit */ if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) goto illegal_op; if (!s->pe) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); gen_helper_sysenter(); gen_eob(s); } break; case 0x135: /* sysexit */ /* For Intel SYSEXIT is valid on 64-bit */ if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) goto illegal_op; if (!s->pe) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); gen_helper_sysexit(tcg_const_i32(dflag)); gen_eob(s); } break; #ifdef TARGET_X86_64 case 0x105: /* syscall */ /* XXX: is it usable in real mode ? */ if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); gen_helper_syscall(tcg_const_i32(s->pc - pc_start)); gen_eob(s); break; case 0x107: /* sysret */ if (!s->pe) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); gen_helper_sysret(tcg_const_i32(s->dflag)); /* condition codes are modified only in long mode */ if (s->lma) s->cc_op = CC_OP_EFLAGS; gen_eob(s); } break; #endif case 0x1a2: /* cpuid */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_cpuid(); break; case 0xf4: /* hlt */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_hlt(tcg_const_i32(s->pc - pc_start)); s->is_jmp = 3; } break; case 0x100: modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; switch(op) { case 0: /* sldt */ if (!s->pe || s->vm86) goto illegal_op; gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,ldt.selector)); ot = OT_WORD; if (mod == 3) ot += s->dflag; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); break; case 2: /* lldt */ if (!s->pe || s->vm86) goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE); gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_jmp_im(pc_start - s->cs_base); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_lldt(cpu_tmp2_i32); } break; case 1: /* str */ if (!s->pe || s->vm86) goto illegal_op; gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,tr.selector)); ot = OT_WORD; if (mod == 3) ot += s->dflag; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); break; case 3: /* ltr */ if (!s->pe || s->vm86) goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE); gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_jmp_im(pc_start - s->cs_base); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_ltr(cpu_tmp2_i32); } break; case 4: /* verr */ case 5: /* verw */ if (!s->pe || s->vm86) goto illegal_op; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); if (op == 4) gen_helper_verr(cpu_T[0]); else gen_helper_verw(cpu_T[0]); s->cc_op = CC_OP_EFLAGS; break; default: goto illegal_op; } break; case 0x101: modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; rm = modrm & 7; switch(op) { case 0: /* sgdt */ if (mod == 3) goto illegal_op; gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.limit)); gen_op_st_T0_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); gen_op_st_T0_A0(CODE64(s) + OT_LONG + s->mem_index); break; case 1: if (mod == 3) { switch (rm) { case 0: /* monitor */ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_movq_A0_reg(R_EAX); } else #endif { gen_op_movl_A0_reg(R_EAX); if (s->aflag == 0) gen_op_andl_A0_ffff(); } gen_add_A0_ds_seg(s); gen_helper_monitor(cpu_A0); break; case 1: /* mwait */ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); gen_helper_mwait(tcg_const_i32(s->pc - pc_start)); gen_eob(s); break; default: goto illegal_op; } } else { /* sidt */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.limit)); gen_op_st_T0_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); gen_op_st_T0_A0(CODE64(s) + OT_LONG + s->mem_index); } break; case 2: /* lgdt */ case 3: /* lidt */ if (mod == 3) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); switch(rm) { case 0: /* VMRUN */ if (!(s->flags & HF_SVME_MASK) || !s->pe) goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; } else { gen_helper_vmrun(tcg_const_i32(s->aflag), tcg_const_i32(s->pc - pc_start)); tcg_gen_exit_tb(0); s->is_jmp = 3; } break; case 1: /* VMMCALL */ if (!(s->flags & HF_SVME_MASK)) goto illegal_op; gen_helper_vmmcall(); break; case 2: /* VMLOAD */ if (!(s->flags & HF_SVME_MASK) || !s->pe) goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; } else { gen_helper_vmload(tcg_const_i32(s->aflag)); } break; case 3: /* VMSAVE */ if (!(s->flags & HF_SVME_MASK) || !s->pe) goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; } else { gen_helper_vmsave(tcg_const_i32(s->aflag)); } break; case 4: /* STGI */ if ((!(s->flags & HF_SVME_MASK) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || !s->pe) goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; } else { gen_helper_stgi(); } break; case 5: /* CLGI */ if (!(s->flags & HF_SVME_MASK) || !s->pe) goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; } else { gen_helper_clgi(); } break; case 6: /* SKINIT */ if ((!(s->flags & HF_SVME_MASK) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || !s->pe) goto illegal_op; gen_helper_skinit(); break; case 7: /* INVLPGA */ if (!(s->flags & HF_SVME_MASK) || !s->pe) goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; } else { gen_helper_invlpga(tcg_const_i32(s->aflag)); } break; default: goto illegal_op; } } else if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_svm_check_intercept(s, pc_start, op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_op_ld_T1_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); gen_op_ld_T0_A0(CODE64(s) + OT_LONG + s->mem_index); if (!s->dflag) gen_op_andl_T0_im(0xffffff); if (op == 2) { tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,gdt.base)); tcg_gen_st32_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,gdt.limit)); } else { tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,idt.base)); tcg_gen_st32_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,idt.limit)); } } break; case 4: /* smsw */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,cr[0])); gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1); break; case 6: /* lmsw */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_helper_lmsw(cpu_T[0]); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; case 7: /* invlpg */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (mod == 3) { #ifdef TARGET_X86_64 if (CODE64(s) && rm == 0) { /* swapgs */ tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,segs[R_GS].base)); tcg_gen_ld_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,kernelgsbase)); tcg_gen_st_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,segs[R_GS].base)); tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,kernelgsbase)); } else #endif { goto illegal_op; } } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_helper_invlpg(cpu_A0); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } } break; default: goto illegal_op; } break; case 0x108: /* invd */ case 0x109: /* wbinvd */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD); /* nothing to do */ } break; case 0x63: /* arpl or movslS (x86_64) */ #ifdef TARGET_X86_64 if (CODE64(s)) { int d_ot; /* d_ot is the size of destination */ d_ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); if (mod == 3) { gen_op_mov_TN_reg(OT_LONG, 0, rm); /* sign extend */ if (d_ot == OT_QUAD) tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(d_ot, reg); } else { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); if (d_ot == OT_QUAD) { gen_op_lds_T0_A0(OT_LONG + s->mem_index); } else { gen_op_ld_T0_A0(OT_LONG + s->mem_index); } gen_op_mov_reg_T0(d_ot, reg); } } else #endif { int label1; TCGv t0, t1, t2; if (!s->pe || s->vm86) goto illegal_op; t0 = tcg_temp_local_new(); t1 = tcg_temp_local_new(); t2 = tcg_temp_local_new(); ot = OT_WORD; modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; rm = modrm & 7; if (mod != 3) { gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); } else { gen_op_mov_v_reg(ot, t0, rm); } gen_op_mov_v_reg(ot, t1, reg); tcg_gen_andi_tl(cpu_tmp0, t0, 3); tcg_gen_andi_tl(t1, t1, 3); tcg_gen_movi_tl(t2, 0); label1 = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_GE, cpu_tmp0, t1, label1); tcg_gen_andi_tl(t0, t0, ~3); tcg_gen_or_tl(t0, t0, t1); tcg_gen_movi_tl(t2, CC_Z); gen_set_label(label1); if (mod != 3) { gen_op_st_v(ot + s->mem_index, t0, cpu_A0); } else { gen_op_mov_reg_v(ot, rm, t0); } if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_compute_eflags(cpu_cc_src); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_Z); tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t2); s->cc_op = CC_OP_EFLAGS; tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free(t2); } break; case 0x102: /* lar */ case 0x103: /* lsl */ { int label1; TCGv t0; if (!s->pe || s->vm86) goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); t0 = tcg_temp_local_new(); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); if (b == 0x102) gen_helper_lar(t0, cpu_T[0]); else gen_helper_lsl(t0, cpu_T[0]); tcg_gen_andi_tl(cpu_tmp0, cpu_cc_src, CC_Z); label1 = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1); gen_op_mov_reg_v(ot, reg, t0); gen_set_label(label1); s->cc_op = CC_OP_EFLAGS; tcg_temp_free(t0); } break; case 0x118: modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; switch(op) { case 0: /* prefetchnta */ case 1: /* prefetchnt0 */ case 2: /* prefetchnt0 */ case 3: /* prefetchnt0 */ if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); /* nothing more to do */ break; default: /* nop (multi byte) */ gen_nop_modrm(s, modrm); break; } break; case 0x119 ... 0x11f: /* nop (multi byte) */ modrm = ldub_code(s->pc++); gen_nop_modrm(s, modrm); break; case 0x120: /* mov reg, crN */ case 0x122: /* mov crN, reg */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { modrm = ldub_code(s->pc++); if ((modrm & 0xc0) != 0xc0) goto illegal_op; rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; if (CODE64(s)) ot = OT_QUAD; else ot = OT_LONG; switch(reg) { case 0: case 2: case 3: case 4: case 8: if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); if (b & 2) { gen_op_mov_TN_reg(ot, 0, rm); gen_helper_write_crN(tcg_const_i32(reg), cpu_T[0]); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { gen_helper_read_crN(cpu_T[0], tcg_const_i32(reg)); gen_op_mov_reg_T0(ot, rm); } break; default: goto illegal_op; } } break; case 0x121: /* mov reg, drN */ case 0x123: /* mov drN, reg */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { modrm = ldub_code(s->pc++); if ((modrm & 0xc0) != 0xc0) goto illegal_op; rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; if (CODE64(s)) ot = OT_QUAD; else ot = OT_LONG; /* XXX: do it dynamically with CR4.DE bit */ if (reg == 4 || reg == 5 || reg >= 8) goto illegal_op; if (b & 2) { gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg); gen_op_mov_TN_reg(ot, 0, rm); gen_helper_movl_drN_T0(tcg_const_i32(reg), cpu_T[0]); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_DR0 + reg); tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,dr[reg])); gen_op_mov_reg_T0(ot, rm); } } break; case 0x106: /* clts */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); gen_helper_clts(); /* abort block because static cpu state changed */ gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; /* MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4 support */ case 0x1c3: /* MOVNTI reg, mem */ if (!(s->cpuid_features & CPUID_SSE2)) goto illegal_op; ot = s->dflag == 2 ? OT_QUAD : OT_LONG; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; reg = ((modrm >> 3) & 7) | rex_r; /* generate a generic store */ gen_ldst_modrm(s, modrm, ot, reg, 1); break; case 0x1ae: modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; switch(op) { case 0: /* fxsave */ if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || (s->flags & HF_EM_MASK)) goto illegal_op; if (s->flags & HF_TS_MASK) { gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fxsave(cpu_A0, tcg_const_i32((s->dflag == 2))); break; case 1: /* fxrstor */ if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || (s->flags & HF_EM_MASK)) goto illegal_op; if (s->flags & HF_TS_MASK) { gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_helper_fxrstor(cpu_A0, tcg_const_i32((s->dflag == 2))); break; case 2: /* ldmxcsr */ case 3: /* stmxcsr */ if (s->flags & HF_TS_MASK) { gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK) || mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); if (op == 2) { gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr)); } else { tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr)); gen_op_st_T0_A0(OT_LONG + s->mem_index); } break; case 5: /* lfence */ case 6: /* mfence */ if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE)) goto illegal_op; break; case 7: /* sfence / clflush */ if ((modrm & 0xc7) == 0xc0) { /* sfence */ /* XXX: also check for cpuid_ext2_features & CPUID_EXT2_EMMX */ if (!(s->cpuid_features & CPUID_SSE)) goto illegal_op; } else { /* clflush */ if (!(s->cpuid_features & CPUID_CLFLUSH)) goto illegal_op; gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); } break; default: goto illegal_op; } break; case 0x10d: /* 3DNow! prefetch(w) */ modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); /* ignore for now */ break; case 0x1aa: /* rsm */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM); if (!(s->flags & HF_SMM_MASK)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(s->pc - s->cs_base); gen_helper_rsm(); gen_eob(s); break; case 0x1b8: /* SSE4.2 popcnt */ if ((prefixes & (PREFIX_REPZ | PREFIX_LOCK | PREFIX_REPNZ)) != PREFIX_REPZ) goto illegal_op; if (!(s->cpuid_ext_features & CPUID_EXT_POPCNT)) goto illegal_op; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7); if (s->prefix & PREFIX_DATA) ot = OT_WORD; else if (s->dflag != 2) ot = OT_LONG; else ot = OT_QUAD; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_helper_popcnt(cpu_T[0], cpu_T[0], tcg_const_i32(ot)); gen_op_mov_reg_T0(ot, reg); s->cc_op = CC_OP_EFLAGS; break; case 0x10e ... 0x10f: /* 3DNow! instructions, ignore prefixes */ s->prefix &= ~(PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA); case 0x110 ... 0x117: case 0x128 ... 0x12f: case 0x138 ... 0x13a: case 0x150 ... 0x177: case 0x17c ... 0x17f: case 0x1c2: case 0x1c4 ... 0x1c6: case 0x1d0 ... 0x1fe: gen_sse(s, b, pc_start, rex_r); break; default: goto illegal_op; } /* lock generation */ if (s->prefix & PREFIX_LOCK) gen_helper_unlock(); return s->pc; illegal_op: if (s->prefix & PREFIX_LOCK) gen_helper_unlock(); /* XXX: ensure that no lock was generated */ gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); return s->pc; }


static void align_position(AVIOContext *pb, int64_t offset, uint64_t size) { if (avio_tell(pb) != offset + size) avio_seek(pb, offset + size, SEEK_SET); }


static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) { USBSerialState *s = (USBSerialState *)dev; int ret = 0; uint8_t devep = p->devep; uint8_t *data = p->data; int len = p->len; int first_len; switch (p->pid) { case USB_TOKEN_OUT: if (devep != 2) goto fail; qemu_chr_write(s->cs, data, len); break; case USB_TOKEN_IN: if (devep != 1) goto fail; first_len = RECV_BUF - s->recv_ptr; if (len <= 2) { ret = USB_RET_NAK; break; } *data++ = usb_get_modem_lines(s) | 1; /* We do not have the uart details */ /* handle serial break */ if (s->event_trigger && s->event_trigger & FTDI_BI) { s->event_trigger &= ~FTDI_BI; *data = FTDI_BI; ret = 2; break; } else { *data++ = 0; } len -= 2; if (len > s->recv_used) len = s->recv_used; if (!len) { ret = USB_RET_NAK; break; } if (first_len > len) first_len = len; memcpy(data, s->recv_buf + s->recv_ptr, first_len); if (len > first_len) memcpy(data + first_len, s->recv_buf, len - first_len); s->recv_used -= len; s->recv_ptr = (s->recv_ptr + len) % RECV_BUF; ret = len + 2; break; default: DPRINTF("Bad token\n"); fail: ret = USB_RET_STALL; break; } return ret; }


void isa_register_portio_list(ISADevice *dev, uint16_t start, const MemoryRegionPortio *pio_start, void *opaque, const char *name) { PortioList piolist; /* START is how we should treat DEV, regardless of the actual contents of the portio array. This is how the old code actually handled e.g. the FDC device. */ isa_init_ioport(dev, start); /* FIXME: the device should store created PortioList in its state. Note that DEV can be NULL here and that single device can register several portio lists. Current implementation is leaking memory allocated in portio_list_init. The leak is not critical because it happens only at initialization time. */ portio_list_init(&piolist, OBJECT(dev), pio_start, opaque, name); portio_list_add(&piolist, isabus->address_space_io, start); }


static inline void write_mem(IVState *s, uint64_t off, const void *buf, size_t len) { QTestState *qtest = global_qtest; global_qtest = s->qtest; qpci_memwrite(s->dev, s->mem_base + off, buf, len); global_qtest = qtest; }


static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) { QEMUTimer **pt, *t; qemu_del_timer(ts); /* add the timer in the sorted list */ /* NOTE: this code must be signal safe because qemu_timer_expired() can be called from a signal. */ pt = &active_timers[ts->clock->type]; for(;;) { t = *pt; if (!t) break; if (t->expire_time > expire_time) break; pt = &t->next; } ts->expire_time = expire_time; ts->next = *pt; *pt = ts; /* Rearm if necessary */ if (pt == &active_timers[ts->clock->type]) { if (!alarm_timer->pending) { qemu_rearm_alarm_timer(alarm_timer); } /* Interrupt execution to force deadline recalculation. */ if (use_icount) qemu_notify_event(); } }


static void co_read_response(void *opaque) { BDRVSheepdogState *s = opaque; if (!s->co_recv) { s->co_recv = qemu_coroutine_create(aio_read_response); } qemu_coroutine_enter(s->co_recv, opaque); }


static void omap2_inth_write(void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size) { struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; int offset = addr; int bank_no, line_no; struct omap_intr_handler_bank_s *bank = NULL; if ((offset & 0xf80) == 0x80) { bank_no = (offset & 0x60) >> 5; if (bank_no < s->nbanks) { offset &= ~0x60; bank = &s->bank[bank_no]; } } switch (offset) { case 0x10: /* INTC_SYSCONFIG */ s->autoidle &= 4; s->autoidle |= (value & 1) << 2; if (value & 2) /* SOFTRESET */ omap_inth_reset(&s->busdev.qdev); case 0x48: /* INTC_CONTROL */ s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */ if (value & 2) { /* NEWFIQAGR */ qemu_set_irq(s->parent_intr[1], 0); s->new_agr[1] = ~0; omap_inth_update(s, 1); } if (value & 1) { /* NEWIRQAGR */ qemu_set_irq(s->parent_intr[0], 0); s->new_agr[0] = ~0; omap_inth_update(s, 0); } case 0x4c: /* INTC_PROTECTION */ /* TODO: Make a bitmap (or sizeof(char)map) of access privileges * for every register, see Chapter 3 and 4 for privileged mode. */ if (value & 1) fprintf(stderr, "%s: protection mode enable attempt\n", __FUNCTION__); case 0x50: /* INTC_IDLE */ s->autoidle &= ~3; s->autoidle |= value & 3; /* Per-bank registers */ case 0x84: /* INTC_MIR */ bank->mask = value; omap_inth_update(s, 0); omap_inth_update(s, 1); case 0x88: /* INTC_MIR_CLEAR */ bank->mask &= ~value; omap_inth_update(s, 0); omap_inth_update(s, 1); case 0x8c: /* INTC_MIR_SET */ bank->mask |= value; case 0x90: /* INTC_ISR_SET */ bank->irqs |= bank->swi |= value; omap_inth_update(s, 0); omap_inth_update(s, 1); case 0x94: /* INTC_ISR_CLEAR */ bank->swi &= ~value; bank->irqs = bank->swi & bank->inputs; /* Per-line registers */ case 0x100 ... 0x300: /* INTC_ILR */ bank_no = (offset - 0x100) >> 7; if (bank_no > s->nbanks) break; bank = &s->bank[bank_no]; line_no = (offset & 0x7f) >> 2; bank->priority[line_no] = (value >> 2) & 0x3f; bank->fiq &= ~(1 << line_no); bank->fiq |= (value & 1) << line_no; case 0x00: /* INTC_REVISION */ case 0x14: /* INTC_SYSSTATUS */ case 0x40: /* INTC_SIR_IRQ */ case 0x44: /* INTC_SIR_FIQ */ case 0x80: /* INTC_ITR */ case 0x98: /* INTC_PENDING_IRQ */ case 0x9c: /* INTC_PENDING_FIQ */ OMAP_RO_REG(addr); } }


static int decode_hextile(VmncContext *c, uint8_t* dst, uint8_t* src, int w, int h, int stride) { int i, j, k; int bg = 0, fg = 0, rects, color, flags, xy, wh; const int bpp = c->bpp2; uint8_t *dst2; int bw = 16, bh = 16; uint8_t *ssrc=src; for(j = 0; j < h; j += 16) { dst2 = dst; bw = 16; if(j + 16 > h) bh = h - j; for(i = 0; i < w; i += 16, dst2 += 16 * bpp) { if(i + 16 > w) bw = w - i; flags = *src++; if(flags & HT_RAW) { paint_raw(dst2, bw, bh, src, bpp, c->bigendian, stride); src += bw * bh * bpp; } else { if(flags & HT_BKG) { bg = vmnc_get_pixel(src, bpp, c->bigendian); src += bpp; } if(flags & HT_FG) { fg = vmnc_get_pixel(src, bpp, c->bigendian); src += bpp; } rects = 0; if(flags & HT_SUB) rects = *src++; color = (flags & HT_CLR); paint_rect(dst2, 0, 0, bw, bh, bg, bpp, stride); for(k = 0; k < rects; k++) { if(color) { fg = vmnc_get_pixel(src, bpp, c->bigendian); src += bpp; } xy = *src++; wh = *src++; paint_rect(dst2, xy >> 4, xy & 0xF, (wh>>4)+1, (wh & 0xF)+1, fg, bpp, stride); } } } dst += stride * 16; } return src - ssrc; }


static void filter_mb_mbaff_edgev( H264Context *h, uint8_t *pix, int stride, int16_t bS[4], int bsi, int qp ) { int i; int index_a = qp + h->slice_alpha_c0_offset; int alpha = (alpha_table+52)[index_a]; int beta = (beta_table+52)[qp + h->slice_beta_offset]; for( i = 0; i < 8; i++, pix += stride) { const int bS_index = (i >> 1) * bsi; if( bS[bS_index] == 0 ) { continue; } if( bS[bS_index] < 4 ) { const int tc0 = (tc0_table+52)[index_a][bS[bS_index]]; const int p0 = pix[-1]; const int p1 = pix[-2]; const int p2 = pix[-3]; const int q0 = pix[0]; const int q1 = pix[1]; const int q2 = pix[2]; if( FFABS( p0 - q0 ) < alpha && FFABS( p1 - p0 ) < beta && FFABS( q1 - q0 ) < beta ) { int tc = tc0; int i_delta; if( FFABS( p2 - p0 ) < beta ) { if(tc0) pix[-2] = p1 + av_clip( ( p2 + ( ( p0 + q0 + 1 ) >> 1 ) - ( p1 << 1 ) ) >> 1, -tc0, tc0 ); tc++; } if( FFABS( q2 - q0 ) < beta ) { if(tc0) pix[1] = q1 + av_clip( ( q2 + ( ( p0 + q0 + 1 ) >> 1 ) - ( q1 << 1 ) ) >> 1, -tc0, tc0 ); tc++; } i_delta = av_clip( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3, -tc, tc ); pix[-1] = av_clip_uint8( p0 + i_delta ); /* p0' */ pix[0] = av_clip_uint8( q0 - i_delta ); /* q0' */ tprintf(h->s.avctx, "filter_mb_mbaff_edgev i:%d, qp:%d, indexA:%d, alpha:%d, beta:%d, tc:%d\n# bS:%d -> [%02x, %02x, %02x, %02x, %02x, %02x] =>[%02x, %02x, %02x, %02x]\n", i, qp[qp_index], index_a, alpha, beta, tc, bS[bS_index], pix[-3], p1, p0, q0, q1, pix[2], p1, pix[-1], pix[0], q1); } }else{ const int p0 = pix[-1]; const int p1 = pix[-2]; const int p2 = pix[-3]; const int q0 = pix[0]; const int q1 = pix[1]; const int q2 = pix[2]; if( FFABS( p0 - q0 ) < alpha && FFABS( p1 - p0 ) < beta && FFABS( q1 - q0 ) < beta ) { if(FFABS( p0 - q0 ) < (( alpha >> 2 ) + 2 )){ if( FFABS( p2 - p0 ) < beta) { const int p3 = pix[-4]; /* p0', p1', p2' */ pix[-1] = ( p2 + 2*p1 + 2*p0 + 2*q0 + q1 + 4 ) >> 3; pix[-2] = ( p2 + p1 + p0 + q0 + 2 ) >> 2; pix[-3] = ( 2*p3 + 3*p2 + p1 + p0 + q0 + 4 ) >> 3; } else { /* p0' */ pix[-1] = ( 2*p1 + p0 + q1 + 2 ) >> 2; } if( FFABS( q2 - q0 ) < beta) { const int q3 = pix[3]; /* q0', q1', q2' */ pix[0] = ( p1 + 2*p0 + 2*q0 + 2*q1 + q2 + 4 ) >> 3; pix[1] = ( p0 + q0 + q1 + q2 + 2 ) >> 2; pix[2] = ( 2*q3 + 3*q2 + q1 + q0 + p0 + 4 ) >> 3; } else { /* q0' */ pix[0] = ( 2*q1 + q0 + p1 + 2 ) >> 2; } }else{ /* p0', q0' */ pix[-1] = ( 2*p1 + p0 + q1 + 2 ) >> 2; pix[ 0] = ( 2*q1 + q0 + p1 + 2 ) >> 2; } tprintf(h->s.avctx, "filter_mb_mbaff_edgev i:%d, qp:%d, indexA:%d, alpha:%d, beta:%d\n# bS:4 -> [%02x, %02x, %02x, %02x, %02x, %02x] =>[%02x, %02x, %02x, %02x, %02x, %02x]\n", i, qp[qp_index], index_a, alpha, beta, p2, p1, p0, q0, q1, q2, pix[-3], pix[-2], pix[-1], pix[0], pix[1], pix[2]); } } } }


static void arm_idct_add(UINT8 *dest, int line_size, DCTELEM *block) { j_rev_dct_ARM (block); add_pixels_clamped(block, dest, line_size); }


static inline void decode_block_intra(MadContext * t, DCTELEM * block) { MpegEncContext *s = &t->s; int level, i, j, run; RLTable *rl = &ff_rl_mpeg1; const uint8_t *scantable = s->intra_scantable.permutated; int16_t *quant_matrix = s->intra_matrix; block[0] = (128 + get_sbits(&s->gb, 8)) * quant_matrix[0]; /* The RL decoder is derived from mpeg1_decode_block_intra; Escaped level and run values a decoded differently */ i = 0; { OPEN_READER(re, &s->gb); /* now quantify & encode AC coefficients */ for (;;) { UPDATE_CACHE(re, &s->gb); GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2, 0); if (level == 127) { break; } else if (level != 0) { i += run; j = scantable[i]; level = (level*quant_matrix[j]) >> 4; level = (level-1)|1; level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); LAST_SKIP_BITS(re, &s->gb, 1); } else { /* escape */ UPDATE_CACHE(re, &s->gb); level = SHOW_SBITS(re, &s->gb, 10); SKIP_BITS(re, &s->gb, 10); UPDATE_CACHE(re, &s->gb); run = SHOW_UBITS(re, &s->gb, 6)+1; LAST_SKIP_BITS(re, &s->gb, 6); i += run; j = scantable[i]; if (level < 0) { level = -level; level = (level*quant_matrix[j]) >> 4; level = (level-1)|1; level = -level; } else { level = (level*quant_matrix[j]) >> 4; level = (level-1)|1; } } if (i > 63) { av_log(s->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); return; } block[j] = level; } CLOSE_READER(re, &s->gb); } }


static void test_ivshmem_memdev(void) { IVState state; /* just for the sake of checking memory-backend property */ setup_vm_cmd(&state, "-object memory-backend-ram,size=1M,id=mb1" " -device ivshmem,x-memdev=mb1", false); qtest_quit(state.qtest); }


static av_cold void init_static(void) { if (!huff_vlc[0].bits) { INIT_VLC_STATIC(&huff_vlc[0], VLC_BITS, 18, &ff_mlp_huffman_tables[0][0][1], 2, 1, &ff_mlp_huffman_tables[0][0][0], 2, 1, 512); INIT_VLC_STATIC(&huff_vlc[1], VLC_BITS, 16, &ff_mlp_huffman_tables[1][0][1], 2, 1, &ff_mlp_huffman_tables[1][0][0], 2, 1, 512); INIT_VLC_STATIC(&huff_vlc[2], VLC_BITS, 15, &ff_mlp_huffman_tables[2][0][1], 2, 1, &ff_mlp_huffman_tables[2][0][0], 2, 1, 512); ff_mlp_init_crc();


void gen_pc_load(CPUState *env, TranslationBlock *tb, unsigned long searched_pc, int pc_pos, void *puc) { env->regs[15] = gen_opc_pc[pc_pos]; }


void virtio_scsi_dataplane_notify(VirtIODevice *vdev, VirtIOSCSIReq *req) { if (virtio_should_notify(vdev, req->vq)) { event_notifier_set(virtio_queue_get_guest_notifier(req->vq)); } }


SwsFunc ff_yuv2rgb_init_mmx(SwsContext *c) { int cpu_flags = av_get_cpu_flags(); if (c->srcFormat != PIX_FMT_YUV420P && c->srcFormat != PIX_FMT_YUVA420P) return NULL; if (HAVE_MMX2 && cpu_flags & AV_CPU_FLAG_MMX2) { switch (c->dstFormat) { case PIX_FMT_RGB24: return yuv420_rgb24_MMX2; case PIX_FMT_BGR24: return yuv420_bgr24_MMX2; } } if (HAVE_MMX && cpu_flags & AV_CPU_FLAG_MMX) { switch (c->dstFormat) { case PIX_FMT_RGB32: if (CONFIG_SWSCALE_ALPHA && c->srcFormat == PIX_FMT_YUVA420P) { #if HAVE_7REGS return yuva420_rgb32_MMX; #endif break; } else return yuv420_rgb32_MMX; case PIX_FMT_BGR32: if (CONFIG_SWSCALE_ALPHA && c->srcFormat == PIX_FMT_YUVA420P) { #if HAVE_7REGS return yuva420_bgr32_MMX; #endif break; } else return yuv420_bgr32_MMX; case PIX_FMT_RGB24: return yuv420_rgb24_MMX; case PIX_FMT_BGR24: return yuv420_bgr24_MMX; case PIX_FMT_RGB565: return yuv420_rgb16_MMX; case PIX_FMT_RGB555: return yuv420_rgb15_MMX; } } return NULL; }


int ide_init_drive(IDEState *s, BlockDriverState *bs, const char *version, const char *serial) { int cylinders, heads, secs; uint64_t nb_sectors; s->bs = bs; bdrv_get_geometry(bs, &nb_sectors); bdrv_guess_geometry(bs, &cylinders, &heads, &secs); if (cylinders < 1 || cylinders > 16383) { error_report("cyls must be between 1 and 16383"); if (heads < 1 || heads > 16) { error_report("heads must be between 1 and 16"); if (secs < 1 || secs > 63) { error_report("secs must be between 1 and 63"); s->cylinders = cylinders; s->heads = heads; s->sectors = secs; s->nb_sectors = nb_sectors; /* The SMART values should be preserved across power cycles but they aren't. */ s->smart_enabled = 1; s->smart_autosave = 1; s->smart_errors = 0; s->smart_selftest_count = 0; if (bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM) { s->drive_kind = IDE_CD; bdrv_set_change_cb(bs, cdrom_change_cb, s); } else { if (bdrv_is_read_only(bs)) { error_report("Can't use a read-only drive"); if (serial) { strncpy(s->drive_serial_str, serial, sizeof(s->drive_serial_str)); } else { snprintf(s->drive_serial_str, sizeof(s->drive_serial_str), "QM%05d", s->drive_serial); if (version) { pstrcpy(s->version, sizeof(s->version), version); } else { pstrcpy(s->version, sizeof(s->version), QEMU_VERSION); ide_reset(s); bdrv_set_removable(bs, s->drive_kind == IDE_CD); return 0;


SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit, bool removable, int bootindex, const char *serial, Error **errp) { const char *driver; DeviceState *dev; Error *err = NULL; driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk"; dev = qdev_create(&bus->qbus, driver); qdev_prop_set_uint32(dev, "scsi-id", unit); if (bootindex >= 0) { qdev_prop_set_int32(dev, "bootindex", bootindex); } if (object_property_find(OBJECT(dev), "removable", NULL)) { qdev_prop_set_bit(dev, "removable", removable); } if (serial) { qdev_prop_set_string(dev, "serial", serial); } if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) { error_setg(errp, "Setting drive property failed"); qdev_free(dev); return NULL; } object_property_set_bool(OBJECT(dev), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); qdev_free(dev); return NULL; } return SCSI_DEVICE(dev); }


static int unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) { QEMUFileSocket *s = opaque; ssize_t len; for (;;) { len = read(s->fd, buf, size); if (len != -1) { break; } if (errno == EAGAIN) { yield_until_fd_readable(s->fd); } else if (errno != EINTR) { break; } } if (len == -1) { len = -errno; } return len; }


DriveInfo *add_init_drive(const char *optstr) { DriveInfo *dinfo; QemuOpts *opts; MachineClass *mc; opts = drive_def(optstr); if (!opts) return NULL; mc = MACHINE_GET_CLASS(current_machine); dinfo = drive_new(opts, mc->block_default_type); if (!dinfo) { qemu_opts_del(opts); return NULL; } return dinfo; }


static void decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src, int log2w, int log2h, int stride){ const int index= size2index[log2h][log2w]; const int h= 1<<log2h; int code= get_vlc2(&f->gb, block_type_vlc[1-(f->version>1)][index].table, BLOCK_TYPE_VLC_BITS, 1); uint16_t *start= (uint16_t*)f->last_picture.data[0]; uint16_t *end= start + stride*(f->avctx->height-h+1) - (1<<log2w); assert(code>=0 && code<=6); if(code == 0){ src += f->mv[ *f->bytestream++ ]; if(start > src || src > end){ av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n"); return; } mcdc(dst, src, log2w, h, stride, 1, 0); }else if(code == 1){ log2h--; decode_p_block(f, dst , src , log2w, log2h, stride); decode_p_block(f, dst + (stride<<log2h), src + (stride<<log2h), log2w, log2h, stride); }else if(code == 2){ log2w--; decode_p_block(f, dst , src , log2w, log2h, stride); decode_p_block(f, dst + (1<<log2w), src + (1<<log2w), log2w, log2h, stride); }else if(code == 3 && f->version<2){ mcdc(dst, src, log2w, h, stride, 1, 0); }else if(code == 4){ src += f->mv[ *f->bytestream++ ]; if(start > src || src > end){ av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n"); return; } mcdc(dst, src, log2w, h, stride, 1, av_le2ne16(*f->wordstream++)); }else if(code == 5){ mcdc(dst, src, log2w, h, stride, 0, av_le2ne16(*f->wordstream++)); }else if(code == 6){ if(log2w){ dst[0] = av_le2ne16(*f->wordstream++); dst[1] = av_le2ne16(*f->wordstream++); }else{ dst[0 ] = av_le2ne16(*f->wordstream++); dst[stride] = av_le2ne16(*f->wordstream++); } } }


static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb, const char *name, const char *tag, int len) { AVDictionaryEntry *t = NULL; uint8_t num; if (!(t = av_dict_get(s->metadata, tag, NULL, 0))) return 0; num = t ? atoi(t->value) : 0; avio_wb32(pb, len+8); ffio_wfourcc(pb, name); if (len==4) avio_wb32(pb, num); else avio_w8 (pb, num); return len+8; }