]> git.proxmox.com Git - mirror_qemu.git/blame - target/i386/hvf/hvf.c
hvf: Split out common code on vcpu init and destroy
[mirror_qemu.git] / target / i386 / hvf / hvf.c
CommitLineData
c97d6d2c
SAGDR
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
e361a772 16 * General Public License for more details.
c97d6d2c 17 *
e361a772
TH
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/>.
d781e24d
IE
20 *
21 * This file contain code under public domain from the hvdos project:
22 * https://github.com/mist64/hvdos
4d98a8e5
PB
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.
c97d6d2c 47 */
54d31236 48
c97d6d2c
SAGDR
49#include "qemu/osdep.h"
50#include "qemu-common.h"
51#include "qemu/error-report.h"
52
53#include "sysemu/hvf.h"
d57bc3c1 54#include "sysemu/hvf_int.h"
54d31236 55#include "sysemu/runstate.h"
c97d6d2c 56#include "hvf-i386.h"
69e0a03c
PB
57#include "vmcs.h"
58#include "vmx.h"
59#include "x86.h"
60#include "x86_descr.h"
61#include "x86_mmu.h"
62#include "x86_decode.h"
63#include "x86_emu.h"
64#include "x86_task.h"
65#include "x86hvf.h"
c97d6d2c
SAGDR
66
67#include <Hypervisor/hv.h>
68#include <Hypervisor/hv_vmx.h>
3b502b0e 69#include <sys/sysctl.h>
c97d6d2c 70
c97d6d2c 71#include "hw/i386/apic_internal.h"
c97d6d2c 72#include "qemu/main-loop.h"
940e43aa 73#include "qemu/accel.h"
c97d6d2c
SAGDR
74#include "target/i386/cpu.h"
75
b86f59c7 76#include "hvf-accel-ops.h"
b52bcba7 77
c97d6d2c
SAGDR
78void vmx_update_tpr(CPUState *cpu)
79{
80 /* TODO: need integrate APIC handling */
81 X86CPU *x86_cpu = X86_CPU(cpu);
82 int tpr = cpu_get_apic_tpr(x86_cpu->apic_state) << 4;
83 int irr = apic_get_highest_priority_irr(x86_cpu->apic_state);
84
85 wreg(cpu->hvf_fd, HV_X86_TPR, tpr);
86 if (irr == -1) {
87 wvmcs(cpu->hvf_fd, VMCS_TPR_THRESHOLD, 0);
88 } else {
89 wvmcs(cpu->hvf_fd, VMCS_TPR_THRESHOLD, (irr > tpr) ? tpr >> 4 :
90 irr >> 4);
91 }
92}
93
583ae161 94static void update_apic_tpr(CPUState *cpu)
c97d6d2c
SAGDR
95{
96 X86CPU *x86_cpu = X86_CPU(cpu);
97 int tpr = rreg(cpu->hvf_fd, HV_X86_TPR) >> 4;
98 cpu_set_apic_tpr(x86_cpu->apic_state, tpr);
99}
100
101#define VECTORING_INFO_VECTOR_MASK 0xff
102
c97d6d2c
SAGDR
103void hvf_handle_io(CPUArchState *env, uint16_t port, void *buffer,
104 int direction, int size, int count)
105{
106 int i;
107 uint8_t *ptr = buffer;
108
109 for (i = 0; i < count; i++) {
110 address_space_rw(&address_space_io, port, MEMTXATTRS_UNSPECIFIED,
111 ptr, size,
112 direction);
113 ptr += size;
114 }
115}
116
ff2de166 117static bool ept_emulation_fault(hvf_slot *slot, uint64_t gpa, uint64_t ept_qual)
c97d6d2c
SAGDR
118{
119 int read, write;
120
121 /* EPT fault on an instruction fetch doesn't make sense here */
122 if (ept_qual & EPT_VIOLATION_INST_FETCH) {
123 return false;
124 }
125
126 /* EPT fault must be a read fault or a write fault */
127 read = ept_qual & EPT_VIOLATION_DATA_READ ? 1 : 0;
128 write = ept_qual & EPT_VIOLATION_DATA_WRITE ? 1 : 0;
129 if ((read | write) == 0) {
130 return false;
131 }
132
babfa20c
SAGDR
133 if (write && slot) {
134 if (slot->flags & HVF_SLOT_LOG) {
135 memory_region_set_dirty(slot->region, gpa - slot->start, 1);
136 hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size,
137 HV_MEMORY_READ | HV_MEMORY_WRITE);
138 }
139 }
140
c97d6d2c
SAGDR
141 /*
142 * The EPT violation must have been caused by accessing a
143 * guest-physical address that is a translation of a guest-linear
144 * address.
145 */
146 if ((ept_qual & EPT_VIOLATION_GLA_VALID) == 0 ||
147 (ept_qual & EPT_VIOLATION_XLAT_VALID) == 0) {
148 return false;
149 }
150
fbafbb6d
CE
151 if (!slot) {
152 return true;
153 }
154 if (!memory_region_is_ram(slot->region) &&
155 !(read && memory_region_is_romd(slot->region))) {
156 return true;
157 }
158 return false;
babfa20c
SAGDR
159}
160
cfe58455 161void hvf_arch_vcpu_destroy(CPUState *cpu)
c97d6d2c 162{
fe76b09c
RB
163 X86CPU *x86_cpu = X86_CPU(cpu);
164 CPUX86State *env = &x86_cpu->env;
165
fe76b09c 166 g_free(env->hvf_mmio_buf);
c97d6d2c
SAGDR
167}
168
3b502b0e
VY
169static void init_tsc_freq(CPUX86State *env)
170{
171 size_t length;
172 uint64_t tsc_freq;
173
174 if (env->tsc_khz != 0) {
175 return;
176 }
177
178 length = sizeof(uint64_t);
179 if (sysctlbyname("machdep.tsc.frequency", &tsc_freq, &length, NULL, 0)) {
180 return;
181 }
182 env->tsc_khz = tsc_freq / 1000; /* Hz to KHz */
183}
184
185static void init_apic_bus_freq(CPUX86State *env)
186{
187 size_t length;
188 uint64_t bus_freq;
189
190 if (env->apic_bus_freq != 0) {
191 return;
192 }
193
194 length = sizeof(uint64_t);
195 if (sysctlbyname("hw.busfrequency", &bus_freq, &length, NULL, 0)) {
196 return;
197 }
198 env->apic_bus_freq = bus_freq;
199}
200
201static inline bool tsc_is_known(CPUX86State *env)
202{
203 return env->tsc_khz != 0;
204}
205
206static inline bool apic_bus_freq_is_known(CPUX86State *env)
207{
208 return env->apic_bus_freq != 0;
209}
210
cfe58455 211int hvf_arch_init_vcpu(CPUState *cpu)
c97d6d2c 212{
c97d6d2c
SAGDR
213 X86CPU *x86cpu = X86_CPU(cpu);
214 CPUX86State *env = &x86cpu->env;
c97d6d2c
SAGDR
215
216 init_emu();
217 init_decoder();
218
219 hvf_state->hvf_caps = g_new0(struct hvf_vcpu_caps, 1);
fe76b09c 220 env->hvf_mmio_buf = g_new(char, 4096);
c97d6d2c 221
3b502b0e
VY
222 if (x86cpu->vmware_cpuid_freq) {
223 init_tsc_freq(env);
224 init_apic_bus_freq(env);
225
226 if (!tsc_is_known(env) || !apic_bus_freq_is_known(env)) {
227 error_report("vmware-cpuid-freq: feature couldn't be enabled");
228 }
229 }
230
c97d6d2c
SAGDR
231 if (hv_vmx_read_capability(HV_VMX_CAP_PINBASED,
232 &hvf_state->hvf_caps->vmx_cap_pinbased)) {
233 abort();
234 }
235 if (hv_vmx_read_capability(HV_VMX_CAP_PROCBASED,
236 &hvf_state->hvf_caps->vmx_cap_procbased)) {
237 abort();
238 }
239 if (hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2,
240 &hvf_state->hvf_caps->vmx_cap_procbased2)) {
241 abort();
242 }
243 if (hv_vmx_read_capability(HV_VMX_CAP_ENTRY,
244 &hvf_state->hvf_caps->vmx_cap_entry)) {
245 abort();
246 }
247
248 /* set VMCS control fields */
249 wvmcs(cpu->hvf_fd, VMCS_PIN_BASED_CTLS,
250 cap2ctrl(hvf_state->hvf_caps->vmx_cap_pinbased,
251 VMCS_PIN_BASED_CTLS_EXTINT |
252 VMCS_PIN_BASED_CTLS_NMI |
253 VMCS_PIN_BASED_CTLS_VNMI));
254 wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS,
255 cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased,
256 VMCS_PRI_PROC_BASED_CTLS_HLT |
257 VMCS_PRI_PROC_BASED_CTLS_MWAIT |
258 VMCS_PRI_PROC_BASED_CTLS_TSC_OFFSET |
259 VMCS_PRI_PROC_BASED_CTLS_TPR_SHADOW) |
260 VMCS_PRI_PROC_BASED_CTLS_SEC_CONTROL);
261 wvmcs(cpu->hvf_fd, VMCS_SEC_PROC_BASED_CTLS,
262 cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased2,
263 VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES));
264
265 wvmcs(cpu->hvf_fd, VMCS_ENTRY_CTLS, cap2ctrl(hvf_state->hvf_caps->vmx_cap_entry,
266 0));
267 wvmcs(cpu->hvf_fd, VMCS_EXCEPTION_BITMAP, 0); /* Double fault */
268
269 wvmcs(cpu->hvf_fd, VMCS_TPR_THRESHOLD, 0);
270
c97d6d2c 271 x86cpu = X86_CPU(cpu);
5b8063c4 272 x86cpu->env.xsave_buf = qemu_memalign(4096, 4096);
c97d6d2c
SAGDR
273
274 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_STAR, 1);
275 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_LSTAR, 1);
276 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_CSTAR, 1);
277 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_FMASK, 1);
278 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_FSBASE, 1);
279 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_GSBASE, 1);
280 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_KERNELGSBASE, 1);
281 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_TSC_AUX, 1);
9fedbbee 282 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_TSC, 1);
c97d6d2c
SAGDR
283 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_SYSENTER_CS, 1);
284 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_SYSENTER_EIP, 1);
285 hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_SYSENTER_ESP, 1);
286
287 return 0;
288}
289
b7394c83
SAGDR
290static void hvf_store_events(CPUState *cpu, uint32_t ins_len, uint64_t idtvec_info)
291{
292 X86CPU *x86_cpu = X86_CPU(cpu);
293 CPUX86State *env = &x86_cpu->env;
294
fd13f23b
LA
295 env->exception_nr = -1;
296 env->exception_pending = 0;
297 env->exception_injected = 0;
b7394c83
SAGDR
298 env->interrupt_injected = -1;
299 env->nmi_injected = false;
64bef038
CE
300 env->ins_len = 0;
301 env->has_error_code = false;
b7394c83
SAGDR
302 if (idtvec_info & VMCS_IDT_VEC_VALID) {
303 switch (idtvec_info & VMCS_IDT_VEC_TYPE) {
304 case VMCS_IDT_VEC_HWINTR:
305 case VMCS_IDT_VEC_SWINTR:
306 env->interrupt_injected = idtvec_info & VMCS_IDT_VEC_VECNUM;
307 break;
308 case VMCS_IDT_VEC_NMI:
309 env->nmi_injected = true;
310 break;
311 case VMCS_IDT_VEC_HWEXCEPTION:
312 case VMCS_IDT_VEC_SWEXCEPTION:
fd13f23b
LA
313 env->exception_nr = idtvec_info & VMCS_IDT_VEC_VECNUM;
314 env->exception_injected = 1;
b7394c83
SAGDR
315 break;
316 case VMCS_IDT_VEC_PRIV_SWEXCEPTION:
317 default:
318 abort();
319 }
320 if ((idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWEXCEPTION ||
321 (idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWINTR) {
322 env->ins_len = ins_len;
323 }
64bef038 324 if (idtvec_info & VMCS_IDT_VEC_ERRCODE_VALID) {
b7394c83
SAGDR
325 env->has_error_code = true;
326 env->error_code = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_ERROR);
327 }
328 }
329 if ((rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
330 VMCS_INTERRUPTIBILITY_NMI_BLOCKING)) {
331 env->hflags2 |= HF2_NMI_MASK;
332 } else {
333 env->hflags2 &= ~HF2_NMI_MASK;
334 }
335 if (rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
336 (VMCS_INTERRUPTIBILITY_STI_BLOCKING |
337 VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)) {
338 env->hflags |= HF_INHIBIT_IRQ_MASK;
339 } else {
340 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
341 }
342}
343
3b502b0e
VY
344static void hvf_cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
345 uint32_t *eax, uint32_t *ebx,
346 uint32_t *ecx, uint32_t *edx)
347{
348 /*
349 * A wrapper extends cpu_x86_cpuid with 0x40000000 and 0x40000010 leafs,
350 * leafs 0x40000001-0x4000000F are filled with zeros
351 * Provides vmware-cpuid-freq support to hvf
352 *
353 * Note: leaf 0x40000000 not exposes HVF,
354 * leaving hypervisor signature empty
355 */
356
357 if (index < 0x40000000 || index > 0x40000010 ||
358 !tsc_is_known(env) || !apic_bus_freq_is_known(env)) {
359
360 cpu_x86_cpuid(env, index, count, eax, ebx, ecx, edx);
361 return;
362 }
363
364 switch (index) {
365 case 0x40000000:
366 *eax = 0x40000010; /* Max available cpuid leaf */
367 *ebx = 0; /* Leave signature empty */
368 *ecx = 0;
369 *edx = 0;
370 break;
371 case 0x40000010:
372 *eax = env->tsc_khz;
373 *ebx = env->apic_bus_freq / 1000; /* Hz to KHz */
374 *ecx = 0;
375 *edx = 0;
376 break;
377 default:
378 *eax = 0;
379 *ebx = 0;
380 *ecx = 0;
381 *edx = 0;
382 break;
383 }
384}
385
c97d6d2c
SAGDR
386int hvf_vcpu_exec(CPUState *cpu)
387{
388 X86CPU *x86_cpu = X86_CPU(cpu);
389 CPUX86State *env = &x86_cpu->env;
390 int ret = 0;
391 uint64_t rip = 0;
392
c97d6d2c
SAGDR
393 if (hvf_process_events(cpu)) {
394 return EXCP_HLT;
395 }
396
397 do {
398 if (cpu->vcpu_dirty) {
399 hvf_put_registers(cpu);
400 cpu->vcpu_dirty = false;
401 }
402
b7394c83
SAGDR
403 if (hvf_inject_interrupts(cpu)) {
404 return EXCP_INTERRUPT;
405 }
c97d6d2c
SAGDR
406 vmx_update_tpr(cpu);
407
408 qemu_mutex_unlock_iothread();
409 if (!cpu_is_bsp(X86_CPU(cpu)) && cpu->halted) {
410 qemu_mutex_lock_iothread();
411 return EXCP_HLT;
412 }
413
414 hv_return_t r = hv_vcpu_run(cpu->hvf_fd);
415 assert_hvf_ok(r);
416
417 /* handle VMEXIT */
418 uint64_t exit_reason = rvmcs(cpu->hvf_fd, VMCS_EXIT_REASON);
419 uint64_t exit_qual = rvmcs(cpu->hvf_fd, VMCS_EXIT_QUALIFICATION);
420 uint32_t ins_len = (uint32_t)rvmcs(cpu->hvf_fd,
421 VMCS_EXIT_INSTRUCTION_LENGTH);
b7394c83 422
c97d6d2c 423 uint64_t idtvec_info = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_INFO);
b7394c83
SAGDR
424
425 hvf_store_events(cpu, ins_len, idtvec_info);
c97d6d2c 426 rip = rreg(cpu->hvf_fd, HV_X86_RIP);
967f4da2 427 env->eflags = rreg(cpu->hvf_fd, HV_X86_RFLAGS);
c97d6d2c
SAGDR
428
429 qemu_mutex_lock_iothread();
430
431 update_apic_tpr(cpu);
432 current_cpu = cpu;
433
434 ret = 0;
435 switch (exit_reason) {
436 case EXIT_REASON_HLT: {
437 macvm_set_rip(cpu, rip + ins_len);
438 if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
967f4da2 439 (env->eflags & IF_MASK))
c97d6d2c
SAGDR
440 && !(cpu->interrupt_request & CPU_INTERRUPT_NMI) &&
441 !(idtvec_info & VMCS_IDT_VEC_VALID)) {
442 cpu->halted = 1;
443 ret = EXCP_HLT;
3b9c59da 444 break;
c97d6d2c
SAGDR
445 }
446 ret = EXCP_INTERRUPT;
447 break;
448 }
449 case EXIT_REASON_MWAIT: {
450 ret = EXCP_INTERRUPT;
451 break;
452 }
fbafbb6d 453 /* Need to check if MMIO or unmapped fault */
c97d6d2c
SAGDR
454 case EXIT_REASON_EPT_FAULT:
455 {
456 hvf_slot *slot;
ff2de166 457 uint64_t gpa = rvmcs(cpu->hvf_fd, VMCS_GUEST_PHYSICAL_ADDRESS);
c97d6d2c
SAGDR
458
459 if (((idtvec_info & VMCS_IDT_VEC_VALID) == 0) &&
460 ((exit_qual & EXIT_QUAL_NMIUDTI) != 0)) {
461 vmx_set_nmi_blocking(cpu);
462 }
463
fbafbb6d 464 slot = hvf_find_overlap_slot(gpa, 1);
c97d6d2c 465 /* mmio */
babfa20c 466 if (ept_emulation_fault(slot, gpa, exit_qual)) {
c97d6d2c
SAGDR
467 struct x86_decode decode;
468
469 load_regs(cpu);
c97d6d2c
SAGDR
470 decode_instruction(env, &decode);
471 exec_instruction(env, &decode);
472 store_regs(cpu);
473 break;
474 }
c97d6d2c
SAGDR
475 break;
476 }
477 case EXIT_REASON_INOUT:
478 {
479 uint32_t in = (exit_qual & 8) != 0;
480 uint32_t size = (exit_qual & 7) + 1;
481 uint32_t string = (exit_qual & 16) != 0;
482 uint32_t port = exit_qual >> 16;
483 /*uint32_t rep = (exit_qual & 0x20) != 0;*/
484
c97d6d2c
SAGDR
485 if (!string && in) {
486 uint64_t val = 0;
487 load_regs(cpu);
488 hvf_handle_io(env, port, &val, 0, size, 1);
489 if (size == 1) {
490 AL(env) = val;
491 } else if (size == 2) {
492 AX(env) = val;
493 } else if (size == 4) {
494 RAX(env) = (uint32_t)val;
495 } else {
da20f5cd 496 RAX(env) = (uint64_t)val;
c97d6d2c 497 }
5d32173f 498 env->eip += ins_len;
c97d6d2c
SAGDR
499 store_regs(cpu);
500 break;
501 } else if (!string && !in) {
502 RAX(env) = rreg(cpu->hvf_fd, HV_X86_RAX);
503 hvf_handle_io(env, port, &RAX(env), 1, size, 1);
504 macvm_set_rip(cpu, rip + ins_len);
505 break;
506 }
c97d6d2c
SAGDR
507 struct x86_decode decode;
508
509 load_regs(cpu);
c97d6d2c 510 decode_instruction(env, &decode);
e62963bf 511 assert(ins_len == decode.len);
c97d6d2c
SAGDR
512 exec_instruction(env, &decode);
513 store_regs(cpu);
514
515 break;
516 }
517 case EXIT_REASON_CPUID: {
518 uint32_t rax = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RAX);
519 uint32_t rbx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RBX);
520 uint32_t rcx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RCX);
521 uint32_t rdx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RDX);
522
106f91d5
AG
523 if (rax == 1) {
524 /* CPUID1.ecx.OSXSAVE needs to know CR4 */
525 env->cr[4] = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR4);
526 }
3b502b0e 527 hvf_cpu_x86_cpuid(env, rax, rcx, &rax, &rbx, &rcx, &rdx);
c97d6d2c
SAGDR
528
529 wreg(cpu->hvf_fd, HV_X86_RAX, rax);
530 wreg(cpu->hvf_fd, HV_X86_RBX, rbx);
531 wreg(cpu->hvf_fd, HV_X86_RCX, rcx);
532 wreg(cpu->hvf_fd, HV_X86_RDX, rdx);
533
534 macvm_set_rip(cpu, rip + ins_len);
535 break;
536 }
537 case EXIT_REASON_XSETBV: {
538 X86CPU *x86_cpu = X86_CPU(cpu);
539 CPUX86State *env = &x86_cpu->env;
540 uint32_t eax = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RAX);
541 uint32_t ecx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RCX);
542 uint32_t edx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RDX);
543
544 if (ecx) {
545 macvm_set_rip(cpu, rip + ins_len);
546 break;
547 }
548 env->xcr0 = ((uint64_t)edx << 32) | eax;
549 wreg(cpu->hvf_fd, HV_X86_XCR0, env->xcr0 | 1);
550 macvm_set_rip(cpu, rip + ins_len);
551 break;
552 }
553 case EXIT_REASON_INTR_WINDOW:
554 vmx_clear_int_window_exiting(cpu);
555 ret = EXCP_INTERRUPT;
556 break;
557 case EXIT_REASON_NMI_WINDOW:
558 vmx_clear_nmi_window_exiting(cpu);
559 ret = EXCP_INTERRUPT;
560 break;
561 case EXIT_REASON_EXT_INTR:
562 /* force exit and allow io handling */
563 ret = EXCP_INTERRUPT;
564 break;
565 case EXIT_REASON_RDMSR:
566 case EXIT_REASON_WRMSR:
567 {
568 load_regs(cpu);
569 if (exit_reason == EXIT_REASON_RDMSR) {
570 simulate_rdmsr(cpu);
571 } else {
572 simulate_wrmsr(cpu);
573 }
5d32173f 574 env->eip += ins_len;
c97d6d2c
SAGDR
575 store_regs(cpu);
576 break;
577 }
578 case EXIT_REASON_CR_ACCESS: {
579 int cr;
580 int reg;
581
582 load_regs(cpu);
583 cr = exit_qual & 15;
584 reg = (exit_qual >> 8) & 15;
585
586 switch (cr) {
587 case 0x0: {
588 macvm_set_cr0(cpu->hvf_fd, RRX(env, reg));
589 break;
590 }
591 case 4: {
592 macvm_set_cr4(cpu->hvf_fd, RRX(env, reg));
593 break;
594 }
595 case 8: {
596 X86CPU *x86_cpu = X86_CPU(cpu);
597 if (exit_qual & 0x10) {
598 RRX(env, reg) = cpu_get_apic_tpr(x86_cpu->apic_state);
599 } else {
600 int tpr = RRX(env, reg);
601 cpu_set_apic_tpr(x86_cpu->apic_state, tpr);
602 ret = EXCP_INTERRUPT;
603 }
604 break;
605 }
606 default:
2d9178d9 607 error_report("Unrecognized CR %d", cr);
c97d6d2c
SAGDR
608 abort();
609 }
5d32173f 610 env->eip += ins_len;
c97d6d2c
SAGDR
611 store_regs(cpu);
612 break;
613 }
614 case EXIT_REASON_APIC_ACCESS: { /* TODO */
615 struct x86_decode decode;
616
617 load_regs(cpu);
c97d6d2c
SAGDR
618 decode_instruction(env, &decode);
619 exec_instruction(env, &decode);
620 store_regs(cpu);
621 break;
622 }
623 case EXIT_REASON_TPR: {
624 ret = 1;
625 break;
626 }
627 case EXIT_REASON_TASK_SWITCH: {
628 uint64_t vinfo = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_INFO);
629 x68_segment_selector sel = {.sel = exit_qual & 0xffff};
630 vmx_handle_task_switch(cpu, sel, (exit_qual >> 30) & 0x3,
631 vinfo & VMCS_INTR_VALID, vinfo & VECTORING_INFO_VECTOR_MASK, vinfo
632 & VMCS_INTR_T_MASK);
633 break;
634 }
635 case EXIT_REASON_TRIPLE_FAULT: {
636 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
637 ret = EXCP_INTERRUPT;
638 break;
639 }
640 case EXIT_REASON_RDPMC:
641 wreg(cpu->hvf_fd, HV_X86_RAX, 0);
642 wreg(cpu->hvf_fd, HV_X86_RDX, 0);
643 macvm_set_rip(cpu, rip + ins_len);
644 break;
645 case VMX_REASON_VMCALL:
fd13f23b
LA
646 env->exception_nr = EXCP0D_GPF;
647 env->exception_injected = 1;
3010460f
SAGDR
648 env->has_error_code = true;
649 env->error_code = 0;
c97d6d2c
SAGDR
650 break;
651 default:
2d9178d9 652 error_report("%llx: unhandled exit %llx", rip, exit_reason);
c97d6d2c
SAGDR
653 }
654 } while (ret == 0);
655
656 return ret;
657}