xref: /qemu/target/i386/tcg/system/svm_helper.c (revision 32cad1ffb81dcecf6f4a8af56d6e5892682839b1)
16bada5e8SBlue Swirl /*
2*32cad1ffSPhilippe Mathieu-Daudé  *  x86 SVM helpers (system only)
36bada5e8SBlue Swirl  *
46bada5e8SBlue Swirl  *  Copyright (c) 2003 Fabrice Bellard
56bada5e8SBlue Swirl  *
66bada5e8SBlue Swirl  * This library is free software; you can redistribute it and/or
76bada5e8SBlue Swirl  * modify it under the terms of the GNU Lesser General Public
86bada5e8SBlue Swirl  * License as published by the Free Software Foundation; either
9d9ff33adSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
106bada5e8SBlue Swirl  *
116bada5e8SBlue Swirl  * This library is distributed in the hope that it will be useful,
126bada5e8SBlue Swirl  * but WITHOUT ANY WARRANTY; without even the implied warranty of
136bada5e8SBlue Swirl  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146bada5e8SBlue Swirl  * Lesser General Public License for more details.
156bada5e8SBlue Swirl  *
166bada5e8SBlue Swirl  * You should have received a copy of the GNU Lesser General Public
176bada5e8SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
186bada5e8SBlue Swirl  */
196bada5e8SBlue Swirl 
20b6a0aa05SPeter Maydell #include "qemu/osdep.h"
21cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
226bada5e8SBlue Swirl #include "cpu.h"
232ef6175aSRichard Henderson #include "exec/helper-proto.h"
2463c91552SPaolo Bonzini #include "exec/exec-all.h"
25f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
26b3903094SClaudio Fontana #include "tcg/helper-tcg.h"
2792fc4b58SBlue Swirl 
286bada5e8SBlue Swirl /* Secure Virtual Machine helpers */
296bada5e8SBlue Swirl 
30726ea335SRichard Henderson static void svm_save_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
316bada5e8SBlue Swirl                          const SegmentCache *sc)
326bada5e8SBlue Swirl {
33726ea335SRichard Henderson     cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
34726ea335SRichard Henderson                       sc->selector, mmu_idx, 0);
35726ea335SRichard Henderson     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base),
36726ea335SRichard Henderson                       sc->base, mmu_idx, 0);
37726ea335SRichard Henderson     cpu_stl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit),
38726ea335SRichard Henderson                       sc->limit, mmu_idx, 0);
39726ea335SRichard Henderson     cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib),
40726ea335SRichard Henderson                       ((sc->flags >> 8) & 0xff)
41726ea335SRichard Henderson                       | ((sc->flags >> 12) & 0x0f00),
42726ea335SRichard Henderson                       mmu_idx, 0);
436bada5e8SBlue Swirl }
446bada5e8SBlue Swirl 
4597afb47eSLara Lazier /*
4697afb47eSLara Lazier  * VMRUN and VMLOAD canonicalizes (i.e., sign-extend to bit 63) all base
4797afb47eSLara Lazier  * addresses in the segment registers that have been loaded.
4897afb47eSLara Lazier  */
4997afb47eSLara Lazier static inline void svm_canonicalization(CPUX86State *env, target_ulong *seg_base)
5097afb47eSLara Lazier {
5197afb47eSLara Lazier     uint16_t shift_amt = 64 - cpu_x86_virtual_addr_width(env);
5297afb47eSLara Lazier     *seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt);
5397afb47eSLara Lazier }
5497afb47eSLara Lazier 
55726ea335SRichard Henderson static void svm_load_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
56052e80d5SBlue Swirl                          SegmentCache *sc)
576bada5e8SBlue Swirl {
586bada5e8SBlue Swirl     unsigned int flags;
596bada5e8SBlue Swirl 
60726ea335SRichard Henderson     sc->selector =
61726ea335SRichard Henderson         cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
62726ea335SRichard Henderson                            mmu_idx, 0);
63726ea335SRichard Henderson     sc->base =
64726ea335SRichard Henderson         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base),
65726ea335SRichard Henderson                           mmu_idx, 0);
66726ea335SRichard Henderson     sc->limit =
67726ea335SRichard Henderson         cpu_ldl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit),
68726ea335SRichard Henderson                           mmu_idx, 0);
69726ea335SRichard Henderson     flags =
70726ea335SRichard Henderson         cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib),
71726ea335SRichard Henderson                            mmu_idx, 0);
726bada5e8SBlue Swirl     sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
73726ea335SRichard Henderson 
7497afb47eSLara Lazier     svm_canonicalization(env, &sc->base);
756bada5e8SBlue Swirl }
766bada5e8SBlue Swirl 
77726ea335SRichard Henderson static void svm_load_seg_cache(CPUX86State *env, int mmu_idx,
78726ea335SRichard Henderson                                hwaddr addr, int seg_reg)
796bada5e8SBlue Swirl {
80726ea335SRichard Henderson     SegmentCache sc;
816bada5e8SBlue Swirl 
82726ea335SRichard Henderson     svm_load_seg(env, mmu_idx, addr, &sc);
83726ea335SRichard Henderson     cpu_x86_load_seg_cache(env, seg_reg, sc.selector,
84726ea335SRichard Henderson                            sc.base, sc.limit, sc.flags);
856bada5e8SBlue Swirl }
866bada5e8SBlue Swirl 
87d499f196SLara Lazier static inline bool is_efer_invalid_state (CPUX86State *env)
88d499f196SLara Lazier {
89d499f196SLara Lazier     if (!(env->efer & MSR_EFER_SVME)) {
90d499f196SLara Lazier         return true;
91d499f196SLara Lazier     }
92d499f196SLara Lazier 
93d499f196SLara Lazier     if (env->efer & MSR_EFER_RESERVED) {
94d499f196SLara Lazier         return true;
95d499f196SLara Lazier     }
96d499f196SLara Lazier 
97d499f196SLara Lazier     if ((env->efer & (MSR_EFER_LMA | MSR_EFER_LME)) &&
98d499f196SLara Lazier             !(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
99d499f196SLara Lazier         return true;
100d499f196SLara Lazier     }
101d499f196SLara Lazier 
102d499f196SLara Lazier     if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
103d499f196SLara Lazier                                 && !(env->cr[4] & CR4_PAE_MASK)) {
104d499f196SLara Lazier         return true;
105d499f196SLara Lazier     }
106d499f196SLara Lazier 
107d499f196SLara Lazier     if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
108d499f196SLara Lazier                                 && !(env->cr[0] & CR0_PE_MASK)) {
109d499f196SLara Lazier         return true;
110d499f196SLara Lazier     }
111d499f196SLara Lazier 
112d499f196SLara Lazier     if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
113d499f196SLara Lazier                                 && (env->cr[4] & CR4_PAE_MASK)
114d499f196SLara Lazier                                 && (env->segs[R_CS].flags & DESC_L_MASK)
115d499f196SLara Lazier                                 && (env->segs[R_CS].flags & DESC_B_MASK)) {
116d499f196SLara Lazier         return true;
117d499f196SLara Lazier     }
118d499f196SLara Lazier 
119d499f196SLara Lazier     return false;
120d499f196SLara Lazier }
121d499f196SLara Lazier 
122e3126a5cSLara Lazier static inline bool virtual_gif_enabled(CPUX86State *env)
123900eeca5SLara Lazier {
124900eeca5SLara Lazier     if (likely(env->hflags & HF_GUEST_MASK)) {
125900eeca5SLara Lazier         return (env->features[FEAT_SVM] & CPUID_SVM_VGIF)
126e3126a5cSLara Lazier                     && (env->int_ctl & V_GIF_ENABLED_MASK);
127900eeca5SLara Lazier     }
128900eeca5SLara Lazier     return false;
129900eeca5SLara Lazier }
130900eeca5SLara Lazier 
13152fb8ad3SLara Lazier static inline bool virtual_vm_load_save_enabled(CPUX86State *env, uint32_t exit_code, uintptr_t retaddr)
13252fb8ad3SLara Lazier {
13352fb8ad3SLara Lazier     uint64_t lbr_ctl;
13452fb8ad3SLara Lazier 
13552fb8ad3SLara Lazier     if (likely(env->hflags & HF_GUEST_MASK)) {
13652fb8ad3SLara Lazier         if (likely(!(env->hflags2 & HF2_NPT_MASK)) || !(env->efer & MSR_EFER_LMA)) {
13752fb8ad3SLara Lazier             cpu_vmexit(env, exit_code, 0, retaddr);
13852fb8ad3SLara Lazier         }
13952fb8ad3SLara Lazier 
14052fb8ad3SLara Lazier         lbr_ctl = x86_ldl_phys(env_cpu(env), env->vm_vmcb + offsetof(struct vmcb,
14152fb8ad3SLara Lazier                                                   control.lbr_ctl));
14252fb8ad3SLara Lazier         return (env->features[FEAT_SVM] & CPUID_SVM_V_VMSAVE_VMLOAD)
14352fb8ad3SLara Lazier                 && (lbr_ctl & V_VMLOAD_VMSAVE_ENABLED_MASK);
14452fb8ad3SLara Lazier 
14552fb8ad3SLara Lazier     }
14652fb8ad3SLara Lazier 
14752fb8ad3SLara Lazier     return false;
14852fb8ad3SLara Lazier }
14952fb8ad3SLara Lazier 
150b67e2796SLara Lazier static inline bool virtual_gif_set(CPUX86State *env)
151b67e2796SLara Lazier {
152b67e2796SLara Lazier     return !virtual_gif_enabled(env) || (env->int_ctl & V_GIF_MASK);
153b67e2796SLara Lazier }
154b67e2796SLara Lazier 
155052e80d5SBlue Swirl void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
1566bada5e8SBlue Swirl {
1576aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
158481077b2SLara Lazier     X86CPU *cpu = env_archcpu(env);
1596bada5e8SBlue Swirl     target_ulong addr;
160fe441054SJan Kiszka     uint64_t nested_ctl;
1616bada5e8SBlue Swirl     uint32_t event_inj;
1627eb54ca9SLara Lazier     uint32_t asid;
163498df2a7SLara Lazier     uint64_t new_cr0;
1643407259bSLara Lazier     uint64_t new_cr3;
165213ff024SLara Lazier     uint64_t new_cr4;
1668aa76496SPaolo Bonzini     uint64_t new_dr6;
1678aa76496SPaolo Bonzini     uint64_t new_dr7;
1686bada5e8SBlue Swirl 
1696bada5e8SBlue Swirl     if (aflag == 2) {
1704b34e3adSliguang         addr = env->regs[R_EAX];
1716bada5e8SBlue Swirl     } else {
1724b34e3adSliguang         addr = (uint32_t)env->regs[R_EAX];
1736bada5e8SBlue Swirl     }
1746bada5e8SBlue Swirl 
175d09c7901SPaolo Bonzini     /* Exceptions are checked before the intercept.  */
176d09c7901SPaolo Bonzini     if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) {
177d09c7901SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
178d09c7901SPaolo Bonzini     }
179d09c7901SPaolo Bonzini 
180d09c7901SPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC());
181d09c7901SPaolo Bonzini 
1826bada5e8SBlue Swirl     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
1836bada5e8SBlue Swirl 
1846bada5e8SBlue Swirl     env->vm_vmcb = addr;
1856bada5e8SBlue Swirl 
1866bada5e8SBlue Swirl     /* save the current CPU state in the hsave page */
187b216aa6cSPaolo Bonzini     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.base),
1886bada5e8SBlue Swirl              env->gdt.base);
189b216aa6cSPaolo Bonzini     x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit),
1906bada5e8SBlue Swirl              env->gdt.limit);
1916bada5e8SBlue Swirl 
192b216aa6cSPaolo Bonzini     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.base),
1936bada5e8SBlue Swirl              env->idt.base);
194b216aa6cSPaolo Bonzini     x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.limit),
1956bada5e8SBlue Swirl              env->idt.limit);
1966bada5e8SBlue Swirl 
197b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
198f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
199b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
200f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
201b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
202f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
203b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
204f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
205b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
206f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
207b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
208f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
2096bada5e8SBlue Swirl 
210b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
211f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
212b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
213f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.rflags),
2146bada5e8SBlue Swirl              cpu_compute_eflags(env));
2156bada5e8SBlue Swirl 
216726ea335SRichard Henderson     svm_save_seg(env, MMU_PHYS_IDX,
217726ea335SRichard Henderson                  env->vm_hsave + offsetof(struct vmcb, save.es),
2186bada5e8SBlue Swirl                  &env->segs[R_ES]);
219726ea335SRichard Henderson     svm_save_seg(env, MMU_PHYS_IDX,
220726ea335SRichard Henderson                  env->vm_hsave + offsetof(struct vmcb, save.cs),
2216bada5e8SBlue Swirl                  &env->segs[R_CS]);
222726ea335SRichard Henderson     svm_save_seg(env, MMU_PHYS_IDX,
223726ea335SRichard Henderson                  env->vm_hsave + offsetof(struct vmcb, save.ss),
2246bada5e8SBlue Swirl                  &env->segs[R_SS]);
225726ea335SRichard Henderson     svm_save_seg(env, MMU_PHYS_IDX,
226726ea335SRichard Henderson                  env->vm_hsave + offsetof(struct vmcb, save.ds),
2276bada5e8SBlue Swirl                  &env->segs[R_DS]);
2286bada5e8SBlue Swirl 
229b216aa6cSPaolo Bonzini     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip),
230a78d0eabSliguang              env->eip + next_eip_addend);
231b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
232f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
233b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
234f606604fSEdgar E. Iglesias              env->vm_hsave + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
2356bada5e8SBlue Swirl 
2366bada5e8SBlue Swirl     /* load the interception bitmaps so we do not need to access the
2376bada5e8SBlue Swirl        vmcb in svm mode */
238b216aa6cSPaolo Bonzini     env->intercept = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
2396bada5e8SBlue Swirl                                                       control.intercept));
240b216aa6cSPaolo Bonzini     env->intercept_cr_read = x86_lduw_phys(cs, env->vm_vmcb +
2416bada5e8SBlue Swirl                                        offsetof(struct vmcb,
2426bada5e8SBlue Swirl                                                 control.intercept_cr_read));
243b216aa6cSPaolo Bonzini     env->intercept_cr_write = x86_lduw_phys(cs, env->vm_vmcb +
2446bada5e8SBlue Swirl                                         offsetof(struct vmcb,
2456bada5e8SBlue Swirl                                                  control.intercept_cr_write));
246b216aa6cSPaolo Bonzini     env->intercept_dr_read = x86_lduw_phys(cs, env->vm_vmcb +
2476bada5e8SBlue Swirl                                        offsetof(struct vmcb,
2486bada5e8SBlue Swirl                                                 control.intercept_dr_read));
249b216aa6cSPaolo Bonzini     env->intercept_dr_write = x86_lduw_phys(cs, env->vm_vmcb +
2506bada5e8SBlue Swirl                                         offsetof(struct vmcb,
2516bada5e8SBlue Swirl                                                  control.intercept_dr_write));
252b216aa6cSPaolo Bonzini     env->intercept_exceptions = x86_ldl_phys(cs, env->vm_vmcb +
2536bada5e8SBlue Swirl                                          offsetof(struct vmcb,
2546bada5e8SBlue Swirl                                                   control.intercept_exceptions
2556bada5e8SBlue Swirl                                                   ));
2566bada5e8SBlue Swirl 
2571a150d33SPaolo Bonzini     env->hflags &= ~HF_INHIBIT_IRQ_MASK;
2581a150d33SPaolo Bonzini     if (x86_ldl_phys(cs, env->vm_vmcb +
2591a150d33SPaolo Bonzini                 offsetof(struct vmcb, control.int_state)) &
2601a150d33SPaolo Bonzini                  SVM_INTERRUPT_SHADOW_MASK) {
2611a150d33SPaolo Bonzini         env->hflags |= HF_INHIBIT_IRQ_MASK;
2621a150d33SPaolo Bonzini     }
2631a150d33SPaolo Bonzini 
264fe441054SJan Kiszka     nested_ctl = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
265fe441054SJan Kiszka                                                           control.nested_ctl));
2667eb54ca9SLara Lazier     asid = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
2677eb54ca9SLara Lazier                                                           control.asid));
268a2d57703SAlexander Boettcher 
269481077b2SLara Lazier     uint64_t msrpm_base_pa = x86_ldq_phys(cs, env->vm_vmcb +
270481077b2SLara Lazier                                     offsetof(struct vmcb,
271481077b2SLara Lazier                                             control.msrpm_base_pa));
272481077b2SLara Lazier     uint64_t iopm_base_pa = x86_ldq_phys(cs, env->vm_vmcb +
273481077b2SLara Lazier                                  offsetof(struct vmcb, control.iopm_base_pa));
274481077b2SLara Lazier 
275481077b2SLara Lazier     if ((msrpm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_MSRPM_SIZE) {
276481077b2SLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
277481077b2SLara Lazier     }
278481077b2SLara Lazier 
279481077b2SLara Lazier     if ((iopm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_IOPM_SIZE) {
280481077b2SLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
281481077b2SLara Lazier     }
282481077b2SLara Lazier 
283a2d57703SAlexander Boettcher     env->nested_pg_mode = 0;
284a2d57703SAlexander Boettcher 
2857eb54ca9SLara Lazier     if (!cpu_svm_has_intercept(env, SVM_EXIT_VMRUN)) {
2867eb54ca9SLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
2877eb54ca9SLara Lazier     }
2887eb54ca9SLara Lazier     if (asid == 0) {
2897eb54ca9SLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
2907eb54ca9SLara Lazier     }
2917eb54ca9SLara Lazier 
292fe441054SJan Kiszka     if (nested_ctl & SVM_NPT_ENABLED) {
293fe441054SJan Kiszka         env->nested_cr3 = x86_ldq_phys(cs,
294fe441054SJan Kiszka                                 env->vm_vmcb + offsetof(struct vmcb,
295fe441054SJan Kiszka                                                         control.nested_cr3));
296fe441054SJan Kiszka         env->hflags2 |= HF2_NPT_MASK;
297fe441054SJan Kiszka 
29831dd35ebSPaolo Bonzini         env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK;
29998281984SRichard Henderson 
30098281984SRichard Henderson         tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX);
301fe441054SJan Kiszka     }
302fe441054SJan Kiszka 
3036bada5e8SBlue Swirl     /* enable intercepts */
304f8dc4c64SPaolo Bonzini     env->hflags |= HF_GUEST_MASK;
3056bada5e8SBlue Swirl 
306b216aa6cSPaolo Bonzini     env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb +
3076bada5e8SBlue Swirl                                offsetof(struct vmcb, control.tsc_offset));
3086bada5e8SBlue Swirl 
309498df2a7SLara Lazier     new_cr0 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr0));
310498df2a7SLara Lazier     if (new_cr0 & SVM_CR0_RESERVED_MASK) {
311498df2a7SLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
312498df2a7SLara Lazier     }
313498df2a7SLara Lazier     if ((new_cr0 & CR0_NW_MASK) && !(new_cr0 & CR0_CD_MASK)) {
314498df2a7SLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
315498df2a7SLara Lazier     }
3163407259bSLara Lazier     new_cr3 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr3));
3173407259bSLara Lazier     if ((env->efer & MSR_EFER_LMA) &&
31824d84c7eSLara Lazier             (new_cr3 & ((~0ULL) << cpu->phys_bits))) {
3193407259bSLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
3203407259bSLara Lazier     }
321213ff024SLara Lazier     new_cr4 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4));
322213ff024SLara Lazier     if (new_cr4 & cr4_reserved_bits(env)) {
323213ff024SLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
324213ff024SLara Lazier     }
3256bada5e8SBlue Swirl     /* clear exit_info_2 so we behave like the real hardware */
326b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
327f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
3286bada5e8SBlue Swirl 
329498df2a7SLara Lazier     cpu_x86_update_cr0(env, new_cr0);
330213ff024SLara Lazier     cpu_x86_update_cr4(env, new_cr4);
3313407259bSLara Lazier     cpu_x86_update_cr3(env, new_cr3);
332b216aa6cSPaolo Bonzini     env->cr[2] = x86_ldq_phys(cs,
3332c17449bSEdgar E. Iglesias                           env->vm_vmcb + offsetof(struct vmcb, save.cr2));
334e3126a5cSLara Lazier     env->int_ctl = x86_ldl_phys(cs,
335fdfba1a2SEdgar E. Iglesias                        env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
3366bada5e8SBlue Swirl     env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
337e3126a5cSLara Lazier     if (env->int_ctl & V_INTR_MASKING_MASK) {
3386bada5e8SBlue Swirl         env->hflags2 |= HF2_VINTR_MASK;
3396bada5e8SBlue Swirl         if (env->eflags & IF_MASK) {
3406bada5e8SBlue Swirl             env->hflags2 |= HF2_HIF_MASK;
3416bada5e8SBlue Swirl         }
3426bada5e8SBlue Swirl     }
3436bada5e8SBlue Swirl 
3446bada5e8SBlue Swirl     cpu_load_efer(env,
345b216aa6cSPaolo Bonzini                   x86_ldq_phys(cs,
3462c17449bSEdgar E. Iglesias                            env->vm_vmcb + offsetof(struct vmcb, save.efer)));
3476bada5e8SBlue Swirl     env->eflags = 0;
348b216aa6cSPaolo Bonzini     cpu_load_eflags(env, x86_ldq_phys(cs,
3492c17449bSEdgar E. Iglesias                                   env->vm_vmcb + offsetof(struct vmcb,
3506bada5e8SBlue Swirl                                                           save.rflags)),
3516bada5e8SBlue Swirl                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
3526bada5e8SBlue Swirl 
353726ea335SRichard Henderson     svm_load_seg_cache(env, MMU_PHYS_IDX,
354726ea335SRichard Henderson                        env->vm_vmcb + offsetof(struct vmcb, save.es), R_ES);
355726ea335SRichard Henderson     svm_load_seg_cache(env, MMU_PHYS_IDX,
356726ea335SRichard Henderson                        env->vm_vmcb + offsetof(struct vmcb, save.cs), R_CS);
357726ea335SRichard Henderson     svm_load_seg_cache(env, MMU_PHYS_IDX,
358726ea335SRichard Henderson                        env->vm_vmcb + offsetof(struct vmcb, save.ss), R_SS);
359726ea335SRichard Henderson     svm_load_seg_cache(env, MMU_PHYS_IDX,
360726ea335SRichard Henderson                        env->vm_vmcb + offsetof(struct vmcb, save.ds), R_DS);
361726ea335SRichard Henderson     svm_load_seg(env, MMU_PHYS_IDX,
362726ea335SRichard Henderson                  env->vm_vmcb + offsetof(struct vmcb, save.idtr), &env->idt);
363726ea335SRichard Henderson     svm_load_seg(env, MMU_PHYS_IDX,
364726ea335SRichard Henderson                  env->vm_vmcb + offsetof(struct vmcb, save.gdtr), &env->gdt);
3656bada5e8SBlue Swirl 
366b216aa6cSPaolo Bonzini     env->eip = x86_ldq_phys(cs,
3672c17449bSEdgar E. Iglesias                         env->vm_vmcb + offsetof(struct vmcb, save.rip));
3680bc60a8aSliguang 
369b216aa6cSPaolo Bonzini     env->regs[R_ESP] = x86_ldq_phys(cs,
3702c17449bSEdgar E. Iglesias                                 env->vm_vmcb + offsetof(struct vmcb, save.rsp));
371b216aa6cSPaolo Bonzini     env->regs[R_EAX] = x86_ldq_phys(cs,
3722c17449bSEdgar E. Iglesias                                 env->vm_vmcb + offsetof(struct vmcb, save.rax));
3738aa76496SPaolo Bonzini 
3748aa76496SPaolo Bonzini     new_dr7 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.dr7));
3758aa76496SPaolo Bonzini     new_dr6 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.dr6));
3766bada5e8SBlue Swirl 
377acf23ffbSLara Lazier #ifdef TARGET_X86_64
3788aa76496SPaolo Bonzini     if (new_dr7 & DR_RESERVED_MASK) {
379acf23ffbSLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
380acf23ffbSLara Lazier     }
3818aa76496SPaolo Bonzini     if (new_dr6 & DR_RESERVED_MASK) {
382acf23ffbSLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
383acf23ffbSLara Lazier     }
384acf23ffbSLara Lazier #endif
3856bada5e8SBlue Swirl 
3868aa76496SPaolo Bonzini     cpu_x86_update_dr7(env, new_dr7);
3878aa76496SPaolo Bonzini     env->dr[6] = new_dr6;
3888aa76496SPaolo Bonzini 
389d499f196SLara Lazier     if (is_efer_invalid_state(env)) {
390d499f196SLara Lazier         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
391d499f196SLara Lazier     }
392d499f196SLara Lazier 
393b216aa6cSPaolo Bonzini     switch (x86_ldub_phys(cs,
3942c17449bSEdgar E. Iglesias                       env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
3956bada5e8SBlue Swirl     case TLB_CONTROL_DO_NOTHING:
3966bada5e8SBlue Swirl         break;
3976bada5e8SBlue Swirl     case TLB_CONTROL_FLUSH_ALL_ASID:
3986bada5e8SBlue Swirl         /* FIXME: this is not 100% correct but should work for now */
399d10eb08fSAlex Bennée         tlb_flush(cs);
4006bada5e8SBlue Swirl         break;
4016bada5e8SBlue Swirl     }
4026bada5e8SBlue Swirl 
4036bada5e8SBlue Swirl     env->hflags2 |= HF2_GIF_MASK;
4046bada5e8SBlue Swirl 
405e3126a5cSLara Lazier     if (ctl_has_irq(env)) {
406259186a7SAndreas Färber         cs->interrupt_request |= CPU_INTERRUPT_VIRQ;
4076bada5e8SBlue Swirl     }
4086bada5e8SBlue Swirl 
409b67e2796SLara Lazier     if (virtual_gif_set(env)) {
410b67e2796SLara Lazier         env->hflags2 |= HF2_VGIF_MASK;
411b67e2796SLara Lazier     }
412b67e2796SLara Lazier 
4136bada5e8SBlue Swirl     /* maybe we need to inject an event */
414b216aa6cSPaolo Bonzini     event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
4156bada5e8SBlue Swirl                                                  control.event_inj));
4166bada5e8SBlue Swirl     if (event_inj & SVM_EVTINJ_VALID) {
4176bada5e8SBlue Swirl         uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
4186bada5e8SBlue Swirl         uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
419b216aa6cSPaolo Bonzini         uint32_t event_inj_err = x86_ldl_phys(cs, env->vm_vmcb +
4206bada5e8SBlue Swirl                                           offsetof(struct vmcb,
4216bada5e8SBlue Swirl                                                    control.event_inj_err));
4226bada5e8SBlue Swirl 
4236bada5e8SBlue Swirl         qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
4246bada5e8SBlue Swirl         /* FIXME: need to implement valid_err */
4256bada5e8SBlue Swirl         switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
4266bada5e8SBlue Swirl         case SVM_EVTINJ_TYPE_INTR:
42727103424SAndreas Färber             cs->exception_index = vector;
4286bada5e8SBlue Swirl             env->error_code = event_inj_err;
4296bada5e8SBlue Swirl             env->exception_is_int = 0;
4306bada5e8SBlue Swirl             env->exception_next_eip = -1;
4316bada5e8SBlue Swirl             qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
4326bada5e8SBlue Swirl             /* XXX: is it always correct? */
4336bada5e8SBlue Swirl             do_interrupt_x86_hardirq(env, vector, 1);
4346bada5e8SBlue Swirl             break;
4356bada5e8SBlue Swirl         case SVM_EVTINJ_TYPE_NMI:
43627103424SAndreas Färber             cs->exception_index = EXCP02_NMI;
4376bada5e8SBlue Swirl             env->error_code = event_inj_err;
4386bada5e8SBlue Swirl             env->exception_is_int = 0;
439a78d0eabSliguang             env->exception_next_eip = env->eip;
4406bada5e8SBlue Swirl             qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
4415638d180SAndreas Färber             cpu_loop_exit(cs);
4426bada5e8SBlue Swirl             break;
4436bada5e8SBlue Swirl         case SVM_EVTINJ_TYPE_EXEPT:
444eceb4f01SLara Lazier             if (vector == EXCP02_NMI || vector >= 31)  {
445eceb4f01SLara Lazier                 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
446eceb4f01SLara Lazier             }
44727103424SAndreas Färber             cs->exception_index = vector;
4486bada5e8SBlue Swirl             env->error_code = event_inj_err;
4496bada5e8SBlue Swirl             env->exception_is_int = 0;
4506bada5e8SBlue Swirl             env->exception_next_eip = -1;
4516bada5e8SBlue Swirl             qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
4525638d180SAndreas Färber             cpu_loop_exit(cs);
4536bada5e8SBlue Swirl             break;
4546bada5e8SBlue Swirl         case SVM_EVTINJ_TYPE_SOFT:
45527103424SAndreas Färber             cs->exception_index = vector;
4566bada5e8SBlue Swirl             env->error_code = event_inj_err;
4576bada5e8SBlue Swirl             env->exception_is_int = 1;
458a78d0eabSliguang             env->exception_next_eip = env->eip;
4596bada5e8SBlue Swirl             qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
4605638d180SAndreas Färber             cpu_loop_exit(cs);
4616bada5e8SBlue Swirl             break;
462eceb4f01SLara Lazier         default:
463eceb4f01SLara Lazier             cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
464eceb4f01SLara Lazier             break;
4656bada5e8SBlue Swirl         }
46627103424SAndreas Färber         qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index,
4676bada5e8SBlue Swirl                       env->error_code);
4686bada5e8SBlue Swirl     }
4696bada5e8SBlue Swirl }
4706bada5e8SBlue Swirl 
471052e80d5SBlue Swirl void helper_vmmcall(CPUX86State *env)
4726bada5e8SBlue Swirl {
47365c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0, GETPC());
4746bada5e8SBlue Swirl     raise_exception(env, EXCP06_ILLOP);
4756bada5e8SBlue Swirl }
4766bada5e8SBlue Swirl 
477052e80d5SBlue Swirl void helper_vmload(CPUX86State *env, int aflag)
4786bada5e8SBlue Swirl {
479726ea335SRichard Henderson     int mmu_idx = MMU_PHYS_IDX;
4806bada5e8SBlue Swirl     target_ulong addr;
4816bada5e8SBlue Swirl 
4826bada5e8SBlue Swirl     if (aflag == 2) {
4834b34e3adSliguang         addr = env->regs[R_EAX];
4846bada5e8SBlue Swirl     } else {
4854b34e3adSliguang         addr = (uint32_t)env->regs[R_EAX];
4866bada5e8SBlue Swirl     }
4876bada5e8SBlue Swirl 
488d09c7901SPaolo Bonzini     /* Exceptions are checked before the intercept.  */
489d09c7901SPaolo Bonzini     if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) {
490d09c7901SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
491d09c7901SPaolo Bonzini     }
492d09c7901SPaolo Bonzini 
493d09c7901SPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC());
494d09c7901SPaolo Bonzini 
49552fb8ad3SLara Lazier     if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) {
496726ea335SRichard Henderson         mmu_idx = MMU_NESTED_IDX;
49752fb8ad3SLara Lazier     }
49852fb8ad3SLara Lazier 
499726ea335SRichard Henderson     svm_load_seg_cache(env, mmu_idx,
500726ea335SRichard Henderson                        addr + offsetof(struct vmcb, save.fs), R_FS);
501726ea335SRichard Henderson     svm_load_seg_cache(env, mmu_idx,
502726ea335SRichard Henderson                        addr + offsetof(struct vmcb, save.gs), R_GS);
503726ea335SRichard Henderson     svm_load_seg(env, mmu_idx,
504726ea335SRichard Henderson                  addr + offsetof(struct vmcb, save.tr), &env->tr);
505726ea335SRichard Henderson     svm_load_seg(env, mmu_idx,
506726ea335SRichard Henderson                  addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
5076bada5e8SBlue Swirl 
5086bada5e8SBlue Swirl #ifdef TARGET_X86_64
509726ea335SRichard Henderson     env->kernelgsbase =
510726ea335SRichard Henderson         cpu_ldq_mmuidx_ra(env,
511726ea335SRichard Henderson                           addr + offsetof(struct vmcb, save.kernel_gs_base),
512726ea335SRichard Henderson                           mmu_idx, 0);
513726ea335SRichard Henderson     env->lstar =
514726ea335SRichard Henderson         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.lstar),
515726ea335SRichard Henderson                           mmu_idx, 0);
516726ea335SRichard Henderson     env->cstar =
517726ea335SRichard Henderson         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.cstar),
518726ea335SRichard Henderson                           mmu_idx, 0);
519726ea335SRichard Henderson     env->fmask =
520726ea335SRichard Henderson         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sfmask),
521726ea335SRichard Henderson                           mmu_idx, 0);
52297afb47eSLara Lazier     svm_canonicalization(env, &env->kernelgsbase);
5236bada5e8SBlue Swirl #endif
524726ea335SRichard Henderson     env->star =
525726ea335SRichard Henderson         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star),
526726ea335SRichard Henderson                           mmu_idx, 0);
527726ea335SRichard Henderson     env->sysenter_cs =
528726ea335SRichard Henderson         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs),
529726ea335SRichard Henderson                           mmu_idx, 0);
530726ea335SRichard Henderson     env->sysenter_esp =
531726ea335SRichard Henderson         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_esp),
532726ea335SRichard Henderson                           mmu_idx, 0);
533726ea335SRichard Henderson     env->sysenter_eip =
534726ea335SRichard Henderson         cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_eip),
535726ea335SRichard Henderson                           mmu_idx, 0);
5366bada5e8SBlue Swirl }
5376bada5e8SBlue Swirl 
538052e80d5SBlue Swirl void helper_vmsave(CPUX86State *env, int aflag)
5396bada5e8SBlue Swirl {
540726ea335SRichard Henderson     int mmu_idx = MMU_PHYS_IDX;
5416bada5e8SBlue Swirl     target_ulong addr;
5426bada5e8SBlue Swirl 
5436bada5e8SBlue Swirl     if (aflag == 2) {
5444b34e3adSliguang         addr = env->regs[R_EAX];
5456bada5e8SBlue Swirl     } else {
5464b34e3adSliguang         addr = (uint32_t)env->regs[R_EAX];
5476bada5e8SBlue Swirl     }
5486bada5e8SBlue Swirl 
549d09c7901SPaolo Bonzini     /* Exceptions are checked before the intercept.  */
550d09c7901SPaolo Bonzini     if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) {
551d09c7901SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
552d09c7901SPaolo Bonzini     }
553d09c7901SPaolo Bonzini 
554d09c7901SPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC());
555d09c7901SPaolo Bonzini 
55652fb8ad3SLara Lazier     if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) {
557726ea335SRichard Henderson         mmu_idx = MMU_NESTED_IDX;
55852fb8ad3SLara Lazier     }
55952fb8ad3SLara Lazier 
560726ea335SRichard Henderson     svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.fs),
5616bada5e8SBlue Swirl                  &env->segs[R_FS]);
562726ea335SRichard Henderson     svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.gs),
5636bada5e8SBlue Swirl                  &env->segs[R_GS]);
564726ea335SRichard Henderson     svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.tr),
5656bada5e8SBlue Swirl                  &env->tr);
566726ea335SRichard Henderson     svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.ldtr),
5676bada5e8SBlue Swirl                  &env->ldt);
5686bada5e8SBlue Swirl 
5696bada5e8SBlue Swirl #ifdef TARGET_X86_64
570726ea335SRichard Henderson     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.kernel_gs_base),
571726ea335SRichard Henderson                       env->kernelgsbase, mmu_idx, 0);
572726ea335SRichard Henderson     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.lstar),
573726ea335SRichard Henderson                       env->lstar, mmu_idx, 0);
574726ea335SRichard Henderson     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.cstar),
575726ea335SRichard Henderson                       env->cstar, mmu_idx, 0);
576726ea335SRichard Henderson     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sfmask),
577726ea335SRichard Henderson                       env->fmask, mmu_idx, 0);
5786bada5e8SBlue Swirl #endif
579726ea335SRichard Henderson     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star),
580726ea335SRichard Henderson                       env->star, mmu_idx, 0);
581726ea335SRichard Henderson     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs),
582726ea335SRichard Henderson                       env->sysenter_cs, mmu_idx, 0);
583726ea335SRichard Henderson     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_esp),
584726ea335SRichard Henderson                       env->sysenter_esp, mmu_idx, 0);
585726ea335SRichard Henderson     cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_eip),
586726ea335SRichard Henderson                       env->sysenter_eip, mmu_idx, 0);
5876bada5e8SBlue Swirl }
5886bada5e8SBlue Swirl 
589052e80d5SBlue Swirl void helper_stgi(CPUX86State *env)
5906bada5e8SBlue Swirl {
59165c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC());
592900eeca5SLara Lazier 
593e3126a5cSLara Lazier     if (virtual_gif_enabled(env)) {
594e3126a5cSLara Lazier         env->int_ctl |= V_GIF_MASK;
595b67e2796SLara Lazier         env->hflags2 |= HF2_VGIF_MASK;
596900eeca5SLara Lazier     } else {
5976bada5e8SBlue Swirl         env->hflags2 |= HF2_GIF_MASK;
5986bada5e8SBlue Swirl     }
599900eeca5SLara Lazier }
6006bada5e8SBlue Swirl 
601052e80d5SBlue Swirl void helper_clgi(CPUX86State *env)
6026bada5e8SBlue Swirl {
60365c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC());
604900eeca5SLara Lazier 
605e3126a5cSLara Lazier     if (virtual_gif_enabled(env)) {
606e3126a5cSLara Lazier         env->int_ctl &= ~V_GIF_MASK;
607b67e2796SLara Lazier         env->hflags2 &= ~HF2_VGIF_MASK;
608900eeca5SLara Lazier     } else {
6096bada5e8SBlue Swirl         env->hflags2 &= ~HF2_GIF_MASK;
6106bada5e8SBlue Swirl     }
611900eeca5SLara Lazier }
6126bada5e8SBlue Swirl 
613813c6459SLara Lazier bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type)
614813c6459SLara Lazier {
615813c6459SLara Lazier     switch (type) {
616813c6459SLara Lazier     case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
617813c6459SLara Lazier         if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
618813c6459SLara Lazier             return true;
619813c6459SLara Lazier         }
620813c6459SLara Lazier         break;
621813c6459SLara Lazier     case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
622813c6459SLara Lazier         if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
623813c6459SLara Lazier             return true;
624813c6459SLara Lazier         }
625813c6459SLara Lazier         break;
626813c6459SLara Lazier     case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
627813c6459SLara Lazier         if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
628813c6459SLara Lazier             return true;
629813c6459SLara Lazier         }
630813c6459SLara Lazier         break;
631813c6459SLara Lazier     case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
632813c6459SLara Lazier         if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
633813c6459SLara Lazier             return true;
634813c6459SLara Lazier         }
635813c6459SLara Lazier         break;
636813c6459SLara Lazier     case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
637813c6459SLara Lazier         if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
638813c6459SLara Lazier             return true;
639813c6459SLara Lazier         }
640813c6459SLara Lazier         break;
641813c6459SLara Lazier     default:
642813c6459SLara Lazier         if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
643813c6459SLara Lazier             return true;
644813c6459SLara Lazier         }
645813c6459SLara Lazier         break;
646813c6459SLara Lazier     }
647813c6459SLara Lazier     return false;
648813c6459SLara Lazier }
649813c6459SLara Lazier 
65065c9d60aSPaolo Bonzini void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
65165c9d60aSPaolo Bonzini                                    uint64_t param, uintptr_t retaddr)
6526bada5e8SBlue Swirl {
6536aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
6542c17449bSEdgar E. Iglesias 
655f8dc4c64SPaolo Bonzini     if (likely(!(env->hflags & HF_GUEST_MASK))) {
6566bada5e8SBlue Swirl         return;
6576bada5e8SBlue Swirl     }
658813c6459SLara Lazier 
659813c6459SLara Lazier     if (!cpu_svm_has_intercept(env, type)) {
660813c6459SLara Lazier         return;
6616bada5e8SBlue Swirl     }
662813c6459SLara Lazier 
663813c6459SLara Lazier     if (type == SVM_EXIT_MSR) {
6646bada5e8SBlue Swirl         /* FIXME: this should be read in at vmrun (faster this way?) */
665b216aa6cSPaolo Bonzini         uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
6666bada5e8SBlue Swirl                                     offsetof(struct vmcb,
6676bada5e8SBlue Swirl                                             control.msrpm_base_pa));
6686bada5e8SBlue Swirl         uint32_t t0, t1;
6696bada5e8SBlue Swirl 
670a4165610Sliguang         switch ((uint32_t)env->regs[R_ECX]) {
6716bada5e8SBlue Swirl         case 0 ... 0x1fff:
672a4165610Sliguang             t0 = (env->regs[R_ECX] * 2) % 8;
673a4165610Sliguang             t1 = (env->regs[R_ECX] * 2) / 8;
6746bada5e8SBlue Swirl             break;
6756bada5e8SBlue Swirl         case 0xc0000000 ... 0xc0001fff:
676a4165610Sliguang             t0 = (8192 + env->regs[R_ECX] - 0xc0000000) * 2;
6776bada5e8SBlue Swirl             t1 = (t0 / 8);
6786bada5e8SBlue Swirl             t0 %= 8;
6796bada5e8SBlue Swirl             break;
6806bada5e8SBlue Swirl         case 0xc0010000 ... 0xc0011fff:
681a4165610Sliguang             t0 = (16384 + env->regs[R_ECX] - 0xc0010000) * 2;
6826bada5e8SBlue Swirl             t1 = (t0 / 8);
6836bada5e8SBlue Swirl             t0 %= 8;
6846bada5e8SBlue Swirl             break;
6856bada5e8SBlue Swirl         default:
68665c9d60aSPaolo Bonzini             cpu_vmexit(env, type, param, retaddr);
6876bada5e8SBlue Swirl             t0 = 0;
6886bada5e8SBlue Swirl             t1 = 0;
6896bada5e8SBlue Swirl             break;
6906bada5e8SBlue Swirl         }
691b216aa6cSPaolo Bonzini         if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) {
69265c9d60aSPaolo Bonzini             cpu_vmexit(env, type, param, retaddr);
6936bada5e8SBlue Swirl         }
694813c6459SLara Lazier         return;
6956bada5e8SBlue Swirl     }
696813c6459SLara Lazier 
69765c9d60aSPaolo Bonzini     cpu_vmexit(env, type, param, retaddr);
6986bada5e8SBlue Swirl }
6996bada5e8SBlue Swirl 
700d051ea04SRichard Henderson void helper_svm_check_intercept(CPUX86State *env, uint32_t type)
7016bada5e8SBlue Swirl {
702d051ea04SRichard Henderson     cpu_svm_check_intercept_param(env, type, 0, GETPC());
7036bada5e8SBlue Swirl }
7046bada5e8SBlue Swirl 
705052e80d5SBlue Swirl void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
7066bada5e8SBlue Swirl                          uint32_t next_eip_addend)
7076bada5e8SBlue Swirl {
7086aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
70919d6ca16SAndreas Färber 
7106bada5e8SBlue Swirl     if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
7116bada5e8SBlue Swirl         /* FIXME: this should be read in at vmrun (faster this way?) */
712b216aa6cSPaolo Bonzini         uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
7136bada5e8SBlue Swirl                                  offsetof(struct vmcb, control.iopm_base_pa));
7146bada5e8SBlue Swirl         uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
7156bada5e8SBlue Swirl 
716b216aa6cSPaolo Bonzini         if (x86_lduw_phys(cs, addr + port / 8) & (mask << (port & 7))) {
717a78d0eabSliguang             /* next env->eip */
718b216aa6cSPaolo Bonzini             x86_stq_phys(cs,
719f606604fSEdgar E. Iglesias                      env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
7206bada5e8SBlue Swirl                      env->eip + next_eip_addend);
72165c9d60aSPaolo Bonzini             cpu_vmexit(env, SVM_EXIT_IOIO, param | (port << 16), GETPC());
7226bada5e8SBlue Swirl         }
7236bada5e8SBlue Swirl     }
7246bada5e8SBlue Swirl }
7256bada5e8SBlue Swirl 
72665c9d60aSPaolo Bonzini void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
72765c9d60aSPaolo Bonzini                 uintptr_t retaddr)
7286bada5e8SBlue Swirl {
7296aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
7306bada5e8SBlue Swirl 
7313d419a4dSRichard Henderson     cpu_restore_state(cs, retaddr);
73265c9d60aSPaolo Bonzini 
7336bada5e8SBlue Swirl     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
7346bada5e8SBlue Swirl                   PRIx64 ", " TARGET_FMT_lx ")!\n",
7356bada5e8SBlue Swirl                   exit_code, exit_info_1,
736b216aa6cSPaolo Bonzini                   x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
7376bada5e8SBlue Swirl                                                    control.exit_info_2)),
738a78d0eabSliguang                   env->eip);
7396bada5e8SBlue Swirl 
74068775856SPaolo Bonzini     cs->exception_index = EXCP_VMEXIT;
74168775856SPaolo Bonzini     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
74268775856SPaolo Bonzini              exit_code);
74368775856SPaolo Bonzini 
74468775856SPaolo Bonzini     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
74568775856SPaolo Bonzini                                              control.exit_info_1), exit_info_1),
74610cde894SPaolo Bonzini 
74710cde894SPaolo Bonzini     /* remove any pending exception */
74810cde894SPaolo Bonzini     env->old_exception = -1;
74910cde894SPaolo Bonzini     cpu_loop_exit(cs);
75010cde894SPaolo Bonzini }
75110cde894SPaolo Bonzini 
75268775856SPaolo Bonzini void do_vmexit(CPUX86State *env)
75310cde894SPaolo Bonzini {
7546aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
75510cde894SPaolo Bonzini 
7566bada5e8SBlue Swirl     if (env->hflags & HF_INHIBIT_IRQ_MASK) {
757b216aa6cSPaolo Bonzini         x86_stl_phys(cs,
758ab1da857SEdgar E. Iglesias                  env->vm_vmcb + offsetof(struct vmcb, control.int_state),
7596bada5e8SBlue Swirl                  SVM_INTERRUPT_SHADOW_MASK);
7606bada5e8SBlue Swirl         env->hflags &= ~HF_INHIBIT_IRQ_MASK;
7616bada5e8SBlue Swirl     } else {
762b216aa6cSPaolo Bonzini         x86_stl_phys(cs,
763ab1da857SEdgar E. Iglesias                  env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
7646bada5e8SBlue Swirl     }
765fe441054SJan Kiszka     env->hflags2 &= ~HF2_NPT_MASK;
76698281984SRichard Henderson     tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX);
7676bada5e8SBlue Swirl 
7686bada5e8SBlue Swirl     /* Save the VM state in the vmcb */
769726ea335SRichard Henderson     svm_save_seg(env, MMU_PHYS_IDX,
770726ea335SRichard Henderson                  env->vm_vmcb + offsetof(struct vmcb, save.es),
7716bada5e8SBlue Swirl                  &env->segs[R_ES]);
772726ea335SRichard Henderson     svm_save_seg(env, MMU_PHYS_IDX,
773726ea335SRichard Henderson                  env->vm_vmcb + offsetof(struct vmcb, save.cs),
7746bada5e8SBlue Swirl                  &env->segs[R_CS]);
775726ea335SRichard Henderson     svm_save_seg(env, MMU_PHYS_IDX,
776726ea335SRichard Henderson                  env->vm_vmcb + offsetof(struct vmcb, save.ss),
7776bada5e8SBlue Swirl                  &env->segs[R_SS]);
778726ea335SRichard Henderson     svm_save_seg(env, MMU_PHYS_IDX,
779726ea335SRichard Henderson                  env->vm_vmcb + offsetof(struct vmcb, save.ds),
7806bada5e8SBlue Swirl                  &env->segs[R_DS]);
7816bada5e8SBlue Swirl 
782b216aa6cSPaolo Bonzini     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
7836bada5e8SBlue Swirl              env->gdt.base);
784b216aa6cSPaolo Bonzini     x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit),
7856bada5e8SBlue Swirl              env->gdt.limit);
7866bada5e8SBlue Swirl 
787b216aa6cSPaolo Bonzini     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.base),
7886bada5e8SBlue Swirl              env->idt.base);
789b216aa6cSPaolo Bonzini     x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit),
7906bada5e8SBlue Swirl              env->idt.limit);
7916bada5e8SBlue Swirl 
792b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
793f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
794b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
795f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
796b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
797f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
798b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
799f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
800b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
801f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
802b216aa6cSPaolo Bonzini     x86_stl_phys(cs,
803e3126a5cSLara Lazier              env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), env->int_ctl);
8046bada5e8SBlue Swirl 
805b216aa6cSPaolo Bonzini     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rflags),
8066bada5e8SBlue Swirl              cpu_compute_eflags(env));
807b216aa6cSPaolo Bonzini     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip),
808052e80d5SBlue Swirl              env->eip);
809b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
810f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
811b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
812f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
813b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
814f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
815b216aa6cSPaolo Bonzini     x86_stq_phys(cs,
816f606604fSEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
817b216aa6cSPaolo Bonzini     x86_stb_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cpl),
8186bada5e8SBlue Swirl              env->hflags & HF_CPL_MASK);
8196bada5e8SBlue Swirl 
8206bada5e8SBlue Swirl     /* Reload the host state from vm_hsave */
8216bada5e8SBlue Swirl     env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
822f8dc4c64SPaolo Bonzini     env->hflags &= ~HF_GUEST_MASK;
8236bada5e8SBlue Swirl     env->intercept = 0;
8246bada5e8SBlue Swirl     env->intercept_exceptions = 0;
8251a150d33SPaolo Bonzini 
8261a150d33SPaolo Bonzini     /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
827259186a7SAndreas Färber     cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
828e3126a5cSLara Lazier     env->int_ctl = 0;
8291a150d33SPaolo Bonzini 
8301a150d33SPaolo Bonzini     /* Clears the TSC_OFFSET inside the processor. */
8316bada5e8SBlue Swirl     env->tsc_offset = 0;
8326bada5e8SBlue Swirl 
833b216aa6cSPaolo Bonzini     env->gdt.base  = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
8346bada5e8SBlue Swirl                                                        save.gdtr.base));
835b216aa6cSPaolo Bonzini     env->gdt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
8366bada5e8SBlue Swirl                                                        save.gdtr.limit));
8376bada5e8SBlue Swirl 
838b216aa6cSPaolo Bonzini     env->idt.base  = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
8396bada5e8SBlue Swirl                                                        save.idtr.base));
840b216aa6cSPaolo Bonzini     env->idt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
8416bada5e8SBlue Swirl                                                        save.idtr.limit));
8426bada5e8SBlue Swirl 
843b216aa6cSPaolo Bonzini     cpu_x86_update_cr0(env, x86_ldq_phys(cs,
8442c17449bSEdgar E. Iglesias                                      env->vm_hsave + offsetof(struct vmcb,
8456bada5e8SBlue Swirl                                                               save.cr0)) |
8466bada5e8SBlue Swirl                        CR0_PE_MASK);
847b216aa6cSPaolo Bonzini     cpu_x86_update_cr4(env, x86_ldq_phys(cs,
8482c17449bSEdgar E. Iglesias                                      env->vm_hsave + offsetof(struct vmcb,
8496bada5e8SBlue Swirl                                                               save.cr4)));
8501a150d33SPaolo Bonzini 
8511a150d33SPaolo Bonzini     /*
8521a150d33SPaolo Bonzini      * Resets the current ASID register to zero (host ASID; TLB flush).
8531a150d33SPaolo Bonzini      *
8541a150d33SPaolo Bonzini      * If the host is in PAE mode, the processor reloads the host's PDPEs
8551a150d33SPaolo Bonzini      * from the page table indicated the host's CR3. FIXME: If the PDPEs
8561a150d33SPaolo Bonzini      * contain illegal state, the processor causes a shutdown (QEMU does
8571a150d33SPaolo Bonzini      * not implement PDPTRs).
8581a150d33SPaolo Bonzini      */
859b216aa6cSPaolo Bonzini     cpu_x86_update_cr3(env, x86_ldq_phys(cs,
8602c17449bSEdgar E. Iglesias                                      env->vm_hsave + offsetof(struct vmcb,
8616bada5e8SBlue Swirl                                                               save.cr3)));
8626bada5e8SBlue Swirl     /* we need to set the efer after the crs so the hidden flags get
8636bada5e8SBlue Swirl        set properly */
864b216aa6cSPaolo Bonzini     cpu_load_efer(env, x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
8656bada5e8SBlue Swirl                                                          save.efer)));
8661a150d33SPaolo Bonzini 
8671a150d33SPaolo Bonzini     /* Completion of the VMRUN instruction clears the host EFLAGS.RF bit.  */
8686bada5e8SBlue Swirl     env->eflags = 0;
869b216aa6cSPaolo Bonzini     cpu_load_eflags(env, x86_ldq_phys(cs,
8702c17449bSEdgar E. Iglesias                                   env->vm_hsave + offsetof(struct vmcb,
8716bada5e8SBlue Swirl                                                            save.rflags)),
87230452029SKevin O'Connor                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK |
8731a150d33SPaolo Bonzini                       RF_MASK | VM_MASK));
8746bada5e8SBlue Swirl 
875726ea335SRichard Henderson     svm_load_seg_cache(env, MMU_PHYS_IDX,
876726ea335SRichard Henderson                        env->vm_hsave + offsetof(struct vmcb, save.es), R_ES);
877726ea335SRichard Henderson     svm_load_seg_cache(env, MMU_PHYS_IDX,
878726ea335SRichard Henderson                        env->vm_hsave + offsetof(struct vmcb, save.cs), R_CS);
879726ea335SRichard Henderson     svm_load_seg_cache(env, MMU_PHYS_IDX,
880726ea335SRichard Henderson                        env->vm_hsave + offsetof(struct vmcb, save.ss), R_SS);
881726ea335SRichard Henderson     svm_load_seg_cache(env, MMU_PHYS_IDX,
882726ea335SRichard Henderson                        env->vm_hsave + offsetof(struct vmcb, save.ds), R_DS);
8836bada5e8SBlue Swirl 
884b216aa6cSPaolo Bonzini     env->eip = x86_ldq_phys(cs,
8852c17449bSEdgar E. Iglesias                         env->vm_hsave + offsetof(struct vmcb, save.rip));
886b216aa6cSPaolo Bonzini     env->regs[R_ESP] = x86_ldq_phys(cs, env->vm_hsave +
88790a2541bSliguang                                 offsetof(struct vmcb, save.rsp));
888b216aa6cSPaolo Bonzini     env->regs[R_EAX] = x86_ldq_phys(cs, env->vm_hsave +
88990a2541bSliguang                                 offsetof(struct vmcb, save.rax));
8906bada5e8SBlue Swirl 
891b216aa6cSPaolo Bonzini     env->dr[6] = x86_ldq_phys(cs,
8922c17449bSEdgar E. Iglesias                           env->vm_hsave + offsetof(struct vmcb, save.dr6));
8938aa76496SPaolo Bonzini 
8948aa76496SPaolo Bonzini     /* Disables all breakpoints in the host DR7 register. */
8958aa76496SPaolo Bonzini     cpu_x86_update_dr7(env,
8968aa76496SPaolo Bonzini              x86_ldq_phys(cs,
8978aa76496SPaolo Bonzini                           env->vm_hsave + offsetof(struct vmcb, save.dr7)) & ~0xff);
8986bada5e8SBlue Swirl 
8996bada5e8SBlue Swirl     /* other setups */
900b216aa6cSPaolo Bonzini     x86_stl_phys(cs,
901ab1da857SEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
902b216aa6cSPaolo Bonzini              x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
9036bada5e8SBlue Swirl                                               control.event_inj)));
904b216aa6cSPaolo Bonzini     x86_stl_phys(cs,
905ab1da857SEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
906b216aa6cSPaolo Bonzini              x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
9076bada5e8SBlue Swirl                                               control.event_inj_err)));
908b216aa6cSPaolo Bonzini     x86_stl_phys(cs,
909ab1da857SEdgar E. Iglesias              env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
9106bada5e8SBlue Swirl 
9116bada5e8SBlue Swirl     env->hflags2 &= ~HF2_GIF_MASK;
912b67e2796SLara Lazier     env->hflags2 &= ~HF2_VGIF_MASK;
9136bada5e8SBlue Swirl 
9146bada5e8SBlue Swirl 
9151a150d33SPaolo Bonzini     /* FIXME: Checks the reloaded host state for consistency. */
9166bada5e8SBlue Swirl 
9171a150d33SPaolo Bonzini     /*
9181a150d33SPaolo Bonzini      * EFLAGS.TF causes a #DB trap after the VMRUN completes on the host
9191a150d33SPaolo Bonzini      * side (i.e., after the #VMEXIT from the guest). Since we're running
9201a150d33SPaolo Bonzini      * in the main loop, call do_interrupt_all directly.
9211a150d33SPaolo Bonzini      */
9221a150d33SPaolo Bonzini     if ((env->eflags & TF_MASK) != 0) {
9231a150d33SPaolo Bonzini         env->dr[6] |= DR6_BS;
9241a150d33SPaolo Bonzini         do_interrupt_all(X86_CPU(cs), EXCP01_DB, 0, 0, env->eip, 0);
9251a150d33SPaolo Bonzini     }
9266bada5e8SBlue Swirl }
927