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