1c97d6d2cSSergio Andres Gomez Del Real /* 2c97d6d2cSSergio Andres Gomez Del Real * Copyright (c) 2003-2008 Fabrice Bellard 3c97d6d2cSSergio Andres Gomez Del Real * Copyright (C) 2016 Veertu Inc, 4c97d6d2cSSergio Andres Gomez Del Real * Copyright (C) 2017 Google Inc, 5c97d6d2cSSergio Andres Gomez Del Real * 6c97d6d2cSSergio Andres Gomez Del Real * This program is free software; you can redistribute it and/or 7996feed4SSergio Andres Gomez Del Real * modify it under the terms of the GNU Lesser General Public 8996feed4SSergio Andres Gomez Del Real * License as published by the Free Software Foundation; either 9996feed4SSergio Andres Gomez Del Real * version 2 of the License, or (at your option) any later version. 10c97d6d2cSSergio Andres Gomez Del Real * 11c97d6d2cSSergio Andres Gomez Del Real * This program is distributed in the hope that it will be useful, 12c97d6d2cSSergio Andres Gomez Del Real * but WITHOUT ANY WARRANTY; without even the implied warranty of 13996feed4SSergio Andres Gomez Del Real * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14996feed4SSergio Andres Gomez Del Real * Lesser General Public License for more details. 15c97d6d2cSSergio Andres Gomez Del Real * 16996feed4SSergio Andres Gomez Del Real * You should have received a copy of the GNU Lesser General Public 17996feed4SSergio Andres Gomez Del Real * License along with this program; if not, see <http://www.gnu.org/licenses/>. 18c97d6d2cSSergio Andres Gomez Del Real */ 19c97d6d2cSSergio Andres Gomez Del Real 20c97d6d2cSSergio Andres Gomez Del Real #include "qemu/osdep.h" 21c97d6d2cSSergio Andres Gomez Del Real #include "qemu-common.h" 22c97d6d2cSSergio Andres Gomez Del Real 23c97d6d2cSSergio Andres Gomez Del Real #include "x86hvf.h" 24c97d6d2cSSergio Andres Gomez Del Real #include "vmx.h" 25c97d6d2cSSergio Andres Gomez Del Real #include "vmcs.h" 26c97d6d2cSSergio Andres Gomez Del Real #include "cpu.h" 27c97d6d2cSSergio Andres Gomez Del Real #include "x86_descr.h" 28c97d6d2cSSergio Andres Gomez Del Real #include "x86_decode.h" 29c97d6d2cSSergio Andres Gomez Del Real 30c97d6d2cSSergio Andres Gomez Del Real #include "hw/i386/apic_internal.h" 31c97d6d2cSSergio Andres Gomez Del Real 32c97d6d2cSSergio Andres Gomez Del Real #include <stdio.h> 33c97d6d2cSSergio Andres Gomez Del Real #include <stdlib.h> 34c97d6d2cSSergio Andres Gomez Del Real #include <Hypervisor/hv.h> 35c97d6d2cSSergio Andres Gomez Del Real #include <Hypervisor/hv_vmx.h> 36c97d6d2cSSergio Andres Gomez Del Real #include <stdint.h> 37c97d6d2cSSergio Andres Gomez Del Real 38c97d6d2cSSergio Andres Gomez Del Real void hvf_set_segment(struct CPUState *cpu, struct vmx_segment *vmx_seg, 39c97d6d2cSSergio Andres Gomez Del Real SegmentCache *qseg, bool is_tr) 40c97d6d2cSSergio Andres Gomez Del Real { 41c97d6d2cSSergio Andres Gomez Del Real vmx_seg->sel = qseg->selector; 42c97d6d2cSSergio Andres Gomez Del Real vmx_seg->base = qseg->base; 43c97d6d2cSSergio Andres Gomez Del Real vmx_seg->limit = qseg->limit; 44c97d6d2cSSergio Andres Gomez Del Real 45c97d6d2cSSergio Andres Gomez Del Real if (!qseg->selector && !x86_is_real(cpu) && !is_tr) { 46c97d6d2cSSergio Andres Gomez Del Real /* the TR register is usable after processor reset despite 47c97d6d2cSSergio Andres Gomez Del Real * having a null selector */ 48c97d6d2cSSergio Andres Gomez Del Real vmx_seg->ar = 1 << 16; 49c97d6d2cSSergio Andres Gomez Del Real return; 50c97d6d2cSSergio Andres Gomez Del Real } 51c97d6d2cSSergio Andres Gomez Del Real vmx_seg->ar = (qseg->flags >> DESC_TYPE_SHIFT) & 0xf; 52c97d6d2cSSergio Andres Gomez Del Real vmx_seg->ar |= ((qseg->flags >> DESC_G_SHIFT) & 1) << 15; 53c97d6d2cSSergio Andres Gomez Del Real vmx_seg->ar |= ((qseg->flags >> DESC_B_SHIFT) & 1) << 14; 54c97d6d2cSSergio Andres Gomez Del Real vmx_seg->ar |= ((qseg->flags >> DESC_L_SHIFT) & 1) << 13; 55c97d6d2cSSergio Andres Gomez Del Real vmx_seg->ar |= ((qseg->flags >> DESC_AVL_SHIFT) & 1) << 12; 56c97d6d2cSSergio Andres Gomez Del Real vmx_seg->ar |= ((qseg->flags >> DESC_P_SHIFT) & 1) << 7; 57c97d6d2cSSergio Andres Gomez Del Real vmx_seg->ar |= ((qseg->flags >> DESC_DPL_SHIFT) & 3) << 5; 58c97d6d2cSSergio Andres Gomez Del Real vmx_seg->ar |= ((qseg->flags >> DESC_S_SHIFT) & 1) << 4; 59c97d6d2cSSergio Andres Gomez Del Real } 60c97d6d2cSSergio Andres Gomez Del Real 61c97d6d2cSSergio Andres Gomez Del Real void hvf_get_segment(SegmentCache *qseg, struct vmx_segment *vmx_seg) 62c97d6d2cSSergio Andres Gomez Del Real { 63c97d6d2cSSergio Andres Gomez Del Real qseg->limit = vmx_seg->limit; 64c97d6d2cSSergio Andres Gomez Del Real qseg->base = vmx_seg->base; 65c97d6d2cSSergio Andres Gomez Del Real qseg->selector = vmx_seg->sel; 66c97d6d2cSSergio Andres Gomez Del Real qseg->flags = ((vmx_seg->ar & 0xf) << DESC_TYPE_SHIFT) | 67c97d6d2cSSergio Andres Gomez Del Real (((vmx_seg->ar >> 4) & 1) << DESC_S_SHIFT) | 68c97d6d2cSSergio Andres Gomez Del Real (((vmx_seg->ar >> 5) & 3) << DESC_DPL_SHIFT) | 69c97d6d2cSSergio Andres Gomez Del Real (((vmx_seg->ar >> 7) & 1) << DESC_P_SHIFT) | 70c97d6d2cSSergio Andres Gomez Del Real (((vmx_seg->ar >> 12) & 1) << DESC_AVL_SHIFT) | 71c97d6d2cSSergio Andres Gomez Del Real (((vmx_seg->ar >> 13) & 1) << DESC_L_SHIFT) | 72c97d6d2cSSergio Andres Gomez Del Real (((vmx_seg->ar >> 14) & 1) << DESC_B_SHIFT) | 73c97d6d2cSSergio Andres Gomez Del Real (((vmx_seg->ar >> 15) & 1) << DESC_G_SHIFT); 74c97d6d2cSSergio Andres Gomez Del Real } 75c97d6d2cSSergio Andres Gomez Del Real 76c97d6d2cSSergio Andres Gomez Del Real void hvf_put_xsave(CPUState *cpu_state) 77c97d6d2cSSergio Andres Gomez Del Real { 78c97d6d2cSSergio Andres Gomez Del Real 79*f585195eSSergio Andres Gomez Del Real struct X86XSaveArea *xsave; 80c97d6d2cSSergio Andres Gomez Del Real 81c97d6d2cSSergio Andres Gomez Del Real xsave = X86_CPU(cpu_state)->env.kvm_xsave_buf; 82c97d6d2cSSergio Andres Gomez Del Real 83*f585195eSSergio Andres Gomez Del Real x86_cpu_xsave_all_areas(X86_CPU(cpu_state), xsave); 84c97d6d2cSSergio Andres Gomez Del Real 85*f585195eSSergio Andres Gomez Del Real if (hv_vcpu_write_fpstate(cpu_state->hvf_fd, (void*)xsave, 4096)) { 86c97d6d2cSSergio Andres Gomez Del Real abort(); 87c97d6d2cSSergio Andres Gomez Del Real } 88c97d6d2cSSergio Andres Gomez Del Real } 89c97d6d2cSSergio Andres Gomez Del Real 90c97d6d2cSSergio Andres Gomez Del Real void hvf_put_segments(CPUState *cpu_state) 91c97d6d2cSSergio Andres Gomez Del Real { 92c97d6d2cSSergio Andres Gomez Del Real CPUX86State *env = &X86_CPU(cpu_state)->env; 93c97d6d2cSSergio Andres Gomez Del Real struct vmx_segment seg; 94c97d6d2cSSergio Andres Gomez Del Real 95c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_GUEST_IDTR_LIMIT, env->idt.limit); 96c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_GUEST_IDTR_BASE, env->idt.base); 97c97d6d2cSSergio Andres Gomez Del Real 98c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_GUEST_GDTR_LIMIT, env->gdt.limit); 99c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_GUEST_GDTR_BASE, env->gdt.base); 100c97d6d2cSSergio Andres Gomez Del Real 101c97d6d2cSSergio Andres Gomez Del Real /* wvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR2, env->cr[2]); */ 102c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR3, env->cr[3]); 103c97d6d2cSSergio Andres Gomez Del Real vmx_update_tpr(cpu_state); 104c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_GUEST_IA32_EFER, env->efer); 105c97d6d2cSSergio Andres Gomez Del Real 106c97d6d2cSSergio Andres Gomez Del Real macvm_set_cr4(cpu_state->hvf_fd, env->cr[4]); 107c97d6d2cSSergio Andres Gomez Del Real macvm_set_cr0(cpu_state->hvf_fd, env->cr[0]); 108c97d6d2cSSergio Andres Gomez Del Real 109c97d6d2cSSergio Andres Gomez Del Real hvf_set_segment(cpu_state, &seg, &env->segs[R_CS], false); 110c97d6d2cSSergio Andres Gomez Del Real vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_CS); 111c97d6d2cSSergio Andres Gomez Del Real 112c97d6d2cSSergio Andres Gomez Del Real hvf_set_segment(cpu_state, &seg, &env->segs[R_DS], false); 113c97d6d2cSSergio Andres Gomez Del Real vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_DS); 114c97d6d2cSSergio Andres Gomez Del Real 115c97d6d2cSSergio Andres Gomez Del Real hvf_set_segment(cpu_state, &seg, &env->segs[R_ES], false); 116c97d6d2cSSergio Andres Gomez Del Real vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_ES); 117c97d6d2cSSergio Andres Gomez Del Real 118c97d6d2cSSergio Andres Gomez Del Real hvf_set_segment(cpu_state, &seg, &env->segs[R_SS], false); 119c97d6d2cSSergio Andres Gomez Del Real vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_SS); 120c97d6d2cSSergio Andres Gomez Del Real 121c97d6d2cSSergio Andres Gomez Del Real hvf_set_segment(cpu_state, &seg, &env->segs[R_FS], false); 122c97d6d2cSSergio Andres Gomez Del Real vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_FS); 123c97d6d2cSSergio Andres Gomez Del Real 124c97d6d2cSSergio Andres Gomez Del Real hvf_set_segment(cpu_state, &seg, &env->segs[R_GS], false); 125c97d6d2cSSergio Andres Gomez Del Real vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_GS); 126c97d6d2cSSergio Andres Gomez Del Real 127c97d6d2cSSergio Andres Gomez Del Real hvf_set_segment(cpu_state, &seg, &env->tr, true); 128c97d6d2cSSergio Andres Gomez Del Real vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_TR); 129c97d6d2cSSergio Andres Gomez Del Real 130c97d6d2cSSergio Andres Gomez Del Real hvf_set_segment(cpu_state, &seg, &env->ldt, false); 131c97d6d2cSSergio Andres Gomez Del Real vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_LDTR); 132c97d6d2cSSergio Andres Gomez Del Real 133c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_flush(cpu_state->hvf_fd); 134c97d6d2cSSergio Andres Gomez Del Real } 135c97d6d2cSSergio Andres Gomez Del Real 136c97d6d2cSSergio Andres Gomez Del Real void hvf_put_msrs(CPUState *cpu_state) 137c97d6d2cSSergio Andres Gomez Del Real { 138c97d6d2cSSergio Andres Gomez Del Real CPUX86State *env = &X86_CPU(cpu_state)->env; 139c97d6d2cSSergio Andres Gomez Del Real 140c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_CS, 141c97d6d2cSSergio Andres Gomez Del Real env->sysenter_cs); 142c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_ESP, 143c97d6d2cSSergio Andres Gomez Del Real env->sysenter_esp); 144c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_EIP, 145c97d6d2cSSergio Andres Gomez Del Real env->sysenter_eip); 146c97d6d2cSSergio Andres Gomez Del Real 147c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_STAR, env->star); 148c97d6d2cSSergio Andres Gomez Del Real 149c97d6d2cSSergio Andres Gomez Del Real #ifdef TARGET_X86_64 150c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_CSTAR, env->cstar); 151c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_KERNELGSBASE, env->kernelgsbase); 152c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_FMASK, env->fmask); 153c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_LSTAR, env->lstar); 154c97d6d2cSSergio Andres Gomez Del Real #endif 155c97d6d2cSSergio Andres Gomez Del Real 156c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_GSBASE, env->segs[R_GS].base); 157c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_FSBASE, env->segs[R_FS].base); 158c97d6d2cSSergio Andres Gomez Del Real 159c97d6d2cSSergio Andres Gomez Del Real /* if (!osx_is_sierra()) 160c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_TSC_OFFSET, env->tsc - rdtscp());*/ 161c97d6d2cSSergio Andres Gomez Del Real hv_vm_sync_tsc(env->tsc); 162c97d6d2cSSergio Andres Gomez Del Real } 163c97d6d2cSSergio Andres Gomez Del Real 164c97d6d2cSSergio Andres Gomez Del Real 165c97d6d2cSSergio Andres Gomez Del Real void hvf_get_xsave(CPUState *cpu_state) 166c97d6d2cSSergio Andres Gomez Del Real { 167*f585195eSSergio Andres Gomez Del Real struct X86XSaveArea *xsave; 168c97d6d2cSSergio Andres Gomez Del Real 169c97d6d2cSSergio Andres Gomez Del Real xsave = X86_CPU(cpu_state)->env.kvm_xsave_buf; 170c97d6d2cSSergio Andres Gomez Del Real 171*f585195eSSergio Andres Gomez Del Real if (hv_vcpu_read_fpstate(cpu_state->hvf_fd, (void*)xsave, 4096)) { 172c97d6d2cSSergio Andres Gomez Del Real abort(); 173c97d6d2cSSergio Andres Gomez Del Real } 174c97d6d2cSSergio Andres Gomez Del Real 175*f585195eSSergio Andres Gomez Del Real x86_cpu_xrstor_all_areas(X86_CPU(cpu_state), xsave); 176c97d6d2cSSergio Andres Gomez Del Real } 177c97d6d2cSSergio Andres Gomez Del Real 178c97d6d2cSSergio Andres Gomez Del Real void hvf_get_segments(CPUState *cpu_state) 179c97d6d2cSSergio Andres Gomez Del Real { 180c97d6d2cSSergio Andres Gomez Del Real CPUX86State *env = &X86_CPU(cpu_state)->env; 181c97d6d2cSSergio Andres Gomez Del Real 182c97d6d2cSSergio Andres Gomez Del Real struct vmx_segment seg; 183c97d6d2cSSergio Andres Gomez Del Real 184c97d6d2cSSergio Andres Gomez Del Real env->interrupt_injected = -1; 185c97d6d2cSSergio Andres Gomez Del Real 186c97d6d2cSSergio Andres Gomez Del Real vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_CS); 187c97d6d2cSSergio Andres Gomez Del Real hvf_get_segment(&env->segs[R_CS], &seg); 188c97d6d2cSSergio Andres Gomez Del Real 189c97d6d2cSSergio Andres Gomez Del Real vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_DS); 190c97d6d2cSSergio Andres Gomez Del Real hvf_get_segment(&env->segs[R_DS], &seg); 191c97d6d2cSSergio Andres Gomez Del Real 192c97d6d2cSSergio Andres Gomez Del Real vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_ES); 193c97d6d2cSSergio Andres Gomez Del Real hvf_get_segment(&env->segs[R_ES], &seg); 194c97d6d2cSSergio Andres Gomez Del Real 195c97d6d2cSSergio Andres Gomez Del Real vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_FS); 196c97d6d2cSSergio Andres Gomez Del Real hvf_get_segment(&env->segs[R_FS], &seg); 197c97d6d2cSSergio Andres Gomez Del Real 198c97d6d2cSSergio Andres Gomez Del Real vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_GS); 199c97d6d2cSSergio Andres Gomez Del Real hvf_get_segment(&env->segs[R_GS], &seg); 200c97d6d2cSSergio Andres Gomez Del Real 201c97d6d2cSSergio Andres Gomez Del Real vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_SS); 202c97d6d2cSSergio Andres Gomez Del Real hvf_get_segment(&env->segs[R_SS], &seg); 203c97d6d2cSSergio Andres Gomez Del Real 204c97d6d2cSSergio Andres Gomez Del Real vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_TR); 205c97d6d2cSSergio Andres Gomez Del Real hvf_get_segment(&env->tr, &seg); 206c97d6d2cSSergio Andres Gomez Del Real 207c97d6d2cSSergio Andres Gomez Del Real vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_LDTR); 208c97d6d2cSSergio Andres Gomez Del Real hvf_get_segment(&env->ldt, &seg); 209c97d6d2cSSergio Andres Gomez Del Real 210c97d6d2cSSergio Andres Gomez Del Real env->idt.limit = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_IDTR_LIMIT); 211c97d6d2cSSergio Andres Gomez Del Real env->idt.base = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_IDTR_BASE); 212c97d6d2cSSergio Andres Gomez Del Real env->gdt.limit = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_GDTR_LIMIT); 213c97d6d2cSSergio Andres Gomez Del Real env->gdt.base = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_GDTR_BASE); 214c97d6d2cSSergio Andres Gomez Del Real 215c97d6d2cSSergio Andres Gomez Del Real env->cr[0] = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR0); 216c97d6d2cSSergio Andres Gomez Del Real env->cr[2] = 0; 217c97d6d2cSSergio Andres Gomez Del Real env->cr[3] = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR3); 218c97d6d2cSSergio Andres Gomez Del Real env->cr[4] = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR4); 219c97d6d2cSSergio Andres Gomez Del Real 220c97d6d2cSSergio Andres Gomez Del Real env->efer = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_IA32_EFER); 221c97d6d2cSSergio Andres Gomez Del Real } 222c97d6d2cSSergio Andres Gomez Del Real 223c97d6d2cSSergio Andres Gomez Del Real void hvf_get_msrs(CPUState *cpu_state) 224c97d6d2cSSergio Andres Gomez Del Real { 225c97d6d2cSSergio Andres Gomez Del Real CPUX86State *env = &X86_CPU(cpu_state)->env; 226c97d6d2cSSergio Andres Gomez Del Real uint64_t tmp; 227c97d6d2cSSergio Andres Gomez Del Real 228c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_CS, &tmp); 229c97d6d2cSSergio Andres Gomez Del Real env->sysenter_cs = tmp; 230c97d6d2cSSergio Andres Gomez Del Real 231c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_ESP, &tmp); 232c97d6d2cSSergio Andres Gomez Del Real env->sysenter_esp = tmp; 233c97d6d2cSSergio Andres Gomez Del Real 234c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_EIP, &tmp); 235c97d6d2cSSergio Andres Gomez Del Real env->sysenter_eip = tmp; 236c97d6d2cSSergio Andres Gomez Del Real 237c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_STAR, &env->star); 238c97d6d2cSSergio Andres Gomez Del Real 239c97d6d2cSSergio Andres Gomez Del Real #ifdef TARGET_X86_64 240c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_CSTAR, &env->cstar); 241c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_KERNELGSBASE, &env->kernelgsbase); 242c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_FMASK, &env->fmask); 243c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_LSTAR, &env->lstar); 244c97d6d2cSSergio Andres Gomez Del Real #endif 245c97d6d2cSSergio Andres Gomez Del Real 246c97d6d2cSSergio Andres Gomez Del Real hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_IA32_APICBASE, &tmp); 247c97d6d2cSSergio Andres Gomez Del Real 248c97d6d2cSSergio Andres Gomez Del Real env->tsc = rdtscp() + rvmcs(cpu_state->hvf_fd, VMCS_TSC_OFFSET); 249c97d6d2cSSergio Andres Gomez Del Real } 250c97d6d2cSSergio Andres Gomez Del Real 251c97d6d2cSSergio Andres Gomez Del Real int hvf_put_registers(CPUState *cpu_state) 252c97d6d2cSSergio Andres Gomez Del Real { 253c97d6d2cSSergio Andres Gomez Del Real X86CPU *x86cpu = X86_CPU(cpu_state); 254c97d6d2cSSergio Andres Gomez Del Real CPUX86State *env = &x86cpu->env; 255c97d6d2cSSergio Andres Gomez Del Real 256c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RAX, env->regs[R_EAX]); 257c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RBX, env->regs[R_EBX]); 258c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RCX, env->regs[R_ECX]); 259c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RDX, env->regs[R_EDX]); 260c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RBP, env->regs[R_EBP]); 261c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RSP, env->regs[R_ESP]); 262c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RSI, env->regs[R_ESI]); 263c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RDI, env->regs[R_EDI]); 264c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_R8, env->regs[8]); 265c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_R9, env->regs[9]); 266c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_R10, env->regs[10]); 267c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_R11, env->regs[11]); 268c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_R12, env->regs[12]); 269c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_R13, env->regs[13]); 270c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_R14, env->regs[14]); 271c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_R15, env->regs[15]); 272c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RFLAGS, env->eflags); 273c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_RIP, env->eip); 274c97d6d2cSSergio Andres Gomez Del Real 275c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_XCR0, env->xcr0); 276c97d6d2cSSergio Andres Gomez Del Real 277c97d6d2cSSergio Andres Gomez Del Real hvf_put_xsave(cpu_state); 278c97d6d2cSSergio Andres Gomez Del Real 279c97d6d2cSSergio Andres Gomez Del Real hvf_put_segments(cpu_state); 280c97d6d2cSSergio Andres Gomez Del Real 281c97d6d2cSSergio Andres Gomez Del Real hvf_put_msrs(cpu_state); 282c97d6d2cSSergio Andres Gomez Del Real 283c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_DR0, env->dr[0]); 284c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_DR1, env->dr[1]); 285c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_DR2, env->dr[2]); 286c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_DR3, env->dr[3]); 287c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_DR4, env->dr[4]); 288c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_DR5, env->dr[5]); 289c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_DR6, env->dr[6]); 290c97d6d2cSSergio Andres Gomez Del Real wreg(cpu_state->hvf_fd, HV_X86_DR7, env->dr[7]); 291c97d6d2cSSergio Andres Gomez Del Real 292c97d6d2cSSergio Andres Gomez Del Real return 0; 293c97d6d2cSSergio Andres Gomez Del Real } 294c97d6d2cSSergio Andres Gomez Del Real 295c97d6d2cSSergio Andres Gomez Del Real int hvf_get_registers(CPUState *cpu_state) 296c97d6d2cSSergio Andres Gomez Del Real { 297c97d6d2cSSergio Andres Gomez Del Real X86CPU *x86cpu = X86_CPU(cpu_state); 298c97d6d2cSSergio Andres Gomez Del Real CPUX86State *env = &x86cpu->env; 299c97d6d2cSSergio Andres Gomez Del Real 300c97d6d2cSSergio Andres Gomez Del Real 301c97d6d2cSSergio Andres Gomez Del Real env->regs[R_EAX] = rreg(cpu_state->hvf_fd, HV_X86_RAX); 302c97d6d2cSSergio Andres Gomez Del Real env->regs[R_EBX] = rreg(cpu_state->hvf_fd, HV_X86_RBX); 303c97d6d2cSSergio Andres Gomez Del Real env->regs[R_ECX] = rreg(cpu_state->hvf_fd, HV_X86_RCX); 304c97d6d2cSSergio Andres Gomez Del Real env->regs[R_EDX] = rreg(cpu_state->hvf_fd, HV_X86_RDX); 305c97d6d2cSSergio Andres Gomez Del Real env->regs[R_EBP] = rreg(cpu_state->hvf_fd, HV_X86_RBP); 306c97d6d2cSSergio Andres Gomez Del Real env->regs[R_ESP] = rreg(cpu_state->hvf_fd, HV_X86_RSP); 307c97d6d2cSSergio Andres Gomez Del Real env->regs[R_ESI] = rreg(cpu_state->hvf_fd, HV_X86_RSI); 308c97d6d2cSSergio Andres Gomez Del Real env->regs[R_EDI] = rreg(cpu_state->hvf_fd, HV_X86_RDI); 309c97d6d2cSSergio Andres Gomez Del Real env->regs[8] = rreg(cpu_state->hvf_fd, HV_X86_R8); 310c97d6d2cSSergio Andres Gomez Del Real env->regs[9] = rreg(cpu_state->hvf_fd, HV_X86_R9); 311c97d6d2cSSergio Andres Gomez Del Real env->regs[10] = rreg(cpu_state->hvf_fd, HV_X86_R10); 312c97d6d2cSSergio Andres Gomez Del Real env->regs[11] = rreg(cpu_state->hvf_fd, HV_X86_R11); 313c97d6d2cSSergio Andres Gomez Del Real env->regs[12] = rreg(cpu_state->hvf_fd, HV_X86_R12); 314c97d6d2cSSergio Andres Gomez Del Real env->regs[13] = rreg(cpu_state->hvf_fd, HV_X86_R13); 315c97d6d2cSSergio Andres Gomez Del Real env->regs[14] = rreg(cpu_state->hvf_fd, HV_X86_R14); 316c97d6d2cSSergio Andres Gomez Del Real env->regs[15] = rreg(cpu_state->hvf_fd, HV_X86_R15); 317c97d6d2cSSergio Andres Gomez Del Real 318c97d6d2cSSergio Andres Gomez Del Real env->eflags = rreg(cpu_state->hvf_fd, HV_X86_RFLAGS); 319c97d6d2cSSergio Andres Gomez Del Real env->eip = rreg(cpu_state->hvf_fd, HV_X86_RIP); 320c97d6d2cSSergio Andres Gomez Del Real 321c97d6d2cSSergio Andres Gomez Del Real hvf_get_xsave(cpu_state); 322c97d6d2cSSergio Andres Gomez Del Real env->xcr0 = rreg(cpu_state->hvf_fd, HV_X86_XCR0); 323c97d6d2cSSergio Andres Gomez Del Real 324c97d6d2cSSergio Andres Gomez Del Real hvf_get_segments(cpu_state); 325c97d6d2cSSergio Andres Gomez Del Real hvf_get_msrs(cpu_state); 326c97d6d2cSSergio Andres Gomez Del Real 327c97d6d2cSSergio Andres Gomez Del Real env->dr[0] = rreg(cpu_state->hvf_fd, HV_X86_DR0); 328c97d6d2cSSergio Andres Gomez Del Real env->dr[1] = rreg(cpu_state->hvf_fd, HV_X86_DR1); 329c97d6d2cSSergio Andres Gomez Del Real env->dr[2] = rreg(cpu_state->hvf_fd, HV_X86_DR2); 330c97d6d2cSSergio Andres Gomez Del Real env->dr[3] = rreg(cpu_state->hvf_fd, HV_X86_DR3); 331c97d6d2cSSergio Andres Gomez Del Real env->dr[4] = rreg(cpu_state->hvf_fd, HV_X86_DR4); 332c97d6d2cSSergio Andres Gomez Del Real env->dr[5] = rreg(cpu_state->hvf_fd, HV_X86_DR5); 333c97d6d2cSSergio Andres Gomez Del Real env->dr[6] = rreg(cpu_state->hvf_fd, HV_X86_DR6); 334c97d6d2cSSergio Andres Gomez Del Real env->dr[7] = rreg(cpu_state->hvf_fd, HV_X86_DR7); 335c97d6d2cSSergio Andres Gomez Del Real 336c97d6d2cSSergio Andres Gomez Del Real return 0; 337c97d6d2cSSergio Andres Gomez Del Real } 338c97d6d2cSSergio Andres Gomez Del Real 339c97d6d2cSSergio Andres Gomez Del Real static void vmx_set_int_window_exiting(CPUState *cpu) 340c97d6d2cSSergio Andres Gomez Del Real { 341c97d6d2cSSergio Andres Gomez Del Real uint64_t val; 342c97d6d2cSSergio Andres Gomez Del Real val = rvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS); 343c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS, val | 344c97d6d2cSSergio Andres Gomez Del Real VMCS_PRI_PROC_BASED_CTLS_INT_WINDOW_EXITING); 345c97d6d2cSSergio Andres Gomez Del Real } 346c97d6d2cSSergio Andres Gomez Del Real 347c97d6d2cSSergio Andres Gomez Del Real void vmx_clear_int_window_exiting(CPUState *cpu) 348c97d6d2cSSergio Andres Gomez Del Real { 349c97d6d2cSSergio Andres Gomez Del Real uint64_t val; 350c97d6d2cSSergio Andres Gomez Del Real val = rvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS); 351c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS, val & 352c97d6d2cSSergio Andres Gomez Del Real ~VMCS_PRI_PROC_BASED_CTLS_INT_WINDOW_EXITING); 353c97d6d2cSSergio Andres Gomez Del Real } 354c97d6d2cSSergio Andres Gomez Del Real 355c97d6d2cSSergio Andres Gomez Del Real #define NMI_VEC 2 356c97d6d2cSSergio Andres Gomez Del Real 357c97d6d2cSSergio Andres Gomez Del Real bool hvf_inject_interrupts(CPUState *cpu_state) 358c97d6d2cSSergio Andres Gomez Del Real { 359c97d6d2cSSergio Andres Gomez Del Real int allow_nmi = !(rvmcs(cpu_state->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) & 360c97d6d2cSSergio Andres Gomez Del Real VMCS_INTERRUPTIBILITY_NMI_BLOCKING); 361c97d6d2cSSergio Andres Gomez Del Real X86CPU *x86cpu = X86_CPU(cpu_state); 362c97d6d2cSSergio Andres Gomez Del Real CPUX86State *env = &x86cpu->env; 363c97d6d2cSSergio Andres Gomez Del Real 364c97d6d2cSSergio Andres Gomez Del Real uint64_t idt_info = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_INFO); 365c97d6d2cSSergio Andres Gomez Del Real uint64_t info = 0; 366c97d6d2cSSergio Andres Gomez Del Real 367c97d6d2cSSergio Andres Gomez Del Real if (idt_info & VMCS_IDT_VEC_VALID) { 368c97d6d2cSSergio Andres Gomez Del Real uint8_t vector = idt_info & 0xff; 369c97d6d2cSSergio Andres Gomez Del Real uint64_t intr_type = idt_info & VMCS_INTR_T_MASK; 370c97d6d2cSSergio Andres Gomez Del Real info = idt_info; 371c97d6d2cSSergio Andres Gomez Del Real 372c97d6d2cSSergio Andres Gomez Del Real uint64_t reason = rvmcs(cpu_state->hvf_fd, VMCS_EXIT_REASON); 373c97d6d2cSSergio Andres Gomez Del Real if (intr_type == VMCS_INTR_T_NMI && reason != EXIT_REASON_TASK_SWITCH) { 374c97d6d2cSSergio Andres Gomez Del Real allow_nmi = 1; 375c97d6d2cSSergio Andres Gomez Del Real vmx_clear_nmi_blocking(cpu_state); 376c97d6d2cSSergio Andres Gomez Del Real } 377c97d6d2cSSergio Andres Gomez Del Real 378c97d6d2cSSergio Andres Gomez Del Real if ((allow_nmi || intr_type != VMCS_INTR_T_NMI)) { 379c97d6d2cSSergio Andres Gomez Del Real info &= ~(1 << 12); /* clear undefined bit */ 380c97d6d2cSSergio Andres Gomez Del Real if (intr_type == VMCS_INTR_T_SWINTR || 381c97d6d2cSSergio Andres Gomez Del Real intr_type == VMCS_INTR_T_PRIV_SWEXCEPTION || 382c97d6d2cSSergio Andres Gomez Del Real intr_type == VMCS_INTR_T_SWEXCEPTION) { 383c97d6d2cSSergio Andres Gomez Del Real uint64_t ins_len = rvmcs(cpu_state->hvf_fd, 384c97d6d2cSSergio Andres Gomez Del Real VMCS_EXIT_INSTRUCTION_LENGTH); 385c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len); 386c97d6d2cSSergio Andres Gomez Del Real } 387c97d6d2cSSergio Andres Gomez Del Real if (vector == EXCEPTION_BP || vector == EXCEPTION_OF) { 388c97d6d2cSSergio Andres Gomez Del Real /* 389c97d6d2cSSergio Andres Gomez Del Real * VT-x requires #BP and #OF to be injected as software 390c97d6d2cSSergio Andres Gomez Del Real * exceptions. 391c97d6d2cSSergio Andres Gomez Del Real */ 392c97d6d2cSSergio Andres Gomez Del Real info &= ~VMCS_INTR_T_MASK; 393c97d6d2cSSergio Andres Gomez Del Real info |= VMCS_INTR_T_SWEXCEPTION; 394c97d6d2cSSergio Andres Gomez Del Real uint64_t ins_len = rvmcs(cpu_state->hvf_fd, 395c97d6d2cSSergio Andres Gomez Del Real VMCS_EXIT_INSTRUCTION_LENGTH); 396c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len); 397c97d6d2cSSergio Andres Gomez Del Real } 398c97d6d2cSSergio Andres Gomez Del Real 399c97d6d2cSSergio Andres Gomez Del Real uint64_t err = 0; 400c97d6d2cSSergio Andres Gomez Del Real if (idt_info & VMCS_INTR_DEL_ERRCODE) { 401c97d6d2cSSergio Andres Gomez Del Real err = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_ERROR); 402c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_EXCEPTION_ERROR, err); 403c97d6d2cSSergio Andres Gomez Del Real } 404c97d6d2cSSergio Andres Gomez Del Real /*printf("reinject %lx err %d\n", info, err);*/ 405c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info); 406c97d6d2cSSergio Andres Gomez Del Real }; 407c97d6d2cSSergio Andres Gomez Del Real } 408c97d6d2cSSergio Andres Gomez Del Real 409c97d6d2cSSergio Andres Gomez Del Real if (cpu_state->interrupt_request & CPU_INTERRUPT_NMI) { 410c97d6d2cSSergio Andres Gomez Del Real if (allow_nmi && !(info & VMCS_INTR_VALID)) { 411c97d6d2cSSergio Andres Gomez Del Real cpu_state->interrupt_request &= ~CPU_INTERRUPT_NMI; 412c97d6d2cSSergio Andres Gomez Del Real info = VMCS_INTR_VALID | VMCS_INTR_T_NMI | NMI_VEC; 413c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info); 414c97d6d2cSSergio Andres Gomez Del Real } else { 415c97d6d2cSSergio Andres Gomez Del Real vmx_set_nmi_window_exiting(cpu_state); 416c97d6d2cSSergio Andres Gomez Del Real } 417c97d6d2cSSergio Andres Gomez Del Real } 418c97d6d2cSSergio Andres Gomez Del Real 419c97d6d2cSSergio Andres Gomez Del Real if (env->hvf_emul->interruptable && 420c97d6d2cSSergio Andres Gomez Del Real (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) && 421c97d6d2cSSergio Andres Gomez Del Real (EFLAGS(env) & IF_MASK) && !(info & VMCS_INTR_VALID)) { 422c97d6d2cSSergio Andres Gomez Del Real int line = cpu_get_pic_interrupt(&x86cpu->env); 423c97d6d2cSSergio Andres Gomez Del Real cpu_state->interrupt_request &= ~CPU_INTERRUPT_HARD; 424c97d6d2cSSergio Andres Gomez Del Real if (line >= 0) { 425c97d6d2cSSergio Andres Gomez Del Real wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, line | 426c97d6d2cSSergio Andres Gomez Del Real VMCS_INTR_VALID | VMCS_INTR_T_HWINTR); 427c97d6d2cSSergio Andres Gomez Del Real } 428c97d6d2cSSergio Andres Gomez Del Real } 429c97d6d2cSSergio Andres Gomez Del Real if (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) { 430c97d6d2cSSergio Andres Gomez Del Real vmx_set_int_window_exiting(cpu_state); 431c97d6d2cSSergio Andres Gomez Del Real } 432c97d6d2cSSergio Andres Gomez Del Real } 433c97d6d2cSSergio Andres Gomez Del Real 434c97d6d2cSSergio Andres Gomez Del Real int hvf_process_events(CPUState *cpu_state) 435c97d6d2cSSergio Andres Gomez Del Real { 436c97d6d2cSSergio Andres Gomez Del Real X86CPU *cpu = X86_CPU(cpu_state); 437c97d6d2cSSergio Andres Gomez Del Real CPUX86State *env = &cpu->env; 438c97d6d2cSSergio Andres Gomez Del Real 439c97d6d2cSSergio Andres Gomez Del Real EFLAGS(env) = rreg(cpu_state->hvf_fd, HV_X86_RFLAGS); 440c97d6d2cSSergio Andres Gomez Del Real 441c97d6d2cSSergio Andres Gomez Del Real if (cpu_state->interrupt_request & CPU_INTERRUPT_INIT) { 442c97d6d2cSSergio Andres Gomez Del Real hvf_cpu_synchronize_state(cpu_state); 443c97d6d2cSSergio Andres Gomez Del Real do_cpu_init(cpu); 444c97d6d2cSSergio Andres Gomez Del Real } 445c97d6d2cSSergio Andres Gomez Del Real 446c97d6d2cSSergio Andres Gomez Del Real if (cpu_state->interrupt_request & CPU_INTERRUPT_POLL) { 447c97d6d2cSSergio Andres Gomez Del Real cpu_state->interrupt_request &= ~CPU_INTERRUPT_POLL; 448c97d6d2cSSergio Andres Gomez Del Real apic_poll_irq(cpu->apic_state); 449c97d6d2cSSergio Andres Gomez Del Real } 450c97d6d2cSSergio Andres Gomez Del Real if (((cpu_state->interrupt_request & CPU_INTERRUPT_HARD) && 451c97d6d2cSSergio Andres Gomez Del Real (EFLAGS(env) & IF_MASK)) || 452c97d6d2cSSergio Andres Gomez Del Real (cpu_state->interrupt_request & CPU_INTERRUPT_NMI)) { 453c97d6d2cSSergio Andres Gomez Del Real cpu_state->halted = 0; 454c97d6d2cSSergio Andres Gomez Del Real } 455c97d6d2cSSergio Andres Gomez Del Real if (cpu_state->interrupt_request & CPU_INTERRUPT_SIPI) { 456c97d6d2cSSergio Andres Gomez Del Real hvf_cpu_synchronize_state(cpu_state); 457c97d6d2cSSergio Andres Gomez Del Real do_cpu_sipi(cpu); 458c97d6d2cSSergio Andres Gomez Del Real } 459c97d6d2cSSergio Andres Gomez Del Real if (cpu_state->interrupt_request & CPU_INTERRUPT_TPR) { 460c97d6d2cSSergio Andres Gomez Del Real cpu_state->interrupt_request &= ~CPU_INTERRUPT_TPR; 461c97d6d2cSSergio Andres Gomez Del Real hvf_cpu_synchronize_state(cpu_state); 462c97d6d2cSSergio Andres Gomez Del Real apic_handle_tpr_access_report(cpu->apic_state, env->eip, 463c97d6d2cSSergio Andres Gomez Del Real env->tpr_access_type); 464c97d6d2cSSergio Andres Gomez Del Real } 465c97d6d2cSSergio Andres Gomez Del Real return cpu_state->halted; 466c97d6d2cSSergio Andres Gomez Del Real } 467