xref: /qemu/target/i386/tcg/sysemu/svm_helper.c (revision 336d354b)
1 /*
2  *  x86 SVM helpers (sysemu only)
3  *
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "qemu/osdep.h"
21 #include "qemu/log.h"
22 #include "cpu.h"
23 #include "exec/helper-proto.h"
24 #include "exec/exec-all.h"
25 #include "exec/cpu_ldst.h"
26 #include "tcg/helper-tcg.h"
27 
28 /* Secure Virtual Machine helpers */
29 
30 static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
31                                 const SegmentCache *sc)
32 {
33     CPUState *cs = env_cpu(env);
34 
35     x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, selector),
36              sc->selector);
37     x86_stq_phys(cs, addr + offsetof(struct vmcb_seg, base),
38              sc->base);
39     x86_stl_phys(cs, addr + offsetof(struct vmcb_seg, limit),
40              sc->limit);
41     x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, attrib),
42              ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
43 }
44 
45 /*
46  * VMRUN and VMLOAD canonicalizes (i.e., sign-extend to bit 63) all base
47  * addresses in the segment registers that have been loaded.
48  */
49 static inline void svm_canonicalization(CPUX86State *env, target_ulong *seg_base)
50 {
51     uint16_t shift_amt = 64 - cpu_x86_virtual_addr_width(env);
52     *seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt);
53 }
54 
55 static inline void svm_load_seg(CPUX86State *env, hwaddr addr,
56                                 SegmentCache *sc)
57 {
58     CPUState *cs = env_cpu(env);
59     unsigned int flags;
60 
61     sc->selector = x86_lduw_phys(cs,
62                              addr + offsetof(struct vmcb_seg, selector));
63     sc->base = x86_ldq_phys(cs, addr + offsetof(struct vmcb_seg, base));
64     sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit));
65     flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib));
66     sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
67     svm_canonicalization(env, &sc->base);
68 }
69 
70 static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr,
71                                       int seg_reg)
72 {
73     SegmentCache sc1, *sc = &sc1;
74 
75     svm_load_seg(env, addr, sc);
76     cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
77                            sc->base, sc->limit, sc->flags);
78 }
79 
80 static inline bool is_efer_invalid_state (CPUX86State *env)
81 {
82     if (!(env->efer & MSR_EFER_SVME)) {
83         return true;
84     }
85 
86     if (env->efer & MSR_EFER_RESERVED) {
87         return true;
88     }
89 
90     if ((env->efer & (MSR_EFER_LMA | MSR_EFER_LME)) &&
91             !(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
92         return true;
93     }
94 
95     if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
96                                 && !(env->cr[4] & CR4_PAE_MASK)) {
97         return true;
98     }
99 
100     if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
101                                 && !(env->cr[0] & CR0_PE_MASK)) {
102         return true;
103     }
104 
105     if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
106                                 && (env->cr[4] & CR4_PAE_MASK)
107                                 && (env->segs[R_CS].flags & DESC_L_MASK)
108                                 && (env->segs[R_CS].flags & DESC_B_MASK)) {
109         return true;
110     }
111 
112     return false;
113 }
114 
115 static inline bool virtual_gif_enabled(CPUX86State *env)
116 {
117     if (likely(env->hflags & HF_GUEST_MASK)) {
118         return (env->features[FEAT_SVM] & CPUID_SVM_VGIF)
119                     && (env->int_ctl & V_GIF_ENABLED_MASK);
120     }
121     return false;
122 }
123 
124 static inline bool virtual_vm_load_save_enabled(CPUX86State *env, uint32_t exit_code, uintptr_t retaddr)
125 {
126     uint64_t lbr_ctl;
127 
128     if (likely(env->hflags & HF_GUEST_MASK)) {
129         if (likely(!(env->hflags2 & HF2_NPT_MASK)) || !(env->efer & MSR_EFER_LMA)) {
130             cpu_vmexit(env, exit_code, 0, retaddr);
131         }
132 
133         lbr_ctl = x86_ldl_phys(env_cpu(env), env->vm_vmcb + offsetof(struct vmcb,
134                                                   control.lbr_ctl));
135         return (env->features[FEAT_SVM] & CPUID_SVM_V_VMSAVE_VMLOAD)
136                 && (lbr_ctl & V_VMLOAD_VMSAVE_ENABLED_MASK);
137 
138     }
139 
140     return false;
141 }
142 
143 static inline bool virtual_gif_set(CPUX86State *env)
144 {
145     return !virtual_gif_enabled(env) || (env->int_ctl & V_GIF_MASK);
146 }
147 
148 void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
149 {
150     CPUState *cs = env_cpu(env);
151     X86CPU *cpu = env_archcpu(env);
152     target_ulong addr;
153     uint64_t nested_ctl;
154     uint32_t event_inj;
155     uint32_t asid;
156     uint64_t new_cr0;
157     uint64_t new_cr3;
158     uint64_t new_cr4;
159 
160     cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC());
161 
162     if (aflag == 2) {
163         addr = env->regs[R_EAX];
164     } else {
165         addr = (uint32_t)env->regs[R_EAX];
166     }
167 
168     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
169 
170     env->vm_vmcb = addr;
171 
172     /* save the current CPU state in the hsave page */
173     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.base),
174              env->gdt.base);
175     x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit),
176              env->gdt.limit);
177 
178     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.base),
179              env->idt.base);
180     x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.limit),
181              env->idt.limit);
182 
183     x86_stq_phys(cs,
184              env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
185     x86_stq_phys(cs,
186              env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
187     x86_stq_phys(cs,
188              env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
189     x86_stq_phys(cs,
190              env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
191     x86_stq_phys(cs,
192              env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
193     x86_stq_phys(cs,
194              env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
195 
196     x86_stq_phys(cs,
197              env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
198     x86_stq_phys(cs,
199              env->vm_hsave + offsetof(struct vmcb, save.rflags),
200              cpu_compute_eflags(env));
201 
202     svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.es),
203                  &env->segs[R_ES]);
204     svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
205                  &env->segs[R_CS]);
206     svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
207                  &env->segs[R_SS]);
208     svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
209                  &env->segs[R_DS]);
210 
211     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip),
212              env->eip + next_eip_addend);
213     x86_stq_phys(cs,
214              env->vm_hsave + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
215     x86_stq_phys(cs,
216              env->vm_hsave + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
217 
218     /* load the interception bitmaps so we do not need to access the
219        vmcb in svm mode */
220     env->intercept = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
221                                                       control.intercept));
222     env->intercept_cr_read = x86_lduw_phys(cs, env->vm_vmcb +
223                                        offsetof(struct vmcb,
224                                                 control.intercept_cr_read));
225     env->intercept_cr_write = x86_lduw_phys(cs, env->vm_vmcb +
226                                         offsetof(struct vmcb,
227                                                  control.intercept_cr_write));
228     env->intercept_dr_read = x86_lduw_phys(cs, env->vm_vmcb +
229                                        offsetof(struct vmcb,
230                                                 control.intercept_dr_read));
231     env->intercept_dr_write = x86_lduw_phys(cs, env->vm_vmcb +
232                                         offsetof(struct vmcb,
233                                                  control.intercept_dr_write));
234     env->intercept_exceptions = x86_ldl_phys(cs, env->vm_vmcb +
235                                          offsetof(struct vmcb,
236                                                   control.intercept_exceptions
237                                                   ));
238 
239     nested_ctl = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
240                                                           control.nested_ctl));
241     asid = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
242                                                           control.asid));
243 
244     uint64_t msrpm_base_pa = x86_ldq_phys(cs, env->vm_vmcb +
245                                     offsetof(struct vmcb,
246                                             control.msrpm_base_pa));
247     uint64_t iopm_base_pa = x86_ldq_phys(cs, env->vm_vmcb +
248                                  offsetof(struct vmcb, control.iopm_base_pa));
249 
250     if ((msrpm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_MSRPM_SIZE) {
251         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
252     }
253 
254     if ((iopm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_IOPM_SIZE) {
255         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
256     }
257 
258     env->nested_pg_mode = 0;
259 
260     if (!cpu_svm_has_intercept(env, SVM_EXIT_VMRUN)) {
261         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
262     }
263     if (asid == 0) {
264         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
265     }
266 
267     if (nested_ctl & SVM_NPT_ENABLED) {
268         env->nested_cr3 = x86_ldq_phys(cs,
269                                 env->vm_vmcb + offsetof(struct vmcb,
270                                                         control.nested_cr3));
271         env->hflags2 |= HF2_NPT_MASK;
272 
273         env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK;
274     }
275 
276     /* enable intercepts */
277     env->hflags |= HF_GUEST_MASK;
278 
279     env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb +
280                                offsetof(struct vmcb, control.tsc_offset));
281 
282     new_cr0 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr0));
283     if (new_cr0 & SVM_CR0_RESERVED_MASK) {
284         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
285     }
286     if ((new_cr0 & CR0_NW_MASK) && !(new_cr0 & CR0_CD_MASK)) {
287         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
288     }
289     new_cr3 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr3));
290     if ((env->efer & MSR_EFER_LMA) &&
291             (new_cr3 & ((~0ULL) << cpu->phys_bits))) {
292         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
293     }
294     new_cr4 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4));
295     if (new_cr4 & cr4_reserved_bits(env)) {
296         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
297     }
298     /* clear exit_info_2 so we behave like the real hardware */
299     x86_stq_phys(cs,
300              env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
301 
302     cpu_x86_update_cr0(env, new_cr0);
303     cpu_x86_update_cr4(env, new_cr4);
304     cpu_x86_update_cr3(env, new_cr3);
305     env->cr[2] = x86_ldq_phys(cs,
306                           env->vm_vmcb + offsetof(struct vmcb, save.cr2));
307     env->int_ctl = x86_ldl_phys(cs,
308                        env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
309     env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
310     if (env->int_ctl & V_INTR_MASKING_MASK) {
311         env->hflags2 |= HF2_VINTR_MASK;
312         if (env->eflags & IF_MASK) {
313             env->hflags2 |= HF2_HIF_MASK;
314         }
315     }
316 
317     cpu_load_efer(env,
318                   x86_ldq_phys(cs,
319                            env->vm_vmcb + offsetof(struct vmcb, save.efer)));
320     env->eflags = 0;
321     cpu_load_eflags(env, x86_ldq_phys(cs,
322                                   env->vm_vmcb + offsetof(struct vmcb,
323                                                           save.rflags)),
324                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
325 
326     svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
327                        R_ES);
328     svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
329                        R_CS);
330     svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
331                        R_SS);
332     svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
333                        R_DS);
334     svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.idtr),
335                        &env->idt);
336     svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.gdtr),
337                        &env->gdt);
338 
339     env->eip = x86_ldq_phys(cs,
340                         env->vm_vmcb + offsetof(struct vmcb, save.rip));
341 
342     env->regs[R_ESP] = x86_ldq_phys(cs,
343                                 env->vm_vmcb + offsetof(struct vmcb, save.rsp));
344     env->regs[R_EAX] = x86_ldq_phys(cs,
345                                 env->vm_vmcb + offsetof(struct vmcb, save.rax));
346     env->dr[7] = x86_ldq_phys(cs,
347                           env->vm_vmcb + offsetof(struct vmcb, save.dr7));
348     env->dr[6] = x86_ldq_phys(cs,
349                           env->vm_vmcb + offsetof(struct vmcb, save.dr6));
350 
351 #ifdef TARGET_X86_64
352     if (env->dr[6] & DR_RESERVED_MASK) {
353         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
354     }
355     if (env->dr[7] & DR_RESERVED_MASK) {
356         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
357     }
358 #endif
359 
360     if (is_efer_invalid_state(env)) {
361         cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
362     }
363 
364     switch (x86_ldub_phys(cs,
365                       env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
366     case TLB_CONTROL_DO_NOTHING:
367         break;
368     case TLB_CONTROL_FLUSH_ALL_ASID:
369         /* FIXME: this is not 100% correct but should work for now */
370         tlb_flush(cs);
371         break;
372     }
373 
374     env->hflags2 |= HF2_GIF_MASK;
375 
376     if (ctl_has_irq(env)) {
377         CPUState *cs = env_cpu(env);
378 
379         cs->interrupt_request |= CPU_INTERRUPT_VIRQ;
380     }
381 
382     if (virtual_gif_set(env)) {
383         env->hflags2 |= HF2_VGIF_MASK;
384     }
385 
386     /* maybe we need to inject an event */
387     event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
388                                                  control.event_inj));
389     if (event_inj & SVM_EVTINJ_VALID) {
390         uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
391         uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
392         uint32_t event_inj_err = x86_ldl_phys(cs, env->vm_vmcb +
393                                           offsetof(struct vmcb,
394                                                    control.event_inj_err));
395 
396         qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
397         /* FIXME: need to implement valid_err */
398         switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
399         case SVM_EVTINJ_TYPE_INTR:
400             cs->exception_index = vector;
401             env->error_code = event_inj_err;
402             env->exception_is_int = 0;
403             env->exception_next_eip = -1;
404             qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
405             /* XXX: is it always correct? */
406             do_interrupt_x86_hardirq(env, vector, 1);
407             break;
408         case SVM_EVTINJ_TYPE_NMI:
409             cs->exception_index = EXCP02_NMI;
410             env->error_code = event_inj_err;
411             env->exception_is_int = 0;
412             env->exception_next_eip = env->eip;
413             qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
414             cpu_loop_exit(cs);
415             break;
416         case SVM_EVTINJ_TYPE_EXEPT:
417             if (vector == EXCP02_NMI || vector >= 31)  {
418                 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
419             }
420             cs->exception_index = vector;
421             env->error_code = event_inj_err;
422             env->exception_is_int = 0;
423             env->exception_next_eip = -1;
424             qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
425             cpu_loop_exit(cs);
426             break;
427         case SVM_EVTINJ_TYPE_SOFT:
428             cs->exception_index = vector;
429             env->error_code = event_inj_err;
430             env->exception_is_int = 1;
431             env->exception_next_eip = env->eip;
432             qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
433             cpu_loop_exit(cs);
434             break;
435         default:
436             cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
437             break;
438         }
439         qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index,
440                       env->error_code);
441     }
442 }
443 
444 void helper_vmmcall(CPUX86State *env)
445 {
446     cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0, GETPC());
447     raise_exception(env, EXCP06_ILLOP);
448 }
449 
450 void helper_vmload(CPUX86State *env, int aflag)
451 {
452     CPUState *cs = env_cpu(env);
453     target_ulong addr;
454     int prot;
455 
456     cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC());
457 
458     if (aflag == 2) {
459         addr = env->regs[R_EAX];
460     } else {
461         addr = (uint32_t)env->regs[R_EAX];
462     }
463 
464     if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) {
465         addr = get_hphys(cs, addr, MMU_DATA_LOAD, &prot);
466     }
467 
468     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx
469                   "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
470                   addr, x86_ldq_phys(cs, addr + offsetof(struct vmcb,
471                                                           save.fs.base)),
472                   env->segs[R_FS].base);
473 
474     svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS);
475     svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS);
476     svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr);
477     svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
478 
479 #ifdef TARGET_X86_64
480     env->kernelgsbase = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
481                                                  save.kernel_gs_base));
482     env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar));
483     env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar));
484     env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask));
485     svm_canonicalization(env, &env->kernelgsbase);
486 #endif
487     env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star));
488     env->sysenter_cs = x86_ldq_phys(cs,
489                                 addr + offsetof(struct vmcb, save.sysenter_cs));
490     env->sysenter_esp = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
491                                                  save.sysenter_esp));
492     env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
493                                                  save.sysenter_eip));
494 
495 }
496 
497 void helper_vmsave(CPUX86State *env, int aflag)
498 {
499     CPUState *cs = env_cpu(env);
500     target_ulong addr;
501     int prot;
502 
503     cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC());
504 
505     if (aflag == 2) {
506         addr = env->regs[R_EAX];
507     } else {
508         addr = (uint32_t)env->regs[R_EAX];
509     }
510 
511     if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) {
512         addr = get_hphys(cs, addr, MMU_DATA_STORE, &prot);
513     }
514 
515     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx
516                   "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
517                   addr, x86_ldq_phys(cs,
518                                  addr + offsetof(struct vmcb, save.fs.base)),
519                   env->segs[R_FS].base);
520 
521     svm_save_seg(env, addr + offsetof(struct vmcb, save.fs),
522                  &env->segs[R_FS]);
523     svm_save_seg(env, addr + offsetof(struct vmcb, save.gs),
524                  &env->segs[R_GS]);
525     svm_save_seg(env, addr + offsetof(struct vmcb, save.tr),
526                  &env->tr);
527     svm_save_seg(env, addr + offsetof(struct vmcb, save.ldtr),
528                  &env->ldt);
529 
530 #ifdef TARGET_X86_64
531     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.kernel_gs_base),
532              env->kernelgsbase);
533     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.lstar), env->lstar);
534     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.cstar), env->cstar);
535     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sfmask), env->fmask);
536 #endif
537     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.star), env->star);
538     x86_stq_phys(cs,
539              addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
540     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_esp),
541              env->sysenter_esp);
542     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip),
543              env->sysenter_eip);
544 }
545 
546 void helper_stgi(CPUX86State *env)
547 {
548     cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC());
549 
550     if (virtual_gif_enabled(env)) {
551         env->int_ctl |= V_GIF_MASK;
552         env->hflags2 |= HF2_VGIF_MASK;
553     } else {
554         env->hflags2 |= HF2_GIF_MASK;
555     }
556 }
557 
558 void helper_clgi(CPUX86State *env)
559 {
560     cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC());
561 
562     if (virtual_gif_enabled(env)) {
563         env->int_ctl &= ~V_GIF_MASK;
564         env->hflags2 &= ~HF2_VGIF_MASK;
565     } else {
566         env->hflags2 &= ~HF2_GIF_MASK;
567     }
568 }
569 
570 bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type)
571 {
572     switch (type) {
573     case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
574         if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
575             return true;
576         }
577         break;
578     case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
579         if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
580             return true;
581         }
582         break;
583     case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
584         if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
585             return true;
586         }
587         break;
588     case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
589         if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
590             return true;
591         }
592         break;
593     case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
594         if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
595             return true;
596         }
597         break;
598     default:
599         if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
600             return true;
601         }
602         break;
603     }
604     return false;
605 }
606 
607 void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
608                                    uint64_t param, uintptr_t retaddr)
609 {
610     CPUState *cs = env_cpu(env);
611 
612     if (likely(!(env->hflags & HF_GUEST_MASK))) {
613         return;
614     }
615 
616     if (!cpu_svm_has_intercept(env, type)) {
617         return;
618     }
619 
620     if (type == SVM_EXIT_MSR) {
621         /* FIXME: this should be read in at vmrun (faster this way?) */
622         uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
623                                     offsetof(struct vmcb,
624                                             control.msrpm_base_pa));
625         uint32_t t0, t1;
626 
627         switch ((uint32_t)env->regs[R_ECX]) {
628         case 0 ... 0x1fff:
629             t0 = (env->regs[R_ECX] * 2) % 8;
630             t1 = (env->regs[R_ECX] * 2) / 8;
631             break;
632         case 0xc0000000 ... 0xc0001fff:
633             t0 = (8192 + env->regs[R_ECX] - 0xc0000000) * 2;
634             t1 = (t0 / 8);
635             t0 %= 8;
636             break;
637         case 0xc0010000 ... 0xc0011fff:
638             t0 = (16384 + env->regs[R_ECX] - 0xc0010000) * 2;
639             t1 = (t0 / 8);
640             t0 %= 8;
641             break;
642         default:
643             cpu_vmexit(env, type, param, retaddr);
644             t0 = 0;
645             t1 = 0;
646             break;
647         }
648         if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) {
649             cpu_vmexit(env, type, param, retaddr);
650         }
651         return;
652     }
653 
654     cpu_vmexit(env, type, param, retaddr);
655 }
656 
657 void helper_svm_check_intercept(CPUX86State *env, uint32_t type)
658 {
659     cpu_svm_check_intercept_param(env, type, 0, GETPC());
660 }
661 
662 void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
663                          uint32_t next_eip_addend)
664 {
665     CPUState *cs = env_cpu(env);
666 
667     if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
668         /* FIXME: this should be read in at vmrun (faster this way?) */
669         uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
670                                  offsetof(struct vmcb, control.iopm_base_pa));
671         uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
672 
673         if (x86_lduw_phys(cs, addr + port / 8) & (mask << (port & 7))) {
674             /* next env->eip */
675             x86_stq_phys(cs,
676                      env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
677                      env->eip + next_eip_addend);
678             cpu_vmexit(env, SVM_EXIT_IOIO, param | (port << 16), GETPC());
679         }
680     }
681 }
682 
683 void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
684                 uintptr_t retaddr)
685 {
686     CPUState *cs = env_cpu(env);
687 
688     cpu_restore_state(cs, retaddr, true);
689 
690     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
691                   PRIx64 ", " TARGET_FMT_lx ")!\n",
692                   exit_code, exit_info_1,
693                   x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
694                                                    control.exit_info_2)),
695                   env->eip);
696 
697     cs->exception_index = EXCP_VMEXIT;
698     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
699              exit_code);
700 
701     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
702                                              control.exit_info_1), exit_info_1),
703 
704     /* remove any pending exception */
705     env->old_exception = -1;
706     cpu_loop_exit(cs);
707 }
708 
709 void do_vmexit(CPUX86State *env)
710 {
711     CPUState *cs = env_cpu(env);
712 
713     if (env->hflags & HF_INHIBIT_IRQ_MASK) {
714         x86_stl_phys(cs,
715                  env->vm_vmcb + offsetof(struct vmcb, control.int_state),
716                  SVM_INTERRUPT_SHADOW_MASK);
717         env->hflags &= ~HF_INHIBIT_IRQ_MASK;
718     } else {
719         x86_stl_phys(cs,
720                  env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
721     }
722     env->hflags2 &= ~HF2_NPT_MASK;
723 
724     /* Save the VM state in the vmcb */
725     svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
726                  &env->segs[R_ES]);
727     svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
728                  &env->segs[R_CS]);
729     svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
730                  &env->segs[R_SS]);
731     svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
732                  &env->segs[R_DS]);
733 
734     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
735              env->gdt.base);
736     x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit),
737              env->gdt.limit);
738 
739     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.base),
740              env->idt.base);
741     x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit),
742              env->idt.limit);
743 
744     x86_stq_phys(cs,
745              env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
746     x86_stq_phys(cs,
747              env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
748     x86_stq_phys(cs,
749              env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
750     x86_stq_phys(cs,
751              env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
752     x86_stq_phys(cs,
753              env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
754     x86_stl_phys(cs,
755              env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), env->int_ctl);
756 
757     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rflags),
758              cpu_compute_eflags(env));
759     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip),
760              env->eip);
761     x86_stq_phys(cs,
762              env->vm_vmcb + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
763     x86_stq_phys(cs,
764              env->vm_vmcb + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
765     x86_stq_phys(cs,
766              env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
767     x86_stq_phys(cs,
768              env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
769     x86_stb_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cpl),
770              env->hflags & HF_CPL_MASK);
771 
772     /* Reload the host state from vm_hsave */
773     env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
774     env->hflags &= ~HF_GUEST_MASK;
775     env->intercept = 0;
776     env->intercept_exceptions = 0;
777     cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
778     env->int_ctl = 0;
779     env->tsc_offset = 0;
780 
781     env->gdt.base  = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
782                                                        save.gdtr.base));
783     env->gdt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
784                                                        save.gdtr.limit));
785 
786     env->idt.base  = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
787                                                        save.idtr.base));
788     env->idt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
789                                                        save.idtr.limit));
790 
791     cpu_x86_update_cr0(env, x86_ldq_phys(cs,
792                                      env->vm_hsave + offsetof(struct vmcb,
793                                                               save.cr0)) |
794                        CR0_PE_MASK);
795     cpu_x86_update_cr4(env, x86_ldq_phys(cs,
796                                      env->vm_hsave + offsetof(struct vmcb,
797                                                               save.cr4)));
798     cpu_x86_update_cr3(env, x86_ldq_phys(cs,
799                                      env->vm_hsave + offsetof(struct vmcb,
800                                                               save.cr3)));
801     /* we need to set the efer after the crs so the hidden flags get
802        set properly */
803     cpu_load_efer(env, x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
804                                                          save.efer)));
805     env->eflags = 0;
806     cpu_load_eflags(env, x86_ldq_phys(cs,
807                                   env->vm_hsave + offsetof(struct vmcb,
808                                                            save.rflags)),
809                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK |
810                       VM_MASK));
811 
812     svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es),
813                        R_ES);
814     svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
815                        R_CS);
816     svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
817                        R_SS);
818     svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
819                        R_DS);
820 
821     env->eip = x86_ldq_phys(cs,
822                         env->vm_hsave + offsetof(struct vmcb, save.rip));
823     env->regs[R_ESP] = x86_ldq_phys(cs, env->vm_hsave +
824                                 offsetof(struct vmcb, save.rsp));
825     env->regs[R_EAX] = x86_ldq_phys(cs, env->vm_hsave +
826                                 offsetof(struct vmcb, save.rax));
827 
828     env->dr[6] = x86_ldq_phys(cs,
829                           env->vm_hsave + offsetof(struct vmcb, save.dr6));
830     env->dr[7] = x86_ldq_phys(cs,
831                           env->vm_hsave + offsetof(struct vmcb, save.dr7));
832 
833     /* other setups */
834     x86_stl_phys(cs,
835              env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
836              x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
837                                               control.event_inj)));
838     x86_stl_phys(cs,
839              env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
840              x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
841                                               control.event_inj_err)));
842     x86_stl_phys(cs,
843              env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
844 
845     env->hflags2 &= ~HF2_GIF_MASK;
846     env->hflags2 &= ~HF2_VGIF_MASK;
847     /* FIXME: Resets the current ASID register to zero (host ASID). */
848 
849     /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
850 
851     /* Clears the TSC_OFFSET inside the processor. */
852 
853     /* If the host is in PAE mode, the processor reloads the host's PDPEs
854        from the page table indicated the host's CR3. If the PDPEs contain
855        illegal state, the processor causes a shutdown. */
856 
857     /* Disables all breakpoints in the host DR7 register. */
858 
859     /* Checks the reloaded host state for consistency. */
860 
861     /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
862        host's code segment or non-canonical (in the case of long mode), a
863        #GP fault is delivered inside the host. */
864 }
865