diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-09-13 13:33:21 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-09-13 13:33:21 +0100 |
commit | 7d79344d4fa44e520e6e89f8fed9a27d3d554a9b (patch) | |
tree | 286e99077f5f0d4192915a9f28bf51e138d12409 /target | |
parent | eae587e8e3694b1aceab23239493fb4c7e1a80f5 (diff) | |
parent | d97327342ea8b32ede19fadaf8290dc29fcfa048 (diff) |
Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging
* Fixes for "-cpu max" on i386 TCG (Daniel)
* vVMLOAD/VMSAVE and vGIF implementation (Lara)
* Reorganize i386 targets documentation in preparation for SGX (myself)
* Meson cleanups (myself, Thomas)
* NVMM fixes (Reinoud)
* Suppress bogus -Wstringop-overflow (Richard)
# gpg: Signature made Mon 13 Sep 2021 12:56:33 BST
# gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg: issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1
# Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83
* remotes/bonzini-gitlab/tags/for-upstream: (21 commits)
docs: link to archived Fedora code of conduct
Fix nvmm_ram_block_added() function arguments
Only check CONFIG_NVMM when NEED_CPU_H is defined
util: Suppress -Wstringop-overflow in qemu_thread_start
fw_cfg: add etc/msr_feature_control
meson: remove dead variable
meson: do not use python.full_path() unnecessarily
meson: look up cp and dtrace with find_program()
meson.build: Do not look for VNC-related libraries if have_system is not set
docs/system: move x86 CPU configuration to a separate document
docs/system: standardize man page sections to --- with overline
docs: standardize directory index to --- with overline
docs: standardize book titles to === with overline
target/i386: Added vVMLOAD and vVMSAVE feature
target/i386: Added changed priority check for VIRQ
target/i386: Added ignore TPR check in ctl_has_irq
target/i386: Added VGIF V_IRQ masking capability
target/i386: Moved int_ctl into CPUX86State structure
target/i386: Added VGIF feature
target/i386: VMRUN and VMLOAD canonicalizations
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r-- | target/i386/cpu.c | 31 | ||||
-rw-r--r-- | target/i386/cpu.h | 23 | ||||
-rw-r--r-- | target/i386/machine.c | 22 | ||||
-rw-r--r-- | target/i386/nvmm/nvmm-all.c | 5 | ||||
-rw-r--r-- | target/i386/svm.h | 8 | ||||
-rw-r--r-- | target/i386/tcg/seg_helper.c | 2 | ||||
-rw-r--r-- | target/i386/tcg/sysemu/excp_helper.c | 2 | ||||
-rw-r--r-- | target/i386/tcg/sysemu/misc_helper.c | 11 | ||||
-rw-r--r-- | target/i386/tcg/sysemu/svm_helper.c | 121 |
9 files changed, 169 insertions, 56 deletions
diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 97e250e876..6b029f1bdf 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 | \ @@ -5115,6 +5116,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 +5527,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) { @@ -5651,8 +5655,9 @@ 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->hflags2 |= HF2_VGIF_MASK; env->hflags &= ~HF_GUEST_MASK; cpu_x86_update_cr0(env, 0x60000010); @@ -6536,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 6c50d3ab4f..71ae3141c3 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 @@ -257,6 +259,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)) @@ -1577,6 +1580,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; @@ -1954,6 +1958,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, @@ -2240,6 +2246,23 @@ 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); +} + +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/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/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index 28dee4c5ee..a488b00e90 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 " diff --git a/target/i386/svm.h b/target/i386/svm.h index adc058dc76..f9a785489d 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) @@ -18,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/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/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index b6d940e04e..7af887be4d 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/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index e7a2ebde81..9ccaa054c4 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,14 @@ 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); + + 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 0d549b3d6c..6d39611eb6 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, @@ -65,16 +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(uint32_t int_ctl) -{ - 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); -} - static inline bool is_efer_invalid_state (CPUX86State *env) { if (!(env->efer & MSR_EFER_SVME)) { @@ -110,6 +111,39 @@ static inline bool is_efer_invalid_state (CPUX86State *env) return false; } +static inline bool virtual_gif_enabled(CPUX86State *env) +{ + if (likely(env->hflags & HF_GUEST_MASK)) { + return (env->features[FEAT_SVM] & CPUID_SVM_VGIF) + && (env->int_ctl & V_GIF_ENABLED_MASK); + } + 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); +} + void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) { CPUState *cs = env_cpu(env); @@ -117,7 +151,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; @@ -245,16 +278,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()); @@ -280,11 +303,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; @@ -308,6 +330,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)); @@ -346,12 +372,16 @@ 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; } + 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)); @@ -420,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()); @@ -429,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, @@ -446,6 +481,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,12 +490,14 @@ 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) { CPUState *cs = env_cpu(env); target_ulong addr; + int prot; cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); @@ -469,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, @@ -503,13 +545,25 @@ 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; + + if (virtual_gif_enabled(env)) { + env->int_ctl |= V_GIF_MASK; + env->hflags2 |= HF2_VGIF_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; + + if (virtual_gif_enabled(env)) { + env->int_ctl &= ~V_GIF_MASK; + env->hflags2 &= ~HF2_VGIF_MASK; + } else { + env->hflags2 &= ~HF2_GIF_MASK; + } } bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type) @@ -654,7 +708,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, @@ -697,16 +750,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)); @@ -729,6 +774,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, @@ -796,6 +842,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. */ |