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