xref: /openbmc/qemu/target/i386/tcg/system/svm_helper.c (revision d9a4282c4b690e45d25c2b933f318bb41eeb271d)
132cad1ffSPhilippe Mathieu-Daudé /*
232cad1ffSPhilippe Mathieu-Daudé  *  x86 SVM helpers (system only)
332cad1ffSPhilippe Mathieu-Daudé  *
432cad1ffSPhilippe Mathieu-Daudé  *  Copyright (c) 2003 Fabrice Bellard
532cad1ffSPhilippe Mathieu-Daudé  *
632cad1ffSPhilippe Mathieu-Daudé  * This library is free software; you can redistribute it and/or
732cad1ffSPhilippe Mathieu-Daudé  * modify it under the terms of the GNU Lesser General Public
832cad1ffSPhilippe Mathieu-Daudé  * License as published by the Free Software Foundation; either
932cad1ffSPhilippe Mathieu-Daudé  * version 2.1 of the License, or (at your option) any later version.
1032cad1ffSPhilippe Mathieu-Daudé  *
1132cad1ffSPhilippe Mathieu-Daudé  * This library is distributed in the hope that it will be useful,
1232cad1ffSPhilippe Mathieu-Daudé  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1332cad1ffSPhilippe Mathieu-Daudé  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1432cad1ffSPhilippe Mathieu-Daudé  * Lesser General Public License for more details.
1532cad1ffSPhilippe Mathieu-Daudé  *
1632cad1ffSPhilippe Mathieu-Daudé  * You should have received a copy of the GNU Lesser General Public
1732cad1ffSPhilippe Mathieu-Daudé  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1832cad1ffSPhilippe Mathieu-Daudé  */
1932cad1ffSPhilippe Mathieu-Daudé 
2032cad1ffSPhilippe Mathieu-Daudé #include "qemu/osdep.h"
2132cad1ffSPhilippe Mathieu-Daudé #include "qemu/log.h"
2232cad1ffSPhilippe Mathieu-Daudé #include "cpu.h"
2332cad1ffSPhilippe Mathieu-Daudé #include "exec/helper-proto.h"
24*6ff5da16SPhilippe Mathieu-Daudé #include "exec/cputlb.h"
2532cad1ffSPhilippe Mathieu-Daudé #include "exec/cpu_ldst.h"
2632cad1ffSPhilippe Mathieu-Daudé #include "tcg/helper-tcg.h"
2732cad1ffSPhilippe Mathieu-Daudé 
2832cad1ffSPhilippe Mathieu-Daudé /* Secure Virtual Machine helpers */
2932cad1ffSPhilippe Mathieu-Daudé 
svm_save_seg(CPUX86State * env,int mmu_idx,hwaddr addr,const SegmentCache * sc)3032cad1ffSPhilippe Mathieu-Daudé static void svm_save_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
3132cad1ffSPhilippe Mathieu-Daudé                          const SegmentCache *sc)
3232cad1ffSPhilippe Mathieu-Daudé {
3332cad1ffSPhilippe Mathieu-Daudé     cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
3432cad1ffSPhilippe Mathieu-Daudé                       sc->selector, mmu_idx, 0);
3532cad1ffSPhilippe Mathieu-Daudé     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base),
3632cad1ffSPhilippe Mathieu-Daudé                       sc->base, mmu_idx, 0);
3732cad1ffSPhilippe Mathieu-Daudé     cpu_stl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit),
3832cad1ffSPhilippe Mathieu-Daudé                       sc->limit, mmu_idx, 0);
3932cad1ffSPhilippe Mathieu-Daudé     cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib),
4032cad1ffSPhilippe Mathieu-Daudé                       ((sc->flags >> 8) & 0xff)
4132cad1ffSPhilippe Mathieu-Daudé                       | ((sc->flags >> 12) & 0x0f00),
4232cad1ffSPhilippe Mathieu-Daudé                       mmu_idx, 0);
4332cad1ffSPhilippe Mathieu-Daudé }
4432cad1ffSPhilippe Mathieu-Daudé 
4532cad1ffSPhilippe Mathieu-Daudé /*
4632cad1ffSPhilippe Mathieu-Daudé  * VMRUN and VMLOAD canonicalizes (i.e., sign-extend to bit 63) all base
4732cad1ffSPhilippe Mathieu-Daudé  * addresses in the segment registers that have been loaded.
4832cad1ffSPhilippe Mathieu-Daudé  */
svm_canonicalization(CPUX86State * env,target_ulong * seg_base)4932cad1ffSPhilippe Mathieu-Daudé static inline void svm_canonicalization(CPUX86State *env, target_ulong *seg_base)
5032cad1ffSPhilippe Mathieu-Daudé {
5132cad1ffSPhilippe Mathieu-Daudé     uint16_t shift_amt = 64 - cpu_x86_virtual_addr_width(env);
5232cad1ffSPhilippe Mathieu-Daudé     *seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt);
5332cad1ffSPhilippe Mathieu-Daudé }
5432cad1ffSPhilippe Mathieu-Daudé 
svm_load_seg(CPUX86State * env,int mmu_idx,hwaddr addr,SegmentCache * sc)5532cad1ffSPhilippe Mathieu-Daudé static void svm_load_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
5632cad1ffSPhilippe Mathieu-Daudé                          SegmentCache *sc)
5732cad1ffSPhilippe Mathieu-Daudé {
5832cad1ffSPhilippe Mathieu-Daudé     unsigned int flags;
5932cad1ffSPhilippe Mathieu-Daudé 
6032cad1ffSPhilippe Mathieu-Daudé     sc->selector =
6132cad1ffSPhilippe Mathieu-Daudé         cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
6232cad1ffSPhilippe Mathieu-Daudé                            mmu_idx, 0);
6332cad1ffSPhilippe Mathieu-Daudé     sc->base =
6432cad1ffSPhilippe Mathieu-Daudé         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base),
6532cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
6632cad1ffSPhilippe Mathieu-Daudé     sc->limit =
6732cad1ffSPhilippe Mathieu-Daudé         cpu_ldl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit),
6832cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
6932cad1ffSPhilippe Mathieu-Daudé     flags =
7032cad1ffSPhilippe Mathieu-Daudé         cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib),
7132cad1ffSPhilippe Mathieu-Daudé                            mmu_idx, 0);
7232cad1ffSPhilippe Mathieu-Daudé     sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
7332cad1ffSPhilippe Mathieu-Daudé 
7432cad1ffSPhilippe Mathieu-Daudé     svm_canonicalization(env, &sc->base);
7532cad1ffSPhilippe Mathieu-Daudé }
7632cad1ffSPhilippe Mathieu-Daudé 
svm_load_seg_cache(CPUX86State * env,int mmu_idx,hwaddr addr,int seg_reg)7732cad1ffSPhilippe Mathieu-Daudé static void svm_load_seg_cache(CPUX86State *env, int mmu_idx,
7832cad1ffSPhilippe Mathieu-Daudé                                hwaddr addr, int seg_reg)
7932cad1ffSPhilippe Mathieu-Daudé {
8032cad1ffSPhilippe Mathieu-Daudé     SegmentCache sc;
8132cad1ffSPhilippe Mathieu-Daudé 
8232cad1ffSPhilippe Mathieu-Daudé     svm_load_seg(env, mmu_idx, addr, &sc);
8332cad1ffSPhilippe Mathieu-Daudé     cpu_x86_load_seg_cache(env, seg_reg, sc.selector,
8432cad1ffSPhilippe Mathieu-Daudé                            sc.base, sc.limit, sc.flags);
8532cad1ffSPhilippe Mathieu-Daudé }
8632cad1ffSPhilippe Mathieu-Daudé 
is_efer_invalid_state(CPUX86State * env)8732cad1ffSPhilippe Mathieu-Daudé static inline bool is_efer_invalid_state (CPUX86State *env)
8832cad1ffSPhilippe Mathieu-Daudé {
8932cad1ffSPhilippe Mathieu-Daudé     if (!(env->efer & MSR_EFER_SVME)) {
9032cad1ffSPhilippe Mathieu-Daudé         return true;
9132cad1ffSPhilippe Mathieu-Daudé     }
9232cad1ffSPhilippe Mathieu-Daudé 
9332cad1ffSPhilippe Mathieu-Daudé     if (env->efer & MSR_EFER_RESERVED) {
9432cad1ffSPhilippe Mathieu-Daudé         return true;
9532cad1ffSPhilippe Mathieu-Daudé     }
9632cad1ffSPhilippe Mathieu-Daudé 
9732cad1ffSPhilippe Mathieu-Daudé     if ((env->efer & (MSR_EFER_LMA | MSR_EFER_LME)) &&
9832cad1ffSPhilippe Mathieu-Daudé             !(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
9932cad1ffSPhilippe Mathieu-Daudé         return true;
10032cad1ffSPhilippe Mathieu-Daudé     }
10132cad1ffSPhilippe Mathieu-Daudé 
10232cad1ffSPhilippe Mathieu-Daudé     if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
10332cad1ffSPhilippe Mathieu-Daudé                                 && !(env->cr[4] & CR4_PAE_MASK)) {
10432cad1ffSPhilippe Mathieu-Daudé         return true;
10532cad1ffSPhilippe Mathieu-Daudé     }
10632cad1ffSPhilippe Mathieu-Daudé 
10732cad1ffSPhilippe Mathieu-Daudé     if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
10832cad1ffSPhilippe Mathieu-Daudé                                 && !(env->cr[0] & CR0_PE_MASK)) {
10932cad1ffSPhilippe Mathieu-Daudé         return true;
11032cad1ffSPhilippe Mathieu-Daudé     }
11132cad1ffSPhilippe Mathieu-Daudé 
11232cad1ffSPhilippe Mathieu-Daudé     if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
11332cad1ffSPhilippe Mathieu-Daudé                                 && (env->cr[4] & CR4_PAE_MASK)
11432cad1ffSPhilippe Mathieu-Daudé                                 && (env->segs[R_CS].flags & DESC_L_MASK)
11532cad1ffSPhilippe Mathieu-Daudé                                 && (env->segs[R_CS].flags & DESC_B_MASK)) {
11632cad1ffSPhilippe Mathieu-Daudé         return true;
11732cad1ffSPhilippe Mathieu-Daudé     }
11832cad1ffSPhilippe Mathieu-Daudé 
11932cad1ffSPhilippe Mathieu-Daudé     return false;
12032cad1ffSPhilippe Mathieu-Daudé }
12132cad1ffSPhilippe Mathieu-Daudé 
virtual_gif_enabled(CPUX86State * env)12232cad1ffSPhilippe Mathieu-Daudé static inline bool virtual_gif_enabled(CPUX86State *env)
12332cad1ffSPhilippe Mathieu-Daudé {
12432cad1ffSPhilippe Mathieu-Daudé     if (likely(env->hflags & HF_GUEST_MASK)) {
12532cad1ffSPhilippe Mathieu-Daudé         return (env->features[FEAT_SVM] & CPUID_SVM_VGIF)
12632cad1ffSPhilippe Mathieu-Daudé                     && (env->int_ctl & V_GIF_ENABLED_MASK);
12732cad1ffSPhilippe Mathieu-Daudé     }
12832cad1ffSPhilippe Mathieu-Daudé     return false;
12932cad1ffSPhilippe Mathieu-Daudé }
13032cad1ffSPhilippe Mathieu-Daudé 
virtual_vm_load_save_enabled(CPUX86State * env,uint32_t exit_code,uintptr_t retaddr)13132cad1ffSPhilippe Mathieu-Daudé static inline bool virtual_vm_load_save_enabled(CPUX86State *env, uint32_t exit_code, uintptr_t retaddr)
13232cad1ffSPhilippe Mathieu-Daudé {
13332cad1ffSPhilippe Mathieu-Daudé     uint64_t lbr_ctl;
13432cad1ffSPhilippe Mathieu-Daudé 
13532cad1ffSPhilippe Mathieu-Daudé     if (likely(env->hflags & HF_GUEST_MASK)) {
13632cad1ffSPhilippe Mathieu-Daudé         if (likely(!(env->hflags2 & HF2_NPT_MASK)) || !(env->efer & MSR_EFER_LMA)) {
13732cad1ffSPhilippe Mathieu-Daudé             cpu_vmexit(env, exit_code, 0, retaddr);
13832cad1ffSPhilippe Mathieu-Daudé         }
13932cad1ffSPhilippe Mathieu-Daudé 
14032cad1ffSPhilippe Mathieu-Daudé         lbr_ctl = x86_ldl_phys(env_cpu(env), env->vm_vmcb + offsetof(struct vmcb,
14132cad1ffSPhilippe Mathieu-Daudé                                                   control.lbr_ctl));
14232cad1ffSPhilippe Mathieu-Daudé         return (env->features[FEAT_SVM] & CPUID_SVM_V_VMSAVE_VMLOAD)
14332cad1ffSPhilippe Mathieu-Daudé                 && (lbr_ctl & V_VMLOAD_VMSAVE_ENABLED_MASK);
14432cad1ffSPhilippe Mathieu-Daudé 
14532cad1ffSPhilippe Mathieu-Daudé     }
14632cad1ffSPhilippe Mathieu-Daudé 
14732cad1ffSPhilippe Mathieu-Daudé     return false;
14832cad1ffSPhilippe Mathieu-Daudé }
14932cad1ffSPhilippe Mathieu-Daudé 
virtual_gif_set(CPUX86State * env)15032cad1ffSPhilippe Mathieu-Daudé static inline bool virtual_gif_set(CPUX86State *env)
15132cad1ffSPhilippe Mathieu-Daudé {
15232cad1ffSPhilippe Mathieu-Daudé     return !virtual_gif_enabled(env) || (env->int_ctl & V_GIF_MASK);
15332cad1ffSPhilippe Mathieu-Daudé }
15432cad1ffSPhilippe Mathieu-Daudé 
helper_vmrun(CPUX86State * env,int aflag,int next_eip_addend)15532cad1ffSPhilippe Mathieu-Daudé void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
15632cad1ffSPhilippe Mathieu-Daudé {
15732cad1ffSPhilippe Mathieu-Daudé     CPUState *cs = env_cpu(env);
15832cad1ffSPhilippe Mathieu-Daudé     X86CPU *cpu = env_archcpu(env);
15932cad1ffSPhilippe Mathieu-Daudé     target_ulong addr;
16032cad1ffSPhilippe Mathieu-Daudé     uint64_t nested_ctl;
16132cad1ffSPhilippe Mathieu-Daudé     uint32_t event_inj;
16232cad1ffSPhilippe Mathieu-Daudé     uint32_t asid;
16332cad1ffSPhilippe Mathieu-Daudé     uint64_t new_cr0;
16432cad1ffSPhilippe Mathieu-Daudé     uint64_t new_cr3;
16532cad1ffSPhilippe Mathieu-Daudé     uint64_t new_cr4;
16632cad1ffSPhilippe Mathieu-Daudé     uint64_t new_dr6;
16732cad1ffSPhilippe Mathieu-Daudé     uint64_t new_dr7;
16832cad1ffSPhilippe Mathieu-Daudé 
16932cad1ffSPhilippe Mathieu-Daudé     if (aflag == 2) {
17032cad1ffSPhilippe Mathieu-Daudé         addr = env->regs[R_EAX];
17132cad1ffSPhilippe Mathieu-Daudé     } else {
17232cad1ffSPhilippe Mathieu-Daudé         addr = (uint32_t)env->regs[R_EAX];
17332cad1ffSPhilippe Mathieu-Daudé     }
17432cad1ffSPhilippe Mathieu-Daudé 
17532cad1ffSPhilippe Mathieu-Daudé     /* Exceptions are checked before the intercept.  */
17632cad1ffSPhilippe Mathieu-Daudé     if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) {
17732cad1ffSPhilippe Mathieu-Daudé         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
17832cad1ffSPhilippe Mathieu-Daudé     }
17932cad1ffSPhilippe Mathieu-Daudé 
18032cad1ffSPhilippe Mathieu-Daudé     cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC());
18132cad1ffSPhilippe Mathieu-Daudé 
18232cad1ffSPhilippe Mathieu-Daudé     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
18332cad1ffSPhilippe Mathieu-Daudé 
18432cad1ffSPhilippe Mathieu-Daudé     env->vm_vmcb = addr;
18532cad1ffSPhilippe Mathieu-Daudé 
18632cad1ffSPhilippe Mathieu-Daudé     /* save the current CPU state in the hsave page */
18732cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.base),
18832cad1ffSPhilippe Mathieu-Daudé              env->gdt.base);
18932cad1ffSPhilippe Mathieu-Daudé     x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit),
19032cad1ffSPhilippe Mathieu-Daudé              env->gdt.limit);
19132cad1ffSPhilippe Mathieu-Daudé 
19232cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.base),
19332cad1ffSPhilippe Mathieu-Daudé              env->idt.base);
19432cad1ffSPhilippe Mathieu-Daudé     x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.limit),
19532cad1ffSPhilippe Mathieu-Daudé              env->idt.limit);
19632cad1ffSPhilippe Mathieu-Daudé 
19732cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
19832cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
19932cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
20032cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
20132cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
20232cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
20332cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
20432cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
20532cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
20632cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
20732cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
20832cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
20932cad1ffSPhilippe Mathieu-Daudé 
21032cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
21132cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
21232cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
21332cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.rflags),
21432cad1ffSPhilippe Mathieu-Daudé              cpu_compute_eflags(env));
21532cad1ffSPhilippe Mathieu-Daudé 
21632cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, MMU_PHYS_IDX,
21732cad1ffSPhilippe Mathieu-Daudé                  env->vm_hsave + offsetof(struct vmcb, save.es),
21832cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_ES]);
21932cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, MMU_PHYS_IDX,
22032cad1ffSPhilippe Mathieu-Daudé                  env->vm_hsave + offsetof(struct vmcb, save.cs),
22132cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_CS]);
22232cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, MMU_PHYS_IDX,
22332cad1ffSPhilippe Mathieu-Daudé                  env->vm_hsave + offsetof(struct vmcb, save.ss),
22432cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_SS]);
22532cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, MMU_PHYS_IDX,
22632cad1ffSPhilippe Mathieu-Daudé                  env->vm_hsave + offsetof(struct vmcb, save.ds),
22732cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_DS]);
22832cad1ffSPhilippe Mathieu-Daudé 
22932cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip),
23032cad1ffSPhilippe Mathieu-Daudé              env->eip + next_eip_addend);
23132cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
23232cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
23332cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
23432cad1ffSPhilippe Mathieu-Daudé              env->vm_hsave + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
23532cad1ffSPhilippe Mathieu-Daudé 
23632cad1ffSPhilippe Mathieu-Daudé     /* load the interception bitmaps so we do not need to access the
23732cad1ffSPhilippe Mathieu-Daudé        vmcb in svm mode */
23832cad1ffSPhilippe Mathieu-Daudé     env->intercept = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
23932cad1ffSPhilippe Mathieu-Daudé                                                       control.intercept));
24032cad1ffSPhilippe Mathieu-Daudé     env->intercept_cr_read = x86_lduw_phys(cs, env->vm_vmcb +
24132cad1ffSPhilippe Mathieu-Daudé                                        offsetof(struct vmcb,
24232cad1ffSPhilippe Mathieu-Daudé                                                 control.intercept_cr_read));
24332cad1ffSPhilippe Mathieu-Daudé     env->intercept_cr_write = x86_lduw_phys(cs, env->vm_vmcb +
24432cad1ffSPhilippe Mathieu-Daudé                                         offsetof(struct vmcb,
24532cad1ffSPhilippe Mathieu-Daudé                                                  control.intercept_cr_write));
24632cad1ffSPhilippe Mathieu-Daudé     env->intercept_dr_read = x86_lduw_phys(cs, env->vm_vmcb +
24732cad1ffSPhilippe Mathieu-Daudé                                        offsetof(struct vmcb,
24832cad1ffSPhilippe Mathieu-Daudé                                                 control.intercept_dr_read));
24932cad1ffSPhilippe Mathieu-Daudé     env->intercept_dr_write = x86_lduw_phys(cs, env->vm_vmcb +
25032cad1ffSPhilippe Mathieu-Daudé                                         offsetof(struct vmcb,
25132cad1ffSPhilippe Mathieu-Daudé                                                  control.intercept_dr_write));
25232cad1ffSPhilippe Mathieu-Daudé     env->intercept_exceptions = x86_ldl_phys(cs, env->vm_vmcb +
25332cad1ffSPhilippe Mathieu-Daudé                                          offsetof(struct vmcb,
25432cad1ffSPhilippe Mathieu-Daudé                                                   control.intercept_exceptions
25532cad1ffSPhilippe Mathieu-Daudé                                                   ));
25632cad1ffSPhilippe Mathieu-Daudé 
25732cad1ffSPhilippe Mathieu-Daudé     env->hflags &= ~HF_INHIBIT_IRQ_MASK;
25832cad1ffSPhilippe Mathieu-Daudé     if (x86_ldl_phys(cs, env->vm_vmcb +
25932cad1ffSPhilippe Mathieu-Daudé                 offsetof(struct vmcb, control.int_state)) &
26032cad1ffSPhilippe Mathieu-Daudé                  SVM_INTERRUPT_SHADOW_MASK) {
26132cad1ffSPhilippe Mathieu-Daudé         env->hflags |= HF_INHIBIT_IRQ_MASK;
26232cad1ffSPhilippe Mathieu-Daudé     }
26332cad1ffSPhilippe Mathieu-Daudé 
26432cad1ffSPhilippe Mathieu-Daudé     nested_ctl = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
26532cad1ffSPhilippe Mathieu-Daudé                                                           control.nested_ctl));
26632cad1ffSPhilippe Mathieu-Daudé     asid = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
26732cad1ffSPhilippe Mathieu-Daudé                                                           control.asid));
26832cad1ffSPhilippe Mathieu-Daudé 
26932cad1ffSPhilippe Mathieu-Daudé     uint64_t msrpm_base_pa = x86_ldq_phys(cs, env->vm_vmcb +
27032cad1ffSPhilippe Mathieu-Daudé                                     offsetof(struct vmcb,
27132cad1ffSPhilippe Mathieu-Daudé                                             control.msrpm_base_pa));
27232cad1ffSPhilippe Mathieu-Daudé     uint64_t iopm_base_pa = x86_ldq_phys(cs, env->vm_vmcb +
27332cad1ffSPhilippe Mathieu-Daudé                                  offsetof(struct vmcb, control.iopm_base_pa));
27432cad1ffSPhilippe Mathieu-Daudé 
27532cad1ffSPhilippe Mathieu-Daudé     if ((msrpm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_MSRPM_SIZE) {
27632cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
27732cad1ffSPhilippe Mathieu-Daudé     }
27832cad1ffSPhilippe Mathieu-Daudé 
27932cad1ffSPhilippe Mathieu-Daudé     if ((iopm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_IOPM_SIZE) {
28032cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
28132cad1ffSPhilippe Mathieu-Daudé     }
28232cad1ffSPhilippe Mathieu-Daudé 
28332cad1ffSPhilippe Mathieu-Daudé     env->nested_pg_mode = 0;
28432cad1ffSPhilippe Mathieu-Daudé 
28532cad1ffSPhilippe Mathieu-Daudé     if (!cpu_svm_has_intercept(env, SVM_EXIT_VMRUN)) {
28632cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
28732cad1ffSPhilippe Mathieu-Daudé     }
28832cad1ffSPhilippe Mathieu-Daudé     if (asid == 0) {
28932cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
29032cad1ffSPhilippe Mathieu-Daudé     }
29132cad1ffSPhilippe Mathieu-Daudé 
29232cad1ffSPhilippe Mathieu-Daudé     if (nested_ctl & SVM_NPT_ENABLED) {
29332cad1ffSPhilippe Mathieu-Daudé         env->nested_cr3 = x86_ldq_phys(cs,
29432cad1ffSPhilippe Mathieu-Daudé                                 env->vm_vmcb + offsetof(struct vmcb,
29532cad1ffSPhilippe Mathieu-Daudé                                                         control.nested_cr3));
29632cad1ffSPhilippe Mathieu-Daudé         env->hflags2 |= HF2_NPT_MASK;
29732cad1ffSPhilippe Mathieu-Daudé 
29832cad1ffSPhilippe Mathieu-Daudé         env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK;
29932cad1ffSPhilippe Mathieu-Daudé 
30032cad1ffSPhilippe Mathieu-Daudé         tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX);
30132cad1ffSPhilippe Mathieu-Daudé     }
30232cad1ffSPhilippe Mathieu-Daudé 
30332cad1ffSPhilippe Mathieu-Daudé     /* enable intercepts */
30432cad1ffSPhilippe Mathieu-Daudé     env->hflags |= HF_GUEST_MASK;
30532cad1ffSPhilippe Mathieu-Daudé 
30632cad1ffSPhilippe Mathieu-Daudé     env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb +
30732cad1ffSPhilippe Mathieu-Daudé                                offsetof(struct vmcb, control.tsc_offset));
30832cad1ffSPhilippe Mathieu-Daudé 
30932cad1ffSPhilippe Mathieu-Daudé     new_cr0 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr0));
31032cad1ffSPhilippe Mathieu-Daudé     if (new_cr0 & SVM_CR0_RESERVED_MASK) {
31132cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
31232cad1ffSPhilippe Mathieu-Daudé     }
31332cad1ffSPhilippe Mathieu-Daudé     if ((new_cr0 & CR0_NW_MASK) && !(new_cr0 & CR0_CD_MASK)) {
31432cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
31532cad1ffSPhilippe Mathieu-Daudé     }
31632cad1ffSPhilippe Mathieu-Daudé     new_cr3 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr3));
31732cad1ffSPhilippe Mathieu-Daudé     if ((env->efer & MSR_EFER_LMA) &&
31832cad1ffSPhilippe Mathieu-Daudé             (new_cr3 & ((~0ULL) << cpu->phys_bits))) {
31932cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
32032cad1ffSPhilippe Mathieu-Daudé     }
32132cad1ffSPhilippe Mathieu-Daudé     new_cr4 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4));
32232cad1ffSPhilippe Mathieu-Daudé     if (new_cr4 & cr4_reserved_bits(env)) {
32332cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
32432cad1ffSPhilippe Mathieu-Daudé     }
32532cad1ffSPhilippe Mathieu-Daudé     /* clear exit_info_2 so we behave like the real hardware */
32632cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
32732cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
32832cad1ffSPhilippe Mathieu-Daudé 
32932cad1ffSPhilippe Mathieu-Daudé     cpu_x86_update_cr0(env, new_cr0);
33032cad1ffSPhilippe Mathieu-Daudé     cpu_x86_update_cr4(env, new_cr4);
33132cad1ffSPhilippe Mathieu-Daudé     cpu_x86_update_cr3(env, new_cr3);
33232cad1ffSPhilippe Mathieu-Daudé     env->cr[2] = x86_ldq_phys(cs,
33332cad1ffSPhilippe Mathieu-Daudé                           env->vm_vmcb + offsetof(struct vmcb, save.cr2));
33432cad1ffSPhilippe Mathieu-Daudé     env->int_ctl = x86_ldl_phys(cs,
33532cad1ffSPhilippe Mathieu-Daudé                        env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
33632cad1ffSPhilippe Mathieu-Daudé     env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
33732cad1ffSPhilippe Mathieu-Daudé     if (env->int_ctl & V_INTR_MASKING_MASK) {
33832cad1ffSPhilippe Mathieu-Daudé         env->hflags2 |= HF2_VINTR_MASK;
33932cad1ffSPhilippe Mathieu-Daudé         if (env->eflags & IF_MASK) {
34032cad1ffSPhilippe Mathieu-Daudé             env->hflags2 |= HF2_HIF_MASK;
34132cad1ffSPhilippe Mathieu-Daudé         }
34232cad1ffSPhilippe Mathieu-Daudé     }
34332cad1ffSPhilippe Mathieu-Daudé 
34432cad1ffSPhilippe Mathieu-Daudé     cpu_load_efer(env,
34532cad1ffSPhilippe Mathieu-Daudé                   x86_ldq_phys(cs,
34632cad1ffSPhilippe Mathieu-Daudé                            env->vm_vmcb + offsetof(struct vmcb, save.efer)));
34732cad1ffSPhilippe Mathieu-Daudé     env->eflags = 0;
34832cad1ffSPhilippe Mathieu-Daudé     cpu_load_eflags(env, x86_ldq_phys(cs,
34932cad1ffSPhilippe Mathieu-Daudé                                   env->vm_vmcb + offsetof(struct vmcb,
35032cad1ffSPhilippe Mathieu-Daudé                                                           save.rflags)),
35132cad1ffSPhilippe Mathieu-Daudé                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
35232cad1ffSPhilippe Mathieu-Daudé 
35332cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, MMU_PHYS_IDX,
35432cad1ffSPhilippe Mathieu-Daudé                        env->vm_vmcb + offsetof(struct vmcb, save.es), R_ES);
35532cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, MMU_PHYS_IDX,
35632cad1ffSPhilippe Mathieu-Daudé                        env->vm_vmcb + offsetof(struct vmcb, save.cs), R_CS);
35732cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, MMU_PHYS_IDX,
35832cad1ffSPhilippe Mathieu-Daudé                        env->vm_vmcb + offsetof(struct vmcb, save.ss), R_SS);
35932cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, MMU_PHYS_IDX,
36032cad1ffSPhilippe Mathieu-Daudé                        env->vm_vmcb + offsetof(struct vmcb, save.ds), R_DS);
36132cad1ffSPhilippe Mathieu-Daudé     svm_load_seg(env, MMU_PHYS_IDX,
36232cad1ffSPhilippe Mathieu-Daudé                  env->vm_vmcb + offsetof(struct vmcb, save.idtr), &env->idt);
36332cad1ffSPhilippe Mathieu-Daudé     svm_load_seg(env, MMU_PHYS_IDX,
36432cad1ffSPhilippe Mathieu-Daudé                  env->vm_vmcb + offsetof(struct vmcb, save.gdtr), &env->gdt);
36532cad1ffSPhilippe Mathieu-Daudé 
36632cad1ffSPhilippe Mathieu-Daudé     env->eip = x86_ldq_phys(cs,
36732cad1ffSPhilippe Mathieu-Daudé                         env->vm_vmcb + offsetof(struct vmcb, save.rip));
36832cad1ffSPhilippe Mathieu-Daudé 
36932cad1ffSPhilippe Mathieu-Daudé     env->regs[R_ESP] = x86_ldq_phys(cs,
37032cad1ffSPhilippe Mathieu-Daudé                                 env->vm_vmcb + offsetof(struct vmcb, save.rsp));
37132cad1ffSPhilippe Mathieu-Daudé     env->regs[R_EAX] = x86_ldq_phys(cs,
37232cad1ffSPhilippe Mathieu-Daudé                                 env->vm_vmcb + offsetof(struct vmcb, save.rax));
37332cad1ffSPhilippe Mathieu-Daudé 
37432cad1ffSPhilippe Mathieu-Daudé     new_dr7 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.dr7));
37532cad1ffSPhilippe Mathieu-Daudé     new_dr6 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.dr6));
37632cad1ffSPhilippe Mathieu-Daudé 
37732cad1ffSPhilippe Mathieu-Daudé #ifdef TARGET_X86_64
37832cad1ffSPhilippe Mathieu-Daudé     if (new_dr7 & DR_RESERVED_MASK) {
37932cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
38032cad1ffSPhilippe Mathieu-Daudé     }
38132cad1ffSPhilippe Mathieu-Daudé     if (new_dr6 & DR_RESERVED_MASK) {
38232cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
38332cad1ffSPhilippe Mathieu-Daudé     }
38432cad1ffSPhilippe Mathieu-Daudé #endif
38532cad1ffSPhilippe Mathieu-Daudé 
38632cad1ffSPhilippe Mathieu-Daudé     cpu_x86_update_dr7(env, new_dr7);
38732cad1ffSPhilippe Mathieu-Daudé     env->dr[6] = new_dr6;
38832cad1ffSPhilippe Mathieu-Daudé 
38932cad1ffSPhilippe Mathieu-Daudé     if (is_efer_invalid_state(env)) {
39032cad1ffSPhilippe Mathieu-Daudé         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
39132cad1ffSPhilippe Mathieu-Daudé     }
39232cad1ffSPhilippe Mathieu-Daudé 
39332cad1ffSPhilippe Mathieu-Daudé     switch (x86_ldub_phys(cs,
39432cad1ffSPhilippe Mathieu-Daudé                       env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
39532cad1ffSPhilippe Mathieu-Daudé     case TLB_CONTROL_DO_NOTHING:
39632cad1ffSPhilippe Mathieu-Daudé         break;
39732cad1ffSPhilippe Mathieu-Daudé     case TLB_CONTROL_FLUSH_ALL_ASID:
39832cad1ffSPhilippe Mathieu-Daudé         /* FIXME: this is not 100% correct but should work for now */
39932cad1ffSPhilippe Mathieu-Daudé         tlb_flush(cs);
40032cad1ffSPhilippe Mathieu-Daudé         break;
40132cad1ffSPhilippe Mathieu-Daudé     }
40232cad1ffSPhilippe Mathieu-Daudé 
40332cad1ffSPhilippe Mathieu-Daudé     env->hflags2 |= HF2_GIF_MASK;
40432cad1ffSPhilippe Mathieu-Daudé 
40532cad1ffSPhilippe Mathieu-Daudé     if (ctl_has_irq(env)) {
40632cad1ffSPhilippe Mathieu-Daudé         cs->interrupt_request |= CPU_INTERRUPT_VIRQ;
40732cad1ffSPhilippe Mathieu-Daudé     }
40832cad1ffSPhilippe Mathieu-Daudé 
40932cad1ffSPhilippe Mathieu-Daudé     if (virtual_gif_set(env)) {
41032cad1ffSPhilippe Mathieu-Daudé         env->hflags2 |= HF2_VGIF_MASK;
41132cad1ffSPhilippe Mathieu-Daudé     }
41232cad1ffSPhilippe Mathieu-Daudé 
41332cad1ffSPhilippe Mathieu-Daudé     /* maybe we need to inject an event */
41432cad1ffSPhilippe Mathieu-Daudé     event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
41532cad1ffSPhilippe Mathieu-Daudé                                                  control.event_inj));
41632cad1ffSPhilippe Mathieu-Daudé     if (event_inj & SVM_EVTINJ_VALID) {
41732cad1ffSPhilippe Mathieu-Daudé         uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
41832cad1ffSPhilippe Mathieu-Daudé         uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
41932cad1ffSPhilippe Mathieu-Daudé         uint32_t event_inj_err = x86_ldl_phys(cs, env->vm_vmcb +
42032cad1ffSPhilippe Mathieu-Daudé                                           offsetof(struct vmcb,
42132cad1ffSPhilippe Mathieu-Daudé                                                    control.event_inj_err));
42232cad1ffSPhilippe Mathieu-Daudé 
42332cad1ffSPhilippe Mathieu-Daudé         qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
42432cad1ffSPhilippe Mathieu-Daudé         /* FIXME: need to implement valid_err */
42532cad1ffSPhilippe Mathieu-Daudé         switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
42632cad1ffSPhilippe Mathieu-Daudé         case SVM_EVTINJ_TYPE_INTR:
42732cad1ffSPhilippe Mathieu-Daudé             cs->exception_index = vector;
42832cad1ffSPhilippe Mathieu-Daudé             env->error_code = event_inj_err;
42932cad1ffSPhilippe Mathieu-Daudé             env->exception_is_int = 0;
43032cad1ffSPhilippe Mathieu-Daudé             env->exception_next_eip = -1;
43132cad1ffSPhilippe Mathieu-Daudé             qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
43232cad1ffSPhilippe Mathieu-Daudé             /* XXX: is it always correct? */
43332cad1ffSPhilippe Mathieu-Daudé             do_interrupt_x86_hardirq(env, vector, 1);
43432cad1ffSPhilippe Mathieu-Daudé             break;
43532cad1ffSPhilippe Mathieu-Daudé         case SVM_EVTINJ_TYPE_NMI:
43632cad1ffSPhilippe Mathieu-Daudé             cs->exception_index = EXCP02_NMI;
43732cad1ffSPhilippe Mathieu-Daudé             env->error_code = event_inj_err;
43832cad1ffSPhilippe Mathieu-Daudé             env->exception_is_int = 0;
43932cad1ffSPhilippe Mathieu-Daudé             env->exception_next_eip = env->eip;
44032cad1ffSPhilippe Mathieu-Daudé             qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
44132cad1ffSPhilippe Mathieu-Daudé             cpu_loop_exit(cs);
44232cad1ffSPhilippe Mathieu-Daudé             break;
44332cad1ffSPhilippe Mathieu-Daudé         case SVM_EVTINJ_TYPE_EXEPT:
44432cad1ffSPhilippe Mathieu-Daudé             if (vector == EXCP02_NMI || vector >= 31)  {
44532cad1ffSPhilippe Mathieu-Daudé                 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
44632cad1ffSPhilippe Mathieu-Daudé             }
44732cad1ffSPhilippe Mathieu-Daudé             cs->exception_index = vector;
44832cad1ffSPhilippe Mathieu-Daudé             env->error_code = event_inj_err;
44932cad1ffSPhilippe Mathieu-Daudé             env->exception_is_int = 0;
45032cad1ffSPhilippe Mathieu-Daudé             env->exception_next_eip = -1;
45132cad1ffSPhilippe Mathieu-Daudé             qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
45232cad1ffSPhilippe Mathieu-Daudé             cpu_loop_exit(cs);
45332cad1ffSPhilippe Mathieu-Daudé             break;
45432cad1ffSPhilippe Mathieu-Daudé         case SVM_EVTINJ_TYPE_SOFT:
45532cad1ffSPhilippe Mathieu-Daudé             cs->exception_index = vector;
45632cad1ffSPhilippe Mathieu-Daudé             env->error_code = event_inj_err;
45732cad1ffSPhilippe Mathieu-Daudé             env->exception_is_int = 1;
45832cad1ffSPhilippe Mathieu-Daudé             env->exception_next_eip = env->eip;
45932cad1ffSPhilippe Mathieu-Daudé             qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
46032cad1ffSPhilippe Mathieu-Daudé             cpu_loop_exit(cs);
46132cad1ffSPhilippe Mathieu-Daudé             break;
46232cad1ffSPhilippe Mathieu-Daudé         default:
46332cad1ffSPhilippe Mathieu-Daudé             cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
46432cad1ffSPhilippe Mathieu-Daudé             break;
46532cad1ffSPhilippe Mathieu-Daudé         }
46632cad1ffSPhilippe Mathieu-Daudé         qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index,
46732cad1ffSPhilippe Mathieu-Daudé                       env->error_code);
46832cad1ffSPhilippe Mathieu-Daudé     }
46932cad1ffSPhilippe Mathieu-Daudé }
47032cad1ffSPhilippe Mathieu-Daudé 
helper_vmmcall(CPUX86State * env)47132cad1ffSPhilippe Mathieu-Daudé void helper_vmmcall(CPUX86State *env)
47232cad1ffSPhilippe Mathieu-Daudé {
47332cad1ffSPhilippe Mathieu-Daudé     cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0, GETPC());
47432cad1ffSPhilippe Mathieu-Daudé     raise_exception(env, EXCP06_ILLOP);
47532cad1ffSPhilippe Mathieu-Daudé }
47632cad1ffSPhilippe Mathieu-Daudé 
helper_vmload(CPUX86State * env,int aflag)47732cad1ffSPhilippe Mathieu-Daudé void helper_vmload(CPUX86State *env, int aflag)
47832cad1ffSPhilippe Mathieu-Daudé {
47932cad1ffSPhilippe Mathieu-Daudé     int mmu_idx = MMU_PHYS_IDX;
48032cad1ffSPhilippe Mathieu-Daudé     target_ulong addr;
48132cad1ffSPhilippe Mathieu-Daudé 
48232cad1ffSPhilippe Mathieu-Daudé     if (aflag == 2) {
48332cad1ffSPhilippe Mathieu-Daudé         addr = env->regs[R_EAX];
48432cad1ffSPhilippe Mathieu-Daudé     } else {
48532cad1ffSPhilippe Mathieu-Daudé         addr = (uint32_t)env->regs[R_EAX];
48632cad1ffSPhilippe Mathieu-Daudé     }
48732cad1ffSPhilippe Mathieu-Daudé 
48832cad1ffSPhilippe Mathieu-Daudé     /* Exceptions are checked before the intercept.  */
48932cad1ffSPhilippe Mathieu-Daudé     if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) {
49032cad1ffSPhilippe Mathieu-Daudé         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
49132cad1ffSPhilippe Mathieu-Daudé     }
49232cad1ffSPhilippe Mathieu-Daudé 
49332cad1ffSPhilippe Mathieu-Daudé     cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC());
49432cad1ffSPhilippe Mathieu-Daudé 
49532cad1ffSPhilippe Mathieu-Daudé     if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) {
49632cad1ffSPhilippe Mathieu-Daudé         mmu_idx = MMU_NESTED_IDX;
49732cad1ffSPhilippe Mathieu-Daudé     }
49832cad1ffSPhilippe Mathieu-Daudé 
49932cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, mmu_idx,
50032cad1ffSPhilippe Mathieu-Daudé                        addr + offsetof(struct vmcb, save.fs), R_FS);
50132cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, mmu_idx,
50232cad1ffSPhilippe Mathieu-Daudé                        addr + offsetof(struct vmcb, save.gs), R_GS);
50332cad1ffSPhilippe Mathieu-Daudé     svm_load_seg(env, mmu_idx,
50432cad1ffSPhilippe Mathieu-Daudé                  addr + offsetof(struct vmcb, save.tr), &env->tr);
50532cad1ffSPhilippe Mathieu-Daudé     svm_load_seg(env, mmu_idx,
50632cad1ffSPhilippe Mathieu-Daudé                  addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
50732cad1ffSPhilippe Mathieu-Daudé 
50832cad1ffSPhilippe Mathieu-Daudé #ifdef TARGET_X86_64
50932cad1ffSPhilippe Mathieu-Daudé     env->kernelgsbase =
51032cad1ffSPhilippe Mathieu-Daudé         cpu_ldq_mmuidx_ra(env,
51132cad1ffSPhilippe Mathieu-Daudé                           addr + offsetof(struct vmcb, save.kernel_gs_base),
51232cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
51332cad1ffSPhilippe Mathieu-Daudé     env->lstar =
51432cad1ffSPhilippe Mathieu-Daudé         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.lstar),
51532cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
51632cad1ffSPhilippe Mathieu-Daudé     env->cstar =
51732cad1ffSPhilippe Mathieu-Daudé         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.cstar),
51832cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
51932cad1ffSPhilippe Mathieu-Daudé     env->fmask =
52032cad1ffSPhilippe Mathieu-Daudé         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sfmask),
52132cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
52232cad1ffSPhilippe Mathieu-Daudé     svm_canonicalization(env, &env->kernelgsbase);
52332cad1ffSPhilippe Mathieu-Daudé #endif
52432cad1ffSPhilippe Mathieu-Daudé     env->star =
52532cad1ffSPhilippe Mathieu-Daudé         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star),
52632cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
52732cad1ffSPhilippe Mathieu-Daudé     env->sysenter_cs =
52832cad1ffSPhilippe Mathieu-Daudé         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs),
52932cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
53032cad1ffSPhilippe Mathieu-Daudé     env->sysenter_esp =
53132cad1ffSPhilippe Mathieu-Daudé         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_esp),
53232cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
53332cad1ffSPhilippe Mathieu-Daudé     env->sysenter_eip =
53432cad1ffSPhilippe Mathieu-Daudé         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_eip),
53532cad1ffSPhilippe Mathieu-Daudé                           mmu_idx, 0);
53632cad1ffSPhilippe Mathieu-Daudé }
53732cad1ffSPhilippe Mathieu-Daudé 
helper_vmsave(CPUX86State * env,int aflag)53832cad1ffSPhilippe Mathieu-Daudé void helper_vmsave(CPUX86State *env, int aflag)
53932cad1ffSPhilippe Mathieu-Daudé {
54032cad1ffSPhilippe Mathieu-Daudé     int mmu_idx = MMU_PHYS_IDX;
54132cad1ffSPhilippe Mathieu-Daudé     target_ulong addr;
54232cad1ffSPhilippe Mathieu-Daudé 
54332cad1ffSPhilippe Mathieu-Daudé     if (aflag == 2) {
54432cad1ffSPhilippe Mathieu-Daudé         addr = env->regs[R_EAX];
54532cad1ffSPhilippe Mathieu-Daudé     } else {
54632cad1ffSPhilippe Mathieu-Daudé         addr = (uint32_t)env->regs[R_EAX];
54732cad1ffSPhilippe Mathieu-Daudé     }
54832cad1ffSPhilippe Mathieu-Daudé 
54932cad1ffSPhilippe Mathieu-Daudé     /* Exceptions are checked before the intercept.  */
55032cad1ffSPhilippe Mathieu-Daudé     if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) {
55132cad1ffSPhilippe Mathieu-Daudé         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
55232cad1ffSPhilippe Mathieu-Daudé     }
55332cad1ffSPhilippe Mathieu-Daudé 
55432cad1ffSPhilippe Mathieu-Daudé     cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC());
55532cad1ffSPhilippe Mathieu-Daudé 
55632cad1ffSPhilippe Mathieu-Daudé     if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) {
55732cad1ffSPhilippe Mathieu-Daudé         mmu_idx = MMU_NESTED_IDX;
55832cad1ffSPhilippe Mathieu-Daudé     }
55932cad1ffSPhilippe Mathieu-Daudé 
56032cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.fs),
56132cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_FS]);
56232cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.gs),
56332cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_GS]);
56432cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.tr),
56532cad1ffSPhilippe Mathieu-Daudé                  &env->tr);
56632cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.ldtr),
56732cad1ffSPhilippe Mathieu-Daudé                  &env->ldt);
56832cad1ffSPhilippe Mathieu-Daudé 
56932cad1ffSPhilippe Mathieu-Daudé #ifdef TARGET_X86_64
57032cad1ffSPhilippe Mathieu-Daudé     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.kernel_gs_base),
57132cad1ffSPhilippe Mathieu-Daudé                       env->kernelgsbase, mmu_idx, 0);
57232cad1ffSPhilippe Mathieu-Daudé     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.lstar),
57332cad1ffSPhilippe Mathieu-Daudé                       env->lstar, mmu_idx, 0);
57432cad1ffSPhilippe Mathieu-Daudé     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.cstar),
57532cad1ffSPhilippe Mathieu-Daudé                       env->cstar, mmu_idx, 0);
57632cad1ffSPhilippe Mathieu-Daudé     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sfmask),
57732cad1ffSPhilippe Mathieu-Daudé                       env->fmask, mmu_idx, 0);
57832cad1ffSPhilippe Mathieu-Daudé #endif
57932cad1ffSPhilippe Mathieu-Daudé     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star),
58032cad1ffSPhilippe Mathieu-Daudé                       env->star, mmu_idx, 0);
58132cad1ffSPhilippe Mathieu-Daudé     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs),
58232cad1ffSPhilippe Mathieu-Daudé                       env->sysenter_cs, mmu_idx, 0);
58332cad1ffSPhilippe Mathieu-Daudé     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_esp),
58432cad1ffSPhilippe Mathieu-Daudé                       env->sysenter_esp, mmu_idx, 0);
58532cad1ffSPhilippe Mathieu-Daudé     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_eip),
58632cad1ffSPhilippe Mathieu-Daudé                       env->sysenter_eip, mmu_idx, 0);
58732cad1ffSPhilippe Mathieu-Daudé }
58832cad1ffSPhilippe Mathieu-Daudé 
helper_stgi(CPUX86State * env)58932cad1ffSPhilippe Mathieu-Daudé void helper_stgi(CPUX86State *env)
59032cad1ffSPhilippe Mathieu-Daudé {
59132cad1ffSPhilippe Mathieu-Daudé     cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC());
59232cad1ffSPhilippe Mathieu-Daudé 
59332cad1ffSPhilippe Mathieu-Daudé     if (virtual_gif_enabled(env)) {
59432cad1ffSPhilippe Mathieu-Daudé         env->int_ctl |= V_GIF_MASK;
59532cad1ffSPhilippe Mathieu-Daudé         env->hflags2 |= HF2_VGIF_MASK;
59632cad1ffSPhilippe Mathieu-Daudé     } else {
59732cad1ffSPhilippe Mathieu-Daudé         env->hflags2 |= HF2_GIF_MASK;
59832cad1ffSPhilippe Mathieu-Daudé     }
59932cad1ffSPhilippe Mathieu-Daudé }
60032cad1ffSPhilippe Mathieu-Daudé 
helper_clgi(CPUX86State * env)60132cad1ffSPhilippe Mathieu-Daudé void helper_clgi(CPUX86State *env)
60232cad1ffSPhilippe Mathieu-Daudé {
60332cad1ffSPhilippe Mathieu-Daudé     cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC());
60432cad1ffSPhilippe Mathieu-Daudé 
60532cad1ffSPhilippe Mathieu-Daudé     if (virtual_gif_enabled(env)) {
60632cad1ffSPhilippe Mathieu-Daudé         env->int_ctl &= ~V_GIF_MASK;
60732cad1ffSPhilippe Mathieu-Daudé         env->hflags2 &= ~HF2_VGIF_MASK;
60832cad1ffSPhilippe Mathieu-Daudé     } else {
60932cad1ffSPhilippe Mathieu-Daudé         env->hflags2 &= ~HF2_GIF_MASK;
61032cad1ffSPhilippe Mathieu-Daudé     }
61132cad1ffSPhilippe Mathieu-Daudé }
61232cad1ffSPhilippe Mathieu-Daudé 
cpu_svm_has_intercept(CPUX86State * env,uint32_t type)61332cad1ffSPhilippe Mathieu-Daudé bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type)
61432cad1ffSPhilippe Mathieu-Daudé {
61532cad1ffSPhilippe Mathieu-Daudé     switch (type) {
61632cad1ffSPhilippe Mathieu-Daudé     case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
61732cad1ffSPhilippe Mathieu-Daudé         if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
61832cad1ffSPhilippe Mathieu-Daudé             return true;
61932cad1ffSPhilippe Mathieu-Daudé         }
62032cad1ffSPhilippe Mathieu-Daudé         break;
62132cad1ffSPhilippe Mathieu-Daudé     case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
62232cad1ffSPhilippe Mathieu-Daudé         if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
62332cad1ffSPhilippe Mathieu-Daudé             return true;
62432cad1ffSPhilippe Mathieu-Daudé         }
62532cad1ffSPhilippe Mathieu-Daudé         break;
62632cad1ffSPhilippe Mathieu-Daudé     case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
62732cad1ffSPhilippe Mathieu-Daudé         if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
62832cad1ffSPhilippe Mathieu-Daudé             return true;
62932cad1ffSPhilippe Mathieu-Daudé         }
63032cad1ffSPhilippe Mathieu-Daudé         break;
63132cad1ffSPhilippe Mathieu-Daudé     case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
63232cad1ffSPhilippe Mathieu-Daudé         if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
63332cad1ffSPhilippe Mathieu-Daudé             return true;
63432cad1ffSPhilippe Mathieu-Daudé         }
63532cad1ffSPhilippe Mathieu-Daudé         break;
63632cad1ffSPhilippe Mathieu-Daudé     case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
63732cad1ffSPhilippe Mathieu-Daudé         if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
63832cad1ffSPhilippe Mathieu-Daudé             return true;
63932cad1ffSPhilippe Mathieu-Daudé         }
64032cad1ffSPhilippe Mathieu-Daudé         break;
64132cad1ffSPhilippe Mathieu-Daudé     default:
64232cad1ffSPhilippe Mathieu-Daudé         if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
64332cad1ffSPhilippe Mathieu-Daudé             return true;
64432cad1ffSPhilippe Mathieu-Daudé         }
64532cad1ffSPhilippe Mathieu-Daudé         break;
64632cad1ffSPhilippe Mathieu-Daudé     }
64732cad1ffSPhilippe Mathieu-Daudé     return false;
64832cad1ffSPhilippe Mathieu-Daudé }
64932cad1ffSPhilippe Mathieu-Daudé 
cpu_svm_check_intercept_param(CPUX86State * env,uint32_t type,uint64_t param,uintptr_t retaddr)65032cad1ffSPhilippe Mathieu-Daudé void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
65132cad1ffSPhilippe Mathieu-Daudé                                    uint64_t param, uintptr_t retaddr)
65232cad1ffSPhilippe Mathieu-Daudé {
65332cad1ffSPhilippe Mathieu-Daudé     CPUState *cs = env_cpu(env);
65432cad1ffSPhilippe Mathieu-Daudé 
65532cad1ffSPhilippe Mathieu-Daudé     if (likely(!(env->hflags & HF_GUEST_MASK))) {
65632cad1ffSPhilippe Mathieu-Daudé         return;
65732cad1ffSPhilippe Mathieu-Daudé     }
65832cad1ffSPhilippe Mathieu-Daudé 
65932cad1ffSPhilippe Mathieu-Daudé     if (!cpu_svm_has_intercept(env, type)) {
66032cad1ffSPhilippe Mathieu-Daudé         return;
66132cad1ffSPhilippe Mathieu-Daudé     }
66232cad1ffSPhilippe Mathieu-Daudé 
66332cad1ffSPhilippe Mathieu-Daudé     if (type == SVM_EXIT_MSR) {
66432cad1ffSPhilippe Mathieu-Daudé         /* FIXME: this should be read in at vmrun (faster this way?) */
66532cad1ffSPhilippe Mathieu-Daudé         uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
66632cad1ffSPhilippe Mathieu-Daudé                                     offsetof(struct vmcb,
66732cad1ffSPhilippe Mathieu-Daudé                                             control.msrpm_base_pa));
66832cad1ffSPhilippe Mathieu-Daudé         uint32_t t0, t1;
66932cad1ffSPhilippe Mathieu-Daudé 
67032cad1ffSPhilippe Mathieu-Daudé         switch ((uint32_t)env->regs[R_ECX]) {
67132cad1ffSPhilippe Mathieu-Daudé         case 0 ... 0x1fff:
67232cad1ffSPhilippe Mathieu-Daudé             t0 = (env->regs[R_ECX] * 2) % 8;
67332cad1ffSPhilippe Mathieu-Daudé             t1 = (env->regs[R_ECX] * 2) / 8;
67432cad1ffSPhilippe Mathieu-Daudé             break;
67532cad1ffSPhilippe Mathieu-Daudé         case 0xc0000000 ... 0xc0001fff:
67632cad1ffSPhilippe Mathieu-Daudé             t0 = (8192 + env->regs[R_ECX] - 0xc0000000) * 2;
67732cad1ffSPhilippe Mathieu-Daudé             t1 = (t0 / 8);
67832cad1ffSPhilippe Mathieu-Daudé             t0 %= 8;
67932cad1ffSPhilippe Mathieu-Daudé             break;
68032cad1ffSPhilippe Mathieu-Daudé         case 0xc0010000 ... 0xc0011fff:
68132cad1ffSPhilippe Mathieu-Daudé             t0 = (16384 + env->regs[R_ECX] - 0xc0010000) * 2;
68232cad1ffSPhilippe Mathieu-Daudé             t1 = (t0 / 8);
68332cad1ffSPhilippe Mathieu-Daudé             t0 %= 8;
68432cad1ffSPhilippe Mathieu-Daudé             break;
68532cad1ffSPhilippe Mathieu-Daudé         default:
68632cad1ffSPhilippe Mathieu-Daudé             cpu_vmexit(env, type, param, retaddr);
68732cad1ffSPhilippe Mathieu-Daudé             t0 = 0;
68832cad1ffSPhilippe Mathieu-Daudé             t1 = 0;
68932cad1ffSPhilippe Mathieu-Daudé             break;
69032cad1ffSPhilippe Mathieu-Daudé         }
69132cad1ffSPhilippe Mathieu-Daudé         if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) {
69232cad1ffSPhilippe Mathieu-Daudé             cpu_vmexit(env, type, param, retaddr);
69332cad1ffSPhilippe Mathieu-Daudé         }
69432cad1ffSPhilippe Mathieu-Daudé         return;
69532cad1ffSPhilippe Mathieu-Daudé     }
69632cad1ffSPhilippe Mathieu-Daudé 
69732cad1ffSPhilippe Mathieu-Daudé     cpu_vmexit(env, type, param, retaddr);
69832cad1ffSPhilippe Mathieu-Daudé }
69932cad1ffSPhilippe Mathieu-Daudé 
helper_svm_check_intercept(CPUX86State * env,uint32_t type)70032cad1ffSPhilippe Mathieu-Daudé void helper_svm_check_intercept(CPUX86State *env, uint32_t type)
70132cad1ffSPhilippe Mathieu-Daudé {
70232cad1ffSPhilippe Mathieu-Daudé     cpu_svm_check_intercept_param(env, type, 0, GETPC());
70332cad1ffSPhilippe Mathieu-Daudé }
70432cad1ffSPhilippe Mathieu-Daudé 
helper_svm_check_io(CPUX86State * env,uint32_t port,uint32_t param,uint32_t next_eip_addend)70532cad1ffSPhilippe Mathieu-Daudé void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
70632cad1ffSPhilippe Mathieu-Daudé                          uint32_t next_eip_addend)
70732cad1ffSPhilippe Mathieu-Daudé {
70832cad1ffSPhilippe Mathieu-Daudé     CPUState *cs = env_cpu(env);
70932cad1ffSPhilippe Mathieu-Daudé 
71032cad1ffSPhilippe Mathieu-Daudé     if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
71132cad1ffSPhilippe Mathieu-Daudé         /* FIXME: this should be read in at vmrun (faster this way?) */
71232cad1ffSPhilippe Mathieu-Daudé         uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
71332cad1ffSPhilippe Mathieu-Daudé                                  offsetof(struct vmcb, control.iopm_base_pa));
71432cad1ffSPhilippe Mathieu-Daudé         uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
71532cad1ffSPhilippe Mathieu-Daudé 
71632cad1ffSPhilippe Mathieu-Daudé         if (x86_lduw_phys(cs, addr + port / 8) & (mask << (port & 7))) {
71732cad1ffSPhilippe Mathieu-Daudé             /* next env->eip */
71832cad1ffSPhilippe Mathieu-Daudé             x86_stq_phys(cs,
71932cad1ffSPhilippe Mathieu-Daudé                      env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
72032cad1ffSPhilippe Mathieu-Daudé                      env->eip + next_eip_addend);
72132cad1ffSPhilippe Mathieu-Daudé             cpu_vmexit(env, SVM_EXIT_IOIO, param | (port << 16), GETPC());
72232cad1ffSPhilippe Mathieu-Daudé         }
72332cad1ffSPhilippe Mathieu-Daudé     }
72432cad1ffSPhilippe Mathieu-Daudé }
72532cad1ffSPhilippe Mathieu-Daudé 
cpu_vmexit(CPUX86State * env,uint32_t exit_code,uint64_t exit_info_1,uintptr_t retaddr)72632cad1ffSPhilippe Mathieu-Daudé void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
72732cad1ffSPhilippe Mathieu-Daudé                 uintptr_t retaddr)
72832cad1ffSPhilippe Mathieu-Daudé {
72932cad1ffSPhilippe Mathieu-Daudé     CPUState *cs = env_cpu(env);
73032cad1ffSPhilippe Mathieu-Daudé 
73132cad1ffSPhilippe Mathieu-Daudé     cpu_restore_state(cs, retaddr);
73232cad1ffSPhilippe Mathieu-Daudé 
73332cad1ffSPhilippe Mathieu-Daudé     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
73432cad1ffSPhilippe Mathieu-Daudé                   PRIx64 ", " TARGET_FMT_lx ")!\n",
73532cad1ffSPhilippe Mathieu-Daudé                   exit_code, exit_info_1,
73632cad1ffSPhilippe Mathieu-Daudé                   x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
73732cad1ffSPhilippe Mathieu-Daudé                                                    control.exit_info_2)),
73832cad1ffSPhilippe Mathieu-Daudé                   env->eip);
73932cad1ffSPhilippe Mathieu-Daudé 
74032cad1ffSPhilippe Mathieu-Daudé     cs->exception_index = EXCP_VMEXIT;
74132cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
74232cad1ffSPhilippe Mathieu-Daudé              exit_code);
74332cad1ffSPhilippe Mathieu-Daudé 
74432cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
74532cad1ffSPhilippe Mathieu-Daudé                                              control.exit_info_1), exit_info_1),
74632cad1ffSPhilippe Mathieu-Daudé 
74732cad1ffSPhilippe Mathieu-Daudé     /* remove any pending exception */
74832cad1ffSPhilippe Mathieu-Daudé     env->old_exception = -1;
74932cad1ffSPhilippe Mathieu-Daudé     cpu_loop_exit(cs);
75032cad1ffSPhilippe Mathieu-Daudé }
75132cad1ffSPhilippe Mathieu-Daudé 
do_vmexit(CPUX86State * env)75232cad1ffSPhilippe Mathieu-Daudé void do_vmexit(CPUX86State *env)
75332cad1ffSPhilippe Mathieu-Daudé {
75432cad1ffSPhilippe Mathieu-Daudé     CPUState *cs = env_cpu(env);
75532cad1ffSPhilippe Mathieu-Daudé 
75632cad1ffSPhilippe Mathieu-Daudé     if (env->hflags & HF_INHIBIT_IRQ_MASK) {
75732cad1ffSPhilippe Mathieu-Daudé         x86_stl_phys(cs,
75832cad1ffSPhilippe Mathieu-Daudé                  env->vm_vmcb + offsetof(struct vmcb, control.int_state),
75932cad1ffSPhilippe Mathieu-Daudé                  SVM_INTERRUPT_SHADOW_MASK);
76032cad1ffSPhilippe Mathieu-Daudé         env->hflags &= ~HF_INHIBIT_IRQ_MASK;
76132cad1ffSPhilippe Mathieu-Daudé     } else {
76232cad1ffSPhilippe Mathieu-Daudé         x86_stl_phys(cs,
76332cad1ffSPhilippe Mathieu-Daudé                  env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
76432cad1ffSPhilippe Mathieu-Daudé     }
76532cad1ffSPhilippe Mathieu-Daudé     env->hflags2 &= ~HF2_NPT_MASK;
76632cad1ffSPhilippe Mathieu-Daudé     tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX);
76732cad1ffSPhilippe Mathieu-Daudé 
76832cad1ffSPhilippe Mathieu-Daudé     /* Save the VM state in the vmcb */
76932cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, MMU_PHYS_IDX,
77032cad1ffSPhilippe Mathieu-Daudé                  env->vm_vmcb + offsetof(struct vmcb, save.es),
77132cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_ES]);
77232cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, MMU_PHYS_IDX,
77332cad1ffSPhilippe Mathieu-Daudé                  env->vm_vmcb + offsetof(struct vmcb, save.cs),
77432cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_CS]);
77532cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, MMU_PHYS_IDX,
77632cad1ffSPhilippe Mathieu-Daudé                  env->vm_vmcb + offsetof(struct vmcb, save.ss),
77732cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_SS]);
77832cad1ffSPhilippe Mathieu-Daudé     svm_save_seg(env, MMU_PHYS_IDX,
77932cad1ffSPhilippe Mathieu-Daudé                  env->vm_vmcb + offsetof(struct vmcb, save.ds),
78032cad1ffSPhilippe Mathieu-Daudé                  &env->segs[R_DS]);
78132cad1ffSPhilippe Mathieu-Daudé 
78232cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
78332cad1ffSPhilippe Mathieu-Daudé              env->gdt.base);
78432cad1ffSPhilippe Mathieu-Daudé     x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit),
78532cad1ffSPhilippe Mathieu-Daudé              env->gdt.limit);
78632cad1ffSPhilippe Mathieu-Daudé 
78732cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.base),
78832cad1ffSPhilippe Mathieu-Daudé              env->idt.base);
78932cad1ffSPhilippe Mathieu-Daudé     x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit),
79032cad1ffSPhilippe Mathieu-Daudé              env->idt.limit);
79132cad1ffSPhilippe Mathieu-Daudé 
79232cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
79332cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
79432cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
79532cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
79632cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
79732cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
79832cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
79932cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
80032cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
80132cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
80232cad1ffSPhilippe Mathieu-Daudé     x86_stl_phys(cs,
80332cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), env->int_ctl);
80432cad1ffSPhilippe Mathieu-Daudé 
80532cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rflags),
80632cad1ffSPhilippe Mathieu-Daudé              cpu_compute_eflags(env));
80732cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip),
80832cad1ffSPhilippe Mathieu-Daudé              env->eip);
80932cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
81032cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
81132cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
81232cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
81332cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
81432cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
81532cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(cs,
81632cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
81732cad1ffSPhilippe Mathieu-Daudé     x86_stb_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cpl),
81832cad1ffSPhilippe Mathieu-Daudé              env->hflags & HF_CPL_MASK);
81932cad1ffSPhilippe Mathieu-Daudé 
82032cad1ffSPhilippe Mathieu-Daudé     /* Reload the host state from vm_hsave */
82132cad1ffSPhilippe Mathieu-Daudé     env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
82232cad1ffSPhilippe Mathieu-Daudé     env->hflags &= ~HF_GUEST_MASK;
82332cad1ffSPhilippe Mathieu-Daudé     env->intercept = 0;
82432cad1ffSPhilippe Mathieu-Daudé     env->intercept_exceptions = 0;
82532cad1ffSPhilippe Mathieu-Daudé 
82632cad1ffSPhilippe Mathieu-Daudé     /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
82732cad1ffSPhilippe Mathieu-Daudé     cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
82832cad1ffSPhilippe Mathieu-Daudé     env->int_ctl = 0;
82932cad1ffSPhilippe Mathieu-Daudé 
83032cad1ffSPhilippe Mathieu-Daudé     /* Clears the TSC_OFFSET inside the processor. */
83132cad1ffSPhilippe Mathieu-Daudé     env->tsc_offset = 0;
83232cad1ffSPhilippe Mathieu-Daudé 
83332cad1ffSPhilippe Mathieu-Daudé     env->gdt.base  = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
83432cad1ffSPhilippe Mathieu-Daudé                                                        save.gdtr.base));
83532cad1ffSPhilippe Mathieu-Daudé     env->gdt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
83632cad1ffSPhilippe Mathieu-Daudé                                                        save.gdtr.limit));
83732cad1ffSPhilippe Mathieu-Daudé 
83832cad1ffSPhilippe Mathieu-Daudé     env->idt.base  = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
83932cad1ffSPhilippe Mathieu-Daudé                                                        save.idtr.base));
84032cad1ffSPhilippe Mathieu-Daudé     env->idt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
84132cad1ffSPhilippe Mathieu-Daudé                                                        save.idtr.limit));
84232cad1ffSPhilippe Mathieu-Daudé 
84332cad1ffSPhilippe Mathieu-Daudé     cpu_x86_update_cr0(env, x86_ldq_phys(cs,
84432cad1ffSPhilippe Mathieu-Daudé                                      env->vm_hsave + offsetof(struct vmcb,
84532cad1ffSPhilippe Mathieu-Daudé                                                               save.cr0)) |
84632cad1ffSPhilippe Mathieu-Daudé                        CR0_PE_MASK);
84732cad1ffSPhilippe Mathieu-Daudé     cpu_x86_update_cr4(env, x86_ldq_phys(cs,
84832cad1ffSPhilippe Mathieu-Daudé                                      env->vm_hsave + offsetof(struct vmcb,
84932cad1ffSPhilippe Mathieu-Daudé                                                               save.cr4)));
85032cad1ffSPhilippe Mathieu-Daudé 
85132cad1ffSPhilippe Mathieu-Daudé     /*
85232cad1ffSPhilippe Mathieu-Daudé      * Resets the current ASID register to zero (host ASID; TLB flush).
85332cad1ffSPhilippe Mathieu-Daudé      *
85432cad1ffSPhilippe Mathieu-Daudé      * If the host is in PAE mode, the processor reloads the host's PDPEs
85532cad1ffSPhilippe Mathieu-Daudé      * from the page table indicated the host's CR3. FIXME: If the PDPEs
85632cad1ffSPhilippe Mathieu-Daudé      * contain illegal state, the processor causes a shutdown (QEMU does
85732cad1ffSPhilippe Mathieu-Daudé      * not implement PDPTRs).
85832cad1ffSPhilippe Mathieu-Daudé      */
85932cad1ffSPhilippe Mathieu-Daudé     cpu_x86_update_cr3(env, x86_ldq_phys(cs,
86032cad1ffSPhilippe Mathieu-Daudé                                      env->vm_hsave + offsetof(struct vmcb,
86132cad1ffSPhilippe Mathieu-Daudé                                                               save.cr3)));
86232cad1ffSPhilippe Mathieu-Daudé     /* we need to set the efer after the crs so the hidden flags get
86332cad1ffSPhilippe Mathieu-Daudé        set properly */
86432cad1ffSPhilippe Mathieu-Daudé     cpu_load_efer(env, x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
86532cad1ffSPhilippe Mathieu-Daudé                                                          save.efer)));
86632cad1ffSPhilippe Mathieu-Daudé 
86732cad1ffSPhilippe Mathieu-Daudé     /* Completion of the VMRUN instruction clears the host EFLAGS.RF bit.  */
86832cad1ffSPhilippe Mathieu-Daudé     env->eflags = 0;
86932cad1ffSPhilippe Mathieu-Daudé     cpu_load_eflags(env, x86_ldq_phys(cs,
87032cad1ffSPhilippe Mathieu-Daudé                                   env->vm_hsave + offsetof(struct vmcb,
87132cad1ffSPhilippe Mathieu-Daudé                                                            save.rflags)),
87232cad1ffSPhilippe Mathieu-Daudé                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK |
87332cad1ffSPhilippe Mathieu-Daudé                       RF_MASK | VM_MASK));
87432cad1ffSPhilippe Mathieu-Daudé 
87532cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, MMU_PHYS_IDX,
87632cad1ffSPhilippe Mathieu-Daudé                        env->vm_hsave + offsetof(struct vmcb, save.es), R_ES);
87732cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, MMU_PHYS_IDX,
87832cad1ffSPhilippe Mathieu-Daudé                        env->vm_hsave + offsetof(struct vmcb, save.cs), R_CS);
87932cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, MMU_PHYS_IDX,
88032cad1ffSPhilippe Mathieu-Daudé                        env->vm_hsave + offsetof(struct vmcb, save.ss), R_SS);
88132cad1ffSPhilippe Mathieu-Daudé     svm_load_seg_cache(env, MMU_PHYS_IDX,
88232cad1ffSPhilippe Mathieu-Daudé                        env->vm_hsave + offsetof(struct vmcb, save.ds), R_DS);
88332cad1ffSPhilippe Mathieu-Daudé 
88432cad1ffSPhilippe Mathieu-Daudé     env->eip = x86_ldq_phys(cs,
88532cad1ffSPhilippe Mathieu-Daudé                         env->vm_hsave + offsetof(struct vmcb, save.rip));
88632cad1ffSPhilippe Mathieu-Daudé     env->regs[R_ESP] = x86_ldq_phys(cs, env->vm_hsave +
88732cad1ffSPhilippe Mathieu-Daudé                                 offsetof(struct vmcb, save.rsp));
88832cad1ffSPhilippe Mathieu-Daudé     env->regs[R_EAX] = x86_ldq_phys(cs, env->vm_hsave +
88932cad1ffSPhilippe Mathieu-Daudé                                 offsetof(struct vmcb, save.rax));
89032cad1ffSPhilippe Mathieu-Daudé 
89132cad1ffSPhilippe Mathieu-Daudé     env->dr[6] = x86_ldq_phys(cs,
89232cad1ffSPhilippe Mathieu-Daudé                           env->vm_hsave + offsetof(struct vmcb, save.dr6));
89332cad1ffSPhilippe Mathieu-Daudé 
89432cad1ffSPhilippe Mathieu-Daudé     /* Disables all breakpoints in the host DR7 register. */
89532cad1ffSPhilippe Mathieu-Daudé     cpu_x86_update_dr7(env,
89632cad1ffSPhilippe Mathieu-Daudé              x86_ldq_phys(cs,
89732cad1ffSPhilippe Mathieu-Daudé                           env->vm_hsave + offsetof(struct vmcb, save.dr7)) & ~0xff);
89832cad1ffSPhilippe Mathieu-Daudé 
89932cad1ffSPhilippe Mathieu-Daudé     /* other setups */
90032cad1ffSPhilippe Mathieu-Daudé     x86_stl_phys(cs,
90132cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
90232cad1ffSPhilippe Mathieu-Daudé              x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
90332cad1ffSPhilippe Mathieu-Daudé                                               control.event_inj)));
90432cad1ffSPhilippe Mathieu-Daudé     x86_stl_phys(cs,
90532cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
90632cad1ffSPhilippe Mathieu-Daudé              x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
90732cad1ffSPhilippe Mathieu-Daudé                                               control.event_inj_err)));
90832cad1ffSPhilippe Mathieu-Daudé     x86_stl_phys(cs,
90932cad1ffSPhilippe Mathieu-Daudé              env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
91032cad1ffSPhilippe Mathieu-Daudé 
91132cad1ffSPhilippe Mathieu-Daudé     env->hflags2 &= ~HF2_GIF_MASK;
91232cad1ffSPhilippe Mathieu-Daudé     env->hflags2 &= ~HF2_VGIF_MASK;
91332cad1ffSPhilippe Mathieu-Daudé 
91432cad1ffSPhilippe Mathieu-Daudé 
91532cad1ffSPhilippe Mathieu-Daudé     /* FIXME: Checks the reloaded host state for consistency. */
91632cad1ffSPhilippe Mathieu-Daudé 
91732cad1ffSPhilippe Mathieu-Daudé     /*
91832cad1ffSPhilippe Mathieu-Daudé      * EFLAGS.TF causes a #DB trap after the VMRUN completes on the host
91932cad1ffSPhilippe Mathieu-Daudé      * side (i.e., after the #VMEXIT from the guest). Since we're running
92032cad1ffSPhilippe Mathieu-Daudé      * in the main loop, call do_interrupt_all directly.
92132cad1ffSPhilippe Mathieu-Daudé      */
92232cad1ffSPhilippe Mathieu-Daudé     if ((env->eflags & TF_MASK) != 0) {
92332cad1ffSPhilippe Mathieu-Daudé         env->dr[6] |= DR6_BS;
92432cad1ffSPhilippe Mathieu-Daudé         do_interrupt_all(X86_CPU(cs), EXCP01_DB, 0, 0, env->eip, 0);
92532cad1ffSPhilippe Mathieu-Daudé     }
92632cad1ffSPhilippe Mathieu-Daudé }
927