From 69e3895f9d37ca39536775b13ce63e8c291427ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 31 Aug 2021 18:50:33 +0100 Subject: target/i386: add missing bits to CR4_RESERVED_MASK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Booting Fedora kernels with -cpu max hangs very early in boot. Disabling the la57 CPUID bit fixes the problem. git bisect traced the regression to commit 213ff024a2f92020290296cb9dc29c2af3d4a221 (HEAD, refs/bisect/bad) Author: Lara Lazier Date: Wed Jul 21 17:26:50 2021 +0200 target/i386: Added consistency checks for CR4 All MBZ bits in CR4 must be zero. (APM2 15.5) Added reserved bitmask and added checks in both helper_vmrun and helper_write_crN. Signed-off-by: Lara Lazier Message-Id: <20210721152651.14683-2-laramglazier@gmail.com> Signed-off-by: Paolo Bonzini In this commit CR4_RESERVED_MASK is missing CR4_LA57_MASK and two others. Adding this lets Fedora kernels boot once again. Signed-off-by: Daniel P. Berrangé Tested-by: Richard W.M. Jones Message-Id: <20210831175033.175584-1-berrange@redhat.com> [Removed VMXE/SMXE, matching the commit message. - Paolo] Fixes: 213ff024a2 ("target/i386: Added consistency checks for CR4", 2021-07-22) Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 1 + 1 file changed, 1 insertion(+) (limited to 'target') diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 6c50d3a..21b33fb 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -257,6 +257,7 @@ typedef enum X86Seg { | CR4_DE_MASK | CR4_PSE_MASK | CR4_PAE_MASK \ | CR4_MCE_MASK | CR4_PGE_MASK | CR4_PCE_MASK \ | CR4_OSFXSR_MASK | CR4_OSXMMEXCPT_MASK |CR4_UMIP_MASK \ + | CR4_LA57_MASK \ | CR4_FSGSBASE_MASK | CR4_PCIDE_MASK | CR4_OSXSAVE_MASK \ | CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK)) -- cgit v1.1 From 97afb47e1509198bed58498358adc9b0fe6b0d75 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Wed, 4 Aug 2021 13:30:58 +0200 Subject: target/i386: VMRUN and VMLOAD canonicalizations APM2 requires that VMRUN and VMLOAD canonicalize (sign extend to 63 from 48/57) all base addresses in the segment registers that have been respectively loaded. Signed-off-by: Lara Lazier Message-Id: <20210804113058.45186-1-laramglazier@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 19 +++++++++++-------- target/i386/cpu.h | 2 ++ target/i386/tcg/sysemu/svm_helper.c | 27 +++++++++++++++++---------- 3 files changed, 30 insertions(+), 18 deletions(-) (limited to 'target') diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 97e250e..fbca4e5 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5115,6 +5115,15 @@ static void x86_register_cpudef_types(const X86CPUDefinition *def) } +uint32_t cpu_x86_virtual_addr_width(CPUX86State *env) +{ + if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_LA57) { + return 57; /* 57 bits virtual */ + } else { + return 48; /* 48 bits virtual */ + } +} + void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) @@ -5517,16 +5526,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 0x80000008: /* virtual & phys address size in low 2 bytes. */ + *eax = cpu->phys_bits; if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { /* 64 bit processor */ - *eax = cpu->phys_bits; /* configurable physical bits */ - if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_LA57) { - *eax |= 0x00003900; /* 57 bits virtual */ - } else { - *eax |= 0x00003000; /* 48 bits virtual */ - } - } else { - *eax = cpu->phys_bits; + *eax |= (cpu_x86_virtual_addr_width(env) << 8); } *ebx = env->features[FEAT_8000_0008_EBX]; if (cs->nr_cores * cs->nr_threads > 1) { diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 21b33fb..aafc2eb 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1955,6 +1955,8 @@ typedef struct PropValue { } PropValue; void x86_cpu_apply_props(X86CPU *cpu, PropValue *props); +uint32_t cpu_x86_virtual_addr_width(CPUX86State *env); + /* cpu.c other functions (cpuid) */ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 0d549b3..0e7de4e 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -41,6 +41,16 @@ static inline void svm_save_seg(CPUX86State *env, hwaddr addr, ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00)); } +/* + * VMRUN and VMLOAD canonicalizes (i.e., sign-extend to bit 63) all base + * addresses in the segment registers that have been loaded. + */ +static inline void svm_canonicalization(CPUX86State *env, target_ulong *seg_base) +{ + uint16_t shift_amt = 64 - cpu_x86_virtual_addr_width(env); + *seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt); +} + static inline void svm_load_seg(CPUX86State *env, hwaddr addr, SegmentCache *sc) { @@ -53,6 +63,7 @@ static inline void svm_load_seg(CPUX86State *env, hwaddr addr, sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit)); flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib)); sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); + svm_canonicalization(env, &sc->base); } static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr, @@ -245,16 +256,6 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset)); - env->gdt.base = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - save.gdtr.base)); - env->gdt.limit = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - save.gdtr.limit)); - - env->idt.base = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - save.idtr.base)); - env->idt.limit = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - save.idtr.limit)); - new_cr0 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr0)); if (new_cr0 & SVM_CR0_RESERVED_MASK) { cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); @@ -308,6 +309,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) R_SS); svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), R_DS); + svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.idtr), + &env->idt); + svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.gdtr), + &env->gdt); env->eip = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip)); @@ -446,6 +451,7 @@ void helper_vmload(CPUX86State *env, int aflag) env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar)); env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar)); env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask)); + svm_canonicalization(env, &env->kernelgsbase); #endif env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star)); env->sysenter_cs = x86_ldq_phys(cs, @@ -454,6 +460,7 @@ void helper_vmload(CPUX86State *env, int aflag) save.sysenter_esp)); env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip)); + } void helper_vmsave(CPUX86State *env, int aflag) -- cgit v1.1 From 900eeca579a87011b701e523b15069e9d23b19cf Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Fri, 30 Jul 2021 09:07:42 +0200 Subject: target/i386: Added VGIF feature VGIF allows STGI and CLGI to execute in guest mode and control virtual interrupts in guest mode. When the VGIF feature is enabled then: * executing STGI in the guest sets bit 9 of the VMCB offset 60h. * executing CLGI in the guest clears bit 9 of the VMCB offset 60h. Signed-off-by: Lara Lazier Message-Id: <20210730070742.9674-1-laramglazier@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 3 ++- target/i386/svm.h | 6 ++++++ target/i386/tcg/sysemu/svm_helper.c | 31 +++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) (limited to 'target') diff --git a/target/i386/cpu.c b/target/i386/cpu.c index fbca4e5..86064ea 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -631,7 +631,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \ CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A) #define TCG_EXT4_FEATURES 0 -#define TCG_SVM_FEATURES CPUID_SVM_NPT +#define TCG_SVM_FEATURES (CPUID_SVM_NPT | CPUID_SVM_VGIF | \ + CPUID_SVM_SVME_ADDR_CHK) #define TCG_KVM_FEATURES 0 #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP | \ CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \ diff --git a/target/i386/svm.h b/target/i386/svm.h index adc058d..036597a 100644 --- a/target/i386/svm.h +++ b/target/i386/svm.h @@ -9,6 +9,12 @@ #define V_IRQ_SHIFT 8 #define V_IRQ_MASK (1 << V_IRQ_SHIFT) +#define V_GIF_ENABLED_SHIFT 25 +#define V_GIF_ENABLED_MASK (1 << V_GIF_ENABLED_SHIFT) + +#define V_GIF_SHIFT 9 +#define V_GIF_MASK (1 << V_GIF_SHIFT) + #define V_INTR_PRIO_SHIFT 16 #define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT) diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 0e7de4e..66c2c1e 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -121,6 +121,17 @@ static inline bool is_efer_invalid_state (CPUX86State *env) return false; } +static inline bool virtual_gif_enabled(CPUX86State *env, uint32_t *int_ctl) +{ + if (likely(env->hflags & HF_GUEST_MASK)) { + *int_ctl = x86_ldl_phys(env_cpu(env), + env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); + return (env->features[FEAT_SVM] & CPUID_SVM_VGIF) + && (*int_ctl & V_GIF_ENABLED_MASK); + } + return false; +} + void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) { CPUState *cs = env_cpu(env); @@ -510,13 +521,29 @@ void helper_vmsave(CPUX86State *env, int aflag) void helper_stgi(CPUX86State *env) { cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC()); - env->hflags2 |= HF2_GIF_MASK; + + CPUState *cs = env_cpu(env); + uint32_t int_ctl; + if (virtual_gif_enabled(env, &int_ctl)) { + x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), + int_ctl | V_GIF_MASK); + } else { + env->hflags2 |= HF2_GIF_MASK; + } } void helper_clgi(CPUX86State *env) { cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC()); - env->hflags2 &= ~HF2_GIF_MASK; + + CPUState *cs = env_cpu(env); + uint32_t int_ctl; + if (virtual_gif_enabled(env, &int_ctl)) { + x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), + int_ctl & ~V_GIF_MASK); + } else { + env->hflags2 &= ~HF2_GIF_MASK; + } } bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type) -- cgit v1.1 From e3126a5c92913b2a7e06111c8f40af3596880302 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Sat, 14 Aug 2021 09:51:00 +0200 Subject: target/i386: Moved int_ctl into CPUX86State structure Moved int_ctl into the CPUX86State structure. It removes some unnecessary stores and loads, and prepares for tracking the vIRQ state even when it is masked due to vGIF. Signed-off-by: Lara Lazier Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- target/i386/cpu.h | 1 + target/i386/machine.c | 22 ++++++++++++++++- target/i386/tcg/seg_helper.c | 2 +- target/i386/tcg/sysemu/misc_helper.c | 4 +-- target/i386/tcg/sysemu/svm_helper.c | 48 +++++++++++------------------------- 6 files changed, 41 insertions(+), 38 deletions(-) (limited to 'target') diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 86064ea..ddc3b63 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5655,7 +5655,7 @@ static void x86_cpu_reset(DeviceState *dev) env->old_exception = -1; /* init to reset state */ - + env->int_ctl = 0; env->hflags2 |= HF2_GIF_MASK; env->hflags &= ~HF_GUEST_MASK; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index aafc2eb..3dfe630 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1578,6 +1578,7 @@ typedef struct CPUX86State { uint64_t nested_cr3; uint32_t nested_pg_mode; uint8_t v_tpr; + uint32_t int_ctl; /* KVM states, automatically cleared on reset */ uint8_t nmi_injected; diff --git a/target/i386/machine.c b/target/i386/machine.c index f6f094f..b094311 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -203,7 +203,7 @@ static int cpu_pre_save(void *opaque) X86CPU *cpu = opaque; CPUX86State *env = &cpu->env; int i; - + env->v_tpr = env->int_ctl & V_TPR_MASK; /* FPU */ env->fpus_vmstate = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; env->fptag_vmstate = 0; @@ -1356,6 +1356,25 @@ static const VMStateDescription vmstate_svm_npt = { } }; +static bool svm_guest_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return tcg_enabled() && env->int_ctl; +} + +static const VMStateDescription vmstate_svm_guest = { + .name = "cpu/svm_guest", + .version_id = 1, + .minimum_version_id = 1, + .needed = svm_guest_needed, + .fields = (VMStateField[]){ + VMSTATE_UINT32(env.int_ctl, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + #ifndef TARGET_X86_64 static bool intel_efer32_needed(void *opaque) { @@ -1524,6 +1543,7 @@ const VMStateDescription vmstate_x86_cpu = { &vmstate_msr_intel_pt, &vmstate_msr_virt_ssbd, &vmstate_svm_npt, + &vmstate_svm_guest, #ifndef TARGET_X86_64 &vmstate_efer32, #endif diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 3ed20ca..cef68b6 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -1166,7 +1166,6 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) break; #if !defined(CONFIG_USER_ONLY) case CPU_INTERRUPT_VIRQ: - /* FIXME: this should respect TPR */ cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0, 0); intno = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); @@ -1174,6 +1173,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) "Servicing virtual hardware INT=0x%02x\n", intno); do_interrupt_x86_hardirq(env, intno, 1); cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + env->int_ctl &= ~V_IRQ_MASK; break; #endif } diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index e7a2ebd..91b0fc9 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -73,7 +73,7 @@ target_ulong helper_read_crN(CPUX86State *env, int reg) if (!(env->hflags2 & HF2_VINTR_MASK)) { val = cpu_get_apic_tpr(env_archcpu(env)->apic_state); } else { - val = env->v_tpr; + val = env->int_ctl & V_TPR_MASK; } break; } @@ -121,7 +121,7 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0); qemu_mutex_unlock_iothread(); } - env->v_tpr = t0 & 0x0f; + env->int_ctl = (env->int_ctl & ~V_TPR_MASK) | (t0 & V_TPR_MASK); break; default: env->cr[reg] = t0; diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 66c2c1e..24c58b6 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -76,14 +76,14 @@ static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr, sc->base, sc->limit, sc->flags); } -static inline bool ctl_has_irq(uint32_t int_ctl) +static inline bool ctl_has_irq(CPUX86State *env) { uint32_t int_prio; uint32_t tpr; - int_prio = (int_ctl & V_INTR_PRIO_MASK) >> V_INTR_PRIO_SHIFT; - tpr = int_ctl & V_TPR_MASK; - return (int_ctl & V_IRQ_MASK) && (int_prio >= tpr); + int_prio = (env->int_ctl & V_INTR_PRIO_MASK) >> V_INTR_PRIO_SHIFT; + tpr = env->int_ctl & V_TPR_MASK; + return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr); } static inline bool is_efer_invalid_state (CPUX86State *env) @@ -121,13 +121,11 @@ static inline bool is_efer_invalid_state (CPUX86State *env) return false; } -static inline bool virtual_gif_enabled(CPUX86State *env, uint32_t *int_ctl) +static inline bool virtual_gif_enabled(CPUX86State *env) { if (likely(env->hflags & HF_GUEST_MASK)) { - *int_ctl = x86_ldl_phys(env_cpu(env), - env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); return (env->features[FEAT_SVM] & CPUID_SVM_VGIF) - && (*int_ctl & V_GIF_ENABLED_MASK); + && (env->int_ctl & V_GIF_ENABLED_MASK); } return false; } @@ -139,7 +137,6 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) target_ulong addr; uint64_t nested_ctl; uint32_t event_inj; - uint32_t int_ctl; uint32_t asid; uint64_t new_cr0; uint64_t new_cr3; @@ -292,11 +289,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) cpu_x86_update_cr3(env, new_cr3); env->cr[2] = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr2)); - int_ctl = x86_ldl_phys(cs, + env->int_ctl = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); - if (int_ctl & V_INTR_MASKING_MASK) { - env->v_tpr = int_ctl & V_TPR_MASK; + if (env->int_ctl & V_INTR_MASKING_MASK) { env->hflags2 |= HF2_VINTR_MASK; if (env->eflags & IF_MASK) { env->hflags2 |= HF2_HIF_MASK; @@ -362,7 +358,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) env->hflags2 |= HF2_GIF_MASK; - if (ctl_has_irq(int_ctl)) { + if (ctl_has_irq(env)) { CPUState *cs = env_cpu(env); cs->interrupt_request |= CPU_INTERRUPT_VIRQ; @@ -522,11 +518,8 @@ void helper_stgi(CPUX86State *env) { cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC()); - CPUState *cs = env_cpu(env); - uint32_t int_ctl; - if (virtual_gif_enabled(env, &int_ctl)) { - x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), - int_ctl | V_GIF_MASK); + if (virtual_gif_enabled(env)) { + env->int_ctl |= V_GIF_MASK; } else { env->hflags2 |= HF2_GIF_MASK; } @@ -536,11 +529,8 @@ void helper_clgi(CPUX86State *env) { cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC()); - CPUState *cs = env_cpu(env); - uint32_t int_ctl; - if (virtual_gif_enabled(env, &int_ctl)) { - x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), - int_ctl & ~V_GIF_MASK); + if (virtual_gif_enabled(env)) { + env->int_ctl &= ~V_GIF_MASK; } else { env->hflags2 &= ~HF2_GIF_MASK; } @@ -688,7 +678,6 @@ void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1, void do_vmexit(CPUX86State *env) { CPUState *cs = env_cpu(env); - uint32_t int_ctl; if (env->hflags & HF_INHIBIT_IRQ_MASK) { x86_stl_phys(cs, @@ -731,16 +720,8 @@ void do_vmexit(CPUX86State *env) env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]); x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]); - - int_ctl = x86_ldl_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); - int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK); - int_ctl |= env->v_tpr & V_TPR_MASK; - if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) { - int_ctl |= V_IRQ_MASK; - } x86_stl_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl); + env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), env->int_ctl); x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rflags), cpu_compute_eflags(env)); @@ -763,6 +744,7 @@ void do_vmexit(CPUX86State *env) env->intercept = 0; env->intercept_exceptions = 0; cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + env->int_ctl = 0; env->tsc_offset = 0; env->gdt.base = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb, -- cgit v1.1 From b67e2796a132f912533a879a4fbe6acad4cbac1e Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Thu, 5 Aug 2021 13:08:23 +0200 Subject: target/i386: Added VGIF V_IRQ masking capability VGIF provides masking capability for when virtual interrupts are taken. (APM2) Signed-off-by: Lara Lazier Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 7 +++++-- target/i386/cpu.h | 2 ++ target/i386/tcg/sysemu/svm_helper.c | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'target') diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ddc3b63..6b029f1 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5657,6 +5657,7 @@ static void x86_cpu_reset(DeviceState *dev) /* init to reset state */ env->int_ctl = 0; env->hflags2 |= HF2_GIF_MASK; + env->hflags2 |= HF2_VGIF_MASK; env->hflags &= ~HF_GUEST_MASK; cpu_x86_update_cr0(env, 0x60000010); @@ -6540,10 +6541,12 @@ int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request) !(env->hflags & HF_INHIBIT_IRQ_MASK))))) { return CPU_INTERRUPT_HARD; #if !defined(CONFIG_USER_ONLY) - } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && + } else if (env->hflags2 & HF2_VGIF_MASK) { + if((interrupt_request & CPU_INTERRUPT_VIRQ) && (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { - return CPU_INTERRUPT_VIRQ; + return CPU_INTERRUPT_VIRQ; + } #endif } } diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 3dfe630..24e8ec5 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -203,6 +203,7 @@ typedef enum X86Seg { #define HF2_MPX_PR_SHIFT 5 /* BNDCFGx.BNDPRESERVE */ #define HF2_NPT_SHIFT 6 /* Nested Paging enabled */ #define HF2_IGNNE_SHIFT 7 /* Ignore CR0.NE=0 */ +#define HF2_VGIF_SHIFT 8 /* Can take VIRQ*/ #define HF2_GIF_MASK (1 << HF2_GIF_SHIFT) #define HF2_HIF_MASK (1 << HF2_HIF_SHIFT) @@ -212,6 +213,7 @@ typedef enum X86Seg { #define HF2_MPX_PR_MASK (1 << HF2_MPX_PR_SHIFT) #define HF2_NPT_MASK (1 << HF2_NPT_SHIFT) #define HF2_IGNNE_MASK (1 << HF2_IGNNE_SHIFT) +#define HF2_VGIF_MASK (1 << HF2_VGIF_SHIFT) #define CR0_PE_SHIFT 0 #define CR0_MP_SHIFT 1 diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 24c58b6..4612dae 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -130,6 +130,11 @@ static inline bool virtual_gif_enabled(CPUX86State *env) return false; } +static inline bool virtual_gif_set(CPUX86State *env) +{ + return !virtual_gif_enabled(env) || (env->int_ctl & V_GIF_MASK); +} + void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) { CPUState *cs = env_cpu(env); @@ -364,6 +369,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) cs->interrupt_request |= CPU_INTERRUPT_VIRQ; } + if (virtual_gif_set(env)) { + env->hflags2 |= HF2_VGIF_MASK; + } + /* maybe we need to inject an event */ event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); @@ -520,6 +529,7 @@ void helper_stgi(CPUX86State *env) if (virtual_gif_enabled(env)) { env->int_ctl |= V_GIF_MASK; + env->hflags2 |= HF2_VGIF_MASK; } else { env->hflags2 |= HF2_GIF_MASK; } @@ -531,6 +541,7 @@ void helper_clgi(CPUX86State *env) if (virtual_gif_enabled(env)) { env->int_ctl &= ~V_GIF_MASK; + env->hflags2 &= ~HF2_VGIF_MASK; } else { env->hflags2 &= ~HF2_GIF_MASK; } @@ -812,6 +823,7 @@ void do_vmexit(CPUX86State *env) env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0); env->hflags2 &= ~HF2_GIF_MASK; + env->hflags2 &= ~HF2_VGIF_MASK; /* FIXME: Resets the current ASID register to zero (host ASID). */ /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */ -- cgit v1.1 From 66a0201ba7a3143689014eb711a5942babca2585 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Tue, 17 Aug 2021 19:30:45 +0200 Subject: target/i386: Added ignore TPR check in ctl_has_irq The APM2 states that if V_IGN_TPR is nonzero, the current virtual interrupt ignores the (virtual) TPR. Signed-off-by: Lara Lazier Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/svm_helper.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'target') diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 4612dae..a35b795 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -83,6 +83,11 @@ static inline bool ctl_has_irq(CPUX86State *env) int_prio = (env->int_ctl & V_INTR_PRIO_MASK) >> V_INTR_PRIO_SHIFT; tpr = env->int_ctl & V_TPR_MASK; + + if (env->int_ctl & V_IGN_TPR_MASK) { + return env->int_ctl & V_IRQ_MASK; + } + return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr); } -- cgit v1.1 From 7760bb069f11fb4259c76c05c69a0d254b5d8a10 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Fri, 13 Aug 2021 11:45:52 +0200 Subject: target/i386: Added changed priority check for VIRQ Writes to cr8 affect v_tpr. This could set or unset an interrupt request as the priority might have changed. Signed-off-by: Lara Lazier Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 15 +++++++++++++++ target/i386/tcg/sysemu/misc_helper.c | 7 +++++++ target/i386/tcg/sysemu/svm_helper.c | 15 --------------- 3 files changed, 22 insertions(+), 15 deletions(-) (limited to 'target') diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 24e8ec5..6b09b8b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2246,6 +2246,21 @@ static inline uint64_t cr4_reserved_bits(CPUX86State *env) return reserved_bits; } +static inline bool ctl_has_irq(CPUX86State *env) +{ + uint32_t int_prio; + uint32_t tpr; + + int_prio = (env->int_ctl & V_INTR_PRIO_MASK) >> V_INTR_PRIO_SHIFT; + tpr = env->int_ctl & V_TPR_MASK; + + if (env->int_ctl & V_IGN_TPR_MASK) { + return (env->int_ctl & V_IRQ_MASK); + } + + return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr); +} + #if defined(TARGET_X86_64) && \ defined(CONFIG_USER_ONLY) && \ defined(CONFIG_LINUX) diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index 91b0fc9..9ccaa05 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -122,6 +122,13 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) qemu_mutex_unlock_iothread(); } env->int_ctl = (env->int_ctl & ~V_TPR_MASK) | (t0 & V_TPR_MASK); + + CPUState *cs = env_cpu(env); + if (ctl_has_irq(env)) { + cpu_interrupt(cs, CPU_INTERRUPT_VIRQ); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_VIRQ); + } break; default: env->cr[reg] = t0; diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index a35b795..7bbd3a1 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -76,21 +76,6 @@ static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr, sc->base, sc->limit, sc->flags); } -static inline bool ctl_has_irq(CPUX86State *env) -{ - uint32_t int_prio; - uint32_t tpr; - - int_prio = (env->int_ctl & V_INTR_PRIO_MASK) >> V_INTR_PRIO_SHIFT; - tpr = env->int_ctl & V_TPR_MASK; - - if (env->int_ctl & V_IGN_TPR_MASK) { - return env->int_ctl & V_IRQ_MASK; - } - - return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr); -} - static inline bool is_efer_invalid_state (CPUX86State *env) { if (!(env->efer & MSR_EFER_SVME)) { -- cgit v1.1 From 52fb8ad37aab791640174048b3d90ce9a576af63 Mon Sep 17 00:00:00 2001 From: Lara Lazier Date: Mon, 9 Aug 2021 16:26:28 +0200 Subject: target/i386: Added vVMLOAD and vVMSAVE feature The feature allows the VMSAVE and VMLOAD instructions to execute in guest mode without causing a VMEXIT. (APM2 15.33.1) Signed-off-by: Lara Lazier Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 2 ++ target/i386/svm.h | 2 ++ target/i386/tcg/sysemu/excp_helper.c | 2 +- target/i386/tcg/sysemu/svm_helper.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) (limited to 'target') diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 6b09b8b..71ae314 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2261,6 +2261,8 @@ static inline bool ctl_has_irq(CPUX86State *env) return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr); } +hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, + int *prot); #if defined(TARGET_X86_64) && \ defined(CONFIG_USER_ONLY) && \ defined(CONFIG_LINUX) diff --git a/target/i386/svm.h b/target/i386/svm.h index 036597a..f9a7854 100644 --- a/target/i386/svm.h +++ b/target/i386/svm.h @@ -24,6 +24,8 @@ #define V_INTR_MASKING_SHIFT 24 #define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) +#define V_VMLOAD_VMSAVE_ENABLED_MASK (1 << 1) + #define SVM_INTERRUPT_SHADOW_MASK 1 #define SVM_IOIO_STR_SHIFT 2 diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index b6d940e..7af887b 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -358,7 +358,7 @@ do_check_protect_pse36: return error_code; } -static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, +hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, int *prot) { CPUX86State *env = &X86_CPU(cs)->env; diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 7bbd3a1..6d39611 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -120,6 +120,25 @@ static inline bool virtual_gif_enabled(CPUX86State *env) return false; } +static inline bool virtual_vm_load_save_enabled(CPUX86State *env, uint32_t exit_code, uintptr_t retaddr) +{ + uint64_t lbr_ctl; + + if (likely(env->hflags & HF_GUEST_MASK)) { + if (likely(!(env->hflags2 & HF2_NPT_MASK)) || !(env->efer & MSR_EFER_LMA)) { + cpu_vmexit(env, exit_code, 0, retaddr); + } + + lbr_ctl = x86_ldl_phys(env_cpu(env), env->vm_vmcb + offsetof(struct vmcb, + control.lbr_ctl)); + return (env->features[FEAT_SVM] & CPUID_SVM_V_VMSAVE_VMLOAD) + && (lbr_ctl & V_VMLOAD_VMSAVE_ENABLED_MASK); + + } + + return false; +} + static inline bool virtual_gif_set(CPUX86State *env) { return !virtual_gif_enabled(env) || (env->int_ctl & V_GIF_MASK); @@ -431,6 +450,7 @@ void helper_vmload(CPUX86State *env, int aflag) { CPUState *cs = env_cpu(env); target_ulong addr; + int prot; cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); @@ -440,6 +460,10 @@ void helper_vmload(CPUX86State *env, int aflag) addr = (uint32_t)env->regs[R_EAX]; } + if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) { + addr = get_hphys(cs, addr, MMU_DATA_LOAD, &prot); + } + qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", addr, x86_ldq_phys(cs, addr + offsetof(struct vmcb, @@ -473,6 +497,7 @@ void helper_vmsave(CPUX86State *env, int aflag) { CPUState *cs = env_cpu(env); target_ulong addr; + int prot; cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); @@ -482,6 +507,10 @@ void helper_vmsave(CPUX86State *env, int aflag) addr = (uint32_t)env->regs[R_EAX]; } + if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) { + addr = get_hphys(cs, addr, MMU_DATA_STORE, &prot); + } + qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", addr, x86_ldq_phys(cs, -- cgit v1.1 From 8d4cd3dd8b7091772ff0fdf84b79619cf083c98c Mon Sep 17 00:00:00 2001 From: Reinoud Zandijk Date: Sun, 18 Jul 2021 15:46:50 +0200 Subject: Fix nvmm_ram_block_added() function arguments A parameter max_size was added to the RAMBlockNotifier ram_block_added function. Use the max_size for pre allocation of hva space. Signed-off-by: Reinoud Zandijk Message-Id: <20210718134650.1191-3-reinoud@NetBSD.org> Signed-off-by: Paolo Bonzini --- target/i386/nvmm/nvmm-all.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'target') diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index 28dee4c..a488b00 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -1132,13 +1132,14 @@ static MemoryListener nvmm_memory_listener = { }; static void -nvmm_ram_block_added(RAMBlockNotifier *n, void *host, size_t size) +nvmm_ram_block_added(RAMBlockNotifier *n, void *host, size_t size, + size_t max_size) { struct nvmm_machine *mach = get_nvmm_mach(); uintptr_t hva = (uintptr_t)host; int ret; - ret = nvmm_hva_map(mach, hva, size); + ret = nvmm_hva_map(mach, hva, max_size); if (ret == -1) { error_report("NVMM: Failed to map HVA, HostVA:%p " -- cgit v1.1