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