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