Home | History | Annotate | Download | only in target-i386
      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 "cpu.h"
     21 #include "exec/cpu-all.h"
     22 #include "helper.h"
     23 
     24 #if !defined(CONFIG_USER_ONLY)
     25 #include "exec/softmmu_exec.h"
     26 #endif /* !defined(CONFIG_USER_ONLY) */
     27 
     28 /* Secure Virtual Machine helpers */
     29 
     30 #if defined(CONFIG_USER_ONLY)
     31 
     32 void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
     33 {
     34 }
     35 void helper_vmmcall(CPUX86State *env)
     36 {
     37 }
     38 void helper_vmload(CPUX86State *env, int aflag)
     39 {
     40 }
     41 void helper_vmsave(CPUX86State *env, int aflag)
     42 {
     43 }
     44 void helper_stgi(CPUX86State *env)
     45 {
     46 }
     47 void helper_clgi(CPUX86State *env)
     48 {
     49 }
     50 void helper_skinit(CPUX86State *env)
     51 {
     52 }
     53 void helper_invlpga(CPUX86State *env, int aflag)
     54 {
     55 }
     56 void helper_vmexit(CPUX86State *env,
     57                    uint32_t exit_code, uint64_t exit_info_1)
     58 {
     59 }
     60 void helper_svm_check_intercept_param(CPUX86State *env,
     61                                       uint32_t type, uint64_t param)
     62 {
     63 }
     64 
     65 void svm_check_intercept(CPUX86State *env, uint32_t type)
     66 {
     67 }
     68 
     69 void helper_svm_check_io(CPUX86State* env,
     70                          uint32_t port, uint32_t param,
     71                          uint32_t next_eip_addend)
     72 {
     73 }
     74 #else
     75 
     76 static inline void svm_save_seg(hwaddr addr,
     77                                 const SegmentCache *sc)
     78 {
     79     stw_phys(addr + offsetof(struct vmcb_seg, selector),
     80              sc->selector);
     81     stq_phys(addr + offsetof(struct vmcb_seg, base),
     82              sc->base);
     83     stl_phys(addr + offsetof(struct vmcb_seg, limit),
     84              sc->limit);
     85     stw_phys(addr + offsetof(struct vmcb_seg, attrib),
     86              ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
     87 }
     88 
     89 static inline void svm_load_seg(hwaddr addr, SegmentCache *sc)
     90 {
     91     unsigned int flags;
     92 
     93     sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
     94     sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
     95     sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
     96     flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
     97     sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
     98 }
     99 
    100 static inline void svm_load_seg_cache(hwaddr addr,
    101                                       CPUX86State *env, int seg_reg)
    102 {
    103     SegmentCache sc1, *sc = &sc1;
    104     svm_load_seg(addr, sc);
    105     cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
    106                            sc->base, sc->limit, sc->flags);
    107 }
    108 
    109 void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
    110 {
    111     target_ulong addr;
    112     uint32_t event_inj;
    113     uint32_t int_ctl;
    114 
    115     helper_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0);
    116 
    117     if (aflag == 2)
    118         addr = EAX;
    119     else
    120         addr = (uint32_t)EAX;
    121 
    122     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
    123 
    124     env->vm_vmcb = addr;
    125 
    126     /* save the current CPU state in the hsave page */
    127     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
    128     stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
    129 
    130     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
    131     stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
    132 
    133     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
    134     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
    135     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
    136     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
    137     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
    138     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
    139 
    140     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
    141     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), cpu_compute_eflags(env));
    142 
    143     svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es),
    144                   &env->segs[R_ES]);
    145     svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs),
    146                  &env->segs[R_CS]);
    147     svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss),
    148                  &env->segs[R_SS]);
    149     svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds),
    150                  &env->segs[R_DS]);
    151 
    152     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
    153              EIP + next_eip_addend);
    154     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
    155     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
    156 
    157     /* load the interception bitmaps so we do not need to access the
    158        vmcb in svm mode */
    159     env->intercept            = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept));
    160     env->intercept_cr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
    161     env->intercept_cr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
    162     env->intercept_dr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
    163     env->intercept_dr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
    164     env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
    165 
    166     /* enable intercepts */
    167     env->hflags |= HF_SVMI_MASK;
    168 
    169     env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
    170 
    171     env->gdt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
    172     env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
    173 
    174     env->idt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
    175     env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
    176 
    177     /* clear exit_info_2 so we behave like the real hardware */
    178     stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
    179 
    180     cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
    181     cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
    182     cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
    183     env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
    184     int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
    185     env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
    186     if (int_ctl & V_INTR_MASKING_MASK) {
    187         env->v_tpr = int_ctl & V_TPR_MASK;
    188         env->hflags2 |= HF2_VINTR_MASK;
    189         if (env->eflags & IF_MASK)
    190             env->hflags2 |= HF2_HIF_MASK;
    191     }
    192 
    193     cpu_load_efer(env,
    194                   ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
    195     env->eflags = 0;
    196     cpu_load_eflags(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
    197                 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
    198     CC_OP = CC_OP_EFLAGS;
    199 
    200     svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
    201                        env, R_ES);
    202     svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
    203                        env, R_CS);
    204     svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
    205                        env, R_SS);
    206     svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
    207                        env, R_DS);
    208 
    209     EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
    210     env->eip = EIP;
    211     ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
    212     EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
    213     env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
    214     env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
    215     cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
    216 
    217     /* FIXME: guest state consistency checks */
    218 
    219     switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
    220         case TLB_CONTROL_DO_NOTHING:
    221             break;
    222         case TLB_CONTROL_FLUSH_ALL_ASID:
    223             /* FIXME: this is not 100% correct but should work for now */
    224             tlb_flush(env, 1);
    225         break;
    226     }
    227 
    228     env->hflags2 |= HF2_GIF_MASK;
    229 
    230     if (int_ctl & V_IRQ_MASK) {
    231         ENV_GET_CPU(env)->interrupt_request |= CPU_INTERRUPT_VIRQ;
    232     }
    233 
    234     /* maybe we need to inject an event */
    235     event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
    236     if (event_inj & SVM_EVTINJ_VALID) {
    237         uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
    238         uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
    239         uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
    240 
    241         qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
    242         /* FIXME: need to implement valid_err */
    243         switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
    244         case SVM_EVTINJ_TYPE_INTR:
    245                 env->exception_index = vector;
    246                 env->error_code = event_inj_err;
    247                 env->exception_is_int = 0;
    248                 env->exception_next_eip = -1;
    249                 qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
    250                 /* XXX: is it always correct ? */
    251                 do_interrupt_x86_hardirq(env, vector, 1);
    252                 break;
    253         case SVM_EVTINJ_TYPE_NMI:
    254                 env->exception_index = EXCP02_NMI;
    255                 env->error_code = event_inj_err;
    256                 env->exception_is_int = 0;
    257                 env->exception_next_eip = EIP;
    258                 qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
    259                 cpu_loop_exit(env);
    260                 break;
    261         case SVM_EVTINJ_TYPE_EXEPT:
    262                 env->exception_index = vector;
    263                 env->error_code = event_inj_err;
    264                 env->exception_is_int = 0;
    265                 env->exception_next_eip = -1;
    266                 qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
    267                 cpu_loop_exit(env);
    268                 break;
    269         case SVM_EVTINJ_TYPE_SOFT:
    270                 env->exception_index = vector;
    271                 env->error_code = event_inj_err;
    272                 env->exception_is_int = 1;
    273                 env->exception_next_eip = EIP;
    274                 qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
    275                 cpu_loop_exit(env);
    276                 break;
    277         }
    278         qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code);
    279     }
    280 }
    281 
    282 void helper_vmmcall(CPUX86State *env)
    283 {
    284     helper_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0);
    285     raise_exception(env, EXCP06_ILLOP);
    286 }
    287 
    288 void helper_vmload(CPUX86State *env, int aflag)
    289 {
    290     target_ulong addr;
    291     helper_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0);
    292 
    293     if (aflag == 2)
    294         addr = EAX;
    295     else
    296         addr = (uint32_t)EAX;
    297 
    298     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
    299                 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
    300                 env->segs[R_FS].base);
    301 
    302     svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
    303                        env, R_FS);
    304     svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
    305                        env, R_GS);
    306     svm_load_seg(addr + offsetof(struct vmcb, save.tr),
    307                  &env->tr);
    308     svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
    309                  &env->ldt);
    310 
    311 #ifdef TARGET_X86_64
    312     env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
    313     env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
    314     env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
    315     env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
    316 #endif
    317     env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
    318     env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
    319     env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
    320     env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
    321 }
    322 
    323 void helper_vmsave(CPUX86State *env, int aflag)
    324 {
    325     target_ulong addr;
    326     helper_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0);
    327 
    328     if (aflag == 2)
    329         addr = EAX;
    330     else
    331         addr = (uint32_t)EAX;
    332 
    333     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
    334                 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
    335                 env->segs[R_FS].base);
    336 
    337     svm_save_seg(addr + offsetof(struct vmcb, save.fs),
    338                  &env->segs[R_FS]);
    339     svm_save_seg(addr + offsetof(struct vmcb, save.gs),
    340                  &env->segs[R_GS]);
    341     svm_save_seg(addr + offsetof(struct vmcb, save.tr),
    342                  &env->tr);
    343     svm_save_seg(addr + offsetof(struct vmcb, save.ldtr),
    344                  &env->ldt);
    345 
    346 #ifdef TARGET_X86_64
    347     stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
    348     stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
    349     stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
    350     stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
    351 #endif
    352     stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
    353     stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
    354     stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
    355     stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
    356 }
    357 
    358 void helper_stgi(CPUX86State *env)
    359 {
    360     helper_svm_check_intercept_param(env, SVM_EXIT_STGI, 0);
    361     env->hflags2 |= HF2_GIF_MASK;
    362 }
    363 
    364 void helper_clgi(CPUX86State *env)
    365 {
    366     helper_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0);
    367     env->hflags2 &= ~HF2_GIF_MASK;
    368 }
    369 
    370 void helper_skinit(CPUX86State *env)
    371 {
    372     helper_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0);
    373     /* XXX: not implemented */
    374     raise_exception(env, EXCP06_ILLOP);
    375 }
    376 
    377 void helper_invlpga(CPUX86State *env, int aflag)
    378 {
    379     target_ulong addr;
    380     helper_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0);
    381 
    382     if (aflag == 2)
    383         addr = EAX;
    384     else
    385         addr = (uint32_t)EAX;
    386 
    387     /* XXX: could use the ASID to see if it is needed to do the
    388        flush */
    389     tlb_flush_page(env, addr);
    390 }
    391 
    392 void helper_svm_check_intercept_param(CPUX86State *env,
    393                                       uint32_t type, uint64_t param)
    394 {
    395     if (likely(!(env->hflags & HF_SVMI_MASK)))
    396         return;
    397     switch(type) {
    398     case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
    399         if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
    400             helper_vmexit(env, type, param);
    401         }
    402         break;
    403     case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
    404         if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
    405             helper_vmexit(env, type, param);
    406         }
    407         break;
    408     case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
    409         if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
    410             helper_vmexit(env, type, param);
    411         }
    412         break;
    413     case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
    414         if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
    415             helper_vmexit(env, type, param);
    416         }
    417         break;
    418     case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
    419         if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
    420             helper_vmexit(env, type, param);
    421         }
    422         break;
    423     case SVM_EXIT_MSR:
    424         if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
    425             /* FIXME: this should be read in at vmrun (faster this way?) */
    426             uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
    427             uint32_t t0, t1;
    428             switch((uint32_t)ECX) {
    429             case 0 ... 0x1fff:
    430                 t0 = (ECX * 2) % 8;
    431                 t1 = ECX / 8;
    432                 break;
    433             case 0xc0000000 ... 0xc0001fff:
    434                 t0 = (8192 + ECX - 0xc0000000) * 2;
    435                 t1 = (t0 / 8);
    436                 t0 %= 8;
    437                 break;
    438             case 0xc0010000 ... 0xc0011fff:
    439                 t0 = (16384 + ECX - 0xc0010000) * 2;
    440                 t1 = (t0 / 8);
    441                 t0 %= 8;
    442                 break;
    443             default:
    444                 helper_vmexit(env, type, param);
    445                 t0 = 0;
    446                 t1 = 0;
    447                 break;
    448             }
    449             if (ldub_phys(addr + t1) & ((1 << param) << t0))
    450                 helper_vmexit(env, type, param);
    451         }
    452         break;
    453     default:
    454         if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
    455             helper_vmexit(env, type, param);
    456         }
    457         break;
    458     }
    459 }
    460 
    461 void svm_check_intercept(CPUArchState *env, uint32_t type)
    462 {
    463     helper_svm_check_intercept_param(env, type, 0);
    464 }
    465 
    466 void helper_svm_check_io(CPUX86State *env,
    467                          uint32_t port, uint32_t param,
    468                          uint32_t next_eip_addend)
    469 {
    470     if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
    471         /* FIXME: this should be read in at vmrun (faster this way?) */
    472         uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
    473         uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
    474         if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
    475             /* next EIP */
    476             stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
    477                      env->eip + next_eip_addend);
    478             helper_vmexit(env, SVM_EXIT_IOIO, param | (port << 16));
    479         }
    480     }
    481 }
    482 
    483 /* Note: currently only 32 bits of exit_code are used */
    484 void helper_vmexit(CPUX86State *env,
    485                    uint32_t exit_code, uint64_t exit_info_1)
    486 {
    487     uint32_t int_ctl;
    488 
    489     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
    490                 exit_code, exit_info_1,
    491                 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
    492                 EIP);
    493 
    494     if(env->hflags & HF_INHIBIT_IRQ_MASK) {
    495         stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
    496         env->hflags &= ~HF_INHIBIT_IRQ_MASK;
    497     } else {
    498         stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
    499     }
    500 
    501     /* Save the VM state in the vmcb */
    502     svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es),
    503                  &env->segs[R_ES]);
    504     svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs),
    505                  &env->segs[R_CS]);
    506     svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss),
    507                  &env->segs[R_SS]);
    508     svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds),
    509                  &env->segs[R_DS]);
    510 
    511     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
    512     stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
    513 
    514     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
    515     stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
    516 
    517     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
    518     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
    519     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
    520     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
    521     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
    522 
    523     int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
    524     int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
    525     int_ctl |= env->v_tpr & V_TPR_MASK;
    526     if (ENV_GET_CPU(env)->interrupt_request & CPU_INTERRUPT_VIRQ)
    527         int_ctl |= V_IRQ_MASK;
    528     stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
    529 
    530     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), cpu_compute_eflags(env));
    531     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
    532     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
    533     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
    534     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
    535     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
    536     stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
    537 
    538     /* Reload the host state from vm_hsave */
    539     env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
    540     env->hflags &= ~HF_SVMI_MASK;
    541     env->intercept = 0;
    542     env->intercept_exceptions = 0;
    543     ENV_GET_CPU(env)->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
    544     env->tsc_offset = 0;
    545 
    546     env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
    547     env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
    548 
    549     env->idt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
    550     env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
    551 
    552     cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
    553     cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
    554     cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
    555     /* we need to set the efer after the crs so the hidden flags get
    556        set properly */
    557     cpu_load_efer(env,
    558                   ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
    559     env->eflags = 0;
    560     cpu_load_eflags(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
    561                 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
    562     CC_OP = CC_OP_EFLAGS;
    563 
    564     svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
    565                        env, R_ES);
    566     svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
    567                        env, R_CS);
    568     svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
    569                        env, R_SS);
    570     svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
    571                        env, R_DS);
    572 
    573     EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
    574     ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
    575     EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
    576 
    577     env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
    578     env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
    579 
    580     /* other setups */
    581     cpu_x86_set_cpl(env, 0);
    582     stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
    583     stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
    584 
    585     stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
    586              ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)));
    587     stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
    588              ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)));
    589 
    590     env->hflags2 &= ~HF2_GIF_MASK;
    591     /* FIXME: Resets the current ASID register to zero (host ASID). */
    592 
    593     /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
    594 
    595     /* Clears the TSC_OFFSET inside the processor. */
    596 
    597     /* If the host is in PAE mode, the processor reloads the host's PDPEs
    598        from the page table indicated the host's CR3. If the PDPEs contain
    599        illegal state, the processor causes a shutdown. */
    600 
    601     /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
    602     env->cr[0] |= CR0_PE_MASK;
    603     env->eflags &= ~VM_MASK;
    604 
    605     /* Disables all breakpoints in the host DR7 register. */
    606 
    607     /* Checks the reloaded host state for consistency. */
    608 
    609     /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
    610        host's code segment or non-canonical (in the case of long mode), a
    611        #GP fault is delivered inside the host.) */
    612 
    613     /* remove any pending exception */
    614     env->exception_index = -1;
    615     env->error_code = 0;
    616     env->old_exception = -1;
    617 
    618     cpu_loop_exit(env);
    619 }
    620 
    621 #endif
    622