diff options
Diffstat (limited to 'target')
| -rw-r--r-- | target/arm/kvm32.c | 5 | ||||
| -rw-r--r-- | target/arm/kvm64.c | 5 | ||||
| -rw-r--r-- | target/i386/cpu.c | 81 | ||||
| -rw-r--r-- | target/i386/cpu.h | 65 | ||||
| -rw-r--r-- | target/i386/hax-all.c | 36 | ||||
| -rw-r--r-- | target/i386/hvf/hvf.c | 10 | ||||
| -rw-r--r-- | target/i386/hvf/x86hvf.c | 4 | ||||
| -rw-r--r-- | target/i386/hyperv-proto.h | 1 | ||||
| -rw-r--r-- | target/i386/hyperv.c | 2 | ||||
| -rw-r--r-- | target/i386/kvm.c | 999 | ||||
| -rw-r--r-- | target/i386/machine.c | 284 | ||||
| -rw-r--r-- | target/mips/kvm.c | 5 | ||||
| -rw-r--r-- | target/mips/msa_helper.c | 148 | ||||
| -rw-r--r-- | target/mips/translate.c | 445 | ||||
| -rw-r--r-- | target/ppc/kvm.c | 5 | ||||
| -rw-r--r-- | target/s390x/kvm.c | 10 |
16 files changed, 1623 insertions, 482 deletions
diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c index 4e54e372a6..51f78f722b 100644 --- a/target/arm/kvm32.c +++ b/target/arm/kvm32.c @@ -240,6 +240,11 @@ int kvm_arch_init_vcpu(CPUState *cs) return kvm_arm_init_cpreg_list(cpu); } +int kvm_arch_destroy_vcpu(CPUState *cs) +{ + return 0; +} + typedef struct Reg { uint64_t id; int offset; diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 998d21f399..22d19c9aec 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -654,6 +654,11 @@ int kvm_arch_init_vcpu(CPUState *cs) return kvm_arm_init_cpreg_list(cpu); } +int kvm_arch_destroy_vcpu(CPUState *cs) +{ + return 0; +} + bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx) { /* Return true if the regidx is a register we should synchronize diff --git a/target/i386/cpu.c b/target/i386/cpu.c index fbed2eb804..da6eb67cfb 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1085,7 +1085,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "spec-ctrl", "stibp", - NULL, "arch-capabilities", NULL, "ssbd", + NULL, "arch-capabilities", "core-capability", "ssbd", }, .cpuid = { .eax = 7, @@ -1203,6 +1203,26 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { } }, }, + [FEAT_CORE_CAPABILITY] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, + NULL, "split-lock-detect", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { + .index = MSR_IA32_CORE_CAPABILITY, + .cpuid_dep = { + FEAT_7_0_EDX, + CPUID_7_0_EDX_CORE_CAPABILITY, + }, + }, + }, }; typedef struct X86RegisterInfo32 { @@ -4799,7 +4819,11 @@ static void x86_cpu_reset(CPUState *s) memset(env->mtrr_fixed, 0, sizeof(env->mtrr_fixed)); env->interrupt_injected = -1; - env->exception_injected = -1; + env->exception_nr = -1; + env->exception_pending = 0; + env->exception_injected = 0; + env->exception_has_payload = false; + env->exception_payload = 0; env->nmi_injected = false; #if !defined(CONFIG_USER_ONLY) /* We hard-wire the BSP to the first CPU. */ @@ -5195,12 +5219,6 @@ static int x86_cpu_filter_features(X86CPU *cpu) return rv; } -#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \ - (env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \ - (env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3) -#define IS_AMD_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && \ - (env)->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && \ - (env)->cpuid_vendor3 == CPUID_VENDOR_AMD_3) static void x86_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -5853,21 +5871,40 @@ static Property x86_cpu_properties[] = { #endif DEFINE_PROP_INT32("node-id", X86CPU, node_id, CPU_UNSET_NUMA_NODE_ID), DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false), + { .name = "hv-spinlocks", .info = &qdev_prop_spinlocks }, - DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false), - DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false), - DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false), - DEFINE_PROP_BOOL("hv-crash", X86CPU, hyperv_crash, false), - DEFINE_PROP_BOOL("hv-reset", X86CPU, hyperv_reset, false), - DEFINE_PROP_BOOL("hv-vpindex", X86CPU, hyperv_vpindex, false), - DEFINE_PROP_BOOL("hv-runtime", X86CPU, hyperv_runtime, false), - DEFINE_PROP_BOOL("hv-synic", X86CPU, hyperv_synic, false), - DEFINE_PROP_BOOL("hv-stimer", X86CPU, hyperv_stimer, false), - DEFINE_PROP_BOOL("hv-frequencies", X86CPU, hyperv_frequencies, false), - DEFINE_PROP_BOOL("hv-reenlightenment", X86CPU, hyperv_reenlightenment, false), - DEFINE_PROP_BOOL("hv-tlbflush", X86CPU, hyperv_tlbflush, false), - DEFINE_PROP_BOOL("hv-evmcs", X86CPU, hyperv_evmcs, false), - DEFINE_PROP_BOOL("hv-ipi", X86CPU, hyperv_ipi, false), + DEFINE_PROP_BIT64("hv-relaxed", X86CPU, hyperv_features, + HYPERV_FEAT_RELAXED, 0), + DEFINE_PROP_BIT64("hv-vapic", X86CPU, hyperv_features, + HYPERV_FEAT_VAPIC, 0), + DEFINE_PROP_BIT64("hv-time", X86CPU, hyperv_features, + HYPERV_FEAT_TIME, 0), + DEFINE_PROP_BIT64("hv-crash", X86CPU, hyperv_features, + HYPERV_FEAT_CRASH, 0), + DEFINE_PROP_BIT64("hv-reset", X86CPU, hyperv_features, + HYPERV_FEAT_RESET, 0), + DEFINE_PROP_BIT64("hv-vpindex", X86CPU, hyperv_features, + HYPERV_FEAT_VPINDEX, 0), + DEFINE_PROP_BIT64("hv-runtime", X86CPU, hyperv_features, + HYPERV_FEAT_RUNTIME, 0), + DEFINE_PROP_BIT64("hv-synic", X86CPU, hyperv_features, + HYPERV_FEAT_SYNIC, 0), + DEFINE_PROP_BIT64("hv-stimer", X86CPU, hyperv_features, + HYPERV_FEAT_STIMER, 0), + DEFINE_PROP_BIT64("hv-frequencies", X86CPU, hyperv_features, + HYPERV_FEAT_FREQUENCIES, 0), + DEFINE_PROP_BIT64("hv-reenlightenment", X86CPU, hyperv_features, + HYPERV_FEAT_REENLIGHTENMENT, 0), + DEFINE_PROP_BIT64("hv-tlbflush", X86CPU, hyperv_features, + HYPERV_FEAT_TLBFLUSH, 0), + DEFINE_PROP_BIT64("hv-evmcs", X86CPU, hyperv_features, + HYPERV_FEAT_EVMCS, 0), + DEFINE_PROP_BIT64("hv-ipi", X86CPU, hyperv_features, + HYPERV_FEAT_IPI, 0), + DEFINE_PROP_BIT64("hv-stimer-direct", X86CPU, hyperv_features, + HYPERV_FEAT_STIMER_DIRECT, 0), + DEFINE_PROP_BOOL("hv-passthrough", X86CPU, hyperv_passthrough, false), + DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true), DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 0732e059ec..93345792f4 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -345,6 +345,7 @@ typedef enum X86Seg { #define MSR_IA32_SPEC_CTRL 0x48 #define MSR_VIRT_SSBD 0xc001011f #define MSR_IA32_PRED_CMD 0x49 +#define MSR_IA32_CORE_CAPABILITY 0xcf #define MSR_IA32_ARCH_CAPABILITIES 0x10a #define MSR_IA32_TSCDEADLINE 0x6e0 @@ -496,6 +497,7 @@ typedef enum FeatureWord { FEAT_XSAVE_COMP_LO, /* CPUID[EAX=0xd,ECX=0].EAX */ FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ FEAT_ARCH_CAPABILITIES, + FEAT_CORE_CAPABILITY, FEATURE_WORDS, } FeatureWord; @@ -687,6 +689,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */ #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Speculation Control */ #define CPUID_7_0_EDX_ARCH_CAPABILITIES (1U << 29) /*Arch Capabilities*/ +#define CPUID_7_0_EDX_CORE_CAPABILITY (1U << 30) /*Core Capability*/ #define CPUID_7_0_EDX_SPEC_CTRL_SSBD (1U << 31) /* Speculative Store Bypass Disable */ #define CPUID_8000_0008_EBX_WBNOINVD (1U << 9) /* Write back and @@ -719,6 +722,13 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_VENDOR_HYGON "HygonGenuine" +#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \ + (env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \ + (env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3) +#define IS_AMD_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && \ + (env)->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && \ + (env)->cpuid_vendor3 == CPUID_VENDOR_AMD_3) + #define CPUID_MWAIT_IBE (1U << 1) /* Interrupts can exit capability */ #define CPUID_MWAIT_EMX (1U << 0) /* enumeration supported */ @@ -734,6 +744,25 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY (1U << 3) #define MSR_ARCH_CAP_SSB_NO (1U << 4) +#define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) + +/* Supported Hyper-V Enlightenments */ +#define HYPERV_FEAT_RELAXED 0 +#define HYPERV_FEAT_VAPIC 1 +#define HYPERV_FEAT_TIME 2 +#define HYPERV_FEAT_CRASH 3 +#define HYPERV_FEAT_RESET 4 +#define HYPERV_FEAT_VPINDEX 5 +#define HYPERV_FEAT_RUNTIME 6 +#define HYPERV_FEAT_SYNIC 7 +#define HYPERV_FEAT_STIMER 8 +#define HYPERV_FEAT_FREQUENCIES 9 +#define HYPERV_FEAT_REENLIGHTENMENT 10 +#define HYPERV_FEAT_TLBFLUSH 11 +#define HYPERV_FEAT_EVMCS 12 +#define HYPERV_FEAT_IPI 13 +#define HYPERV_FEAT_STIMER_DIRECT 14 + #ifndef HYPERV_SPINLOCK_NEVER_RETRY #define HYPERV_SPINLOCK_NEVER_RETRY 0xFFFFFFFF #endif @@ -1319,10 +1348,14 @@ typedef struct CPUX86State { /* For KVM */ uint32_t mp_state; - int32_t exception_injected; + int32_t exception_nr; int32_t interrupt_injected; uint8_t soft_interrupt; + uint8_t exception_pending; + uint8_t exception_injected; uint8_t has_error_code; + uint8_t exception_has_payload; + uint64_t exception_payload; uint32_t ins_len; uint32_t sipi_vector; bool tsc_valid; @@ -1331,6 +1364,9 @@ typedef struct CPUX86State { #if defined(CONFIG_KVM) || defined(CONFIG_HVF) void *xsave_buf; #endif +#if defined(CONFIG_KVM) + struct kvm_nested_state *nested_state; +#endif #if defined(CONFIG_HVF) HVFX86EmulatorState *hvf_emul; #endif @@ -1370,23 +1406,12 @@ struct X86CPU { CPUNegativeOffsetState neg; CPUX86State env; - bool hyperv_vapic; - bool hyperv_relaxed_timing; int hyperv_spinlock_attempts; char *hyperv_vendor_id; - bool hyperv_time; - bool hyperv_crash; - bool hyperv_reset; - bool hyperv_vpindex; - bool hyperv_runtime; - bool hyperv_synic; bool hyperv_synic_kvm_only; - bool hyperv_stimer; - bool hyperv_frequencies; - bool hyperv_reenlightenment; - bool hyperv_tlbflush; - bool hyperv_evmcs; - bool hyperv_ipi; + uint64_t hyperv_features; + bool hyperv_passthrough; + bool check_cpuid; bool enforce_cpuid; bool expose_kvm; @@ -1837,6 +1862,11 @@ static inline int32_t x86_get_a20_mask(CPUX86State *env) } } +static inline bool cpu_has_vmx(CPUX86State *env) +{ + return env->features[FEAT_1_ECX] & CPUID_EXT_VMX; +} + /* fpu_helper.c */ void update_fp_status(CPUX86State *env); void update_mxcsr_status(CPUX86State *env); @@ -1906,4 +1936,9 @@ void x86_cpu_xrstor_all_areas(X86CPU *cpu, const X86XSaveArea *buf); void x86_cpu_xsave_all_areas(X86CPU *cpu, X86XSaveArea *buf); void x86_update_hflags(CPUX86State* env); +static inline bool hyperv_feat_enabled(X86CPU *cpu, int feat) +{ + return !!(cpu->hyperv_features & BIT(feat)); +} + #endif /* I386_CPU_H */ diff --git a/target/i386/hax-all.c b/target/i386/hax-all.c index 64fd51ad4a..9e7b77965d 100644 --- a/target/i386/hax-all.c +++ b/target/i386/hax-all.c @@ -471,13 +471,35 @@ static int hax_vcpu_hax_exec(CPUArchState *env) return 0; } - cpu->halted = 0; - if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { cpu->interrupt_request &= ~CPU_INTERRUPT_POLL; apic_poll_irq(x86_cpu->apic_state); } + /* After a vcpu is halted (either because it is an AP and has just been + * reset, or because it has executed the HLT instruction), it will not be + * run (hax_vcpu_run()) until it is unhalted. The next few if blocks check + * for events that may change the halted state of this vcpu: + * a) Maskable interrupt, when RFLAGS.IF is 1; + * Note: env->eflags may not reflect the current RFLAGS state, because + * it is not updated after each hax_vcpu_run(). We cannot afford + * to fail to recognize any unhalt-by-maskable-interrupt event + * (in which case the vcpu will halt forever), and yet we cannot + * afford the overhead of hax_vcpu_sync_state(). The current + * solution is to err on the side of caution and have the HLT + * handler (see case HAX_EXIT_HLT below) unconditionally set the + * IF_MASK bit in env->eflags, which, in effect, disables the + * RFLAGS.IF check. + * b) NMI; + * c) INIT signal; + * d) SIPI signal. + */ + if (((cpu->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) || + (cpu->interrupt_request & CPU_INTERRUPT_NMI)) { + cpu->halted = 0; + } + if (cpu->interrupt_request & CPU_INTERRUPT_INIT) { DPRINTF("\nhax_vcpu_hax_exec: handling INIT for %d\n", cpu->cpu_index); @@ -493,6 +515,16 @@ static int hax_vcpu_hax_exec(CPUArchState *env) hax_vcpu_sync_state(env, 1); } + if (cpu->halted) { + /* If this vcpu is halted, we must not ask HAXM to run it. Instead, we + * break out of hax_smp_cpu_exec() as if this vcpu had executed HLT. + * That way, this vcpu thread will be trapped in qemu_wait_io_event(), + * until the vcpu is unhalted. + */ + cpu->exception_index = EXCP_HLT; + return 0; + } + do { int hax_ret; diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 2751c8125c..dc4bb63536 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -605,7 +605,9 @@ static void hvf_store_events(CPUState *cpu, uint32_t ins_len, uint64_t idtvec_in X86CPU *x86_cpu = X86_CPU(cpu); CPUX86State *env = &x86_cpu->env; - env->exception_injected = -1; + env->exception_nr = -1; + env->exception_pending = 0; + env->exception_injected = 0; env->interrupt_injected = -1; env->nmi_injected = false; if (idtvec_info & VMCS_IDT_VEC_VALID) { @@ -619,7 +621,8 @@ static void hvf_store_events(CPUState *cpu, uint32_t ins_len, uint64_t idtvec_in break; case VMCS_IDT_VEC_HWEXCEPTION: case VMCS_IDT_VEC_SWEXCEPTION: - env->exception_injected = idtvec_info & VMCS_IDT_VEC_VECNUM; + env->exception_nr = idtvec_info & VMCS_IDT_VEC_VECNUM; + env->exception_injected = 1; break; case VMCS_IDT_VEC_PRIV_SWEXCEPTION: default: @@ -912,7 +915,8 @@ int hvf_vcpu_exec(CPUState *cpu) macvm_set_rip(cpu, rip + ins_len); break; case VMX_REASON_VMCALL: - env->exception_injected = EXCP0D_GPF; + env->exception_nr = EXCP0D_GPF; + env->exception_injected = 1; env->has_error_code = true; env->error_code = 0; break; diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c index df8e946fbc..e0ea02d631 100644 --- a/target/i386/hvf/x86hvf.c +++ b/target/i386/hvf/x86hvf.c @@ -362,8 +362,8 @@ bool hvf_inject_interrupts(CPUState *cpu_state) if (env->interrupt_injected != -1) { vector = env->interrupt_injected; intr_type = VMCS_INTR_T_SWINTR; - } else if (env->exception_injected != -1) { - vector = env->exception_injected; + } else if (env->exception_nr != -1) { + vector = env->exception_nr; if (vector == EXCP03_INT3 || vector == EXCP04_INTO) { intr_type = VMCS_INTR_T_SWEXCEPTION; } else { diff --git a/target/i386/hyperv-proto.h b/target/i386/hyperv-proto.h index c0272b3a01..cffac10b45 100644 --- a/target/i386/hyperv-proto.h +++ b/target/i386/hyperv-proto.h @@ -49,6 +49,7 @@ #define HV_GUEST_IDLE_STATE_AVAILABLE (1u << 5) #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8) #define HV_GUEST_CRASH_MSR_AVAILABLE (1u << 10) +#define HV_STIMER_DIRECT_MODE_AVAILABLE (1u << 19) /* * HV_CPUID_ENLIGHTMENT_INFO.EAX bits diff --git a/target/i386/hyperv.c b/target/i386/hyperv.c index b264a28620..26efc1e0e6 100644 --- a/target/i386/hyperv.c +++ b/target/i386/hyperv.c @@ -52,7 +52,7 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit) switch (exit->type) { case KVM_EXIT_HYPERV_SYNIC: - if (!cpu->hyperv_synic) { + if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) { return -1; } diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 6899061b4e..e4b4f5756a 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -95,6 +95,7 @@ static bool has_msr_spec_ctrl; static bool has_msr_virt_ssbd; static bool has_msr_smi_count; static bool has_msr_arch_capabs; +static bool has_msr_core_capabs; static uint32_t has_architectural_pmu_version; static uint32_t num_architectural_pmu_gp_counters; @@ -103,6 +104,7 @@ static uint32_t num_architectural_pmu_fixed_counters; static int has_xsave; static int has_xcrs; static int has_pit_state2; +static int has_exception_payload; static bool has_msr_mcg_ext_ctl; @@ -583,15 +585,56 @@ void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr) /* Hope we are lucky for AO MCE */ } +static void kvm_reset_exception(CPUX86State *env) +{ + env->exception_nr = -1; + env->exception_pending = 0; + env->exception_injected = 0; + env->exception_has_payload = false; + env->exception_payload = 0; +} + +static void kvm_queue_exception(CPUX86State *env, + int32_t exception_nr, + uint8_t exception_has_payload, + uint64_t exception_payload) +{ + assert(env->exception_nr == -1); + assert(!env->exception_pending); + assert(!env->exception_injected); + assert(!env->exception_has_payload); + + env->exception_nr = exception_nr; + + if (has_exception_payload) { + env->exception_pending = 1; + + env->exception_has_payload = exception_has_payload; + env->exception_payload = exception_payload; + } else { + env->exception_injected = 1; + + if (exception_nr == EXCP01_DB) { + assert(exception_has_payload); + env->dr[6] = exception_payload; + } else if (exception_nr == EXCP0E_PAGE) { + assert(exception_has_payload); + env->cr[2] = exception_payload; + } else { + assert(!exception_has_payload); + } + } +} + static int kvm_inject_mce_oldstyle(X86CPU *cpu) { CPUX86State *env = &cpu->env; - if (!kvm_has_vcpu_events() && env->exception_injected == EXCP12_MCHK) { + if (!kvm_has_vcpu_events() && env->exception_nr == EXCP12_MCHK) { unsigned int bank, bank_num = env->mcg_cap & 0xff; struct kvm_x86_mce mce; - env->exception_injected = -1; + kvm_reset_exception(env); /* * There must be at least one bank in use if an MCE is pending. @@ -634,28 +677,12 @@ unsigned long kvm_arch_vcpu_id(CPUState *cs) #define KVM_CPUID_SIGNATURE_NEXT 0x40000100 #endif -static bool hyperv_hypercall_available(X86CPU *cpu) -{ - return cpu->hyperv_vapic || - (cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY); -} - static bool hyperv_enabled(X86CPU *cpu) { CPUState *cs = CPU(cpu); return kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV) > 0 && - (hyperv_hypercall_available(cpu) || - cpu->hyperv_time || - cpu->hyperv_relaxed_timing || - cpu->hyperv_crash || - cpu->hyperv_reset || - cpu->hyperv_vpindex || - cpu->hyperv_runtime || - cpu->hyperv_synic || - cpu->hyperv_stimer || - cpu->hyperv_reenlightenment || - cpu->hyperv_tlbflush || - cpu->hyperv_ipi); + ((cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY) || + cpu->hyperv_features || cpu->hyperv_passthrough); } static int kvm_arch_set_tsc_khz(CPUState *cs) @@ -699,164 +726,573 @@ static bool tsc_is_stable_and_known(CPUX86State *env) || env->user_tsc_khz; } -static int hyperv_handle_properties(CPUState *cs) +static struct { + const char *desc; + struct { + uint32_t fw; + uint32_t bits; + } flags[2]; + uint64_t dependencies; +} kvm_hyperv_properties[] = { + [HYPERV_FEAT_RELAXED] = { + .desc = "relaxed timing (hv-relaxed)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_HYPERCALL_AVAILABLE}, + {.fw = FEAT_HV_RECOMM_EAX, + .bits = HV_RELAXED_TIMING_RECOMMENDED} + } + }, + [HYPERV_FEAT_VAPIC] = { + .desc = "virtual APIC (hv-vapic)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_HYPERCALL_AVAILABLE | HV_APIC_ACCESS_AVAILABLE}, + {.fw = FEAT_HV_RECOMM_EAX, + .bits = HV_APIC_ACCESS_RECOMMENDED} + } + }, + [HYPERV_FEAT_TIME] = { + .desc = "clocksources (hv-time)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_HYPERCALL_AVAILABLE | HV_TIME_REF_COUNT_AVAILABLE | + HV_REFERENCE_TSC_AVAILABLE} + } + }, + [HYPERV_FEAT_CRASH] = { + .desc = "crash MSRs (hv-crash)", + .flags = { + {.fw = FEAT_HYPERV_EDX, + .bits = HV_GUEST_CRASH_MSR_AVAILABLE} + } + }, + [HYPERV_FEAT_RESET] = { + .desc = "reset MSR (hv-reset)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_RESET_AVAILABLE} + } + }, + [HYPERV_FEAT_VPINDEX] = { + .desc = "VP_INDEX MSR (hv-vpindex)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_VP_INDEX_AVAILABLE} + } + }, + [HYPERV_FEAT_RUNTIME] = { + .desc = "VP_RUNTIME MSR (hv-runtime)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_VP_RUNTIME_AVAILABLE} + } + }, + [HYPERV_FEAT_SYNIC] = { + .desc = "synthetic interrupt controller (hv-synic)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_SYNIC_AVAILABLE} + } + }, + [HYPERV_FEAT_STIMER] = { + .desc = "synthetic timers (hv-stimer)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_SYNTIMERS_AVAILABLE} + }, + .dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_TIME) + }, + [HYPERV_FEAT_FREQUENCIES] = { + .desc = "frequency MSRs (hv-frequencies)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_ACCESS_FREQUENCY_MSRS}, + {.fw = FEAT_HYPERV_EDX, + .bits = HV_FREQUENCY_MSRS_AVAILABLE} + } + }, + [HYPERV_FEAT_REENLIGHTENMENT] = { + .desc = "reenlightenment MSRs (hv-reenlightenment)", + .flags = { + {.fw = FEAT_HYPERV_EAX, + .bits = HV_ACCESS_REENLIGHTENMENTS_CONTROL} + } + }, + [HYPERV_FEAT_TLBFLUSH] = { + .desc = "paravirtualized TLB flush (hv-tlbflush)", + .flags = { + {.fw = FEAT_HV_RECOMM_EAX, + .bits = HV_REMOTE_TLB_FLUSH_RECOMMENDED | + HV_EX_PROCESSOR_MASKS_RECOMMENDED} + }, + .dependencies = BIT(HYPERV_FEAT_VPINDEX) + }, + [HYPERV_FEAT_EVMCS] = { + .desc = "enlightened VMCS (hv-evmcs)", + .flags = { + {.fw = FEAT_HV_RECOMM_EAX, + .bits = HV_ENLIGHTENED_VMCS_RECOMMENDED} + }, + .dependencies = BIT(HYPERV_FEAT_VAPIC) + }, + [HYPERV_FEAT_IPI] = { + .desc = "paravirtualized IPI (hv-ipi)", + .flags = { + {.fw = FEAT_HV_RECOMM_EAX, + .bits = HV_CLUSTER_IPI_RECOMMENDED | + HV_EX_PROCESSOR_MASKS_RECOMMENDED} + }, + .dependencies = BIT(HYPERV_FEAT_VPINDEX) + }, + [HYPERV_FEAT_STIMER_DIRECT] = { + .desc = "direct mode synthetic timers (hv-stimer-direct)", + .flags = { + {.fw = FEAT_HYPERV_EDX, + .bits = HV_STIMER_DIRECT_MODE_AVAILABLE} + }, + .dependencies = BIT(HYPERV_FEAT_STIMER) + }, +}; + +static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max) +{ + struct kvm_cpuid2 *cpuid; + int r, size; + + size = sizeof(*cpuid) + max * sizeof(*cpuid->entries); + cpuid = g_malloc0(size); + cpuid->nent = max; + + r = kvm_vcpu_ioctl(cs, KVM_GET_SUPPORTED_HV_CPUID, cpuid); + if (r == 0 && cpuid->nent >= max) { + r = -E2BIG; + } + if (r < 0) { + if (r == -E2BIG) { + g_free(cpuid); + return NULL; + } else { + fprintf(stderr, "KVM_GET_SUPPORTED_HV_CPUID failed: %s\n", + strerror(-r)); + exit(1); + } + } + return cpuid; +} + +/* + * Run KVM_GET_SUPPORTED_HV_CPUID ioctl(), allocating a buffer large enough + * for all entries. + */ +static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs) +{ + struct kvm_cpuid2 *cpuid; + int max = 7; /* 0x40000000..0x40000005, 0x4000000A */ + + /* + * When the buffer is too small, KVM_GET_SUPPORTED_HV_CPUID fails with + * -E2BIG, however, it doesn't report back the right size. Keep increasing + * it and re-trying until we succeed. + */ + while ((cpuid = try_get_hv_cpuid(cs, max)) == NULL) { + max++; + } + return cpuid; +} + +/* + * When KVM_GET_SUPPORTED_HV_CPUID is not supported we fill CPUID feature + * leaves from KVM_CAP_HYPERV* and present MSRs data. + */ +static struct kvm_cpuid2 *get_supported_hv_cpuid_legacy(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; + struct kvm_cpuid2 *cpuid; + struct kvm_cpuid_entry2 *entry_feat, *entry_recomm; - if (cpu->hyperv_relaxed_timing) { - env->features[FEAT_HYPERV_EAX] |= HV_HYPERCALL_AVAILABLE; + /* HV_CPUID_FEATURES, HV_CPUID_ENLIGHTMENT_INFO */ + cpuid = g_malloc0(sizeof(*cpuid) + 2 * sizeof(*cpuid->entries)); + cpuid->nent = 2; + + /* HV_CPUID_VENDOR_AND_MAX_FUNCTIONS */ + entry_feat = &cpuid->entries[0]; + entry_feat->function = HV_CPUID_FEATURES; + + entry_recomm = &cpuid->entries[1]; + entry_recomm->function = HV_CPUID_ENLIGHTMENT_INFO; + entry_recomm->ebx = cpu->hyperv_spinlock_attempts; + + if (kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV) > 0) { + entry_feat->eax |= HV_HYPERCALL_AVAILABLE; + entry_feat->eax |= HV_APIC_ACCESS_AVAILABLE; + entry_feat->edx |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE; + entry_recomm->eax |= HV_RELAXED_TIMING_RECOMMENDED; + entry_recomm->eax |= HV_APIC_ACCESS_RECOMMENDED; } - if (cpu->hyperv_vapic) { - env->features[FEAT_HYPERV_EAX] |= HV_HYPERCALL_AVAILABLE; - env->features[FEAT_HYPERV_EAX] |= HV_APIC_ACCESS_AVAILABLE; + + if (kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) { + entry_feat->eax |= HV_TIME_REF_COUNT_AVAILABLE; + entry_feat->eax |= HV_REFERENCE_TSC_AVAILABLE; } - if (cpu->hyperv_time) { - if (kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) <= 0) { - fprintf(stderr, "Hyper-V clocksources " - "(requested by 'hv-time' cpu flag) " - "are not supported by kernel\n"); - return -ENOSYS; - } - env->features[FEAT_HYPERV_EAX] |= HV_HYPERCALL_AVAILABLE; - env->features[FEAT_HYPERV_EAX] |= HV_TIME_REF_COUNT_AVAILABLE; - env->features[FEAT_HYPERV_EAX] |= HV_REFERENCE_TSC_AVAILABLE; + + if (has_msr_hv_frequencies) { + entry_feat->eax |= HV_ACCESS_FREQUENCY_MSRS; + entry_feat->edx |= HV_FREQUENCY_MSRS_AVAILABLE; } - if (cpu->hyperv_frequencies) { - if (!has_msr_hv_frequencies) { - fprintf(stderr, "Hyper-V frequency MSRs " - "(requested by 'hv-frequencies' cpu flag) " - "are not supported by kernel\n"); - return -ENOSYS; - } - env->features[FEAT_HYPERV_EAX] |= HV_ACCESS_FREQUENCY_MSRS; - env->features[FEAT_HYPERV_EDX] |= HV_FREQUENCY_MSRS_AVAILABLE; + + if (has_msr_hv_crash) { + entry_feat->edx |= HV_GUEST_CRASH_MSR_AVAILABLE; } - if (cpu->hyperv_crash) { - if (!has_msr_hv_crash) { - fprintf(stderr, "Hyper-V crash MSRs " - "(requested by 'hv-crash' cpu flag) " - "are not supported by kernel\n"); - return -ENOSYS; - } - env->features[FEAT_HYPERV_EDX] |= HV_GUEST_CRASH_MSR_AVAILABLE; + + if (has_msr_hv_reenlightenment) { + entry_feat->eax |= HV_ACCESS_REENLIGHTENMENTS_CONTROL; } - if (cpu->hyperv_reenlightenment) { - if (!has_msr_hv_reenlightenment) { - fprintf(stderr, - "Hyper-V Reenlightenment MSRs " - "(requested by 'hv-reenlightenment' cpu flag) " - "are not supported by kernel\n"); - return -ENOSYS; - } - env->features[FEAT_HYPERV_EAX] |= HV_ACCESS_REENLIGHTENMENTS_CONTROL; + + if (has_msr_hv_reset) { + entry_feat->eax |= HV_RESET_AVAILABLE; } - env->features[FEAT_HYPERV_EDX] |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE; - if (cpu->hyperv_reset) { - if (!has_msr_hv_reset) { - fprintf(stderr, "Hyper-V reset MSR " - "(requested by 'hv-reset' cpu flag) " - "is not supported by kernel\n"); - return -ENOSYS; - } - env->features[FEAT_HYPERV_EAX] |= HV_RESET_AVAILABLE; + + if (has_msr_hv_vpindex) { + entry_feat->eax |= HV_VP_INDEX_AVAILABLE; } - if (cpu->hyperv_vpindex) { - if (!has_msr_hv_vpindex) { - fprintf(stderr, "Hyper-V VP_INDEX MSR " - "(requested by 'hv-vpindex' cpu flag) " - "is not supported by kernel\n"); - return -ENOSYS; + + if (has_msr_hv_runtime) { + entry_feat->eax |= HV_VP_RUNTIME_AVAILABLE; + } + + if (has_msr_hv_synic) { + unsigned int cap = cpu->hyperv_synic_kvm_only ? + KVM_CAP_HYPERV_SYNIC : KVM_CAP_HYPERV_SYNIC2; + + if (kvm_check_extension(cs->kvm_state, cap) > 0) { + entry_feat->eax |= HV_SYNIC_AVAILABLE; } - env->features[FEAT_HYPERV_EAX] |= HV_VP_INDEX_AVAILABLE; } - if (cpu->hyperv_runtime) { - if (!has_msr_hv_runtime) { - fprintf(stderr, "Hyper-V VP_RUNTIME MSR " - "(requested by 'hv-runtime' cpu flag) " - "is not supported by kernel\n"); - return -ENOSYS; + + if (has_msr_hv_stimer) { + entry_feat->eax |= HV_SYNTIMERS_AVAILABLE; + } + + if (kvm_check_extension(cs->kvm_state, + KVM_CAP_HYPERV_TLBFLUSH) > 0) { + entry_recomm->eax |= HV_REMOTE_TLB_FLUSH_RECOMMENDED; + entry_recomm->eax |= HV_EX_PROCESSOR_MASKS_RECOMMENDED; + } + + if (kvm_check_extension(cs->kvm_state, + KVM_CAP_HYPERV_ENLIGHTENED_VMCS) > 0) { + entry_recomm->eax |= HV_ENLIGHTENED_VMCS_RECOMMENDED; + } + + if (kvm_check_extension(cs->kvm_state, + KVM_CAP_HYPERV_SEND_IPI) > 0) { + entry_recomm->eax |= HV_CLUSTER_IPI_RECOMMENDED; + entry_recomm->eax |= HV_EX_PROCESSOR_MASKS_RECOMMENDED; + } + + return cpuid; +} + +static int hv_cpuid_get_fw(struct kvm_cpuid2 *cpuid, int fw, uint32_t *r) +{ + struct kvm_cpuid_entry2 *entry; + uint32_t func; + int reg; + + switch (fw) { + case FEAT_HYPERV_EAX: + reg = R_EAX; + func = HV_CPUID_FEATURES; + break; + case FEAT_HYPERV_EDX: + reg = R_EDX; + func = HV_CPUID_FEATURES; + break; + case FEAT_HV_RECOMM_EAX: + reg = R_EAX; + func = HV_CPUID_ENLIGHTMENT_INFO; + break; + default: + return -EINVAL; + } + + entry = cpuid_find_entry(cpuid, func, 0); + if (!entry) { + return -ENOENT; + } + + switch (reg) { + case R_EAX: + *r = entry->eax; + break; + case R_EDX: + *r = entry->edx; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid, + int feature) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + uint32_t r, fw, bits; + uint64_t deps; + int i, dep_feat = 0; + + if (!hyperv_feat_enabled(cpu, feature) && !cpu->hyperv_passthrough) { + return 0; + } + + deps = kvm_hyperv_properties[feature].dependencies; + while ((dep_feat = find_next_bit(&deps, 64, dep_feat)) < 64) { + if (!(hyperv_feat_enabled(cpu, dep_feat))) { + fprintf(stderr, + "Hyper-V %s requires Hyper-V %s\n", + kvm_hyperv_properties[feature].desc, + kvm_hyperv_properties[dep_feat].desc); + return 1; } - env->features[FEAT_HYPERV_EAX] |= HV_VP_RUNTIME_AVAILABLE; + dep_feat++; } - if (cpu->hyperv_synic) { - unsigned int cap = KVM_CAP_HYPERV_SYNIC; - if (!cpu->hyperv_synic_kvm_only) { - if (!cpu->hyperv_vpindex) { - fprintf(stderr, "Hyper-V SynIC " - "(requested by 'hv-synic' cpu flag) " - "requires Hyper-V VP_INDEX ('hv-vpindex')\n"); - return -ENOSYS; - } - cap = KVM_CAP_HYPERV_SYNIC2; + + for (i = 0; i < ARRAY_SIZE(kvm_hyperv_properties[feature].flags); i++) { + fw = kvm_hyperv_properties[feature].flags[i].fw; + bits = kvm_hyperv_properties[feature].flags[i].bits; + + if (!fw) { + continue; } - if (!has_msr_hv_synic || !kvm_check_extension(cs->kvm_state, cap)) { - fprintf(stderr, "Hyper-V SynIC (requested by 'hv-synic' cpu flag) " - "is not supported by kernel\n"); - return -ENOSYS; + if (hv_cpuid_get_fw(cpuid, fw, &r) || (r & bits) != bits) { + if (hyperv_feat_enabled(cpu, feature)) { + fprintf(stderr, + "Hyper-V %s is not supported by kernel\n", + kvm_hyperv_properties[feature].desc); + return 1; + } else { + return 0; + } } - env->features[FEAT_HYPERV_EAX] |= HV_SYNIC_AVAILABLE; + env->features[fw] |= bits; } - if (cpu->hyperv_stimer) { - if (!has_msr_hv_stimer) { - fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); + + if (cpu->hyperv_passthrough) { + cpu->hyperv_features |= BIT(feature); + } + + return 0; +} + +/* + * Fill in Hyper-V CPUIDs. Returns the number of entries filled in cpuid_ent in + * case of success, errno < 0 in case of failure and 0 when no Hyper-V + * extentions are enabled. + */ +static int hyperv_handle_properties(CPUState *cs, + struct kvm_cpuid_entry2 *cpuid_ent) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + struct kvm_cpuid2 *cpuid; + struct kvm_cpuid_entry2 *c; + uint32_t signature[3]; + uint32_t cpuid_i = 0; + int r; + + if (!hyperv_enabled(cpu)) + return 0; + + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) || + cpu->hyperv_passthrough) { + uint16_t evmcs_version; + + r = kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, 0, + (uintptr_t)&evmcs_version); + + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) && r) { + fprintf(stderr, "Hyper-V %s is not supported by kernel\n", + kvm_hyperv_properties[HYPERV_FEAT_EVMCS].desc); return -ENOSYS; } - env->features[FEAT_HYPERV_EAX] |= HV_SYNTIMERS_AVAILABLE; - } - if (cpu->hyperv_relaxed_timing) { - env->features[FEAT_HV_RECOMM_EAX] |= HV_RELAXED_TIMING_RECOMMENDED; + + if (!r) { + env->features[FEAT_HV_RECOMM_EAX] |= + HV_ENLIGHTENED_VMCS_RECOMMENDED; + env->features[FEAT_HV_NESTED_EAX] = evmcs_version; + } } - if (cpu->hyperv_vapic) { - env->features[FEAT_HV_RECOMM_EAX] |= HV_APIC_ACCESS_RECOMMENDED; + + if (kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_CPUID) > 0) { + cpuid = get_supported_hv_cpuid(cs); + } else { + cpuid = get_supported_hv_cpuid_legacy(cs); } - if (cpu->hyperv_tlbflush) { - if (kvm_check_extension(cs->kvm_state, - KVM_CAP_HYPERV_TLBFLUSH) <= 0) { - fprintf(stderr, "Hyper-V TLB flush support " - "(requested by 'hv-tlbflush' cpu flag) " - " is not supported by kernel\n"); - return -ENOSYS; + + if (cpu->hyperv_passthrough) { + memcpy(cpuid_ent, &cpuid->entries[0], + cpuid->nent * sizeof(cpuid->entries[0])); + + c = cpuid_find_entry(cpuid, HV_CPUID_FEATURES, 0); + if (c) { + env->features[FEAT_HYPERV_EAX] = c->eax; + env->features[FEAT_HYPERV_EBX] = c->ebx; + env->features[FEAT_HYPERV_EDX] = c->eax; } - env->features[FEAT_HV_RECOMM_EAX] |= HV_REMOTE_TLB_FLUSH_RECOMMENDED; - env->features[FEAT_HV_RECOMM_EAX] |= HV_EX_PROCESSOR_MASKS_RECOMMENDED; - } - if (cpu->hyperv_ipi) { - if (kvm_check_extension(cs->kvm_state, - KVM_CAP_HYPERV_SEND_IPI) <= 0) { - fprintf(stderr, "Hyper-V IPI send support " - "(requested by 'hv-ipi' cpu flag) " - " is not supported by kernel\n"); - return -ENOSYS; + c = cpuid_find_entry(cpuid, HV_CPUID_ENLIGHTMENT_INFO, 0); + if (c) { + env->features[FEAT_HV_RECOMM_EAX] = c->eax; + + /* hv-spinlocks may have been overriden */ + if (cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY) { + c->ebx = cpu->hyperv_spinlock_attempts; + } + } + c = cpuid_find_entry(cpuid, HV_CPUID_NESTED_FEATURES, 0); + if (c) { + env->features[FEAT_HV_NESTED_EAX] = c->eax; } - env->features[FEAT_HV_RECOMM_EAX] |= HV_CLUSTER_IPI_RECOMMENDED; - env->features[FEAT_HV_RECOMM_EAX] |= HV_EX_PROCESSOR_MASKS_RECOMMENDED; } - if (cpu->hyperv_evmcs) { - uint16_t evmcs_version; - if (kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, 0, - (uintptr_t)&evmcs_version)) { - fprintf(stderr, "Hyper-V Enlightened VMCS " - "(requested by 'hv-evmcs' cpu flag) " - "is not supported by kernel\n"); - return -ENOSYS; + /* Features */ + r = hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_RELAXED); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_VAPIC); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_TIME); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_CRASH); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_RESET); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_VPINDEX); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_RUNTIME); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_SYNIC); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_STIMER); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_FREQUENCIES); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_REENLIGHTENMENT); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_TLBFLUSH); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_EVMCS); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_IPI); + r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_STIMER_DIRECT); + + /* Additional dependencies not covered by kvm_hyperv_properties[] */ + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC) && + !cpu->hyperv_synic_kvm_only && + !hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX)) { + fprintf(stderr, "Hyper-V %s requires Hyper-V %s\n", + kvm_hyperv_properties[HYPERV_FEAT_SYNIC].desc, + kvm_hyperv_properties[HYPERV_FEAT_VPINDEX].desc); + r |= 1; + } + + /* Not exposed by KVM but needed to make CPU hotplug in Windows work */ + env->features[FEAT_HYPERV_EDX] |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE; + + if (r) { + r = -ENOSYS; + goto free; + } + + if (cpu->hyperv_passthrough) { + /* We already copied all feature words from KVM as is */ + r = cpuid->nent; + goto free; + } + + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_VENDOR_AND_MAX_FUNCTIONS; + if (!cpu->hyperv_vendor_id) { + memcpy(signature, "Microsoft Hv", 12); + } else { + size_t len = strlen(cpu->hyperv_vendor_id); + + if (len > 12) { + error_report("hv-vendor-id truncated to 12 characters"); + len = 12; + } + memset(signature, 0, 12); + memcpy(signature, cpu->hyperv_vendor_id, len); + } + c->eax = hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) ? + HV_CPUID_NESTED_FEATURES : HV_CPUID_IMPLEMENT_LIMITS; + c->ebx = signature[0]; + c->ecx = signature[1]; + c->edx = signature[2]; + + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_INTERFACE; + memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12); + c->eax = signature[0]; + c->ebx = 0; + c->ecx = 0; + c->edx = 0; + + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_VERSION; + c->eax = 0x00001bbc; + c->ebx = 0x00060001; + + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_FEATURES; + c->eax = env->features[FEAT_HYPERV_EAX]; + c->ebx = env->features[FEAT_HYPERV_EBX]; + c->edx = env->features[FEAT_HYPERV_EDX]; + + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_ENLIGHTMENT_INFO; + c->eax = env->features[FEAT_HV_RECOMM_EAX]; + c->ebx = cpu->hyperv_spinlock_attempts; + + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_IMPLEMENT_LIMITS; + c->eax = cpu->hv_max_vps; + c->ebx = 0x40; + + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { + __u32 function; + + /* Create zeroed 0x40000006..0x40000009 leaves */ + for (function = HV_CPUID_IMPLEMENT_LIMITS + 1; + function < HV_CPUID_NESTED_FEATURES; function++) { + c = &cpuid_ent[cpuid_i++]; + c->function = function; } - env->features[FEAT_HV_RECOMM_EAX] |= HV_ENLIGHTENED_VMCS_RECOMMENDED; - env->features[FEAT_HV_NESTED_EAX] = evmcs_version; + + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_NESTED_FEATURES; + c->eax = env->features[FEAT_HV_NESTED_EAX]; } + r = cpuid_i; - return 0; +free: + g_free(cpuid); + + return r; } +static Error *hv_passthrough_mig_blocker; + static int hyperv_init_vcpu(X86CPU *cpu) { CPUState *cs = CPU(cpu); + Error *local_err = NULL; int ret; - if (cpu->hyperv_vpindex && !hv_vpindex_settable) { + if (cpu->hyperv_passthrough && hv_passthrough_mig_blocker == NULL) { + error_setg(&hv_passthrough_mig_blocker, + "'hv-passthrough' CPU flag prevents migration, use explicit" + " set of hv-* flags instead"); + ret = migrate_add_blocker(hv_passthrough_mig_blocker, &local_err); + if (local_err) { + error_report_err(local_err); + error_free(hv_passthrough_mig_blocker); + return ret; + } + } + + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) && !hv_vpindex_settable) { /* * the kernel doesn't support setting vp_index; assert that its value * is in sync @@ -881,7 +1317,7 @@ static int hyperv_init_vcpu(X86CPU *cpu) } } - if (cpu->hyperv_synic) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) { uint32_t synic_cap = cpu->hyperv_synic_kvm_only ? KVM_CAP_HYPERV_SYNIC : KVM_CAP_HYPERV_SYNIC2; ret = kvm_vcpu_enable_cap(cs, synic_cap, 0); @@ -905,7 +1341,7 @@ static int hyperv_init_vcpu(X86CPU *cpu) } static Error *invtsc_mig_blocker; -static Error *vmx_mig_blocker; +static Error *nested_virt_mig_blocker; #define KVM_MAX_CPUID_ENTRIES 100 @@ -930,6 +1366,7 @@ int kvm_arch_init_vcpu(CPUState *cs) struct kvm_cpuid_entry2 *c; uint32_t signature[3]; int kvm_base = KVM_CPUID_SIGNATURE; + int max_nested_state_len; int r; Error *local_err = NULL; @@ -939,7 +1376,7 @@ int kvm_arch_init_vcpu(CPUState *cs) r = kvm_arch_set_tsc_khz(cs); if (r < 0) { - goto fail; + return r; } /* vcpu's TSC frequency is either specified by user, or following @@ -957,79 +1394,13 @@ int kvm_arch_init_vcpu(CPUState *cs) } /* Paravirtualization CPUIDs */ - if (hyperv_enabled(cpu)) { - c = &cpuid_data.entries[cpuid_i++]; - c->function = HV_CPUID_VENDOR_AND_MAX_FUNCTIONS; - if (!cpu->hyperv_vendor_id) { - memcpy(signature, "Microsoft Hv", 12); - } else { - size_t len = strlen(cpu->hyperv_vendor_id); - - if (len > 12) { - error_report("hv-vendor-id truncated to 12 characters"); - len = 12; - } - memset(signature, 0, 12); - memcpy(signature, cpu->hyperv_vendor_id, len); - } - c->eax = cpu->hyperv_evmcs ? - HV_CPUID_NESTED_FEATURES : HV_CPUID_IMPLEMENT_LIMITS; - c->ebx = signature[0]; - c->ecx = signature[1]; - c->edx = signature[2]; - - c = &cpuid_data.entries[cpuid_i++]; - c->function = HV_CPUID_INTERFACE; - memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12); - c->eax = signature[0]; - c->ebx = 0; - c->ecx = 0; - c->edx = 0; - - c = &cpuid_data.entries[cpuid_i++]; - c->function = HV_CPUID_VERSION; - c->eax = 0x00001bbc; - c->ebx = 0x00060001; - - c = &cpuid_data.entries[cpuid_i++]; - c->function = HV_CPUID_FEATURES; - r = hyperv_handle_properties(cs); - if (r) { - return r; - } - c->eax = env->features[FEAT_HYPERV_EAX]; - c->ebx = env->features[FEAT_HYPERV_EBX]; - c->edx = env->features[FEAT_HYPERV_EDX]; - - c = &cpuid_data.entries[cpuid_i++]; - c->function = HV_CPUID_ENLIGHTMENT_INFO; - - c->eax = env->features[FEAT_HV_RECOMM_EAX]; - c->ebx = cpu->hyperv_spinlock_attempts; - - c = &cpuid_data.entries[cpuid_i++]; - c->function = HV_CPUID_IMPLEMENT_LIMITS; - - c->eax = cpu->hv_max_vps; - c->ebx = 0x40; - + r = hyperv_handle_properties(cs, cpuid_data.entries); + if (r < 0) { + return r; + } else if (r > 0) { + cpuid_i = r; kvm_base = KVM_CPUID_SIGNATURE_NEXT; has_msr_hv_hypercall = true; - - if (cpu->hyperv_evmcs) { - __u32 function; - - /* Create zeroed 0x40000006..0x40000009 leaves */ - for (function = HV_CPUID_IMPLEMENT_LIMITS + 1; - function < HV_CPUID_NESTED_FEATURES; function++) { - c = &cpuid_data.entries[cpuid_i++]; - c->function = function; - } - - c = &cpuid_data.entries[cpuid_i++]; - c->function = HV_CPUID_NESTED_FEATURES; - c->eax = env->features[FEAT_HV_NESTED_EAX]; - } } if (cpu->expose_kvm) { @@ -1269,13 +1640,18 @@ int kvm_arch_init_vcpu(CPUState *cs) !!(c->ecx & CPUID_EXT_SMX); } - if ((env->features[FEAT_1_ECX] & CPUID_EXT_VMX) && !vmx_mig_blocker) { - error_setg(&vmx_mig_blocker, - "Nested VMX virtualization does not support live migration yet"); - r = migrate_add_blocker(vmx_mig_blocker, &local_err); + if (cpu_has_vmx(env) && !nested_virt_mig_blocker && + ((kvm_max_nested_state_length() <= 0) || !has_exception_payload)) { + error_setg(&nested_virt_mig_blocker, + "Kernel do not provide required capabilities for " + "nested virtualization migration. " + "(CAP_NESTED_STATE=%d, CAP_EXCEPTION_PAYLOAD=%d)", + kvm_max_nested_state_length() > 0, + has_exception_payload); + r = migrate_add_blocker(nested_virt_mig_blocker, &local_err); if (local_err) { error_report_err(local_err); - error_free(vmx_mig_blocker); + error_free(nested_virt_mig_blocker); return r; } } @@ -1294,7 +1670,7 @@ int kvm_arch_init_vcpu(CPUState *cs) if (local_err) { error_report_err(local_err); error_free(invtsc_mig_blocker); - return r; + goto fail2; } } } @@ -1330,6 +1706,24 @@ int kvm_arch_init_vcpu(CPUState *cs) if (has_xsave) { env->xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave)); } + + max_nested_state_len = kvm_max_nested_state_length(); + if (max_nested_state_len > 0) { + assert(max_nested_state_len >= offsetof(struct kvm_nested_state, data)); + env->nested_state = g_malloc0(max_nested_state_len); + + env->nested_state->size = max_nested_state_len; + + if (IS_INTEL_CPU(env)) { + struct kvm_vmx_nested_state_hdr *vmx_hdr = + &env->nested_state->hdr.vmx; + + env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX; + vmx_hdr->vmxon_pa = -1ull; + vmx_hdr->vmcs12_pa = -1ull; + } + } + cpu->kvm_msr_buf = g_malloc0(MSR_BUF_SIZE); if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_RDTSCP)) { @@ -1345,9 +1739,30 @@ int kvm_arch_init_vcpu(CPUState *cs) fail: migrate_del_blocker(invtsc_mig_blocker); + fail2: + migrate_del_blocker(nested_virt_mig_blocker); + return r; } +int kvm_arch_destroy_vcpu(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + if (cpu->kvm_msr_buf) { + g_free(cpu->kvm_msr_buf); + cpu->kvm_msr_buf = NULL; + } + + if (env->nested_state) { + g_free(env->nested_state); + env->nested_state = NULL; + } + + return 0; +} + void kvm_arch_reset_vcpu(X86CPU *cpu) { CPUX86State *env = &cpu->env; @@ -1360,7 +1775,7 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) env->mp_state = KVM_MP_STATE_RUNNABLE; } - if (cpu->hyperv_synic) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) { int i; for (i = 0; i < ARRAY_SIZE(env->msr_hv_synic_sint); i++) { env->msr_hv_synic_sint[i] = HV_SINT_MASKED; @@ -1515,6 +1930,9 @@ static int kvm_get_supported_msrs(KVMState *s) case MSR_IA32_ARCH_CAPABILITIES: has_msr_arch_capabs = true; break; + case MSR_IA32_CORE_CAPABILITY: + has_msr_core_capabs = true; + break; } } } @@ -1572,6 +1990,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s) hv_vpindex_settable = kvm_check_extension(s, KVM_CAP_HYPERV_VP_INDEX); + has_exception_payload = kvm_check_extension(s, KVM_CAP_EXCEPTION_PAYLOAD); + if (has_exception_payload) { + ret = kvm_vm_enable_cap(s, KVM_CAP_EXCEPTION_PAYLOAD, 0, true); + if (ret < 0) { + error_report("kvm: Failed to enable exception payload cap: %s", + strerror(-ret)); + return ret; + } + } + ret = kvm_get_supported_msrs(s); if (ret < 0) { return ret; @@ -2041,6 +2469,11 @@ static int kvm_put_msrs(X86CPU *cpu, int level) env->features[FEAT_ARCH_CAPABILITIES]); } + if (has_msr_core_capabs) { + kvm_msr_entry_add(cpu, MSR_IA32_CORE_CAPABILITY, + env->features[FEAT_CORE_CAPABILITY]); + } + /* * The following MSRs have side effects on the guest or are too heavy * for normal writeback. Limit them to reset or full state updates. @@ -2100,11 +2533,11 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_add(cpu, HV_X64_MSR_HYPERCALL, env->msr_hv_hypercall); } - if (cpu->hyperv_time) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_TIME)) { kvm_msr_entry_add(cpu, HV_X64_MSR_REFERENCE_TSC, env->msr_hv_tsc); } - if (cpu->hyperv_reenlightenment) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_REENLIGHTENMENT)) { kvm_msr_entry_add(cpu, HV_X64_MSR_REENLIGHTENMENT_CONTROL, env->msr_hv_reenlightenment_control); kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_CONTROL, @@ -2113,7 +2546,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level) env->msr_hv_tsc_emulation_status); } } - if (cpu->hyperv_vapic) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VAPIC)) { kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE, env->msr_hv_vapic); } @@ -2129,11 +2562,12 @@ static int kvm_put_msrs(X86CPU *cpu, int level) if (has_msr_hv_runtime) { kvm_msr_entry_add(cpu, HV_X64_MSR_VP_RUNTIME, env->msr_hv_runtime); } - if (cpu->hyperv_vpindex && hv_vpindex_settable) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) + && hv_vpindex_settable) { kvm_msr_entry_add(cpu, HV_X64_MSR_VP_INDEX, hyperv_vp_index(CPU(cpu))); } - if (cpu->hyperv_synic) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) { int j; kvm_msr_entry_add(cpu, HV_X64_MSR_SVERSION, HV_SYNIC_VERSION); @@ -2473,13 +2907,13 @@ static int kvm_get_msrs(X86CPU *cpu) kvm_msr_entry_add(cpu, HV_X64_MSR_HYPERCALL, 0); kvm_msr_entry_add(cpu, HV_X64_MSR_GUEST_OS_ID, 0); } - if (cpu->hyperv_vapic) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VAPIC)) { kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE, 0); } - if (cpu->hyperv_time) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_TIME)) { kvm_msr_entry_add(cpu, HV_X64_MSR_REFERENCE_TSC, 0); } - if (cpu->hyperv_reenlightenment) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_REENLIGHTENMENT)) { kvm_msr_entry_add(cpu, HV_X64_MSR_REENLIGHTENMENT_CONTROL, 0); kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_CONTROL, 0); kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_STATUS, 0); @@ -2494,7 +2928,7 @@ static int kvm_get_msrs(X86CPU *cpu) if (has_msr_hv_runtime) { kvm_msr_entry_add(cpu, HV_X64_MSR_VP_RUNTIME, 0); } - if (cpu->hyperv_synic) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) { uint32_t msr; kvm_msr_entry_add(cpu, HV_X64_MSR_SCONTROL, 0); @@ -2876,8 +3310,16 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) return 0; } - events.exception.injected = (env->exception_injected >= 0); - events.exception.nr = env->exception_injected; + events.flags = 0; + + if (has_exception_payload) { + events.flags |= KVM_VCPUEVENT_VALID_PAYLOAD; + events.exception.pending = env->exception_pending; + events.exception_has_payload = env->exception_has_payload; + events.exception_payload = env->exception_payload; + } + events.exception.nr = env->exception_nr; + events.exception.injected = env->exception_injected; events.exception.has_error_code = env->has_error_code; events.exception.error_code = env->error_code; @@ -2890,7 +3332,6 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) events.nmi.masked = !!(env->hflags2 & HF2_NMI_MASK); events.sipi_vector = env->sipi_vector; - events.flags = 0; if (has_msr_smbase) { events.smi.smm = !!(env->hflags & HF_SMM_MASK); @@ -2940,8 +3381,19 @@ static int kvm_get_vcpu_events(X86CPU *cpu) if (ret < 0) { return ret; } - env->exception_injected = - events.exception.injected ? events.exception.nr : -1; + + if (events.flags & KVM_VCPUEVENT_VALID_PAYLOAD) { + env->exception_pending = events.exception.pending; + env->exception_has_payload = events.exception_has_payload; + env->exception_payload = events.exception_payload; + } else { + env->exception_pending = 0; + env->exception_has_payload = false; + } + env->exception_injected = events.exception.injected; + env->exception_nr = + (env->exception_pending || env->exception_injected) ? + events.exception.nr : -1; env->has_error_code = events.exception.has_error_code; env->error_code = events.exception.error_code; @@ -2993,12 +3445,12 @@ static int kvm_guest_debug_workarounds(X86CPU *cpu) unsigned long reinject_trap = 0; if (!kvm_has_vcpu_events()) { - if (env->exception_injected == 1) { + if (env->exception_nr == EXCP01_DB) { reinject_trap = KVM_GUESTDBG_INJECT_DB; - } else if (env->exception_injected == 3) { + } else if (env->exception_injected == EXCP03_INT3) { reinject_trap = KVM_GUESTDBG_INJECT_BP; } - env->exception_injected = -1; + kvm_reset_exception(env); } /* @@ -3059,6 +3511,52 @@ static int kvm_get_debugregs(X86CPU *cpu) return 0; } +static int kvm_put_nested_state(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + int max_nested_state_len = kvm_max_nested_state_length(); + + if (max_nested_state_len <= 0) { + return 0; + } + + assert(env->nested_state->size <= max_nested_state_len); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_NESTED_STATE, env->nested_state); +} + +static int kvm_get_nested_state(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + int max_nested_state_len = kvm_max_nested_state_length(); + int ret; + + if (max_nested_state_len <= 0) { + return 0; + } + + /* + * It is possible that migration restored a smaller size into + * nested_state->hdr.size than what our kernel support. + * We preserve migration origin nested_state->hdr.size for + * call to KVM_SET_NESTED_STATE but wish that our next call + * to KVM_GET_NESTED_STATE will use max size our kernel support. + */ + env->nested_state->size = max_nested_state_len; + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_NESTED_STATE, env->nested_state); + if (ret < 0) { + return ret; + } + + if (env->nested_state->flags & KVM_STATE_NESTED_GUEST_MODE) { + env->hflags |= HF_GUEST_MASK; + } else { + env->hflags &= ~HF_GUEST_MASK; + } + + return ret; +} + int kvm_arch_put_registers(CPUState *cpu, int level) { X86CPU *x86_cpu = X86_CPU(cpu); @@ -3066,6 +3564,11 @@ int kvm_arch_put_registers(CPUState *cpu, int level) assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); + ret = kvm_put_nested_state(x86_cpu); + if (ret < 0) { + return ret; + } + if (level >= KVM_PUT_RESET_STATE) { ret = kvm_put_msr_feature_control(x86_cpu); if (ret < 0) { @@ -3181,6 +3684,10 @@ int kvm_arch_get_registers(CPUState *cs) if (ret < 0) { goto out; } + ret = kvm_get_nested_state(cpu); + if (ret < 0) { + goto out; + } ret = 0; out: cpu_sync_bndcs_hflags(&cpu->env); @@ -3319,13 +3826,13 @@ int kvm_arch_process_async_events(CPUState *cs) kvm_cpu_synchronize_state(cs); - if (env->exception_injected == EXCP08_DBLE) { + if (env->exception_nr == EXCP08_DBLE) { /* this means triple fault */ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); cs->exit_request = 1; return 0; } - env->exception_injected = EXCP12_MCHK; + kvm_queue_exception(env, EXCP12_MCHK, 0, 0); env->has_error_code = 0; cs->halted = 0; @@ -3507,8 +4014,8 @@ static int kvm_handle_debug(X86CPU *cpu, int ret = 0; int n; - if (arch_info->exception == 1) { - if (arch_info->dr6 & (1 << 14)) { + if (arch_info->exception == EXCP01_DB) { + if (arch_info->dr6 & DR6_BS) { if (cs->singlestep_enabled) { ret = EXCP_DEBUG; } @@ -3540,10 +4047,12 @@ static int kvm_handle_debug(X86CPU *cpu, } if (ret == 0) { cpu_synchronize_state(cs); - assert(env->exception_injected == -1); + assert(env->exception_nr == -1); /* pass to guest */ - env->exception_injected = arch_info->exception; + kvm_queue_exception(env, arch_info->exception, + arch_info->exception == EXCP01_DB, + arch_info->dr6); env->has_error_code = 0; } diff --git a/target/i386/machine.c b/target/i386/machine.c index 4aff1a763f..851b249d1a 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -231,6 +231,50 @@ static int cpu_pre_save(void *opaque) env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK); } +#ifdef CONFIG_KVM + /* Verify we have nested virtualization state from kernel if required */ + if (kvm_enabled() && cpu_has_vmx(env) && !env->nested_state) { + error_report("Guest enabled nested virtualization but kernel " + "does not support saving of nested state"); + return -EINVAL; + } +#endif + + /* + * When vCPU is running L2 and exception is still pending, + * it can potentially be intercepted by L1 hypervisor. + * In contrast to an injected exception which cannot be + * intercepted anymore. + * + * Furthermore, when a L2 exception is intercepted by L1 + * hypervisor, it's exception payload (CR2/DR6 on #PF/#DB) + * should not be set yet in the respective vCPU register. + * Thus, in case an exception is pending, it is + * important to save the exception payload seperately. + * + * Therefore, if an exception is not in a pending state + * or vCPU is not in guest-mode, it is not important to + * distinguish between a pending and injected exception + * and we don't need to store seperately the exception payload. + * + * In order to preserve better backwards-compatabile migration, + * convert a pending exception to an injected exception in + * case it is not important to distingiush between them + * as described above. + */ + if (env->exception_pending && !(env->hflags & HF_GUEST_MASK)) { + env->exception_pending = 0; + env->exception_injected = 1; + + if (env->exception_has_payload) { + if (env->exception_nr == EXCP01_DB) { + env->dr[6] = env->exception_payload; + } else if (env->exception_nr == EXCP0E_PAGE) { + env->cr[2] = env->exception_payload; + } + } + } + return 0; } @@ -278,6 +322,33 @@ static int cpu_post_load(void *opaque, int version_id) env->hflags &= ~HF_CPL_MASK; env->hflags |= (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK; +#ifdef CONFIG_KVM + if ((env->hflags & HF_GUEST_MASK) && + (!env->nested_state || + !(env->nested_state->flags & KVM_STATE_NESTED_GUEST_MODE))) { + error_report("vCPU set in guest-mode inconsistent with " + "migrated kernel nested state"); + return -EINVAL; + } +#endif + + /* + * There are cases that we can get valid exception_nr with both + * exception_pending and exception_injected being cleared. + * This can happen in one of the following scenarios: + * 1) Source is older QEMU without KVM_CAP_EXCEPTION_PAYLOAD support. + * 2) Source is running on kernel without KVM_CAP_EXCEPTION_PAYLOAD support. + * 3) "cpu/exception_info" subsection not sent because there is no exception + * pending or guest wasn't running L2 (See comment in cpu_pre_save()). + * + * In those cases, we can just deduce that a valid exception_nr means + * we can treat the exception as already injected. + */ + if ((env->exception_nr != -1) && + !env->exception_pending && !env->exception_injected) { + env->exception_injected = 1; + } + env->fpstt = (env->fpus_vmstate >> 11) & 7; env->fpus = env->fpus_vmstate & ~0x3800; env->fptag_vmstate ^= 0xff; @@ -323,6 +394,35 @@ static bool steal_time_msr_needed(void *opaque) return cpu->env.steal_time_msr != 0; } +static bool exception_info_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + /* + * It is important to save exception-info only in case + * we need to distingiush between a pending and injected + * exception. Which is only required in case there is a + * pending exception and vCPU is running L2. + * For more info, refer to comment in cpu_pre_save(). + */ + return env->exception_pending && (env->hflags & HF_GUEST_MASK); +} + +static const VMStateDescription vmstate_exception_info = { + .name = "cpu/exception_info", + .version_id = 1, + .minimum_version_id = 1, + .needed = exception_info_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT8(env.exception_pending, X86CPU), + VMSTATE_UINT8(env.exception_injected, X86CPU), + VMSTATE_UINT8(env.exception_has_payload, X86CPU), + VMSTATE_UINT64(env.exception_payload, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_steal_time_msr = { .name = "cpu/steal_time_msr", .version_id = 1, @@ -634,7 +734,7 @@ static bool hyperv_runtime_enable_needed(void *opaque) X86CPU *cpu = opaque; CPUX86State *env = &cpu->env; - if (!cpu->hyperv_runtime) { + if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_RUNTIME)) { return false; } @@ -851,6 +951,182 @@ static const VMStateDescription vmstate_tsc_khz = { } }; +#ifdef CONFIG_KVM + +static bool vmx_vmcs12_needed(void *opaque) +{ + struct kvm_nested_state *nested_state = opaque; + return (nested_state->size > + offsetof(struct kvm_nested_state, data.vmx[0].vmcs12)); +} + +static const VMStateDescription vmstate_vmx_vmcs12 = { + .name = "cpu/kvm_nested_state/vmx/vmcs12", + .version_id = 1, + .minimum_version_id = 1, + .needed = vmx_vmcs12_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(data.vmx[0].vmcs12, + struct kvm_nested_state, + KVM_STATE_NESTED_VMX_VMCS_SIZE), + VMSTATE_END_OF_LIST() + } +}; + +static bool vmx_shadow_vmcs12_needed(void *opaque) +{ + struct kvm_nested_state *nested_state = opaque; + return (nested_state->size > + offsetof(struct kvm_nested_state, data.vmx[0].shadow_vmcs12)); +} + +static const VMStateDescription vmstate_vmx_shadow_vmcs12 = { + .name = "cpu/kvm_nested_state/vmx/shadow_vmcs12", + .version_id = 1, + .minimum_version_id = 1, + .needed = vmx_shadow_vmcs12_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(data.vmx[0].shadow_vmcs12, + struct kvm_nested_state, + KVM_STATE_NESTED_VMX_VMCS_SIZE), + VMSTATE_END_OF_LIST() + } +}; + +static bool vmx_nested_state_needed(void *opaque) +{ + struct kvm_nested_state *nested_state = opaque; + + return ((nested_state->format == KVM_STATE_NESTED_FORMAT_VMX) && + ((nested_state->hdr.vmx.vmxon_pa != -1ull) || + (nested_state->hdr.vmx.smm.flags & KVM_STATE_NESTED_SMM_VMXON))); +} + +static const VMStateDescription vmstate_vmx_nested_state = { + .name = "cpu/kvm_nested_state/vmx", + .version_id = 1, + .minimum_version_id = 1, + .needed = vmx_nested_state_needed, + .fields = (VMStateField[]) { + VMSTATE_U64(hdr.vmx.vmxon_pa, struct kvm_nested_state), + VMSTATE_U64(hdr.vmx.vmcs12_pa, struct kvm_nested_state), + VMSTATE_U16(hdr.vmx.smm.flags, struct kvm_nested_state), + VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &vmstate_vmx_vmcs12, + &vmstate_vmx_shadow_vmcs12, + NULL, + } +}; + +static bool svm_nested_state_needed(void *opaque) +{ + struct kvm_nested_state *nested_state = opaque; + + return (nested_state->format == KVM_STATE_NESTED_FORMAT_SVM); +} + +static const VMStateDescription vmstate_svm_nested_state = { + .name = "cpu/kvm_nested_state/svm", + .version_id = 1, + .minimum_version_id = 1, + .needed = svm_nested_state_needed, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static bool nested_state_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return (env->nested_state && + (vmx_nested_state_needed(env->nested_state) || + svm_nested_state_needed(env->nested_state))); +} + +static int nested_state_post_load(void *opaque, int version_id) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + struct kvm_nested_state *nested_state = env->nested_state; + int min_nested_state_len = offsetof(struct kvm_nested_state, data); + int max_nested_state_len = kvm_max_nested_state_length(); + + /* + * If our kernel don't support setting nested state + * and we have received nested state from migration stream, + * we need to fail migration + */ + if (max_nested_state_len <= 0) { + error_report("Received nested state when kernel cannot restore it"); + return -EINVAL; + } + + /* + * Verify that the size of received nested_state struct + * at least cover required header and is not larger + * than the max size that our kernel support + */ + if (nested_state->size < min_nested_state_len) { + error_report("Received nested state size less than min: " + "len=%d, min=%d", + nested_state->size, min_nested_state_len); + return -EINVAL; + } + if (nested_state->size > max_nested_state_len) { + error_report("Recieved unsupported nested state size: " + "nested_state->size=%d, max=%d", + nested_state->size, max_nested_state_len); + return -EINVAL; + } + + /* Verify format is valid */ + if ((nested_state->format != KVM_STATE_NESTED_FORMAT_VMX) && + (nested_state->format != KVM_STATE_NESTED_FORMAT_SVM)) { + error_report("Received invalid nested state format: %d", + nested_state->format); + return -EINVAL; + } + + return 0; +} + +static const VMStateDescription vmstate_kvm_nested_state = { + .name = "cpu/kvm_nested_state", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_U16(flags, struct kvm_nested_state), + VMSTATE_U16(format, struct kvm_nested_state), + VMSTATE_U32(size, struct kvm_nested_state), + VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &vmstate_vmx_nested_state, + &vmstate_svm_nested_state, + NULL + } +}; + +static const VMStateDescription vmstate_nested_state = { + .name = "cpu/nested_state", + .version_id = 1, + .minimum_version_id = 1, + .needed = nested_state_needed, + .post_load = nested_state_post_load, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_POINTER(env.nested_state, X86CPU, + vmstate_kvm_nested_state, + struct kvm_nested_state), + VMSTATE_END_OF_LIST() + } +}; + +#endif + static bool mcg_ext_ctl_needed(void *opaque) { X86CPU *cpu = opaque; @@ -1056,7 +1332,7 @@ VMStateDescription vmstate_x86_cpu = { VMSTATE_INT32(env.interrupt_injected, X86CPU), VMSTATE_UINT32(env.mp_state, X86CPU), VMSTATE_UINT64(env.tsc, X86CPU), - VMSTATE_INT32(env.exception_injected, X86CPU), + VMSTATE_INT32(env.exception_nr, X86CPU), VMSTATE_UINT8(env.soft_interrupt, X86CPU), VMSTATE_UINT8(env.nmi_injected, X86CPU), VMSTATE_UINT8(env.nmi_pending, X86CPU), @@ -1080,6 +1356,7 @@ VMStateDescription vmstate_x86_cpu = { /* The above list is not sorted /wrt version numbers, watch out! */ }, .subsections = (const VMStateDescription*[]) { + &vmstate_exception_info, &vmstate_async_pf_msr, &vmstate_pv_eoi_msr, &vmstate_steal_time_msr, @@ -1113,6 +1390,9 @@ VMStateDescription vmstate_x86_cpu = { #ifndef TARGET_X86_64 &vmstate_efer32, #endif +#ifdef CONFIG_KVM + &vmstate_nested_state, +#endif NULL } }; diff --git a/target/mips/kvm.c b/target/mips/kvm.c index 8e72850962..938f8f144b 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -91,6 +91,11 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } +int kvm_arch_destroy_vcpu(CPUState *cs) +{ + return 0; +} + void kvm_mips_reset_vcpu(MIPSCPU *cpu) { CPUMIPSState *env = &cpu->env; diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index be059a3d6f..7a9bfb3f36 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -1737,6 +1737,24 @@ void helper_msa_ilvev_df(CPUMIPSState *env, uint32_t df, uint32_t wd, switch (df) { case DF_BYTE: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->b[8] = pws->b[9]; + pwd->b[9] = pwt->b[9]; + pwd->b[10] = pws->b[11]; + pwd->b[11] = pwt->b[11]; + pwd->b[12] = pws->b[13]; + pwd->b[13] = pwt->b[13]; + pwd->b[14] = pws->b[15]; + pwd->b[15] = pwt->b[15]; + pwd->b[0] = pws->b[1]; + pwd->b[1] = pwt->b[1]; + pwd->b[2] = pws->b[3]; + pwd->b[3] = pwt->b[3]; + pwd->b[4] = pws->b[5]; + pwd->b[5] = pwt->b[5]; + pwd->b[6] = pws->b[7]; + pwd->b[7] = pwt->b[7]; +#else pwd->b[15] = pws->b[14]; pwd->b[14] = pwt->b[14]; pwd->b[13] = pws->b[12]; @@ -1753,8 +1771,19 @@ void helper_msa_ilvev_df(CPUMIPSState *env, uint32_t df, uint32_t wd, pwd->b[2] = pwt->b[2]; pwd->b[1] = pws->b[0]; pwd->b[0] = pwt->b[0]; +#endif break; case DF_HALF: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->h[4] = pws->h[5]; + pwd->h[5] = pwt->h[5]; + pwd->h[6] = pws->h[7]; + pwd->h[7] = pwt->h[7]; + pwd->h[0] = pws->h[1]; + pwd->h[1] = pwt->h[1]; + pwd->h[2] = pws->h[3]; + pwd->h[3] = pwt->h[3]; +#else pwd->h[7] = pws->h[6]; pwd->h[6] = pwt->h[6]; pwd->h[5] = pws->h[4]; @@ -1763,12 +1792,20 @@ void helper_msa_ilvev_df(CPUMIPSState *env, uint32_t df, uint32_t wd, pwd->h[2] = pwt->h[2]; pwd->h[1] = pws->h[0]; pwd->h[0] = pwt->h[0]; +#endif break; case DF_WORD: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->w[2] = pws->w[3]; + pwd->w[3] = pwt->w[3]; + pwd->w[0] = pws->w[1]; + pwd->w[1] = pwt->w[1]; +#else pwd->w[3] = pws->w[2]; pwd->w[2] = pwt->w[2]; pwd->w[1] = pws->w[0]; pwd->w[0] = pwt->w[0]; +#endif break; case DF_DOUBLE: pwd->d[1] = pws->d[0]; @@ -1788,6 +1825,24 @@ void helper_msa_ilvod_df(CPUMIPSState *env, uint32_t df, uint32_t wd, switch (df) { case DF_BYTE: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->b[7] = pwt->b[6]; + pwd->b[6] = pws->b[6]; + pwd->b[5] = pwt->b[4]; + pwd->b[4] = pws->b[4]; + pwd->b[3] = pwt->b[2]; + pwd->b[2] = pws->b[2]; + pwd->b[1] = pwt->b[0]; + pwd->b[0] = pws->b[0]; + pwd->b[15] = pwt->b[14]; + pwd->b[14] = pws->b[14]; + pwd->b[13] = pwt->b[12]; + pwd->b[12] = pws->b[12]; + pwd->b[11] = pwt->b[10]; + pwd->b[10] = pws->b[10]; + pwd->b[9] = pwt->b[8]; + pwd->b[8] = pws->b[8]; +#else pwd->b[0] = pwt->b[1]; pwd->b[1] = pws->b[1]; pwd->b[2] = pwt->b[3]; @@ -1804,8 +1859,19 @@ void helper_msa_ilvod_df(CPUMIPSState *env, uint32_t df, uint32_t wd, pwd->b[13] = pws->b[13]; pwd->b[14] = pwt->b[15]; pwd->b[15] = pws->b[15]; +#endif break; case DF_HALF: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->h[3] = pwt->h[2]; + pwd->h[2] = pws->h[2]; + pwd->h[1] = pwt->h[0]; + pwd->h[0] = pws->h[0]; + pwd->h[7] = pwt->h[6]; + pwd->h[6] = pws->h[6]; + pwd->h[5] = pwt->h[4]; + pwd->h[4] = pws->h[4]; +#else pwd->h[0] = pwt->h[1]; pwd->h[1] = pws->h[1]; pwd->h[2] = pwt->h[3]; @@ -1814,12 +1880,20 @@ void helper_msa_ilvod_df(CPUMIPSState *env, uint32_t df, uint32_t wd, pwd->h[5] = pws->h[5]; pwd->h[6] = pwt->h[7]; pwd->h[7] = pws->h[7]; +#endif break; case DF_WORD: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->w[1] = pwt->w[0]; + pwd->w[0] = pws->w[0]; + pwd->w[3] = pwt->w[2]; + pwd->w[2] = pws->w[2]; +#else pwd->w[0] = pwt->w[1]; pwd->w[1] = pws->w[1]; pwd->w[2] = pwt->w[3]; pwd->w[3] = pws->w[3]; +#endif break; case DF_DOUBLE: pwd->d[0] = pwt->d[1]; @@ -1839,6 +1913,24 @@ void helper_msa_ilvl_df(CPUMIPSState *env, uint32_t df, uint32_t wd, switch (df) { case DF_BYTE: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->b[7] = pwt->b[15]; + pwd->b[6] = pws->b[15]; + pwd->b[5] = pwt->b[14]; + pwd->b[4] = pws->b[14]; + pwd->b[3] = pwt->b[13]; + pwd->b[2] = pws->b[13]; + pwd->b[1] = pwt->b[12]; + pwd->b[0] = pws->b[12]; + pwd->b[15] = pwt->b[11]; + pwd->b[14] = pws->b[11]; + pwd->b[13] = pwt->b[10]; + pwd->b[12] = pws->b[10]; + pwd->b[11] = pwt->b[9]; + pwd->b[10] = pws->b[9]; + pwd->b[9] = pwt->b[8]; + pwd->b[8] = pws->b[8]; +#else pwd->b[0] = pwt->b[8]; pwd->b[1] = pws->b[8]; pwd->b[2] = pwt->b[9]; @@ -1855,8 +1947,19 @@ void helper_msa_ilvl_df(CPUMIPSState *env, uint32_t df, uint32_t wd, pwd->b[13] = pws->b[14]; pwd->b[14] = pwt->b[15]; pwd->b[15] = pws->b[15]; +#endif break; case DF_HALF: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->h[3] = pwt->h[7]; + pwd->h[2] = pws->h[7]; + pwd->h[1] = pwt->h[6]; + pwd->h[0] = pws->h[6]; + pwd->h[7] = pwt->h[5]; + pwd->h[6] = pws->h[5]; + pwd->h[5] = pwt->h[4]; + pwd->h[4] = pws->h[4]; +#else pwd->h[0] = pwt->h[4]; pwd->h[1] = pws->h[4]; pwd->h[2] = pwt->h[5]; @@ -1865,12 +1968,20 @@ void helper_msa_ilvl_df(CPUMIPSState *env, uint32_t df, uint32_t wd, pwd->h[5] = pws->h[6]; pwd->h[6] = pwt->h[7]; pwd->h[7] = pws->h[7]; +#endif break; case DF_WORD: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->w[1] = pwt->w[3]; + pwd->w[0] = pws->w[3]; + pwd->w[3] = pwt->w[2]; + pwd->w[2] = pws->w[2]; +#else pwd->w[0] = pwt->w[2]; pwd->w[1] = pws->w[2]; pwd->w[2] = pwt->w[3]; pwd->w[3] = pws->w[3]; +#endif break; case DF_DOUBLE: pwd->d[0] = pwt->d[1]; @@ -1890,6 +2001,24 @@ void helper_msa_ilvr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, switch (df) { case DF_BYTE: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->b[8] = pws->b[0]; + pwd->b[9] = pwt->b[0]; + pwd->b[10] = pws->b[1]; + pwd->b[11] = pwt->b[1]; + pwd->b[12] = pws->b[2]; + pwd->b[13] = pwt->b[2]; + pwd->b[14] = pws->b[3]; + pwd->b[15] = pwt->b[3]; + pwd->b[0] = pws->b[4]; + pwd->b[1] = pwt->b[4]; + pwd->b[2] = pws->b[5]; + pwd->b[3] = pwt->b[5]; + pwd->b[4] = pws->b[6]; + pwd->b[5] = pwt->b[6]; + pwd->b[6] = pws->b[7]; + pwd->b[7] = pwt->b[7]; +#else pwd->b[15] = pws->b[7]; pwd->b[14] = pwt->b[7]; pwd->b[13] = pws->b[6]; @@ -1906,8 +2035,19 @@ void helper_msa_ilvr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, pwd->b[2] = pwt->b[1]; pwd->b[1] = pws->b[0]; pwd->b[0] = pwt->b[0]; +#endif break; case DF_HALF: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->h[4] = pws->h[0]; + pwd->h[5] = pwt->h[0]; + pwd->h[6] = pws->h[1]; + pwd->h[7] = pwt->h[1]; + pwd->h[0] = pws->h[2]; + pwd->h[1] = pwt->h[2]; + pwd->h[2] = pws->h[3]; + pwd->h[3] = pwt->h[3]; +#else pwd->h[7] = pws->h[3]; pwd->h[6] = pwt->h[3]; pwd->h[5] = pws->h[2]; @@ -1916,12 +2056,20 @@ void helper_msa_ilvr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, pwd->h[2] = pwt->h[1]; pwd->h[1] = pws->h[0]; pwd->h[0] = pwt->h[0]; +#endif break; case DF_WORD: +#if defined(TARGET_WORDS_BIGENDIAN) + pwd->w[2] = pws->w[0]; + pwd->w[3] = pwt->w[0]; + pwd->w[0] = pws->w[1]; + pwd->w[1] = pwt->w[1]; +#else pwd->w[3] = pws->w[1]; pwd->w[2] = pwt->w[1]; pwd->w[1] = pws->w[0]; pwd->w[0] = pwt->w[0]; +#endif break; case DF_DOUBLE: pwd->d[1] = pws->d[0]; diff --git a/target/mips/translate.c b/target/mips/translate.c index a3cf976ab6..e3a0f08dea 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -2617,28 +2617,30 @@ static const char * const mxuregnames[] = { } while (0) /* General purpose registers moves. */ -static inline void gen_load_gpr (TCGv t, int reg) +static inline void gen_load_gpr(TCGv t, int reg) { - if (reg == 0) + if (reg == 0) { tcg_gen_movi_tl(t, 0); - else + } else { tcg_gen_mov_tl(t, cpu_gpr[reg]); + } } -static inline void gen_store_gpr (TCGv t, int reg) +static inline void gen_store_gpr(TCGv t, int reg) { - if (reg != 0) + if (reg != 0) { tcg_gen_mov_tl(cpu_gpr[reg], t); + } } /* Moves to/from shadow registers. */ -static inline void gen_load_srsgpr (int from, int to) +static inline void gen_load_srsgpr(int from, int to) { TCGv t0 = tcg_temp_new(); - if (from == 0) + if (from == 0) { tcg_gen_movi_tl(t0, 0); - else { + } else { TCGv_i32 t2 = tcg_temp_new_i32(); TCGv_ptr addr = tcg_temp_new_ptr(); @@ -2839,16 +2841,18 @@ static void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) } } -static inline int get_fp_bit (int cc) +static inline int get_fp_bit(int cc) { - if (cc) + if (cc) { return 24 + cc; - else + } else { return 23; + } } /* Addresses computation */ -static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1) +static inline void gen_op_addr_add(DisasContext *ctx, TCGv ret, TCGv arg0, + TCGv arg1) { tcg_gen_add_tl(ret, arg0, arg1); @@ -2907,14 +2911,16 @@ static inline void gen_move_high32(TCGv ret, TCGv_i64 arg) static inline void check_cp0_enabled(DisasContext *ctx) { - if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) { generate_exception_err(ctx, EXCP_CpU, 0); + } } static inline void check_cp1_enabled(DisasContext *ctx) { - if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU))) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU))) { generate_exception_err(ctx, EXCP_CpU, 1); + } } /* Verify that the processor is running with COP1X instructions enabled. @@ -2923,8 +2929,9 @@ static inline void check_cp1_enabled(DisasContext *ctx) static inline void check_cop1x(DisasContext *ctx) { - if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X))) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X))) { generate_exception_end(ctx, EXCP_RI); + } } /* Verify that the processor is running with 64-bit floating-point @@ -2932,8 +2939,9 @@ static inline void check_cop1x(DisasContext *ctx) static inline void check_cp1_64bitmode(DisasContext *ctx) { - if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) + if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) { generate_exception_end(ctx, EXCP_RI); + } } /* @@ -2949,8 +2957,9 @@ static inline void check_cp1_64bitmode(DisasContext *ctx) */ static inline void check_cp1_registers(DisasContext *ctx, int regs) { - if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1))) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1))) { generate_exception_end(ctx, EXCP_RI); + } } /* Verify that the processor is running with DSP instructions enabled. @@ -3039,8 +3048,9 @@ static inline void check_ps(DisasContext *ctx) instructions are not enabled. */ static inline void check_mips_64(DisasContext *ctx) { - if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) { generate_exception_end(ctx, EXCP_RI); + } } #endif @@ -3125,13 +3135,12 @@ static inline void check_nms(DisasContext *ctx) */ static inline void check_nms_dl_il_sl_tl_l2c(DisasContext *ctx) { - if (unlikely(ctx->CP0_Config5 & (1 << CP0C5_NMS)) && - !(ctx->CP0_Config1 & (1 << CP0C1_DL)) && - !(ctx->CP0_Config1 & (1 << CP0C1_IL)) && - !(ctx->CP0_Config2 & (1 << CP0C2_SL)) && - !(ctx->CP0_Config2 & (1 << CP0C2_TL)) && - !(ctx->CP0_Config5 & (1 << CP0C5_L2C))) - { + if (unlikely((ctx->CP0_Config5 & (1 << CP0C5_NMS)) && + !(ctx->CP0_Config1 & (1 << CP0C1_DL)) && + !(ctx->CP0_Config1 & (1 << CP0C1_IL)) && + !(ctx->CP0_Config2 & (1 << CP0C2_SL)) && + !(ctx->CP0_Config2 & (1 << CP0C2_TL)) && + !(ctx->CP0_Config5 & (1 << CP0C5_L2C)))) { generate_exception_end(ctx, EXCP_RI); } } @@ -3179,23 +3188,56 @@ static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n, \ gen_ldcmp_fpr##bits (ctx, fp0, fs); \ gen_ldcmp_fpr##bits (ctx, fp1, ft); \ switch (n) { \ - case 0: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc); break;\ - case 1: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc); break;\ - case 2: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc); break;\ - case 3: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc); break;\ - case 4: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc); break;\ - case 5: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc); break;\ - case 6: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc); break;\ - case 7: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc); break;\ - case 8: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc); break;\ - case 9: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); break;\ - case 10: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc); break;\ - case 11: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc); break;\ - case 12: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc); break;\ - case 13: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc); break;\ - case 14: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc); break;\ - case 15: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc); break;\ - default: abort(); \ + case 0: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc); \ + break; \ + case 1: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc); \ + break; \ + case 2: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc); \ + break; \ + case 3: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc); \ + break; \ + case 4: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc); \ + break; \ + case 5: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc); \ + break; \ + case 6: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc); \ + break; \ + case 7: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc); \ + break; \ + case 8: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc); \ + break; \ + case 9: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); \ + break; \ + case 10: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc); \ + break; \ + case 11: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc); \ + break; \ + case 12: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc); \ + break; \ + case 13: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc); \ + break; \ + case 14: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc); \ + break; \ + case 15: \ + gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc); \ + break; \ + default: \ + abort(); \ } \ tcg_temp_free_i##bits (fp0); \ tcg_temp_free_i##bits (fp1); \ @@ -3328,8 +3370,8 @@ OP_LD_ATOMIC(lld,ld64); #endif #undef OP_LD_ATOMIC -static void gen_base_offset_addr (DisasContext *ctx, TCGv addr, - int base, int offset) +static void gen_base_offset_addr(DisasContext *ctx, TCGv addr, + int base, int offset) { if (base == 0) { tcg_gen_movi_tl(addr, offset); @@ -3341,7 +3383,7 @@ static void gen_base_offset_addr (DisasContext *ctx, TCGv addr, } } -static target_ulong pc_relative_pc (DisasContext *ctx) +static target_ulong pc_relative_pc(DisasContext *ctx) { target_ulong pc = ctx->base.pc_next; @@ -3578,8 +3620,8 @@ static void gen_llwp(DisasContext *ctx, uint32_t base, int16_t offset, } /* Store */ -static void gen_st (DisasContext *ctx, uint32_t opc, int rt, - int base, int offset) +static void gen_st(DisasContext *ctx, uint32_t opc, int rt, + int base, int offset) { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -3717,8 +3759,8 @@ static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset, } /* Load and store */ -static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, - TCGv t0) +static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft, + TCGv t0) { /* Don't do NOP if destination is zero: we must perform the actual memory access. */ @@ -3881,22 +3923,25 @@ static void gen_logic_imm(DisasContext *ctx, uint32_t opc, uimm = (uint16_t)imm; switch (opc) { case OPC_ANDI: - if (likely(rs != 0)) + if (likely(rs != 0)) { tcg_gen_andi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); - else + } else { tcg_gen_movi_tl(cpu_gpr[rt], 0); + } break; case OPC_ORI: - if (rs != 0) + if (rs != 0) { tcg_gen_ori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); - else + } else { tcg_gen_movi_tl(cpu_gpr[rt], uimm); + } break; case OPC_XORI: - if (likely(rs != 0)) + if (likely(rs != 0)) { tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); - else + } else { tcg_gen_movi_tl(cpu_gpr[rt], uimm); + } break; case OPC_LUI: if (rs != 0 && (ctx->insn_flags & ISA_MIPS32R6)) { @@ -5132,8 +5177,8 @@ static void gen_mul_txx9(DisasContext *ctx, uint32_t opc, tcg_temp_free(t1); } -static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, - int rd, int rs, int rt) +static void gen_mul_vr54xx(DisasContext *ctx, uint32_t opc, + int rd, int rs, int rt) { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -5196,8 +5241,8 @@ static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, tcg_temp_free(t1); } -static void gen_cl (DisasContext *ctx, uint32_t opc, - int rd, int rs) +static void gen_cl(DisasContext *ctx, uint32_t opc, + int rd, int rs) { TCGv t0; @@ -6059,8 +6104,9 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, } out: - if (insn_bytes == 2) + if (insn_bytes == 2) { ctx->hflags |= MIPS_HFLAG_B16; + } tcg_temp_free(t0); tcg_temp_free(t1); } @@ -6188,8 +6234,8 @@ static void gen_compute_branch_nm(DisasContext *ctx, uint32_t opc, /* special3 bitfield operations */ -static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, - int rs, int lsb, int msb) +static void gen_bitops(DisasContext *ctx, uint32_t opc, int rt, + int rs, int lsb, int msb) { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -6259,7 +6305,7 @@ fail: tcg_temp_free(t1); } -static void gen_bshfl (DisasContext *ctx, uint32_t op2, int rt, int rd) +static void gen_bshfl(DisasContext *ctx, uint32_t op2, int rt, int rd) { TCGv t0; @@ -6502,7 +6548,7 @@ static inline void gen_mfhc0_load64(TCGv arg, target_ulong off, int shift) tcg_temp_free_i64(t0); } -static inline void gen_mfc0_load32 (TCGv arg, target_ulong off) +static inline void gen_mfc0_load32(TCGv arg, target_ulong off) { TCGv_i32 t0 = tcg_temp_new_i32(); @@ -6511,13 +6557,13 @@ static inline void gen_mfc0_load32 (TCGv arg, target_ulong off) tcg_temp_free_i32(t0); } -static inline void gen_mfc0_load64 (TCGv arg, target_ulong off) +static inline void gen_mfc0_load64(TCGv arg, target_ulong off) { tcg_gen_ld_tl(arg, cpu_env, off); tcg_gen_ext32s_tl(arg, arg); } -static inline void gen_mtc0_store32 (TCGv arg, target_ulong off) +static inline void gen_mtc0_store32(TCGv arg, target_ulong off) { TCGv_i32 t0 = tcg_temp_new_i32(); @@ -6707,8 +6753,9 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *register_name = "invalid"; - if (sel != 0) + if (sel != 0) { check_insn(ctx, ISA_MIPS32); + } switch (reg) { case CP0_REGISTER_00: @@ -7463,8 +7510,9 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *register_name = "invalid"; - if (sel != 0) + if (sel != 0) { check_insn(ctx, ISA_MIPS32); + } if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); @@ -8209,8 +8257,9 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *register_name = "invalid"; - if (sel != 0) + if (sel != 0) { check_insn(ctx, ISA_MIPS64); + } switch (reg) { case CP0_REGISTER_00: @@ -8919,8 +8968,9 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *register_name = "invalid"; - if (sel != 0) + if (sel != 0) { check_insn(ctx, ISA_MIPS64); + } if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); @@ -9657,12 +9707,12 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) != - (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE)))) + (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE)))) { tcg_gen_movi_tl(t0, -1); - else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > - (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) + } else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > + (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) { tcg_gen_movi_tl(t0, -1); - else if (u == 0) { + } else if (u == 0) { switch (rt) { case 1: switch (sel) { @@ -9882,12 +9932,12 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, gen_load_gpr(t0, rt); if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) != - (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE)))) + (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE)))) { /* NOP */ ; - else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > - (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) + } else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > + (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) { /* NOP */ ; - else if (u == 0) { + } else if (u == 0) { switch (rd) { case 1: switch (sel) { @@ -10077,7 +10127,8 @@ die: generate_exception_end(ctx, EXCP_RI); } -static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, int rd) +static void gen_cp0(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, + int rt, int rd) { const char *opn = "ldst"; @@ -10160,8 +10211,9 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, break; case OPC_TLBWI: opn = "tlbwi"; - if (!env->tlb->helper_tlbwi) + if (!env->tlb->helper_tlbwi) { goto die; + } gen_helper_tlbwi(cpu_env); break; case OPC_TLBINV: @@ -10184,20 +10236,23 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, break; case OPC_TLBWR: opn = "tlbwr"; - if (!env->tlb->helper_tlbwr) + if (!env->tlb->helper_tlbwr) { goto die; + } gen_helper_tlbwr(cpu_env); break; case OPC_TLBP: opn = "tlbp"; - if (!env->tlb->helper_tlbp) + if (!env->tlb->helper_tlbp) { goto die; + } gen_helper_tlbp(cpu_env); break; case OPC_TLBR: opn = "tlbr"; - if (!env->tlb->helper_tlbr) + if (!env->tlb->helper_tlbr) { goto die; + } gen_helper_tlbr(cpu_env); break; case OPC_ERET: /* OPC_ERETNC */ @@ -10271,8 +10326,9 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op, goto out; } - if (cc != 0) + if (cc != 0) { check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); + } btarget = ctx->base.pc_next + 4 + offset; @@ -10465,22 +10521,22 @@ enum fopcode { OPC_CVT_W_S = FOP(36, FMT_S), OPC_CVT_L_S = FOP(37, FMT_S), OPC_CVT_PS_S = FOP(38, FMT_S), - OPC_CMP_F_S = FOP (48, FMT_S), - OPC_CMP_UN_S = FOP (49, FMT_S), - OPC_CMP_EQ_S = FOP (50, FMT_S), - OPC_CMP_UEQ_S = FOP (51, FMT_S), - OPC_CMP_OLT_S = FOP (52, FMT_S), - OPC_CMP_ULT_S = FOP (53, FMT_S), - OPC_CMP_OLE_S = FOP (54, FMT_S), - OPC_CMP_ULE_S = FOP (55, FMT_S), - OPC_CMP_SF_S = FOP (56, FMT_S), - OPC_CMP_NGLE_S = FOP (57, FMT_S), - OPC_CMP_SEQ_S = FOP (58, FMT_S), - OPC_CMP_NGL_S = FOP (59, FMT_S), - OPC_CMP_LT_S = FOP (60, FMT_S), - OPC_CMP_NGE_S = FOP (61, FMT_S), - OPC_CMP_LE_S = FOP (62, FMT_S), - OPC_CMP_NGT_S = FOP (63, FMT_S), + OPC_CMP_F_S = FOP(48, FMT_S), + OPC_CMP_UN_S = FOP(49, FMT_S), + OPC_CMP_EQ_S = FOP(50, FMT_S), + OPC_CMP_UEQ_S = FOP(51, FMT_S), + OPC_CMP_OLT_S = FOP(52, FMT_S), + OPC_CMP_ULT_S = FOP(53, FMT_S), + OPC_CMP_OLE_S = FOP(54, FMT_S), + OPC_CMP_ULE_S = FOP(55, FMT_S), + OPC_CMP_SF_S = FOP(56, FMT_S), + OPC_CMP_NGLE_S = FOP(57, FMT_S), + OPC_CMP_SEQ_S = FOP(58, FMT_S), + OPC_CMP_NGL_S = FOP(59, FMT_S), + OPC_CMP_LT_S = FOP(60, FMT_S), + OPC_CMP_NGE_S = FOP(61, FMT_S), + OPC_CMP_LE_S = FOP(62, FMT_S), + OPC_CMP_NGT_S = FOP(63, FMT_S), OPC_ADD_D = FOP(0, FMT_D), OPC_SUB_D = FOP(1, FMT_D), @@ -10521,22 +10577,22 @@ enum fopcode { OPC_CVT_S_D = FOP(32, FMT_D), OPC_CVT_W_D = FOP(36, FMT_D), OPC_CVT_L_D = FOP(37, FMT_D), - OPC_CMP_F_D = FOP (48, FMT_D), - OPC_CMP_UN_D = FOP (49, FMT_D), - OPC_CMP_EQ_D = FOP (50, FMT_D), - OPC_CMP_UEQ_D = FOP (51, FMT_D), - OPC_CMP_OLT_D = FOP (52, FMT_D), - OPC_CMP_ULT_D = FOP (53, FMT_D), - OPC_CMP_OLE_D = FOP (54, FMT_D), - OPC_CMP_ULE_D = FOP (55, FMT_D), - OPC_CMP_SF_D = FOP (56, FMT_D), - OPC_CMP_NGLE_D = FOP (57, FMT_D), - OPC_CMP_SEQ_D = FOP (58, FMT_D), - OPC_CMP_NGL_D = FOP (59, FMT_D), - OPC_CMP_LT_D = FOP (60, FMT_D), - OPC_CMP_NGE_D = FOP (61, FMT_D), - OPC_CMP_LE_D = FOP (62, FMT_D), - OPC_CMP_NGT_D = FOP (63, FMT_D), + OPC_CMP_F_D = FOP(48, FMT_D), + OPC_CMP_UN_D = FOP(49, FMT_D), + OPC_CMP_EQ_D = FOP(50, FMT_D), + OPC_CMP_UEQ_D = FOP(51, FMT_D), + OPC_CMP_OLT_D = FOP(52, FMT_D), + OPC_CMP_ULT_D = FOP(53, FMT_D), + OPC_CMP_OLE_D = FOP(54, FMT_D), + OPC_CMP_ULE_D = FOP(55, FMT_D), + OPC_CMP_SF_D = FOP(56, FMT_D), + OPC_CMP_NGLE_D = FOP(57, FMT_D), + OPC_CMP_SEQ_D = FOP(58, FMT_D), + OPC_CMP_NGL_D = FOP(59, FMT_D), + OPC_CMP_LT_D = FOP(60, FMT_D), + OPC_CMP_NGE_D = FOP(61, FMT_D), + OPC_CMP_LE_D = FOP(62, FMT_D), + OPC_CMP_NGT_D = FOP(63, FMT_D), OPC_CVT_S_W = FOP(32, FMT_W), OPC_CVT_D_W = FOP(33, FMT_W), @@ -10568,22 +10624,22 @@ enum fopcode { OPC_PLU_PS = FOP(45, FMT_PS), OPC_PUL_PS = FOP(46, FMT_PS), OPC_PUU_PS = FOP(47, FMT_PS), - OPC_CMP_F_PS = FOP (48, FMT_PS), - OPC_CMP_UN_PS = FOP (49, FMT_PS), - OPC_CMP_EQ_PS = FOP (50, FMT_PS), - OPC_CMP_UEQ_PS = FOP (51, FMT_PS), - OPC_CMP_OLT_PS = FOP (52, FMT_PS), - OPC_CMP_ULT_PS = FOP (53, FMT_PS), - OPC_CMP_OLE_PS = FOP (54, FMT_PS), - OPC_CMP_ULE_PS = FOP (55, FMT_PS), - OPC_CMP_SF_PS = FOP (56, FMT_PS), - OPC_CMP_NGLE_PS = FOP (57, FMT_PS), - OPC_CMP_SEQ_PS = FOP (58, FMT_PS), - OPC_CMP_NGL_PS = FOP (59, FMT_PS), - OPC_CMP_LT_PS = FOP (60, FMT_PS), - OPC_CMP_NGE_PS = FOP (61, FMT_PS), - OPC_CMP_LE_PS = FOP (62, FMT_PS), - OPC_CMP_NGT_PS = FOP (63, FMT_PS), + OPC_CMP_F_PS = FOP(48, FMT_PS), + OPC_CMP_UN_PS = FOP(49, FMT_PS), + OPC_CMP_EQ_PS = FOP(50, FMT_PS), + OPC_CMP_UEQ_PS = FOP(51, FMT_PS), + OPC_CMP_OLT_PS = FOP(52, FMT_PS), + OPC_CMP_ULT_PS = FOP(53, FMT_PS), + OPC_CMP_OLE_PS = FOP(54, FMT_PS), + OPC_CMP_ULE_PS = FOP(55, FMT_PS), + OPC_CMP_SF_PS = FOP(56, FMT_PS), + OPC_CMP_NGLE_PS = FOP(57, FMT_PS), + OPC_CMP_SEQ_PS = FOP(58, FMT_PS), + OPC_CMP_NGL_PS = FOP(59, FMT_PS), + OPC_CMP_LT_PS = FOP(60, FMT_PS), + OPC_CMP_NGE_PS = FOP(61, FMT_PS), + OPC_CMP_LE_PS = FOP(62, FMT_PS), + OPC_CMP_NGT_PS = FOP(63, FMT_PS), }; enum r6_f_cmp_op { @@ -10633,7 +10689,8 @@ enum r6_f_cmp_op { R6_OPC_CMP_SUNE_D = FOP(26, FMT_L), R6_OPC_CMP_SNE_D = FOP(27, FMT_L), }; -static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) + +static void gen_cp1(DisasContext *ctx, uint32_t opc, int rt, int fs) { TCGv t0 = tcg_temp_new(); @@ -10714,7 +10771,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) tcg_temp_free(t0); } -static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) +static void gen_movci(DisasContext *ctx, int rd, int rs, int cc, int tf) { TCGLabel *l1; TCGCond cond; @@ -10725,10 +10782,11 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) return; } - if (tf) + if (tf) { cond = TCG_COND_EQ; - else + } else { cond = TCG_COND_NE; + } l1 = gen_new_label(); t0 = tcg_temp_new_i32(); @@ -10750,10 +10808,11 @@ static inline void gen_movcf_s(DisasContext *ctx, int fs, int fd, int cc, TCGv_i32 t0 = tcg_temp_new_i32(); TCGLabel *l1 = gen_new_label(); - if (tf) + if (tf) { cond = TCG_COND_EQ; - else + } else { cond = TCG_COND_NE; + } tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc)); tcg_gen_brcondi_i32(cond, t0, 0, l1); @@ -10763,17 +10822,19 @@ static inline void gen_movcf_s(DisasContext *ctx, int fs, int fd, int cc, tcg_temp_free_i32(t0); } -static inline void gen_movcf_d (DisasContext *ctx, int fs, int fd, int cc, int tf) +static inline void gen_movcf_d(DisasContext *ctx, int fs, int fd, int cc, + int tf) { int cond; TCGv_i32 t0 = tcg_temp_new_i32(); TCGv_i64 fp0; TCGLabel *l1 = gen_new_label(); - if (tf) + if (tf) { cond = TCG_COND_EQ; - else + } else { cond = TCG_COND_NE; + } tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc)); tcg_gen_brcondi_i32(cond, t0, 0, l1); @@ -10793,10 +10854,11 @@ static inline void gen_movcf_ps(DisasContext *ctx, int fs, int fd, TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); - if (tf) + if (tf) { cond = TCG_COND_EQ; - else + } else { cond = TCG_COND_NE; + } tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc)); tcg_gen_brcondi_i32(cond, t0, 0, l1); @@ -10886,8 +10948,8 @@ static void gen_sel_d(DisasContext *ctx, enum fopcode op1, int fd, int ft, tcg_temp_free_i64(t1); } -static void gen_farith (DisasContext *ctx, enum fopcode op1, - int ft, int fs, int fd, int cc) +static void gen_farith(DisasContext *ctx, enum fopcode op1, + int ft, int fs, int fd, int cc) { uint32_t func = ctx->opcode & 0x3f; switch (op1) { @@ -12092,8 +12154,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGLabel *l1 = gen_new_label(); TCGv_i64 fp0; - if (ft != 0) + if (ft != 0) { tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1); + } fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); gen_store_fpr64(ctx, fp0, fd); @@ -12314,8 +12377,8 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, } /* Coprocessor 3 (FPU) */ -static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, - int fd, int fs, int base, int index) +static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc, + int fd, int fs, int base, int index) { TCGv t0 = tcg_temp_new(); @@ -12394,8 +12457,8 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, tcg_temp_free(t0); } -static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, - int fd, int fr, int fs, int ft) +static void gen_flt3_arith(DisasContext *ctx, uint32_t opc, + int fd, int fr, int fs, int ft) { switch (opc) { case OPC_ALNV_PS: @@ -13157,17 +13220,17 @@ enum { RR_RY_CNVT_SEW = 0x6, }; -static int xlat (int r) +static int xlat(int r) { static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; return map[r]; } -static void gen_mips16_save (DisasContext *ctx, - int xsregs, int aregs, - int do_ra, int do_s0, int do_s1, - int framesize) +static void gen_mips16_save(DisasContext *ctx, + int xsregs, int aregs, + int do_ra, int do_s0, int do_s1, + int framesize) { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -13322,10 +13385,10 @@ static void gen_mips16_save (DisasContext *ctx, tcg_temp_free(t2); } -static void gen_mips16_restore (DisasContext *ctx, - int xsregs, int aregs, - int do_ra, int do_s0, int do_s1, - int framesize) +static void gen_mips16_restore(DisasContext *ctx, + int xsregs, int aregs, + int do_ra, int do_s0, int do_s1, + int framesize) { int astatic; TCGv t0 = tcg_temp_new(); @@ -13428,8 +13491,8 @@ static void gen_mips16_restore (DisasContext *ctx, tcg_temp_free(t2); } -static void gen_addiupc (DisasContext *ctx, int rx, int imm, - int is_64_bit, int extended) +static void gen_addiupc(DisasContext *ctx, int rx, int imm, + int is_64_bit, int extended) { TCGv t0; @@ -13459,9 +13522,9 @@ static void gen_cache_operation(DisasContext *ctx, uint32_t op, int base, } #if defined(TARGET_MIPS64) -static void decode_i64_mips16 (DisasContext *ctx, - int ry, int funct, int16_t offset, - int extended) +static void decode_i64_mips16(DisasContext *ctx, + int ry, int funct, int16_t offset, + int extended) { switch (funct) { case I64_LDSP: @@ -13520,7 +13583,7 @@ static void decode_i64_mips16 (DisasContext *ctx, } #endif -static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) +static int decode_extended_mips16_opc(CPUMIPSState *env, DisasContext *ctx) { int extend = cpu_lduw_code(env, ctx->base.pc_next + 2); int op, rx, ry, funct, sa; @@ -13734,7 +13797,7 @@ static inline void gen_helper_do_semihosting(void *env) } #endif -static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) +static int decode_mips16_opc(CPUMIPSState *env, DisasContext *ctx) { int rx, ry; int sa; @@ -13957,7 +14020,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) case M16_OPC_LWPC: gen_ld(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2); break; -#if defined (TARGET_MIPS64) +#if defined(TARGET_MIPS64) case M16_OPC_LWU: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); @@ -14061,7 +14124,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) case RR_SRAV: gen_shift(ctx, OPC_SRAV, ry, rx, ry); break; -#if defined (TARGET_MIPS64) +#if defined(TARGET_MIPS64) case RR_DSRL: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); @@ -14124,7 +14187,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) case RR_MFLO: gen_HILO(ctx, OPC_MFLO, 0, rx); break; -#if defined (TARGET_MIPS64) +#if defined(TARGET_MIPS64) case RR_DSRA: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); @@ -14158,7 +14221,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) case RR_DIVU: gen_muldiv(ctx, OPC_DIVU, 0, rx, ry); break; -#if defined (TARGET_MIPS64) +#if defined(TARGET_MIPS64) case RR_DMULT: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); @@ -14802,7 +14865,7 @@ enum { ADDIUR1SP = 0x1 }; -static int mmreg (int r) +static int mmreg(int r) { static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; @@ -14810,7 +14873,7 @@ static int mmreg (int r) } /* Used for 16-bit store instructions. */ -static int mmreg2 (int r) +static int mmreg2(int r) { static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 }; @@ -14885,8 +14948,8 @@ static void gen_andi16(DisasContext *ctx) gen_logic_imm(ctx, OPC_ANDI, rd, rs, decoded_imm[encoded]); } -static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, - int base, int16_t offset) +static void gen_ldst_multiple(DisasContext *ctx, uint32_t opc, int reglist, + int base, int16_t offset) { TCGv t0, t1; TCGv_i32 t2; @@ -15159,7 +15222,7 @@ static void gen_pool16c_r6_insn(DisasContext *ctx) } } -static void gen_ldxs (DisasContext *ctx, int base, int index, int rd) +static void gen_ldxs(DisasContext *ctx, int base, int index, int rd) { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -15179,8 +15242,8 @@ static void gen_ldxs (DisasContext *ctx, int base, int index, int rd) tcg_temp_free(t1); } -static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd, - int base, int16_t offset) +static void gen_ldst_pair(DisasContext *ctx, uint32_t opc, int rd, + int base, int16_t offset) { TCGv t0, t1; @@ -15205,14 +15268,14 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd, tcg_gen_movi_tl(t1, 4); gen_op_addr_add(ctx, t0, t0, t1); tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); - gen_store_gpr(t1, rd+1); + gen_store_gpr(t1, rd + 1); break; case SWP: gen_load_gpr(t1, rd); tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); tcg_gen_movi_tl(t1, 4); gen_op_addr_add(ctx, t0, t0, t1); - gen_load_gpr(t1, rd+1); + gen_load_gpr(t1, rd + 1); tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); break; #ifdef TARGET_MIPS64 @@ -15226,14 +15289,14 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd, tcg_gen_movi_tl(t1, 8); gen_op_addr_add(ctx, t0, t0, t1); tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ); - gen_store_gpr(t1, rd+1); + gen_store_gpr(t1, rd + 1); break; case SDP: gen_load_gpr(t1, rd); tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); tcg_gen_movi_tl(t1, 8); gen_op_addr_add(ctx, t0, t0, t1); - gen_load_gpr(t1, rd+1); + gen_load_gpr(t1, rd + 1); tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); break; #endif @@ -15270,7 +15333,7 @@ static void gen_sync(int stype) tcg_gen_mb(tcg_mo); } -static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) +static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs) { int extension = (ctx->opcode >> 6) & 0x3f; int minor = (ctx->opcode >> 12) & 0xf; @@ -17234,7 +17297,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) } } -static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) +static int decode_micromips_opc(CPUMIPSState *env, DisasContext *ctx) { uint32_t op; @@ -27881,11 +27944,11 @@ static void gen_check_zero_element(TCGv tresult, uint8_t df, uint8_t wt) eval_big = 0x8000000000000000ULL; break; } - tcg_gen_subi_i64(t0, msa_wr_d[wt<<1], eval_zero_or_big); - tcg_gen_andc_i64(t0, t0, msa_wr_d[wt<<1]); + tcg_gen_subi_i64(t0, msa_wr_d[wt << 1], eval_zero_or_big); + tcg_gen_andc_i64(t0, t0, msa_wr_d[wt << 1]); tcg_gen_andi_i64(t0, t0, eval_big); - tcg_gen_subi_i64(t1, msa_wr_d[(wt<<1)+1], eval_zero_or_big); - tcg_gen_andc_i64(t1, t1, msa_wr_d[(wt<<1)+1]); + tcg_gen_subi_i64(t1, msa_wr_d[(wt << 1) + 1], eval_zero_or_big); + tcg_gen_andc_i64(t1, t1, msa_wr_d[(wt << 1) + 1]); tcg_gen_andi_i64(t1, t1, eval_big); tcg_gen_or_i64(t0, t0, t1); /* if all bits are zero then all elements are not zero */ @@ -27913,7 +27976,7 @@ static void gen_msa_branch(CPUMIPSState *env, DisasContext *ctx, uint32_t op1) case OPC_BNZ_V: { TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_or_i64(t0, msa_wr_d[wt<<1], msa_wr_d[(wt<<1)+1]); + tcg_gen_or_i64(t0, msa_wr_d[wt << 1], msa_wr_d[(wt << 1) + 1]); tcg_gen_setcondi_i64((op1 == OPC_BZ_V) ? TCG_COND_EQ : TCG_COND_NE, t0, t0, 0); tcg_gen_trunc_i64_tl(bcond, t0); @@ -29987,12 +30050,14 @@ void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags) env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0], env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { - if ((i & 3) == 0) + if ((i & 3) == 0) { qemu_fprintf(f, "GPR%02d:", i); + } qemu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->active_tc.gpr[i]); - if ((i & 3) == 3) + if ((i & 3) == 3) { qemu_fprintf(f, "\n"); + } } qemu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index d4107dd70d..4b4989c0af 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -521,6 +521,11 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } +int kvm_arch_destroy_vcpu(CPUState *cs) +{ + return 0; +} + static void kvm_sw_tlb_put(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index bcec9795ec..0267c6c2f6 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -368,6 +368,16 @@ int kvm_arch_init_vcpu(CPUState *cs) return 0; } +int kvm_arch_destroy_vcpu(CPUState *cs) +{ + S390CPU *cpu = S390_CPU(cs); + + g_free(cpu->irqstate); + cpu->irqstate = NULL; + + return 0; +} + void kvm_s390_reset_vcpu(S390CPU *cpu) { CPUState *cs = CPU(cpu); |