qemu/target/i386/hvf/hvf.c
<<
>>
Prefs
   1/* Copyright 2008 IBM Corporation
   2 *           2008 Red Hat, Inc.
   3 * Copyright 2011 Intel Corporation
   4 * Copyright 2016 Veertu, Inc.
   5 * Copyright 2017 The Android Open Source Project
   6 *
   7 * QEMU Hypervisor.framework support
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of version 2 of the GNU General Public
  11 * License as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 * General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  20 *
  21 * This file contain code under public domain from the hvdos project:
  22 * https://github.com/mist64/hvdos
  23 *
  24 * Parts Copyright (c) 2011 NetApp, Inc.
  25 * All rights reserved.
  26 *
  27 * Redistribution and use in source and binary forms, with or without
  28 * modification, are permitted provided that the following conditions
  29 * are met:
  30 * 1. Redistributions of source code must retain the above copyright
  31 *    notice, this list of conditions and the following disclaimer.
  32 * 2. Redistributions in binary form must reproduce the above copyright
  33 *    notice, this list of conditions and the following disclaimer in the
  34 *    documentation and/or other materials provided with the distribution.
  35 *
  36 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
  37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  39 * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
  40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  42 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46 * SUCH DAMAGE.
  47 */
  48
  49#include "qemu/osdep.h"
  50#include "qemu/error-report.h"
  51#include "qemu/memalign.h"
  52
  53#include "sysemu/hvf.h"
  54#include "sysemu/hvf_int.h"
  55#include "sysemu/runstate.h"
  56#include "sysemu/cpus.h"
  57#include "hvf-i386.h"
  58#include "vmcs.h"
  59#include "vmx.h"
  60#include "x86.h"
  61#include "x86_descr.h"
  62#include "x86_mmu.h"
  63#include "x86_decode.h"
  64#include "x86_emu.h"
  65#include "x86_task.h"
  66#include "x86hvf.h"
  67
  68#include <Hypervisor/hv.h>
  69#include <Hypervisor/hv_vmx.h>
  70#include <sys/sysctl.h>
  71
  72#include "hw/i386/apic_internal.h"
  73#include "qemu/main-loop.h"
  74#include "qemu/accel.h"
  75#include "target/i386/cpu.h"
  76
  77void vmx_update_tpr(CPUState *cpu)
  78{
  79    /* TODO: need integrate APIC handling */
  80    X86CPU *x86_cpu = X86_CPU(cpu);
  81    int tpr = cpu_get_apic_tpr(x86_cpu->apic_state) << 4;
  82    int irr = apic_get_highest_priority_irr(x86_cpu->apic_state);
  83
  84    wreg(cpu->hvf->fd, HV_X86_TPR, tpr);
  85    if (irr == -1) {
  86        wvmcs(cpu->hvf->fd, VMCS_TPR_THRESHOLD, 0);
  87    } else {
  88        wvmcs(cpu->hvf->fd, VMCS_TPR_THRESHOLD, (irr > tpr) ? tpr >> 4 :
  89              irr >> 4);
  90    }
  91}
  92
  93static void update_apic_tpr(CPUState *cpu)
  94{
  95    X86CPU *x86_cpu = X86_CPU(cpu);
  96    int tpr = rreg(cpu->hvf->fd, HV_X86_TPR) >> 4;
  97    cpu_set_apic_tpr(x86_cpu->apic_state, tpr);
  98}
  99
 100#define VECTORING_INFO_VECTOR_MASK     0xff
 101
 102void hvf_handle_io(CPUArchState *env, uint16_t port, void *buffer,
 103                  int direction, int size, int count)
 104{
 105    int i;
 106    uint8_t *ptr = buffer;
 107
 108    for (i = 0; i < count; i++) {
 109        address_space_rw(&address_space_io, port, MEMTXATTRS_UNSPECIFIED,
 110                         ptr, size,
 111                         direction);
 112        ptr += size;
 113    }
 114}
 115
 116static bool ept_emulation_fault(hvf_slot *slot, uint64_t gpa, uint64_t ept_qual)
 117{
 118    int read, write;
 119
 120    /* EPT fault on an instruction fetch doesn't make sense here */
 121    if (ept_qual & EPT_VIOLATION_INST_FETCH) {
 122        return false;
 123    }
 124
 125    /* EPT fault must be a read fault or a write fault */
 126    read = ept_qual & EPT_VIOLATION_DATA_READ ? 1 : 0;
 127    write = ept_qual & EPT_VIOLATION_DATA_WRITE ? 1 : 0;
 128    if ((read | write) == 0) {
 129        return false;
 130    }
 131
 132    if (write && slot) {
 133        if (slot->flags & HVF_SLOT_LOG) {
 134            memory_region_set_dirty(slot->region, gpa - slot->start, 1);
 135            hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size,
 136                          HV_MEMORY_READ | HV_MEMORY_WRITE);
 137        }
 138    }
 139
 140    /*
 141     * The EPT violation must have been caused by accessing a
 142     * guest-physical address that is a translation of a guest-linear
 143     * address.
 144     */
 145    if ((ept_qual & EPT_VIOLATION_GLA_VALID) == 0 ||
 146        (ept_qual & EPT_VIOLATION_XLAT_VALID) == 0) {
 147        return false;
 148    }
 149
 150    if (!slot) {
 151        return true;
 152    }
 153    if (!memory_region_is_ram(slot->region) &&
 154        !(read && memory_region_is_romd(slot->region))) {
 155        return true;
 156    }
 157    return false;
 158}
 159
 160void hvf_arch_vcpu_destroy(CPUState *cpu)
 161{
 162    X86CPU *x86_cpu = X86_CPU(cpu);
 163    CPUX86State *env = &x86_cpu->env;
 164
 165    g_free(env->hvf_mmio_buf);
 166}
 167
 168static void init_tsc_freq(CPUX86State *env)
 169{
 170    size_t length;
 171    uint64_t tsc_freq;
 172
 173    if (env->tsc_khz != 0) {
 174        return;
 175    }
 176
 177    length = sizeof(uint64_t);
 178    if (sysctlbyname("machdep.tsc.frequency", &tsc_freq, &length, NULL, 0)) {
 179        return;
 180    }
 181    env->tsc_khz = tsc_freq / 1000;  /* Hz to KHz */
 182}
 183
 184static void init_apic_bus_freq(CPUX86State *env)
 185{
 186    size_t length;
 187    uint64_t bus_freq;
 188
 189    if (env->apic_bus_freq != 0) {
 190        return;
 191    }
 192
 193    length = sizeof(uint64_t);
 194    if (sysctlbyname("hw.busfrequency", &bus_freq, &length, NULL, 0)) {
 195        return;
 196    }
 197    env->apic_bus_freq = bus_freq;
 198}
 199
 200static inline bool tsc_is_known(CPUX86State *env)
 201{
 202    return env->tsc_khz != 0;
 203}
 204
 205static inline bool apic_bus_freq_is_known(CPUX86State *env)
 206{
 207    return env->apic_bus_freq != 0;
 208}
 209
 210void hvf_kick_vcpu_thread(CPUState *cpu)
 211{
 212    cpus_kick_thread(cpu);
 213}
 214
 215int hvf_arch_init(void)
 216{
 217    return 0;
 218}
 219
 220int hvf_arch_init_vcpu(CPUState *cpu)
 221{
 222    X86CPU *x86cpu = X86_CPU(cpu);
 223    CPUX86State *env = &x86cpu->env;
 224    uint64_t reqCap;
 225
 226    init_emu();
 227    init_decoder();
 228
 229    hvf_state->hvf_caps = g_new0(struct hvf_vcpu_caps, 1);
 230    env->hvf_mmio_buf = g_new(char, 4096);
 231
 232    if (x86cpu->vmware_cpuid_freq) {
 233        init_tsc_freq(env);
 234        init_apic_bus_freq(env);
 235
 236        if (!tsc_is_known(env) || !apic_bus_freq_is_known(env)) {
 237            error_report("vmware-cpuid-freq: feature couldn't be enabled");
 238        }
 239    }
 240
 241    if (hv_vmx_read_capability(HV_VMX_CAP_PINBASED,
 242        &hvf_state->hvf_caps->vmx_cap_pinbased)) {
 243        abort();
 244    }
 245    if (hv_vmx_read_capability(HV_VMX_CAP_PROCBASED,
 246        &hvf_state->hvf_caps->vmx_cap_procbased)) {
 247        abort();
 248    }
 249    if (hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2,
 250        &hvf_state->hvf_caps->vmx_cap_procbased2)) {
 251        abort();
 252    }
 253    if (hv_vmx_read_capability(HV_VMX_CAP_ENTRY,
 254        &hvf_state->hvf_caps->vmx_cap_entry)) {
 255        abort();
 256    }
 257
 258    /* set VMCS control fields */
 259    wvmcs(cpu->hvf->fd, VMCS_PIN_BASED_CTLS,
 260          cap2ctrl(hvf_state->hvf_caps->vmx_cap_pinbased,
 261                   VMCS_PIN_BASED_CTLS_EXTINT |
 262                   VMCS_PIN_BASED_CTLS_NMI |
 263                   VMCS_PIN_BASED_CTLS_VNMI));
 264    wvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS,
 265          cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased,
 266                   VMCS_PRI_PROC_BASED_CTLS_HLT |
 267                   VMCS_PRI_PROC_BASED_CTLS_MWAIT |
 268                   VMCS_PRI_PROC_BASED_CTLS_TSC_OFFSET |
 269                   VMCS_PRI_PROC_BASED_CTLS_TPR_SHADOW) |
 270          VMCS_PRI_PROC_BASED_CTLS_SEC_CONTROL);
 271
 272    reqCap = VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES;
 273
 274    /* Is RDTSCP support in CPUID?  If so, enable it in the VMCS. */
 275    if (hvf_get_supported_cpuid(0x80000001, 0, R_EDX) & CPUID_EXT2_RDTSCP) {
 276        reqCap |= VMCS_PRI_PROC_BASED2_CTLS_RDTSCP;
 277    }
 278
 279    wvmcs(cpu->hvf->fd, VMCS_SEC_PROC_BASED_CTLS,
 280          cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased2, reqCap));
 281
 282    wvmcs(cpu->hvf->fd, VMCS_ENTRY_CTLS, cap2ctrl(hvf_state->hvf_caps->vmx_cap_entry,
 283          0));
 284    wvmcs(cpu->hvf->fd, VMCS_EXCEPTION_BITMAP, 0); /* Double fault */
 285
 286    wvmcs(cpu->hvf->fd, VMCS_TPR_THRESHOLD, 0);
 287
 288    x86cpu = X86_CPU(cpu);
 289    x86cpu->env.xsave_buf_len = 4096;
 290    x86cpu->env.xsave_buf = qemu_memalign(4096, x86cpu->env.xsave_buf_len);
 291
 292    /*
 293     * The allocated storage must be large enough for all of the
 294     * possible XSAVE state components.
 295     */
 296    assert(hvf_get_supported_cpuid(0xd, 0, R_ECX) <= x86cpu->env.xsave_buf_len);
 297
 298    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_STAR, 1);
 299    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_LSTAR, 1);
 300    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_CSTAR, 1);
 301    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_FMASK, 1);
 302    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_FSBASE, 1);
 303    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_GSBASE, 1);
 304    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_KERNELGSBASE, 1);
 305    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_TSC_AUX, 1);
 306    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_IA32_TSC, 1);
 307    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_IA32_SYSENTER_CS, 1);
 308    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_IA32_SYSENTER_EIP, 1);
 309    hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_IA32_SYSENTER_ESP, 1);
 310
 311    return 0;
 312}
 313
 314static void hvf_store_events(CPUState *cpu, uint32_t ins_len, uint64_t idtvec_info)
 315{
 316    X86CPU *x86_cpu = X86_CPU(cpu);
 317    CPUX86State *env = &x86_cpu->env;
 318
 319    env->exception_nr = -1;
 320    env->exception_pending = 0;
 321    env->exception_injected = 0;
 322    env->interrupt_injected = -1;
 323    env->nmi_injected = false;
 324    env->ins_len = 0;
 325    env->has_error_code = false;
 326    if (idtvec_info & VMCS_IDT_VEC_VALID) {
 327        switch (idtvec_info & VMCS_IDT_VEC_TYPE) {
 328        case VMCS_IDT_VEC_HWINTR:
 329        case VMCS_IDT_VEC_SWINTR:
 330            env->interrupt_injected = idtvec_info & VMCS_IDT_VEC_VECNUM;
 331            break;
 332        case VMCS_IDT_VEC_NMI:
 333            env->nmi_injected = true;
 334            break;
 335        case VMCS_IDT_VEC_HWEXCEPTION:
 336        case VMCS_IDT_VEC_SWEXCEPTION:
 337            env->exception_nr = idtvec_info & VMCS_IDT_VEC_VECNUM;
 338            env->exception_injected = 1;
 339            break;
 340        case VMCS_IDT_VEC_PRIV_SWEXCEPTION:
 341        default:
 342            abort();
 343        }
 344        if ((idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWEXCEPTION ||
 345            (idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWINTR) {
 346            env->ins_len = ins_len;
 347        }
 348        if (idtvec_info & VMCS_IDT_VEC_ERRCODE_VALID) {
 349            env->has_error_code = true;
 350            env->error_code = rvmcs(cpu->hvf->fd, VMCS_IDT_VECTORING_ERROR);
 351        }
 352    }
 353    if ((rvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY) &
 354        VMCS_INTERRUPTIBILITY_NMI_BLOCKING)) {
 355        env->hflags2 |= HF2_NMI_MASK;
 356    } else {
 357        env->hflags2 &= ~HF2_NMI_MASK;
 358    }
 359    if (rvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY) &
 360         (VMCS_INTERRUPTIBILITY_STI_BLOCKING |
 361         VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)) {
 362        env->hflags |= HF_INHIBIT_IRQ_MASK;
 363    } else {
 364        env->hflags &= ~HF_INHIBIT_IRQ_MASK;
 365    }
 366}
 367
 368static void hvf_cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
 369                              uint32_t *eax, uint32_t *ebx,
 370                              uint32_t *ecx, uint32_t *edx)
 371{
 372    /*
 373     * A wrapper extends cpu_x86_cpuid with 0x40000000 and 0x40000010 leafs,
 374     * leafs 0x40000001-0x4000000F are filled with zeros
 375     * Provides vmware-cpuid-freq support to hvf
 376     *
 377     * Note: leaf 0x40000000 not exposes HVF,
 378     * leaving hypervisor signature empty
 379     */
 380
 381    if (index < 0x40000000 || index > 0x40000010 ||
 382        !tsc_is_known(env) || !apic_bus_freq_is_known(env)) {
 383
 384        cpu_x86_cpuid(env, index, count, eax, ebx, ecx, edx);
 385        return;
 386    }
 387
 388    switch (index) {
 389    case 0x40000000:
 390        *eax = 0x40000010;    /* Max available cpuid leaf */
 391        *ebx = 0;             /* Leave signature empty */
 392        *ecx = 0;
 393        *edx = 0;
 394        break;
 395    case 0x40000010:
 396        *eax = env->tsc_khz;
 397        *ebx = env->apic_bus_freq / 1000; /* Hz to KHz */
 398        *ecx = 0;
 399        *edx = 0;
 400        break;
 401    default:
 402        *eax = 0;
 403        *ebx = 0;
 404        *ecx = 0;
 405        *edx = 0;
 406        break;
 407    }
 408}
 409
 410int hvf_vcpu_exec(CPUState *cpu)
 411{
 412    X86CPU *x86_cpu = X86_CPU(cpu);
 413    CPUX86State *env = &x86_cpu->env;
 414    int ret = 0;
 415    uint64_t rip = 0;
 416
 417    if (hvf_process_events(cpu)) {
 418        return EXCP_HLT;
 419    }
 420
 421    do {
 422        if (cpu->vcpu_dirty) {
 423            hvf_put_registers(cpu);
 424            cpu->vcpu_dirty = false;
 425        }
 426
 427        if (hvf_inject_interrupts(cpu)) {
 428            return EXCP_INTERRUPT;
 429        }
 430        vmx_update_tpr(cpu);
 431
 432        qemu_mutex_unlock_iothread();
 433        if (!cpu_is_bsp(X86_CPU(cpu)) && cpu->halted) {
 434            qemu_mutex_lock_iothread();
 435            return EXCP_HLT;
 436        }
 437
 438        hv_return_t r  = hv_vcpu_run(cpu->hvf->fd);
 439        assert_hvf_ok(r);
 440
 441        /* handle VMEXIT */
 442        uint64_t exit_reason = rvmcs(cpu->hvf->fd, VMCS_EXIT_REASON);
 443        uint64_t exit_qual = rvmcs(cpu->hvf->fd, VMCS_EXIT_QUALIFICATION);
 444        uint32_t ins_len = (uint32_t)rvmcs(cpu->hvf->fd,
 445                                           VMCS_EXIT_INSTRUCTION_LENGTH);
 446
 447        uint64_t idtvec_info = rvmcs(cpu->hvf->fd, VMCS_IDT_VECTORING_INFO);
 448
 449        hvf_store_events(cpu, ins_len, idtvec_info);
 450        rip = rreg(cpu->hvf->fd, HV_X86_RIP);
 451        env->eflags = rreg(cpu->hvf->fd, HV_X86_RFLAGS);
 452
 453        qemu_mutex_lock_iothread();
 454
 455        update_apic_tpr(cpu);
 456        current_cpu = cpu;
 457
 458        ret = 0;
 459        switch (exit_reason) {
 460        case EXIT_REASON_HLT: {
 461            macvm_set_rip(cpu, rip + ins_len);
 462            if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
 463                (env->eflags & IF_MASK))
 464                && !(cpu->interrupt_request & CPU_INTERRUPT_NMI) &&
 465                !(idtvec_info & VMCS_IDT_VEC_VALID)) {
 466                cpu->halted = 1;
 467                ret = EXCP_HLT;
 468                break;
 469            }
 470            ret = EXCP_INTERRUPT;
 471            break;
 472        }
 473        case EXIT_REASON_MWAIT: {
 474            ret = EXCP_INTERRUPT;
 475            break;
 476        }
 477        /* Need to check if MMIO or unmapped fault */
 478        case EXIT_REASON_EPT_FAULT:
 479        {
 480            hvf_slot *slot;
 481            uint64_t gpa = rvmcs(cpu->hvf->fd, VMCS_GUEST_PHYSICAL_ADDRESS);
 482
 483            if (((idtvec_info & VMCS_IDT_VEC_VALID) == 0) &&
 484                ((exit_qual & EXIT_QUAL_NMIUDTI) != 0)) {
 485                vmx_set_nmi_blocking(cpu);
 486            }
 487
 488            slot = hvf_find_overlap_slot(gpa, 1);
 489            /* mmio */
 490            if (ept_emulation_fault(slot, gpa, exit_qual)) {
 491                struct x86_decode decode;
 492
 493                load_regs(cpu);
 494                decode_instruction(env, &decode);
 495                exec_instruction(env, &decode);
 496                store_regs(cpu);
 497                break;
 498            }
 499            break;
 500        }
 501        case EXIT_REASON_INOUT:
 502        {
 503            uint32_t in = (exit_qual & 8) != 0;
 504            uint32_t size =  (exit_qual & 7) + 1;
 505            uint32_t string =  (exit_qual & 16) != 0;
 506            uint32_t port =  exit_qual >> 16;
 507            /*uint32_t rep = (exit_qual & 0x20) != 0;*/
 508
 509            if (!string && in) {
 510                uint64_t val = 0;
 511                load_regs(cpu);
 512                hvf_handle_io(env, port, &val, 0, size, 1);
 513                if (size == 1) {
 514                    AL(env) = val;
 515                } else if (size == 2) {
 516                    AX(env) = val;
 517                } else if (size == 4) {
 518                    RAX(env) = (uint32_t)val;
 519                } else {
 520                    RAX(env) = (uint64_t)val;
 521                }
 522                env->eip += ins_len;
 523                store_regs(cpu);
 524                break;
 525            } else if (!string && !in) {
 526                RAX(env) = rreg(cpu->hvf->fd, HV_X86_RAX);
 527                hvf_handle_io(env, port, &RAX(env), 1, size, 1);
 528                macvm_set_rip(cpu, rip + ins_len);
 529                break;
 530            }
 531            struct x86_decode decode;
 532
 533            load_regs(cpu);
 534            decode_instruction(env, &decode);
 535            assert(ins_len == decode.len);
 536            exec_instruction(env, &decode);
 537            store_regs(cpu);
 538
 539            break;
 540        }
 541        case EXIT_REASON_CPUID: {
 542            uint32_t rax = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RAX);
 543            uint32_t rbx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RBX);
 544            uint32_t rcx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RCX);
 545            uint32_t rdx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RDX);
 546
 547            if (rax == 1) {
 548                /* CPUID1.ecx.OSXSAVE needs to know CR4 */
 549                env->cr[4] = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR4);
 550            }
 551            hvf_cpu_x86_cpuid(env, rax, rcx, &rax, &rbx, &rcx, &rdx);
 552
 553            wreg(cpu->hvf->fd, HV_X86_RAX, rax);
 554            wreg(cpu->hvf->fd, HV_X86_RBX, rbx);
 555            wreg(cpu->hvf->fd, HV_X86_RCX, rcx);
 556            wreg(cpu->hvf->fd, HV_X86_RDX, rdx);
 557
 558            macvm_set_rip(cpu, rip + ins_len);
 559            break;
 560        }
 561        case EXIT_REASON_XSETBV: {
 562            X86CPU *x86_cpu = X86_CPU(cpu);
 563            CPUX86State *env = &x86_cpu->env;
 564            uint32_t eax = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RAX);
 565            uint32_t ecx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RCX);
 566            uint32_t edx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RDX);
 567
 568            if (ecx) {
 569                macvm_set_rip(cpu, rip + ins_len);
 570                break;
 571            }
 572            env->xcr0 = ((uint64_t)edx << 32) | eax;
 573            wreg(cpu->hvf->fd, HV_X86_XCR0, env->xcr0 | 1);
 574            macvm_set_rip(cpu, rip + ins_len);
 575            break;
 576        }
 577        case EXIT_REASON_INTR_WINDOW:
 578            vmx_clear_int_window_exiting(cpu);
 579            ret = EXCP_INTERRUPT;
 580            break;
 581        case EXIT_REASON_NMI_WINDOW:
 582            vmx_clear_nmi_window_exiting(cpu);
 583            ret = EXCP_INTERRUPT;
 584            break;
 585        case EXIT_REASON_EXT_INTR:
 586            /* force exit and allow io handling */
 587            ret = EXCP_INTERRUPT;
 588            break;
 589        case EXIT_REASON_RDMSR:
 590        case EXIT_REASON_WRMSR:
 591        {
 592            load_regs(cpu);
 593            if (exit_reason == EXIT_REASON_RDMSR) {
 594                simulate_rdmsr(cpu);
 595            } else {
 596                simulate_wrmsr(cpu);
 597            }
 598            env->eip += ins_len;
 599            store_regs(cpu);
 600            break;
 601        }
 602        case EXIT_REASON_CR_ACCESS: {
 603            int cr;
 604            int reg;
 605
 606            load_regs(cpu);
 607            cr = exit_qual & 15;
 608            reg = (exit_qual >> 8) & 15;
 609
 610            switch (cr) {
 611            case 0x0: {
 612                macvm_set_cr0(cpu->hvf->fd, RRX(env, reg));
 613                break;
 614            }
 615            case 4: {
 616                macvm_set_cr4(cpu->hvf->fd, RRX(env, reg));
 617                break;
 618            }
 619            case 8: {
 620                X86CPU *x86_cpu = X86_CPU(cpu);
 621                if (exit_qual & 0x10) {
 622                    RRX(env, reg) = cpu_get_apic_tpr(x86_cpu->apic_state);
 623                } else {
 624                    int tpr = RRX(env, reg);
 625                    cpu_set_apic_tpr(x86_cpu->apic_state, tpr);
 626                    ret = EXCP_INTERRUPT;
 627                }
 628                break;
 629            }
 630            default:
 631                error_report("Unrecognized CR %d", cr);
 632                abort();
 633            }
 634            env->eip += ins_len;
 635            store_regs(cpu);
 636            break;
 637        }
 638        case EXIT_REASON_APIC_ACCESS: { /* TODO */
 639            struct x86_decode decode;
 640
 641            load_regs(cpu);
 642            decode_instruction(env, &decode);
 643            exec_instruction(env, &decode);
 644            store_regs(cpu);
 645            break;
 646        }
 647        case EXIT_REASON_TPR: {
 648            ret = 1;
 649            break;
 650        }
 651        case EXIT_REASON_TASK_SWITCH: {
 652            uint64_t vinfo = rvmcs(cpu->hvf->fd, VMCS_IDT_VECTORING_INFO);
 653            x68_segment_selector sel = {.sel = exit_qual & 0xffff};
 654            vmx_handle_task_switch(cpu, sel, (exit_qual >> 30) & 0x3,
 655             vinfo & VMCS_INTR_VALID, vinfo & VECTORING_INFO_VECTOR_MASK, vinfo
 656             & VMCS_INTR_T_MASK);
 657            break;
 658        }
 659        case EXIT_REASON_TRIPLE_FAULT: {
 660            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 661            ret = EXCP_INTERRUPT;
 662            break;
 663        }
 664        case EXIT_REASON_RDPMC:
 665            wreg(cpu->hvf->fd, HV_X86_RAX, 0);
 666            wreg(cpu->hvf->fd, HV_X86_RDX, 0);
 667            macvm_set_rip(cpu, rip + ins_len);
 668            break;
 669        case VMX_REASON_VMCALL:
 670            env->exception_nr = EXCP0D_GPF;
 671            env->exception_injected = 1;
 672            env->has_error_code = true;
 673            env->error_code = 0;
 674            break;
 675        default:
 676            error_report("%llx: unhandled exit %llx", rip, exit_reason);
 677        }
 678    } while (ret == 0);
 679
 680    return ret;
 681}
 682