aboutsummaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
Diffstat (limited to 'target-i386')
-rw-r--r--target-i386/cpu.c14
-rw-r--r--target-i386/helper.h1
-rw-r--r--target-i386/kvm-stub.c12
-rw-r--r--target-i386/kvm.c13
-rw-r--r--target-i386/misc_helper.c22
-rw-r--r--target-i386/translate.c97
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 */