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