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