diff options
Diffstat (limited to 'target-i386')
-rw-r--r-- | target-i386/cpu.c | 14 | ||||
-rw-r--r-- | target-i386/helper.h | 1 | ||||
-rw-r--r-- | target-i386/kvm-stub.c | 12 | ||||
-rw-r--r-- | target-i386/kvm.c | 13 | ||||
-rw-r--r-- | target-i386/misc_helper.c | 22 | ||||
-rw-r--r-- | target-i386/translate.c | 97 |
6 files changed, 96 insertions, 63 deletions
diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 864c80eb47..47af9a8816 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2086,14 +2086,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, /* cache info: needed for Core compatibility */ if (cpu->cache_info_passthrough) { host_cpuid(index, count, eax, ebx, ecx, edx); - break; - } - if (cs->nr_cores > 1) { - *eax = (cs->nr_cores - 1) << 26; + *eax &= ~0xFC000000; } else { *eax = 0; - } - switch (count) { + switch (count) { case 0: /* L1 dcache info */ *eax |= CPUID_4_TYPE_DCACHE | \ CPUID_4_LEVEL(1) | \ @@ -2133,6 +2129,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ecx = 0; *edx = 0; break; + } + } + + /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ + if ((*eax & 31) && cs->nr_cores > 1) { + *eax |= (cs->nr_cores - 1) << 26; } break; case 5: diff --git a/target-i386/helper.h b/target-i386/helper.h index d6974dfd6b..3775abeba7 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -58,6 +58,7 @@ DEF_HELPER_2(sysret, void, env, int) DEF_HELPER_2(hlt, void, env, int) DEF_HELPER_2(monitor, void, env, tl) DEF_HELPER_2(mwait, void, env, int) +DEF_HELPER_2(pause, void, env, int) DEF_HELPER_1(debug, void, env) DEF_HELPER_1(reset_rf, void, env) DEF_HELPER_3(raise_interrupt, void, env, int, int) diff --git a/target-i386/kvm-stub.c b/target-i386/kvm-stub.c index 11429c461e..2b9e8011fb 100644 --- a/target-i386/kvm-stub.c +++ b/target-i386/kvm-stub.c @@ -16,3 +16,15 @@ bool kvm_allows_irq0_override(void) { return 1; } + +#ifndef __OPTIMIZE__ +/* This function is only called inside conditionals which we + * rely on the compiler to optimize out when CONFIG_KVM is not + * defined. + */ +uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function, + uint32_t index, int reg) +{ + abort(); +} +#endif diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 749aa09a21..1188482359 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -456,11 +456,12 @@ int kvm_arch_init_vcpu(CPUState *cs) uint32_t signature[3]; int r; + memset(&cpuid_data, 0, sizeof(cpuid_data)); + cpuid_i = 0; /* Paravirtualization CPUIDs */ c = &cpuid_data.entries[cpuid_i++]; - memset(c, 0, sizeof(*c)); c->function = KVM_CPUID_SIGNATURE; if (!hyperv_enabled(cpu)) { memcpy(signature, "KVMKVMKVM\0\0\0", 12); @@ -474,7 +475,6 @@ int kvm_arch_init_vcpu(CPUState *cs) c->edx = signature[2]; c = &cpuid_data.entries[cpuid_i++]; - memset(c, 0, sizeof(*c)); c->function = KVM_CPUID_FEATURES; c->eax = env->features[FEAT_KVM]; @@ -483,13 +483,11 @@ int kvm_arch_init_vcpu(CPUState *cs) c->eax = signature[0]; c = &cpuid_data.entries[cpuid_i++]; - memset(c, 0, sizeof(*c)); c->function = HYPERV_CPUID_VERSION; c->eax = 0x00001bbc; c->ebx = 0x00060001; c = &cpuid_data.entries[cpuid_i++]; - memset(c, 0, sizeof(*c)); c->function = HYPERV_CPUID_FEATURES; if (cpu->hyperv_relaxed_timing) { c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; @@ -500,7 +498,6 @@ int kvm_arch_init_vcpu(CPUState *cs) } c = &cpuid_data.entries[cpuid_i++]; - memset(c, 0, sizeof(*c)); c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) { c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED; @@ -511,13 +508,11 @@ int kvm_arch_init_vcpu(CPUState *cs) c->ebx = cpu->hyperv_spinlock_attempts; c = &cpuid_data.entries[cpuid_i++]; - memset(c, 0, sizeof(*c)); c->function = HYPERV_CPUID_IMPLEMENT_LIMITS; c->eax = 0x40; c->ebx = 0x40; c = &cpuid_data.entries[cpuid_i++]; - memset(c, 0, sizeof(*c)); c->function = KVM_CPUID_SIGNATURE_NEXT; memcpy(signature, "KVMKVMKVM\0\0\0", 12); c->eax = 0; @@ -1314,8 +1309,8 @@ static int kvm_get_xcrs(X86CPU *cpu) for (i = 0; i < xcrs.nr_xcrs; i++) { /* Only support xcr0 now */ - if (xcrs.xcrs[0].xcr == 0) { - env->xcr0 = xcrs.xcrs[0].value; + if (xcrs.xcrs[i].xcr == 0) { + env->xcr0 = xcrs.xcrs[i].value; break; } } diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index 93933fd162..b6307ca386 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -566,6 +566,15 @@ void helper_rdmsr(CPUX86State *env) } #endif +static void do_pause(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + + /* Just let another CPU run. */ + env->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(env); +} + static void do_hlt(X86CPU *cpu) { CPUState *cs = CPU(cpu); @@ -611,13 +620,22 @@ void helper_mwait(CPUX86State *env, int next_eip_addend) cs = CPU(cpu); /* XXX: not complete but not completely erroneous */ if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) { - /* more than one CPU: do not sleep because another CPU may - wake this one */ + do_pause(cpu); } else { do_hlt(cpu); } } +void helper_pause(CPUX86State *env, int next_eip_addend) +{ + X86CPU *cpu = x86_env_get_cpu(env); + + cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0); + env->eip += next_eip_addend; + + do_pause(cpu); +} + void helper_debug(CPUX86State *env) { env->exception_index = EXCP_DEBUG; diff --git a/target-i386/translate.c b/target-i386/translate.c index eb0ea93dbb..7916e5b1f6 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2090,6 +2090,7 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm, int scale; int opreg; int mod, rm, code, override, must_add_seg; + TCGv sum; override = s->override; must_add_seg = s->addseg; @@ -2099,10 +2100,9 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm, rm = modrm & 7; if (s->aflag) { - havesib = 0; base = rm; - index = 0; + index = -1; scale = 0; if (base == 4) { @@ -2110,6 +2110,9 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm, code = cpu_ldub_code(env, s->pc++); scale = (code >> 6) & 3; index = ((code >> 3) & 7) | REX_X(s); + if (index == 4) { + index = -1; /* no index */ + } base = (code & 7); } base |= REX_B(s); @@ -2137,59 +2140,57 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm, break; } - if (base >= 0) { - /* for correct popl handling with esp */ - if (base == 4 && s->popl_esp_hack) - disp += s->popl_esp_hack; -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_movq_A0_reg(base); - if (disp != 0) { - gen_op_addq_A0_im(disp); - } - } else -#endif - { - gen_op_movl_A0_reg(base); - if (disp != 0) - gen_op_addl_A0_im(disp); + /* For correct popl handling with esp. */ + if (base == R_ESP && s->popl_esp_hack) { + disp += s->popl_esp_hack; + } + + /* Compute the address, with a minimum number of TCG ops. */ + TCGV_UNUSED(sum); + if (index >= 0) { + if (scale == 0) { + sum = cpu_regs[index]; + } else { + tcg_gen_shli_tl(cpu_A0, cpu_regs[index], scale); + sum = cpu_A0; } - } else { -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_movq_A0_im(disp); - } else -#endif - { - gen_op_movl_A0_im(disp); + if (base >= 0) { + tcg_gen_add_tl(cpu_A0, sum, cpu_regs[base]); + sum = cpu_A0; } + } else if (base >= 0) { + sum = cpu_regs[base]; } - /* index == 4 means no index */ - if (havesib && (index != 4)) { -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_addq_A0_reg_sN(scale, index); - } else -#endif - { - gen_op_addl_A0_reg_sN(scale, index); - } + if (TCGV_IS_UNUSED(sum)) { + tcg_gen_movi_tl(cpu_A0, disp); + } else { + tcg_gen_addi_tl(cpu_A0, sum, disp); } + if (must_add_seg) { if (override < 0) { - if (base == R_EBP || base == R_ESP) + if (base == R_EBP || base == R_ESP) { override = R_SS; - else + } else { override = R_DS; + } } -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_addq_A0_seg(override); - } else -#endif - { - gen_op_addl_A0_seg(s, override); + + tcg_gen_ld_tl(cpu_tmp0, cpu_env, + offsetof(CPUX86State, segs[override].base)); + if (CODE64(s)) { + if (s->aflag != 2) { + tcg_gen_ext32u_tl(cpu_A0, cpu_A0); + } + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); + goto done; } + + tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0); + } + + if (s->aflag != 2) { + tcg_gen_ext32u_tl(cpu_A0, cpu_A0); } } else { switch (mod) { @@ -2259,6 +2260,7 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm, } } + done: opreg = OR_A0; disp = 0; *reg_ptr = opreg; @@ -7224,7 +7226,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, goto do_xchg_reg_eax; } if (prefixes & PREFIX_REPZ) { - gen_svm_check_intercept(s, pc_start, SVM_EXIT_PAUSE); + gen_update_cc_op(s); + gen_jmp_im(pc_start - s->cs_base); + gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start)); + s->is_jmp = DISAS_TB_JUMP; } break; case 0x9b: /* fwait */ |