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 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'target/i386/cpu.c') diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 97e250e876..fbca4e5860 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) { -- cgit 1.4.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/i386/cpu.c') diff --git a/target/i386/cpu.c b/target/i386/cpu.c index fbca4e5860..86064ea1f9 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 adc058dc76..036597a2ff 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 0e7de4e054..66c2c1e61f 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 1.4.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/i386/cpu.c') diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 86064ea1f9..ddc3b63cb8 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 aafc2eb696..3dfe630d7e 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 f6f094f1c9..b0943118d1 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 3ed20ca31d..cef68b610a 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 e7a2ebde81..91b0fc916b 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 66c2c1e61f..24c58b6a38 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 1.4.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/i386/cpu.c') diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ddc3b63cb8..6b029f1bdf 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 3dfe630d7e..24e8ec5273 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 24c58b6a38..4612dae1ac 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 1.4.1