diff options
Diffstat (limited to 'target-i386')
-rw-r--r-- | target-i386/cpu.c | 15 | ||||
-rw-r--r-- | target-i386/cpu.h | 1 | ||||
-rw-r--r-- | target-i386/kvm.c | 13 | ||||
-rw-r--r-- | target-i386/machine.c | 21 | ||||
-rw-r--r-- | target-i386/translate.c | 14 |
5 files changed, 59 insertions, 5 deletions
diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 120a2e3d3..423e00905 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -33,6 +33,9 @@ #include "hyperv.h" #include "hw/hw.h" +#if defined(CONFIG_KVM) +#include <linux/kvm_para.h> +#endif /* feature flags taken from "Intel Processor Identification and the CPUID * Instruction" and AMD's "CPUID Specification". In cases of disagreement @@ -887,7 +890,17 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) memcpy(x86_cpu_def, def, sizeof(*def)); } - plus_kvm_features = ~0; /* not supported bits will be filtered out later */ +#if defined(CONFIG_KVM) + plus_kvm_features = (1 << KVM_FEATURE_CLOCKSOURCE) | + (1 << KVM_FEATURE_NOP_IO_DELAY) | + (1 << KVM_FEATURE_MMU_OP) | + (1 << KVM_FEATURE_CLOCKSOURCE2) | + (1 << KVM_FEATURE_ASYNC_PF) | + (1 << KVM_FEATURE_STEAL_TIME) | + (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT); +#else + plus_kvm_features = 0; +#endif add_flagname_to_bitmaps("hypervisor", &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index aabf99395..3c57d8b6b 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -699,6 +699,7 @@ typedef struct CPUX86State { uint64_t system_time_msr; uint64_t wall_clock_msr; uint64_t async_pf_en_msr; + uint64_t pv_eoi_en_msr; uint64_t tsc; uint64_t tsc_deadline; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 5e2d4f5db..6790180b0 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -64,6 +64,7 @@ static bool has_msr_star; static bool has_msr_hsave_pa; static bool has_msr_tsc_deadline; static bool has_msr_async_pf_en; +static bool has_msr_pv_eoi_en; static bool has_msr_misc_enable; static int lm_capable_kernel; @@ -456,6 +457,8 @@ int kvm_arch_init_vcpu(CPUX86State *env) has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF); + has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI); + cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused); for (i = 0; i <= limit; i++) { @@ -1018,6 +1021,10 @@ static int kvm_put_msrs(CPUX86State *env, int level) kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr); } + if (has_msr_pv_eoi_en) { + kvm_msr_entry_set(&msrs[n++], MSR_KVM_PV_EOI_EN, + env->pv_eoi_en_msr); + } if (hyperv_hypercall_available()) { kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0); kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0); @@ -1260,6 +1267,9 @@ static int kvm_get_msrs(CPUX86State *env) if (has_msr_async_pf_en) { msrs[n++].index = MSR_KVM_ASYNC_PF_EN; } + if (has_msr_pv_eoi_en) { + msrs[n++].index = MSR_KVM_PV_EOI_EN; + } if (env->mcg_cap) { msrs[n++].index = MSR_MCG_STATUS; @@ -1339,6 +1349,9 @@ static int kvm_get_msrs(CPUX86State *env) case MSR_KVM_ASYNC_PF_EN: env->async_pf_en_msr = msrs[i].data; break; + case MSR_KVM_PV_EOI_EN: + env->pv_eoi_en_msr = msrs[i].data; + break; } } diff --git a/target-i386/machine.c b/target-i386/machine.c index a8be058d2..477150887 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -279,6 +279,13 @@ static bool async_pf_msr_needed(void *opaque) return cpu->async_pf_en_msr != 0; } +static bool pv_eoi_msr_needed(void *opaque) +{ + CPUX86State *cpu = opaque; + + return cpu->pv_eoi_en_msr != 0; +} + static const VMStateDescription vmstate_async_pf_msr = { .name = "cpu/async_pf_msr", .version_id = 1, @@ -290,6 +297,17 @@ static const VMStateDescription vmstate_async_pf_msr = { } }; +static const VMStateDescription vmstate_pv_eoi_msr = { + .name = "cpu/async_pv_eoi_msr", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64(pv_eoi_en_msr, CPUX86State), + VMSTATE_END_OF_LIST() + } +}; + static bool fpop_ip_dp_needed(void *opaque) { CPUX86State *env = opaque; @@ -454,6 +472,9 @@ static const VMStateDescription vmstate_cpu = { .vmsd = &vmstate_async_pf_msr, .needed = async_pf_msr_needed, } , { + .vmsd = &vmstate_pv_eoi_msr, + .needed = pv_eoi_msr_needed, + } , { .vmsd = &vmstate_fpop_ip_dp, .needed = fpop_ip_dp_needed, }, { diff --git a/target-i386/translate.c b/target-i386/translate.c index 7ab2ccb19..eb0cabcf1 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7551,8 +7551,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { modrm = cpu_ldub_code(cpu_single_env, s->pc++); - if ((modrm & 0xc0) != 0xc0) - goto illegal_op; + /* Ignore the mod bits (assume (modrm&0xc0)==0xc0). + * AMD documentation (24594.pdf) and testing of + * intel 386 and 486 processors all show that the mod bits + * are assumed to be 1's, regardless of actual values. + */ rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; if (CODE64(s)) @@ -7594,8 +7597,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { modrm = cpu_ldub_code(cpu_single_env, s->pc++); - if ((modrm & 0xc0) != 0xc0) - goto illegal_op; + /* Ignore the mod bits (assume (modrm&0xc0)==0xc0). + * AMD documentation (24594.pdf) and testing of + * intel 386 and 486 processors all show that the mod bits + * are assumed to be 1's, regardless of actual values. + */ rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; if (CODE64(s)) |