xref: /qemu/target/i386/hvf/x86hvf.c (revision 6701d81d74b3fbc7afd73a18d1c82602a811e409)
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 
22f9fea777SPaolo Bonzini #include "qemu-common.h"
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 
79f585195eSSergio 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 
83f585195eSSergio Andres Gomez Del Real     x86_cpu_xsave_all_areas(X86_CPU(cpu_state), xsave);
84c97d6d2cSSergio Andres Gomez Del Real 
85f585195eSSergio 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);
110*6701d81dSPaolo Bonzini     vmx_write_segment_descriptor(cpu_state, &seg, R_CS);
111c97d6d2cSSergio Andres Gomez Del Real 
112c97d6d2cSSergio Andres Gomez Del Real     hvf_set_segment(cpu_state, &seg, &env->segs[R_DS], false);
113*6701d81dSPaolo Bonzini     vmx_write_segment_descriptor(cpu_state, &seg, R_DS);
114c97d6d2cSSergio Andres Gomez Del Real 
115c97d6d2cSSergio Andres Gomez Del Real     hvf_set_segment(cpu_state, &seg, &env->segs[R_ES], false);
116*6701d81dSPaolo Bonzini     vmx_write_segment_descriptor(cpu_state, &seg, R_ES);
117c97d6d2cSSergio Andres Gomez Del Real 
118c97d6d2cSSergio Andres Gomez Del Real     hvf_set_segment(cpu_state, &seg, &env->segs[R_SS], false);
119*6701d81dSPaolo Bonzini     vmx_write_segment_descriptor(cpu_state, &seg, R_SS);
120c97d6d2cSSergio Andres Gomez Del Real 
121c97d6d2cSSergio Andres Gomez Del Real     hvf_set_segment(cpu_state, &seg, &env->segs[R_FS], false);
122*6701d81dSPaolo Bonzini     vmx_write_segment_descriptor(cpu_state, &seg, R_FS);
123c97d6d2cSSergio Andres Gomez Del Real 
124c97d6d2cSSergio Andres Gomez Del Real     hvf_set_segment(cpu_state, &seg, &env->segs[R_GS], false);
125*6701d81dSPaolo Bonzini     vmx_write_segment_descriptor(cpu_state, &seg, R_GS);
126c97d6d2cSSergio Andres Gomez Del Real 
127c97d6d2cSSergio Andres Gomez Del Real     hvf_set_segment(cpu_state, &seg, &env->tr, true);
128*6701d81dSPaolo Bonzini     vmx_write_segment_descriptor(cpu_state, &seg, R_TR);
129c97d6d2cSSergio Andres Gomez Del Real 
130c97d6d2cSSergio Andres Gomez Del Real     hvf_set_segment(cpu_state, &seg, &env->ldt, false);
131*6701d81dSPaolo Bonzini     vmx_write_segment_descriptor(cpu_state, &seg, R_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 {
167f585195eSSergio 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 
171f585195eSSergio 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 
175f585195eSSergio 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 
186*6701d81dSPaolo Bonzini     vmx_read_segment_descriptor(cpu_state, &seg, R_CS);
187c97d6d2cSSergio Andres Gomez Del Real     hvf_get_segment(&env->segs[R_CS], &seg);
188c97d6d2cSSergio Andres Gomez Del Real 
189*6701d81dSPaolo Bonzini     vmx_read_segment_descriptor(cpu_state, &seg, R_DS);
190c97d6d2cSSergio Andres Gomez Del Real     hvf_get_segment(&env->segs[R_DS], &seg);
191c97d6d2cSSergio Andres Gomez Del Real 
192*6701d81dSPaolo Bonzini     vmx_read_segment_descriptor(cpu_state, &seg, R_ES);
193c97d6d2cSSergio Andres Gomez Del Real     hvf_get_segment(&env->segs[R_ES], &seg);
194c97d6d2cSSergio Andres Gomez Del Real 
195*6701d81dSPaolo Bonzini     vmx_read_segment_descriptor(cpu_state, &seg, R_FS);
196c97d6d2cSSergio Andres Gomez Del Real     hvf_get_segment(&env->segs[R_FS], &seg);
197c97d6d2cSSergio Andres Gomez Del Real 
198*6701d81dSPaolo Bonzini     vmx_read_segment_descriptor(cpu_state, &seg, R_GS);
199c97d6d2cSSergio Andres Gomez Del Real     hvf_get_segment(&env->segs[R_GS], &seg);
200c97d6d2cSSergio Andres Gomez Del Real 
201*6701d81dSPaolo Bonzini     vmx_read_segment_descriptor(cpu_state, &seg, R_SS);
202c97d6d2cSSergio Andres Gomez Del Real     hvf_get_segment(&env->segs[R_SS], &seg);
203c97d6d2cSSergio Andres Gomez Del Real 
204*6701d81dSPaolo Bonzini     vmx_read_segment_descriptor(cpu_state, &seg, R_TR);
205c97d6d2cSSergio Andres Gomez Del Real     hvf_get_segment(&env->tr, &seg);
206c97d6d2cSSergio Andres Gomez Del Real 
207*6701d81dSPaolo Bonzini     vmx_read_segment_descriptor(cpu_state, &seg, R_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     X86CPU *x86cpu = X86_CPU(cpu_state);
360c97d6d2cSSergio Andres Gomez Del Real     CPUX86State *env = &x86cpu->env;
361c97d6d2cSSergio Andres Gomez Del Real 
362b7394c83SSergio Andres Gomez Del Real     uint8_t vector;
363b7394c83SSergio Andres Gomez Del Real     uint64_t intr_type;
364b7394c83SSergio Andres Gomez Del Real     bool have_event = true;
365b7394c83SSergio Andres Gomez Del Real     if (env->interrupt_injected != -1) {
366b7394c83SSergio Andres Gomez Del Real         vector = env->interrupt_injected;
367b7394c83SSergio Andres Gomez Del Real         intr_type = VMCS_INTR_T_SWINTR;
368b7394c83SSergio Andres Gomez Del Real     } else if (env->exception_injected != -1) {
369b7394c83SSergio Andres Gomez Del Real         vector = env->exception_injected;
370b7394c83SSergio Andres Gomez Del Real         if (vector == EXCP03_INT3 || vector == EXCP04_INTO) {
371b7394c83SSergio Andres Gomez Del Real             intr_type = VMCS_INTR_T_SWEXCEPTION;
372b7394c83SSergio Andres Gomez Del Real         } else {
373b7394c83SSergio Andres Gomez Del Real             intr_type = VMCS_INTR_T_HWEXCEPTION;
374b7394c83SSergio Andres Gomez Del Real         }
375b7394c83SSergio Andres Gomez Del Real     } else if (env->nmi_injected) {
376b7394c83SSergio Andres Gomez Del Real         vector = NMI_VEC;
377b7394c83SSergio Andres Gomez Del Real         intr_type = VMCS_INTR_T_NMI;
378b7394c83SSergio Andres Gomez Del Real     } else {
379b7394c83SSergio Andres Gomez Del Real         have_event = false;
380b7394c83SSergio Andres Gomez Del Real     }
381b7394c83SSergio Andres Gomez Del Real 
382c97d6d2cSSergio Andres Gomez Del Real     uint64_t info = 0;
383b7394c83SSergio Andres Gomez Del Real     if (have_event) {
384b7394c83SSergio Andres Gomez Del Real         info = vector | intr_type | VMCS_INTR_VALID;
385c97d6d2cSSergio Andres Gomez Del Real         uint64_t reason = rvmcs(cpu_state->hvf_fd, VMCS_EXIT_REASON);
386b7394c83SSergio Andres Gomez Del Real         if (env->nmi_injected && reason != EXIT_REASON_TASK_SWITCH) {
387c97d6d2cSSergio Andres Gomez Del Real             vmx_clear_nmi_blocking(cpu_state);
388c97d6d2cSSergio Andres Gomez Del Real         }
389c97d6d2cSSergio Andres Gomez Del Real 
390b7394c83SSergio Andres Gomez Del Real         if (!(env->hflags2 & HF2_NMI_MASK) || intr_type != VMCS_INTR_T_NMI) {
391c97d6d2cSSergio Andres Gomez Del Real             info &= ~(1 << 12); /* clear undefined bit */
392c97d6d2cSSergio Andres Gomez Del Real             if (intr_type == VMCS_INTR_T_SWINTR ||
393c97d6d2cSSergio Andres Gomez Del Real                 intr_type == VMCS_INTR_T_SWEXCEPTION) {
394b7394c83SSergio Andres Gomez Del Real                 wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, env->ins_len);
395c97d6d2cSSergio Andres Gomez Del Real             }
396c97d6d2cSSergio Andres Gomez Del Real 
397b7394c83SSergio Andres Gomez Del Real             if (env->has_error_code) {
398b7394c83SSergio Andres Gomez Del Real                 wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_EXCEPTION_ERROR,
399b7394c83SSergio Andres Gomez Del Real                       env->error_code);
400c97d6d2cSSergio Andres Gomez Del Real             }
401c97d6d2cSSergio Andres Gomez Del Real             /*printf("reinject  %lx err %d\n", info, err);*/
402c97d6d2cSSergio Andres Gomez Del Real             wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info);
403c97d6d2cSSergio Andres Gomez Del Real         };
404c97d6d2cSSergio Andres Gomez Del Real     }
405c97d6d2cSSergio Andres Gomez Del Real 
406c97d6d2cSSergio Andres Gomez Del Real     if (cpu_state->interrupt_request & CPU_INTERRUPT_NMI) {
407b7394c83SSergio Andres Gomez Del Real         if (!(env->hflags2 & HF2_NMI_MASK) && !(info & VMCS_INTR_VALID)) {
408c97d6d2cSSergio Andres Gomez Del Real             cpu_state->interrupt_request &= ~CPU_INTERRUPT_NMI;
409c97d6d2cSSergio Andres Gomez Del Real             info = VMCS_INTR_VALID | VMCS_INTR_T_NMI | NMI_VEC;
410c97d6d2cSSergio Andres Gomez Del Real             wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info);
411c97d6d2cSSergio Andres Gomez Del Real         } else {
412c97d6d2cSSergio Andres Gomez Del Real             vmx_set_nmi_window_exiting(cpu_state);
413c97d6d2cSSergio Andres Gomez Del Real         }
414c97d6d2cSSergio Andres Gomez Del Real     }
415c97d6d2cSSergio Andres Gomez Del Real 
416b7394c83SSergio Andres Gomez Del Real     if (!(env->hflags & HF_INHIBIT_IRQ_MASK) &&
417c97d6d2cSSergio Andres Gomez Del Real         (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) &&
418c97d6d2cSSergio Andres Gomez Del Real         (EFLAGS(env) & IF_MASK) && !(info & VMCS_INTR_VALID)) {
419c97d6d2cSSergio Andres Gomez Del Real         int line = cpu_get_pic_interrupt(&x86cpu->env);
420c97d6d2cSSergio Andres Gomez Del Real         cpu_state->interrupt_request &= ~CPU_INTERRUPT_HARD;
421c97d6d2cSSergio Andres Gomez Del Real         if (line >= 0) {
422c97d6d2cSSergio Andres Gomez Del Real             wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, line |
423c97d6d2cSSergio Andres Gomez Del Real                   VMCS_INTR_VALID | VMCS_INTR_T_HWINTR);
424c97d6d2cSSergio Andres Gomez Del Real         }
425c97d6d2cSSergio Andres Gomez Del Real     }
426c97d6d2cSSergio Andres Gomez Del Real     if (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) {
427c97d6d2cSSergio Andres Gomez Del Real         vmx_set_int_window_exiting(cpu_state);
428c97d6d2cSSergio Andres Gomez Del Real     }
429b7394c83SSergio Andres Gomez Del Real     return (cpu_state->interrupt_request
430b7394c83SSergio Andres Gomez Del Real             & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR));
431c97d6d2cSSergio Andres Gomez Del Real }
432c97d6d2cSSergio Andres Gomez Del Real 
433c97d6d2cSSergio Andres Gomez Del Real int hvf_process_events(CPUState *cpu_state)
434c97d6d2cSSergio Andres Gomez Del Real {
435c97d6d2cSSergio Andres Gomez Del Real     X86CPU *cpu = X86_CPU(cpu_state);
436c97d6d2cSSergio Andres Gomez Del Real     CPUX86State *env = &cpu->env;
437c97d6d2cSSergio Andres Gomez Del Real 
438c97d6d2cSSergio Andres Gomez Del Real     EFLAGS(env) = rreg(cpu_state->hvf_fd, HV_X86_RFLAGS);
439c97d6d2cSSergio Andres Gomez Del Real 
440c97d6d2cSSergio Andres Gomez Del Real     if (cpu_state->interrupt_request & CPU_INTERRUPT_INIT) {
441c97d6d2cSSergio Andres Gomez Del Real         hvf_cpu_synchronize_state(cpu_state);
442c97d6d2cSSergio Andres Gomez Del Real         do_cpu_init(cpu);
443c97d6d2cSSergio Andres Gomez Del Real     }
444c97d6d2cSSergio Andres Gomez Del Real 
445c97d6d2cSSergio Andres Gomez Del Real     if (cpu_state->interrupt_request & CPU_INTERRUPT_POLL) {
446c97d6d2cSSergio Andres Gomez Del Real         cpu_state->interrupt_request &= ~CPU_INTERRUPT_POLL;
447c97d6d2cSSergio Andres Gomez Del Real         apic_poll_irq(cpu->apic_state);
448c97d6d2cSSergio Andres Gomez Del Real     }
449c97d6d2cSSergio Andres Gomez Del Real     if (((cpu_state->interrupt_request & CPU_INTERRUPT_HARD) &&
450c97d6d2cSSergio Andres Gomez Del Real         (EFLAGS(env) & IF_MASK)) ||
451c97d6d2cSSergio Andres Gomez Del Real         (cpu_state->interrupt_request & CPU_INTERRUPT_NMI)) {
452c97d6d2cSSergio Andres Gomez Del Real         cpu_state->halted = 0;
453c97d6d2cSSergio Andres Gomez Del Real     }
454c97d6d2cSSergio Andres Gomez Del Real     if (cpu_state->interrupt_request & CPU_INTERRUPT_SIPI) {
455c97d6d2cSSergio Andres Gomez Del Real         hvf_cpu_synchronize_state(cpu_state);
456c97d6d2cSSergio Andres Gomez Del Real         do_cpu_sipi(cpu);
457c97d6d2cSSergio Andres Gomez Del Real     }
458c97d6d2cSSergio Andres Gomez Del Real     if (cpu_state->interrupt_request & CPU_INTERRUPT_TPR) {
459c97d6d2cSSergio Andres Gomez Del Real         cpu_state->interrupt_request &= ~CPU_INTERRUPT_TPR;
460c97d6d2cSSergio Andres Gomez Del Real         hvf_cpu_synchronize_state(cpu_state);
461c97d6d2cSSergio Andres Gomez Del Real         apic_handle_tpr_access_report(cpu->apic_state, env->eip,
462c97d6d2cSSergio Andres Gomez Del Real                                       env->tpr_access_type);
463c97d6d2cSSergio Andres Gomez Del Real     }
464c97d6d2cSSergio Andres Gomez Del Real     return cpu_state->halted;
465c97d6d2cSSergio Andres Gomez Del Real }
466