VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp@ 96407

Last change on this file since 96407 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 163.6 KB
Line 
1/* $Id: NEMR3Native-darwin.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * NEM - Native execution manager, native ring-3 macOS backend using Hypervisor.framework.
4 *
5 * Log group 2: Exit logging.
6 * Log group 3: Log context on exit.
7 * Log group 5: Ring-3 memory management
8 */
9
10/*
11 * Copyright (C) 2020-2022 Oracle and/or its affiliates.
12 *
13 * This file is part of VirtualBox base platform packages, as
14 * available from https://www.virtualbox.org.
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation, in version 3 of the
19 * License.
20 *
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see <https://www.gnu.org/licenses>.
28 *
29 * SPDX-License-Identifier: GPL-3.0-only
30 */
31
32
33/*********************************************************************************************************************************
34* Header Files *
35*********************************************************************************************************************************/
36#define LOG_GROUP LOG_GROUP_NEM
37#define VMCPU_INCL_CPUM_GST_CTX
38#include <VBox/vmm/nem.h>
39#include <VBox/vmm/iem.h>
40#include <VBox/vmm/em.h>
41#include <VBox/vmm/apic.h>
42#include <VBox/vmm/pdm.h>
43#include <VBox/vmm/hm.h>
44#include <VBox/vmm/hm_vmx.h>
45#include <VBox/vmm/dbgftrace.h>
46#include <VBox/vmm/gcm.h>
47#include "VMXInternal.h"
48#include "NEMInternal.h"
49#include <VBox/vmm/vmcc.h>
50#include "dtrace/VBoxVMM.h"
51
52#include <iprt/asm.h>
53#include <iprt/ldr.h>
54#include <iprt/mem.h>
55#include <iprt/path.h>
56#include <iprt/string.h>
57#include <iprt/system.h>
58#include <iprt/utf16.h>
59
60#include <mach/mach_time.h>
61#include <mach/kern_return.h>
62
63
64/*********************************************************************************************************************************
65* Defined Constants And Macros *
66*********************************************************************************************************************************/
67/* No nested hwvirt (for now). */
68#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
69# undef VBOX_WITH_NESTED_HWVIRT_VMX
70#endif
71
72
73/** @name HV return codes.
74 * @{ */
75/** Operation was successful. */
76#define HV_SUCCESS 0
77/** An error occurred during operation. */
78#define HV_ERROR 0xfae94001
79/** The operation could not be completed right now, try again. */
80#define HV_BUSY 0xfae94002
81/** One of the parameters passed wis invalid. */
82#define HV_BAD_ARGUMENT 0xfae94003
83/** Not enough resources left to fulfill the operation. */
84#define HV_NO_RESOURCES 0xfae94005
85/** The device could not be found. */
86#define HV_NO_DEVICE 0xfae94006
87/** The operation is not supportd on this platform with this configuration. */
88#define HV_UNSUPPORTED 0xfae94007
89/** @} */
90
91
92/** @name HV memory protection flags.
93 * @{ */
94/** Memory is readable. */
95#define HV_MEMORY_READ RT_BIT_64(0)
96/** Memory is writeable. */
97#define HV_MEMORY_WRITE RT_BIT_64(1)
98/** Memory is executable. */
99#define HV_MEMORY_EXEC RT_BIT_64(2)
100/** @} */
101
102
103/** @name HV shadow VMCS protection flags.
104 * @{ */
105/** Shadow VMCS field is not accessible. */
106#define HV_SHADOW_VMCS_NONE 0
107/** Shadow VMCS fild is readable. */
108#define HV_SHADOW_VMCS_READ RT_BIT_64(0)
109/** Shadow VMCS field is writeable. */
110#define HV_SHADOW_VMCS_WRITE RT_BIT_64(1)
111/** @} */
112
113
114/** Default VM creation flags. */
115#define HV_VM_DEFAULT 0
116/** Default guest address space creation flags. */
117#define HV_VM_SPACE_DEFAULT 0
118/** Default vCPU creation flags. */
119#define HV_VCPU_DEFAULT 0
120
121#define HV_DEADLINE_FOREVER UINT64_MAX
122
123
124/*********************************************************************************************************************************
125* Structures and Typedefs *
126*********************************************************************************************************************************/
127
128/** HV return code type. */
129typedef uint32_t hv_return_t;
130/** HV capability bitmask. */
131typedef uint64_t hv_capability_t;
132/** Option bitmask type when creating a VM. */
133typedef uint64_t hv_vm_options_t;
134/** Option bitmask when creating a vCPU. */
135typedef uint64_t hv_vcpu_options_t;
136/** HV memory protection flags type. */
137typedef uint64_t hv_memory_flags_t;
138/** Shadow VMCS protection flags. */
139typedef uint64_t hv_shadow_flags_t;
140/** Guest physical address type. */
141typedef uint64_t hv_gpaddr_t;
142
143
144/**
145 * VMX Capability enumeration.
146 */
147typedef enum
148{
149 HV_VMX_CAP_PINBASED = 0,
150 HV_VMX_CAP_PROCBASED,
151 HV_VMX_CAP_PROCBASED2,
152 HV_VMX_CAP_ENTRY,
153 HV_VMX_CAP_EXIT,
154 HV_VMX_CAP_BASIC, /* Since 11.0 */
155 HV_VMX_CAP_TRUE_PINBASED, /* Since 11.0 */
156 HV_VMX_CAP_TRUE_PROCBASED, /* Since 11.0 */
157 HV_VMX_CAP_TRUE_ENTRY, /* Since 11.0 */
158 HV_VMX_CAP_TRUE_EXIT, /* Since 11.0 */
159 HV_VMX_CAP_MISC, /* Since 11.0 */
160 HV_VMX_CAP_CR0_FIXED0, /* Since 11.0 */
161 HV_VMX_CAP_CR0_FIXED1, /* Since 11.0 */
162 HV_VMX_CAP_CR4_FIXED0, /* Since 11.0 */
163 HV_VMX_CAP_CR4_FIXED1, /* Since 11.0 */
164 HV_VMX_CAP_VMCS_ENUM, /* Since 11.0 */
165 HV_VMX_CAP_EPT_VPID_CAP, /* Since 11.0 */
166 HV_VMX_CAP_PREEMPTION_TIMER = 32
167} hv_vmx_capability_t;
168
169
170/**
171 * HV x86 register enumeration.
172 */
173typedef enum
174{
175 HV_X86_RIP = 0,
176 HV_X86_RFLAGS,
177 HV_X86_RAX,
178 HV_X86_RCX,
179 HV_X86_RDX,
180 HV_X86_RBX,
181 HV_X86_RSI,
182 HV_X86_RDI,
183 HV_X86_RSP,
184 HV_X86_RBP,
185 HV_X86_R8,
186 HV_X86_R9,
187 HV_X86_R10,
188 HV_X86_R11,
189 HV_X86_R12,
190 HV_X86_R13,
191 HV_X86_R14,
192 HV_X86_R15,
193 HV_X86_CS,
194 HV_X86_SS,
195 HV_X86_DS,
196 HV_X86_ES,
197 HV_X86_FS,
198 HV_X86_GS,
199 HV_X86_IDT_BASE,
200 HV_X86_IDT_LIMIT,
201 HV_X86_GDT_BASE,
202 HV_X86_GDT_LIMIT,
203 HV_X86_LDTR,
204 HV_X86_LDT_BASE,
205 HV_X86_LDT_LIMIT,
206 HV_X86_LDT_AR,
207 HV_X86_TR,
208 HV_X86_TSS_BASE,
209 HV_X86_TSS_LIMIT,
210 HV_X86_TSS_AR,
211 HV_X86_CR0,
212 HV_X86_CR1,
213 HV_X86_CR2,
214 HV_X86_CR3,
215 HV_X86_CR4,
216 HV_X86_DR0,
217 HV_X86_DR1,
218 HV_X86_DR2,
219 HV_X86_DR3,
220 HV_X86_DR4,
221 HV_X86_DR5,
222 HV_X86_DR6,
223 HV_X86_DR7,
224 HV_X86_TPR,
225 HV_X86_XCR0,
226 HV_X86_REGISTERS_MAX
227} hv_x86_reg_t;
228
229
230/** MSR permission flags type. */
231typedef uint32_t hv_msr_flags_t;
232/** MSR can't be accessed. */
233#define HV_MSR_NONE 0
234/** MSR is readable by the guest. */
235#define HV_MSR_READ RT_BIT(0)
236/** MSR is writeable by the guest. */
237#define HV_MSR_WRITE RT_BIT(1)
238
239
240typedef hv_return_t FN_HV_CAPABILITY(hv_capability_t capability, uint64_t *valu);
241typedef hv_return_t FN_HV_VM_CREATE(hv_vm_options_t flags);
242typedef hv_return_t FN_HV_VM_DESTROY(void);
243typedef hv_return_t FN_HV_VM_SPACE_CREATE(hv_vm_space_t *asid);
244typedef hv_return_t FN_HV_VM_SPACE_DESTROY(hv_vm_space_t asid);
245typedef hv_return_t FN_HV_VM_MAP(const void *uva, hv_gpaddr_t gpa, size_t size, hv_memory_flags_t flags);
246typedef hv_return_t FN_HV_VM_UNMAP(hv_gpaddr_t gpa, size_t size);
247typedef hv_return_t FN_HV_VM_PROTECT(hv_gpaddr_t gpa, size_t size, hv_memory_flags_t flags);
248typedef hv_return_t FN_HV_VM_MAP_SPACE(hv_vm_space_t asid, const void *uva, hv_gpaddr_t gpa, size_t size, hv_memory_flags_t flags);
249typedef hv_return_t FN_HV_VM_UNMAP_SPACE(hv_vm_space_t asid, hv_gpaddr_t gpa, size_t size);
250typedef hv_return_t FN_HV_VM_PROTECT_SPACE(hv_vm_space_t asid, hv_gpaddr_t gpa, size_t size, hv_memory_flags_t flags);
251typedef hv_return_t FN_HV_VM_SYNC_TSC(uint64_t tsc);
252
253typedef hv_return_t FN_HV_VCPU_CREATE(hv_vcpuid_t *vcpu, hv_vcpu_options_t flags);
254typedef hv_return_t FN_HV_VCPU_DESTROY(hv_vcpuid_t vcpu);
255typedef hv_return_t FN_HV_VCPU_SET_SPACE(hv_vcpuid_t vcpu, hv_vm_space_t asid);
256typedef hv_return_t FN_HV_VCPU_READ_REGISTER(hv_vcpuid_t vcpu, hv_x86_reg_t reg, uint64_t *value);
257typedef hv_return_t FN_HV_VCPU_WRITE_REGISTER(hv_vcpuid_t vcpu, hv_x86_reg_t reg, uint64_t value);
258typedef hv_return_t FN_HV_VCPU_READ_FPSTATE(hv_vcpuid_t vcpu, void *buffer, size_t size);
259typedef hv_return_t FN_HV_VCPU_WRITE_FPSTATE(hv_vcpuid_t vcpu, const void *buffer, size_t size);
260typedef hv_return_t FN_HV_VCPU_ENABLE_NATIVE_MSR(hv_vcpuid_t vcpu, uint32_t msr, bool enable);
261typedef hv_return_t FN_HV_VCPU_READ_MSR(hv_vcpuid_t vcpu, uint32_t msr, uint64_t *value);
262typedef hv_return_t FN_HV_VCPU_WRITE_MSR(hv_vcpuid_t vcpu, uint32_t msr, uint64_t value);
263typedef hv_return_t FN_HV_VCPU_FLUSH(hv_vcpuid_t vcpu);
264typedef hv_return_t FN_HV_VCPU_INVALIDATE_TLB(hv_vcpuid_t vcpu);
265typedef hv_return_t FN_HV_VCPU_RUN(hv_vcpuid_t vcpu);
266typedef hv_return_t FN_HV_VCPU_RUN_UNTIL(hv_vcpuid_t vcpu, uint64_t deadline);
267typedef hv_return_t FN_HV_VCPU_INTERRUPT(hv_vcpuid_t *vcpus, unsigned int vcpu_count);
268typedef hv_return_t FN_HV_VCPU_GET_EXEC_TIME(hv_vcpuid_t *vcpus, uint64_t *time);
269
270typedef hv_return_t FN_HV_VMX_VCPU_READ_VMCS(hv_vcpuid_t vcpu, uint32_t field, uint64_t *value);
271typedef hv_return_t FN_HV_VMX_VCPU_WRITE_VMCS(hv_vcpuid_t vcpu, uint32_t field, uint64_t value);
272
273typedef hv_return_t FN_HV_VMX_VCPU_READ_SHADOW_VMCS(hv_vcpuid_t vcpu, uint32_t field, uint64_t *value);
274typedef hv_return_t FN_HV_VMX_VCPU_WRITE_SHADOW_VMCS(hv_vcpuid_t vcpu, uint32_t field, uint64_t value);
275typedef hv_return_t FN_HV_VMX_VCPU_SET_SHADOW_ACCESS(hv_vcpuid_t vcpu, uint32_t field, hv_shadow_flags_t flags);
276
277typedef hv_return_t FN_HV_VMX_READ_CAPABILITY(hv_vmx_capability_t field, uint64_t *value);
278typedef hv_return_t FN_HV_VMX_VCPU_SET_APIC_ADDRESS(hv_vcpuid_t vcpu, hv_gpaddr_t gpa);
279
280/* Since 11.0 */
281typedef hv_return_t FN_HV_VMX_VCPU_GET_CAP_WRITE_VMCS(hv_vcpuid_t vcpu, uint32_t field, uint64_t *allowed_0, uint64_t *allowed_1);
282typedef hv_return_t FN_HV_VCPU_ENABLE_MANAGED_MSR(hv_vcpuid_t vcpu, uint32_t msr, bool enable);
283typedef hv_return_t FN_HV_VCPU_SET_MSR_ACCESS(hv_vcpuid_t vcpu, uint32_t msr, hv_msr_flags_t flags);
284
285
286/*********************************************************************************************************************************
287* Global Variables *
288*********************************************************************************************************************************/
289/** NEM_DARWIN_PAGE_STATE_XXX names. */
290NEM_TMPL_STATIC const char * const g_apszPageStates[4] = { "not-set", "unmapped", "readable", "writable" };
291/** MSRs. */
292static SUPHWVIRTMSRS g_HmMsrs;
293/** VMX: Set if swapping EFER is supported. */
294static bool g_fHmVmxSupportsVmcsEfer = false;
295/** @name APIs imported from Hypervisor.framework.
296 * @{ */
297static FN_HV_CAPABILITY *g_pfnHvCapability = NULL; /* Since 10.15 */
298static FN_HV_VM_CREATE *g_pfnHvVmCreate = NULL; /* Since 10.10 */
299static FN_HV_VM_DESTROY *g_pfnHvVmDestroy = NULL; /* Since 10.10 */
300static FN_HV_VM_SPACE_CREATE *g_pfnHvVmSpaceCreate = NULL; /* Since 10.15 */
301static FN_HV_VM_SPACE_DESTROY *g_pfnHvVmSpaceDestroy = NULL; /* Since 10.15 */
302static FN_HV_VM_MAP *g_pfnHvVmMap = NULL; /* Since 10.10 */
303static FN_HV_VM_UNMAP *g_pfnHvVmUnmap = NULL; /* Since 10.10 */
304static FN_HV_VM_PROTECT *g_pfnHvVmProtect = NULL; /* Since 10.10 */
305static FN_HV_VM_MAP_SPACE *g_pfnHvVmMapSpace = NULL; /* Since 10.15 */
306static FN_HV_VM_UNMAP_SPACE *g_pfnHvVmUnmapSpace = NULL; /* Since 10.15 */
307static FN_HV_VM_PROTECT_SPACE *g_pfnHvVmProtectSpace = NULL; /* Since 10.15 */
308static FN_HV_VM_SYNC_TSC *g_pfnHvVmSyncTsc = NULL; /* Since 10.10 */
309
310static FN_HV_VCPU_CREATE *g_pfnHvVCpuCreate = NULL; /* Since 10.10 */
311static FN_HV_VCPU_DESTROY *g_pfnHvVCpuDestroy = NULL; /* Since 10.10 */
312static FN_HV_VCPU_SET_SPACE *g_pfnHvVCpuSetSpace = NULL; /* Since 10.15 */
313static FN_HV_VCPU_READ_REGISTER *g_pfnHvVCpuReadRegister = NULL; /* Since 10.10 */
314static FN_HV_VCPU_WRITE_REGISTER *g_pfnHvVCpuWriteRegister = NULL; /* Since 10.10 */
315static FN_HV_VCPU_READ_FPSTATE *g_pfnHvVCpuReadFpState = NULL; /* Since 10.10 */
316static FN_HV_VCPU_WRITE_FPSTATE *g_pfnHvVCpuWriteFpState = NULL; /* Since 10.10 */
317static FN_HV_VCPU_ENABLE_NATIVE_MSR *g_pfnHvVCpuEnableNativeMsr = NULL; /* Since 10.10 */
318static FN_HV_VCPU_READ_MSR *g_pfnHvVCpuReadMsr = NULL; /* Since 10.10 */
319static FN_HV_VCPU_WRITE_MSR *g_pfnHvVCpuWriteMsr = NULL; /* Since 10.10 */
320static FN_HV_VCPU_FLUSH *g_pfnHvVCpuFlush = NULL; /* Since 10.10 */
321static FN_HV_VCPU_INVALIDATE_TLB *g_pfnHvVCpuInvalidateTlb = NULL; /* Since 10.10 */
322static FN_HV_VCPU_RUN *g_pfnHvVCpuRun = NULL; /* Since 10.10 */
323static FN_HV_VCPU_RUN_UNTIL *g_pfnHvVCpuRunUntil = NULL; /* Since 10.15 */
324static FN_HV_VCPU_INTERRUPT *g_pfnHvVCpuInterrupt = NULL; /* Since 10.10 */
325static FN_HV_VCPU_GET_EXEC_TIME *g_pfnHvVCpuGetExecTime = NULL; /* Since 10.10 */
326
327static FN_HV_VMX_READ_CAPABILITY *g_pfnHvVmxReadCapability = NULL; /* Since 10.10 */
328static FN_HV_VMX_VCPU_READ_VMCS *g_pfnHvVmxVCpuReadVmcs = NULL; /* Since 10.10 */
329static FN_HV_VMX_VCPU_WRITE_VMCS *g_pfnHvVmxVCpuWriteVmcs = NULL; /* Since 10.10 */
330static FN_HV_VMX_VCPU_READ_SHADOW_VMCS *g_pfnHvVmxVCpuReadShadowVmcs = NULL; /* Since 10.15 */
331static FN_HV_VMX_VCPU_WRITE_SHADOW_VMCS *g_pfnHvVmxVCpuWriteShadowVmcs = NULL; /* Since 10.15 */
332static FN_HV_VMX_VCPU_SET_SHADOW_ACCESS *g_pfnHvVmxVCpuSetShadowAccess = NULL; /* Since 10.15 */
333static FN_HV_VMX_VCPU_SET_APIC_ADDRESS *g_pfnHvVmxVCpuSetApicAddress = NULL; /* Since 10.10 */
334
335static FN_HV_VMX_VCPU_GET_CAP_WRITE_VMCS *g_pfnHvVmxVCpuGetCapWriteVmcs = NULL; /* Since 11.0 */
336static FN_HV_VCPU_ENABLE_MANAGED_MSR *g_pfnHvVCpuEnableManagedMsr = NULL; /* Since 11.0 */
337static FN_HV_VCPU_SET_MSR_ACCESS *g_pfnHvVCpuSetMsrAccess = NULL; /* Since 11.0 */
338/** @} */
339
340
341/**
342 * Import instructions.
343 */
344static const struct
345{
346 bool fOptional; /**< Set if import is optional. */
347 void **ppfn; /**< The function pointer variable. */
348 const char *pszName; /**< The function name. */
349} g_aImports[] =
350{
351#define NEM_DARWIN_IMPORT(a_fOptional, a_Pfn, a_Name) { (a_fOptional), (void **)&(a_Pfn), #a_Name }
352 NEM_DARWIN_IMPORT(true, g_pfnHvCapability, hv_capability),
353 NEM_DARWIN_IMPORT(false, g_pfnHvVmCreate, hv_vm_create),
354 NEM_DARWIN_IMPORT(false, g_pfnHvVmDestroy, hv_vm_destroy),
355 NEM_DARWIN_IMPORT(true, g_pfnHvVmSpaceCreate, hv_vm_space_create),
356 NEM_DARWIN_IMPORT(true, g_pfnHvVmSpaceDestroy, hv_vm_space_destroy),
357 NEM_DARWIN_IMPORT(false, g_pfnHvVmMap, hv_vm_map),
358 NEM_DARWIN_IMPORT(false, g_pfnHvVmUnmap, hv_vm_unmap),
359 NEM_DARWIN_IMPORT(false, g_pfnHvVmProtect, hv_vm_protect),
360 NEM_DARWIN_IMPORT(true, g_pfnHvVmMapSpace, hv_vm_map_space),
361 NEM_DARWIN_IMPORT(true, g_pfnHvVmUnmapSpace, hv_vm_unmap_space),
362 NEM_DARWIN_IMPORT(true, g_pfnHvVmProtectSpace, hv_vm_protect_space),
363 NEM_DARWIN_IMPORT(false, g_pfnHvVmSyncTsc, hv_vm_sync_tsc),
364
365 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuCreate, hv_vcpu_create),
366 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuDestroy, hv_vcpu_destroy),
367 NEM_DARWIN_IMPORT(true, g_pfnHvVCpuSetSpace, hv_vcpu_set_space),
368 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuReadRegister, hv_vcpu_read_register),
369 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuWriteRegister, hv_vcpu_write_register),
370 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuReadFpState, hv_vcpu_read_fpstate),
371 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuWriteFpState, hv_vcpu_write_fpstate),
372 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuEnableNativeMsr, hv_vcpu_enable_native_msr),
373 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuReadMsr, hv_vcpu_read_msr),
374 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuWriteMsr, hv_vcpu_write_msr),
375 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuFlush, hv_vcpu_flush),
376 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuInvalidateTlb, hv_vcpu_invalidate_tlb),
377 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuRun, hv_vcpu_run),
378 NEM_DARWIN_IMPORT(true, g_pfnHvVCpuRunUntil, hv_vcpu_run_until),
379 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuInterrupt, hv_vcpu_interrupt),
380 NEM_DARWIN_IMPORT(true, g_pfnHvVCpuGetExecTime, hv_vcpu_get_exec_time),
381 NEM_DARWIN_IMPORT(false, g_pfnHvVmxReadCapability, hv_vmx_read_capability),
382 NEM_DARWIN_IMPORT(false, g_pfnHvVmxVCpuReadVmcs, hv_vmx_vcpu_read_vmcs),
383 NEM_DARWIN_IMPORT(false, g_pfnHvVmxVCpuWriteVmcs, hv_vmx_vcpu_write_vmcs),
384 NEM_DARWIN_IMPORT(true, g_pfnHvVmxVCpuReadShadowVmcs, hv_vmx_vcpu_read_shadow_vmcs),
385 NEM_DARWIN_IMPORT(true, g_pfnHvVmxVCpuWriteShadowVmcs, hv_vmx_vcpu_write_shadow_vmcs),
386 NEM_DARWIN_IMPORT(true, g_pfnHvVmxVCpuSetShadowAccess, hv_vmx_vcpu_set_shadow_access),
387 NEM_DARWIN_IMPORT(false, g_pfnHvVmxVCpuSetApicAddress, hv_vmx_vcpu_set_apic_address),
388 NEM_DARWIN_IMPORT(true, g_pfnHvVmxVCpuGetCapWriteVmcs, hv_vmx_vcpu_get_cap_write_vmcs),
389 NEM_DARWIN_IMPORT(true, g_pfnHvVCpuEnableManagedMsr, hv_vcpu_enable_managed_msr),
390 NEM_DARWIN_IMPORT(true, g_pfnHvVCpuSetMsrAccess, hv_vcpu_set_msr_access)
391#undef NEM_DARWIN_IMPORT
392};
393
394
395/*
396 * Let the preprocessor alias the APIs to import variables for better autocompletion.
397 */
398#ifndef IN_SLICKEDIT
399# define hv_capability g_pfnHvCapability
400# define hv_vm_create g_pfnHvVmCreate
401# define hv_vm_destroy g_pfnHvVmDestroy
402# define hv_vm_space_create g_pfnHvVmSpaceCreate
403# define hv_vm_space_destroy g_pfnHvVmSpaceDestroy
404# define hv_vm_map g_pfnHvVmMap
405# define hv_vm_unmap g_pfnHvVmUnmap
406# define hv_vm_protect g_pfnHvVmProtect
407# define hv_vm_map_space g_pfnHvVmMapSpace
408# define hv_vm_unmap_space g_pfnHvVmUnmapSpace
409# define hv_vm_protect_space g_pfnHvVmProtectSpace
410# define hv_vm_sync_tsc g_pfnHvVmSyncTsc
411
412# define hv_vcpu_create g_pfnHvVCpuCreate
413# define hv_vcpu_destroy g_pfnHvVCpuDestroy
414# define hv_vcpu_set_space g_pfnHvVCpuSetSpace
415# define hv_vcpu_read_register g_pfnHvVCpuReadRegister
416# define hv_vcpu_write_register g_pfnHvVCpuWriteRegister
417# define hv_vcpu_read_fpstate g_pfnHvVCpuReadFpState
418# define hv_vcpu_write_fpstate g_pfnHvVCpuWriteFpState
419# define hv_vcpu_enable_native_msr g_pfnHvVCpuEnableNativeMsr
420# define hv_vcpu_read_msr g_pfnHvVCpuReadMsr
421# define hv_vcpu_write_msr g_pfnHvVCpuWriteMsr
422# define hv_vcpu_flush g_pfnHvVCpuFlush
423# define hv_vcpu_invalidate_tlb g_pfnHvVCpuInvalidateTlb
424# define hv_vcpu_run g_pfnHvVCpuRun
425# define hv_vcpu_run_until g_pfnHvVCpuRunUntil
426# define hv_vcpu_interrupt g_pfnHvVCpuInterrupt
427# define hv_vcpu_get_exec_time g_pfnHvVCpuGetExecTime
428
429# define hv_vmx_read_capability g_pfnHvVmxReadCapability
430# define hv_vmx_vcpu_read_vmcs g_pfnHvVmxVCpuReadVmcs
431# define hv_vmx_vcpu_write_vmcs g_pfnHvVmxVCpuWriteVmcs
432# define hv_vmx_vcpu_read_shadow_vmcs g_pfnHvVmxVCpuReadShadowVmcs
433# define hv_vmx_vcpu_write_shadow_vmcs g_pfnHvVmxVCpuWriteShadowVmcs
434# define hv_vmx_vcpu_set_shadow_access g_pfnHvVmxVCpuSetShadowAccess
435# define hv_vmx_vcpu_set_apic_address g_pfnHvVmxVCpuSetApicAddress
436
437# define hv_vmx_vcpu_get_cap_write_vmcs g_pfnHvVmxVCpuGetCapWriteVmcs
438# define hv_vcpu_enable_managed_msr g_pfnHvVCpuEnableManagedMsr
439# define hv_vcpu_set_msr_access g_pfnHvVCpuSetMsrAccess
440#endif
441
442static const struct
443{
444 uint32_t u32VmcsFieldId; /**< The VMCS field identifier. */
445 const char *pszVmcsField; /**< The VMCS field name. */
446 bool f64Bit;
447} g_aVmcsFieldsCap[] =
448{
449#define NEM_DARWIN_VMCS64_FIELD_CAP(a_u32VmcsFieldId) { (a_u32VmcsFieldId), #a_u32VmcsFieldId, true }
450#define NEM_DARWIN_VMCS32_FIELD_CAP(a_u32VmcsFieldId) { (a_u32VmcsFieldId), #a_u32VmcsFieldId, false }
451
452 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PIN_EXEC),
453 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PROC_EXEC),
454 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_EXCEPTION_BITMAP),
455 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_EXIT),
456 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_ENTRY),
457 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PROC_EXEC2),
458 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PLE_GAP),
459 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PLE_WINDOW),
460 NEM_DARWIN_VMCS64_FIELD_CAP(VMX_VMCS64_CTRL_TSC_OFFSET_FULL),
461 NEM_DARWIN_VMCS64_FIELD_CAP(VMX_VMCS64_GUEST_DEBUGCTL_FULL)
462#undef NEM_DARWIN_VMCS64_FIELD_CAP
463#undef NEM_DARWIN_VMCS32_FIELD_CAP
464};
465
466
467/*********************************************************************************************************************************
468* Internal Functions *
469*********************************************************************************************************************************/
470static void vmxHCImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo);
471
472/**
473 * Converts a HV return code to a VBox status code.
474 *
475 * @returns VBox status code.
476 * @param hrc The HV return code to convert.
477 */
478DECLINLINE(int) nemR3DarwinHvSts2Rc(hv_return_t hrc)
479{
480 if (hrc == HV_SUCCESS)
481 return VINF_SUCCESS;
482
483 switch (hrc)
484 {
485 case HV_ERROR: return VERR_INVALID_STATE;
486 case HV_BUSY: return VERR_RESOURCE_BUSY;
487 case HV_BAD_ARGUMENT: return VERR_INVALID_PARAMETER;
488 case HV_NO_RESOURCES: return VERR_OUT_OF_RESOURCES;
489 case HV_NO_DEVICE: return VERR_NOT_FOUND;
490 case HV_UNSUPPORTED: return VERR_NOT_SUPPORTED;
491 }
492
493 return VERR_IPE_UNEXPECTED_STATUS;
494}
495
496
497/**
498 * Unmaps the given guest physical address range (page aligned).
499 *
500 * @returns VBox status code.
501 * @param pVM The cross context VM structure.
502 * @param GCPhys The guest physical address to start unmapping at.
503 * @param cb The size of the range to unmap in bytes.
504 */
505DECLINLINE(int) nemR3DarwinUnmap(PVM pVM, RTGCPHYS GCPhys, size_t cb)
506{
507 LogFlowFunc(("Unmapping %RGp LB %zu\n", GCPhys, cb));
508 hv_return_t hrc;
509 if (pVM->nem.s.fCreatedAsid)
510 hrc = hv_vm_unmap_space(pVM->nem.s.uVmAsid, GCPhys, cb);
511 else
512 hrc = hv_vm_unmap(GCPhys, cb);
513 return nemR3DarwinHvSts2Rc(hrc);
514}
515
516
517/**
518 * Maps a given guest physical address range backed by the given memory with the given
519 * protection flags.
520 *
521 * @returns VBox status code.
522 * @param pVM The cross context VM structure.
523 * @param GCPhys The guest physical address to start mapping.
524 * @param pvRam The R3 pointer of the memory to back the range with.
525 * @param cb The size of the range, page aligned.
526 * @param fPageProt The page protection flags to use for this range, combination of NEM_PAGE_PROT_XXX
527 */
528DECLINLINE(int) nemR3DarwinMap(PVM pVM, RTGCPHYS GCPhys, void *pvRam, size_t cb, uint32_t fPageProt)
529{
530 LogFlowFunc(("Mapping %RGp LB %zu fProt=%#x\n", GCPhys, cb, fPageProt));
531
532 hv_memory_flags_t fHvMemProt = 0;
533 if (fPageProt & NEM_PAGE_PROT_READ)
534 fHvMemProt |= HV_MEMORY_READ;
535 if (fPageProt & NEM_PAGE_PROT_WRITE)
536 fHvMemProt |= HV_MEMORY_WRITE;
537 if (fPageProt & NEM_PAGE_PROT_EXECUTE)
538 fHvMemProt |= HV_MEMORY_EXEC;
539
540 hv_return_t hrc;
541 if (pVM->nem.s.fCreatedAsid)
542 hrc = hv_vm_map_space(pVM->nem.s.uVmAsid, pvRam, GCPhys, cb, fHvMemProt);
543 else
544 hrc = hv_vm_map(pvRam, GCPhys, cb, fHvMemProt);
545 return nemR3DarwinHvSts2Rc(hrc);
546}
547
548
549#if 0 /* unused */
550DECLINLINE(int) nemR3DarwinProtectPage(PVM pVM, RTGCPHYS GCPhys, size_t cb, uint32_t fPageProt)
551{
552 hv_memory_flags_t fHvMemProt = 0;
553 if (fPageProt & NEM_PAGE_PROT_READ)
554 fHvMemProt |= HV_MEMORY_READ;
555 if (fPageProt & NEM_PAGE_PROT_WRITE)
556 fHvMemProt |= HV_MEMORY_WRITE;
557 if (fPageProt & NEM_PAGE_PROT_EXECUTE)
558 fHvMemProt |= HV_MEMORY_EXEC;
559
560 if (pVM->nem.s.fCreatedAsid)
561 hrc = hv_vm_protect_space(pVM->nem.s.uVmAsid, GCPhys, cb, fHvMemProt);
562 else
563 hrc = hv_vm_protect(GCPhys, cb, fHvMemProt);
564
565 return nemR3DarwinHvSts2Rc(hrc);
566}
567#endif
568
569
570DECLINLINE(int) nemR3NativeGCPhys2R3PtrReadOnly(PVM pVM, RTGCPHYS GCPhys, const void **ppv)
571{
572 PGMPAGEMAPLOCK Lock;
573 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, ppv, &Lock);
574 if (RT_SUCCESS(rc))
575 PGMPhysReleasePageMappingLock(pVM, &Lock);
576 return rc;
577}
578
579
580DECLINLINE(int) nemR3NativeGCPhys2R3PtrWriteable(PVM pVM, RTGCPHYS GCPhys, void **ppv)
581{
582 PGMPAGEMAPLOCK Lock;
583 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhys, ppv, &Lock);
584 if (RT_SUCCESS(rc))
585 PGMPhysReleasePageMappingLock(pVM, &Lock);
586 return rc;
587}
588
589
590/**
591 * Worker that maps pages into Hyper-V.
592 *
593 * This is used by the PGM physical page notifications as well as the memory
594 * access VMEXIT handlers.
595 *
596 * @returns VBox status code.
597 * @param pVM The cross context VM structure.
598 * @param pVCpu The cross context virtual CPU structure of the
599 * calling EMT.
600 * @param GCPhysSrc The source page address.
601 * @param GCPhysDst The hyper-V destination page. This may differ from
602 * GCPhysSrc when A20 is disabled.
603 * @param fPageProt NEM_PAGE_PROT_XXX.
604 * @param pu2State Our page state (input/output).
605 * @param fBackingChanged Set if the page backing is being changed.
606 * @thread EMT(pVCpu)
607 */
608NEM_TMPL_STATIC int nemHCNativeSetPhysPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst,
609 uint32_t fPageProt, uint8_t *pu2State, bool fBackingChanged)
610{
611 /*
612 * Looks like we need to unmap a page before we can change the backing
613 * or even modify the protection. This is going to be *REALLY* efficient.
614 * PGM lends us two bits to keep track of the state here.
615 */
616 RT_NOREF(pVCpu);
617 uint8_t const u2OldState = *pu2State;
618 uint8_t const u2NewState = fPageProt & NEM_PAGE_PROT_WRITE ? NEM_DARWIN_PAGE_STATE_WRITABLE
619 : fPageProt & NEM_PAGE_PROT_READ ? NEM_DARWIN_PAGE_STATE_READABLE : NEM_DARWIN_PAGE_STATE_UNMAPPED;
620 if ( fBackingChanged
621 || u2NewState != u2OldState)
622 {
623 if (u2OldState > NEM_DARWIN_PAGE_STATE_UNMAPPED)
624 {
625 int rc = nemR3DarwinUnmap(pVM, GCPhysDst, X86_PAGE_SIZE);
626 if (RT_SUCCESS(rc))
627 {
628 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
629 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
630 if (u2NewState == NEM_DARWIN_PAGE_STATE_UNMAPPED)
631 {
632 Log5(("NEM GPA unmapped/set: %RGp (was %s)\n", GCPhysDst, g_apszPageStates[u2OldState]));
633 return VINF_SUCCESS;
634 }
635 }
636 else
637 {
638 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
639 LogRel(("nemHCNativeSetPhysPage/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
640 return VERR_NEM_INIT_FAILED;
641 }
642 }
643 }
644
645 /*
646 * Writeable mapping?
647 */
648 if (fPageProt & NEM_PAGE_PROT_WRITE)
649 {
650 void *pvPage;
651 int rc = nemR3NativeGCPhys2R3PtrWriteable(pVM, GCPhysSrc, &pvPage);
652 if (RT_SUCCESS(rc))
653 {
654 rc = nemR3DarwinMap(pVM, GCPhysDst, pvPage, X86_PAGE_SIZE, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
655 if (RT_SUCCESS(rc))
656 {
657 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
658 STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPage);
659 Log5(("NEM GPA mapped/set: %RGp %s (was %s)\n", GCPhysDst, g_apszPageStates[u2NewState], g_apszPageStates[u2OldState]));
660 return VINF_SUCCESS;
661 }
662 STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPageFailed);
663 LogRel(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst));
664 return VERR_NEM_INIT_FAILED;
665 }
666 LogRel(("nemHCNativeSetPhysPage/writable: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
667 return rc;
668 }
669
670 if (fPageProt & NEM_PAGE_PROT_READ)
671 {
672 const void *pvPage;
673 int rc = nemR3NativeGCPhys2R3PtrReadOnly(pVM, GCPhysSrc, &pvPage);
674 if (RT_SUCCESS(rc))
675 {
676 rc = nemR3DarwinMap(pVM, GCPhysDst, (void *)pvPage, X86_PAGE_SIZE, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE);
677 if (RT_SUCCESS(rc))
678 {
679 *pu2State = NEM_DARWIN_PAGE_STATE_READABLE;
680 STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPage);
681 Log5(("NEM GPA mapped/set: %RGp %s (was %s)\n", GCPhysDst, g_apszPageStates[u2NewState], g_apszPageStates[u2OldState]));
682 return VINF_SUCCESS;
683 }
684 STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPageFailed);
685 LogRel(("nemHCNativeSetPhysPage/readonly: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
686 return VERR_NEM_INIT_FAILED;
687 }
688 LogRel(("nemHCNativeSetPhysPage/readonly: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
689 return rc;
690 }
691
692 /* We already unmapped it above. */
693 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
694 return VINF_SUCCESS;
695}
696
697
698#ifdef LOG_ENABLED
699/**
700 * Logs the current CPU state.
701 */
702static void nemR3DarwinLogState(PVMCC pVM, PVMCPUCC pVCpu)
703{
704 if (LogIs3Enabled())
705 {
706#if 0
707 char szRegs[4096];
708 DBGFR3RegPrintf(pVM->pUVM, pVCpu->idCpu, &szRegs[0], sizeof(szRegs),
709 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n"
710 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n"
711 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n"
712 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n"
713 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n"
714 "cs={%04VR{cs} base=%016VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} cr0=%016VR{cr0}\n"
715 "ds={%04VR{ds} base=%016VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} cr2=%016VR{cr2}\n"
716 "es={%04VR{es} base=%016VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} cr3=%016VR{cr3}\n"
717 "fs={%04VR{fs} base=%016VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr4=%016VR{cr4}\n"
718 "gs={%04VR{gs} base=%016VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr8=%016VR{cr8}\n"
719 "ss={%04VR{ss} base=%016VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n"
720 "dr0=%016VR{dr0} dr1=%016VR{dr1} dr2=%016VR{dr2} dr3=%016VR{dr3}\n"
721 "dr6=%016VR{dr6} dr7=%016VR{dr7}\n"
722 "gdtr=%016VR{gdtr_base}:%04VR{gdtr_lim} idtr=%016VR{idtr_base}:%04VR{idtr_lim} rflags=%08VR{rflags}\n"
723 "ldtr={%04VR{ldtr} base=%016VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%08VR{ldtr_attr}}\n"
724 "tr ={%04VR{tr} base=%016VR{tr_base} limit=%08VR{tr_lim} flags=%08VR{tr_attr}}\n"
725 " sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n"
726 " efer=%016VR{efer}\n"
727 " pat=%016VR{pat}\n"
728 " sf_mask=%016VR{sf_mask}\n"
729 "krnl_gs_base=%016VR{krnl_gs_base}\n"
730 " lstar=%016VR{lstar}\n"
731 " star=%016VR{star} cstar=%016VR{cstar}\n"
732 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n"
733 );
734
735 char szInstr[256];
736 DBGFR3DisasInstrEx(pVM->pUVM, pVCpu->idCpu, 0, 0,
737 DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,
738 szInstr, sizeof(szInstr), NULL);
739 Log3(("%s%s\n", szRegs, szInstr));
740#else
741 RT_NOREF(pVM, pVCpu);
742#endif
743 }
744}
745#endif /* LOG_ENABLED */
746
747
748DECLINLINE(int) nemR3DarwinReadVmcs16(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint16_t *pData)
749{
750 uint64_t u64Data;
751 hv_return_t hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, &u64Data);
752 if (RT_LIKELY(hrc == HV_SUCCESS))
753 {
754 *pData = (uint16_t)u64Data;
755 return VINF_SUCCESS;
756 }
757
758 return nemR3DarwinHvSts2Rc(hrc);
759}
760
761
762DECLINLINE(int) nemR3DarwinReadVmcs32(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint32_t *pData)
763{
764 uint64_t u64Data;
765 hv_return_t hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, &u64Data);
766 if (RT_LIKELY(hrc == HV_SUCCESS))
767 {
768 *pData = (uint32_t)u64Data;
769 return VINF_SUCCESS;
770 }
771
772 return nemR3DarwinHvSts2Rc(hrc);
773}
774
775
776DECLINLINE(int) nemR3DarwinReadVmcs64(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint64_t *pData)
777{
778 hv_return_t hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, pData);
779 if (RT_LIKELY(hrc == HV_SUCCESS))
780 return VINF_SUCCESS;
781
782 return nemR3DarwinHvSts2Rc(hrc);
783}
784
785
786DECLINLINE(int) nemR3DarwinWriteVmcs16(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint16_t u16Val)
787{
788 hv_return_t hrc = hv_vmx_vcpu_write_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, u16Val);
789 if (RT_LIKELY(hrc == HV_SUCCESS))
790 return VINF_SUCCESS;
791
792 return nemR3DarwinHvSts2Rc(hrc);
793}
794
795
796DECLINLINE(int) nemR3DarwinWriteVmcs32(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint32_t u32Val)
797{
798 hv_return_t hrc = hv_vmx_vcpu_write_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, u32Val);
799 if (RT_LIKELY(hrc == HV_SUCCESS))
800 return VINF_SUCCESS;
801
802 return nemR3DarwinHvSts2Rc(hrc);
803}
804
805
806DECLINLINE(int) nemR3DarwinWriteVmcs64(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint64_t u64Val)
807{
808 hv_return_t hrc = hv_vmx_vcpu_write_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, u64Val);
809 if (RT_LIKELY(hrc == HV_SUCCESS))
810 return VINF_SUCCESS;
811
812 return nemR3DarwinHvSts2Rc(hrc);
813}
814
815DECLINLINE(int) nemR3DarwinMsrRead(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t *pu64Val)
816{
817 hv_return_t hrc = hv_vcpu_read_msr(pVCpu->nem.s.hVCpuId, idMsr, pu64Val);
818 if (RT_LIKELY(hrc == HV_SUCCESS))
819 return VINF_SUCCESS;
820
821 return nemR3DarwinHvSts2Rc(hrc);
822}
823
824#if 0 /*unused*/
825DECLINLINE(int) nemR3DarwinMsrWrite(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t u64Val)
826{
827 hv_return_t hrc = hv_vcpu_write_msr(pVCpu->nem.s.hVCpuId, idMsr, u64Val);
828 if (RT_LIKELY(hrc == HV_SUCCESS))
829 return VINF_SUCCESS;
830
831 return nemR3DarwinHvSts2Rc(hrc);
832}
833#endif
834
835static int nemR3DarwinCopyStateFromHv(PVMCC pVM, PVMCPUCC pVCpu, uint64_t fWhat)
836{
837#define READ_GREG(a_GReg, a_Value) \
838 do \
839 { \
840 hrc = hv_vcpu_read_register(pVCpu->nem.s.hVCpuId, (a_GReg), &(a_Value)); \
841 if (RT_LIKELY(hrc == HV_SUCCESS)) \
842 { /* likely */ } \
843 else \
844 return VERR_INTERNAL_ERROR; \
845 } while(0)
846#define READ_VMCS_FIELD(a_Field, a_Value) \
847 do \
848 { \
849 hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, (a_Field), &(a_Value)); \
850 if (RT_LIKELY(hrc == HV_SUCCESS)) \
851 { /* likely */ } \
852 else \
853 return VERR_INTERNAL_ERROR; \
854 } while(0)
855#define READ_VMCS16_FIELD(a_Field, a_Value) \
856 do \
857 { \
858 uint64_t u64Data; \
859 hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, (a_Field), &u64Data); \
860 if (RT_LIKELY(hrc == HV_SUCCESS)) \
861 { (a_Value) = (uint16_t)u64Data; } \
862 else \
863 return VERR_INTERNAL_ERROR; \
864 } while(0)
865#define READ_VMCS32_FIELD(a_Field, a_Value) \
866 do \
867 { \
868 uint64_t u64Data; \
869 hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, (a_Field), &u64Data); \
870 if (RT_LIKELY(hrc == HV_SUCCESS)) \
871 { (a_Value) = (uint32_t)u64Data; } \
872 else \
873 return VERR_INTERNAL_ERROR; \
874 } while(0)
875#define READ_MSR(a_Msr, a_Value) \
876 do \
877 { \
878 hrc = hv_vcpu_read_msr(pVCpu->nem.s.hVCpuId, (a_Msr), &(a_Value)); \
879 if (RT_LIKELY(hrc == HV_SUCCESS)) \
880 { /* likely */ } \
881 else \
882 AssertFailedReturn(VERR_INTERNAL_ERROR); \
883 } while(0)
884
885 STAM_PROFILE_ADV_START(&pVCpu->nem.s.StatProfGstStateImport, x);
886
887 RT_NOREF(pVM);
888 fWhat &= pVCpu->cpum.GstCtx.fExtrn;
889
890 if (fWhat & (CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI))
891 vmxHCImportGuestIntrState(pVCpu, &pVCpu->nem.s.VmcsInfo);
892
893 /* GPRs */
894 hv_return_t hrc;
895 if (fWhat & CPUMCTX_EXTRN_GPRS_MASK)
896 {
897 if (fWhat & CPUMCTX_EXTRN_RAX)
898 READ_GREG(HV_X86_RAX, pVCpu->cpum.GstCtx.rax);
899 if (fWhat & CPUMCTX_EXTRN_RCX)
900 READ_GREG(HV_X86_RCX, pVCpu->cpum.GstCtx.rcx);
901 if (fWhat & CPUMCTX_EXTRN_RDX)
902 READ_GREG(HV_X86_RDX, pVCpu->cpum.GstCtx.rdx);
903 if (fWhat & CPUMCTX_EXTRN_RBX)
904 READ_GREG(HV_X86_RBX, pVCpu->cpum.GstCtx.rbx);
905 if (fWhat & CPUMCTX_EXTRN_RSP)
906 READ_GREG(HV_X86_RSP, pVCpu->cpum.GstCtx.rsp);
907 if (fWhat & CPUMCTX_EXTRN_RBP)
908 READ_GREG(HV_X86_RBP, pVCpu->cpum.GstCtx.rbp);
909 if (fWhat & CPUMCTX_EXTRN_RSI)
910 READ_GREG(HV_X86_RSI, pVCpu->cpum.GstCtx.rsi);
911 if (fWhat & CPUMCTX_EXTRN_RDI)
912 READ_GREG(HV_X86_RDI, pVCpu->cpum.GstCtx.rdi);
913 if (fWhat & CPUMCTX_EXTRN_R8_R15)
914 {
915 READ_GREG(HV_X86_R8, pVCpu->cpum.GstCtx.r8);
916 READ_GREG(HV_X86_R9, pVCpu->cpum.GstCtx.r9);
917 READ_GREG(HV_X86_R10, pVCpu->cpum.GstCtx.r10);
918 READ_GREG(HV_X86_R11, pVCpu->cpum.GstCtx.r11);
919 READ_GREG(HV_X86_R12, pVCpu->cpum.GstCtx.r12);
920 READ_GREG(HV_X86_R13, pVCpu->cpum.GstCtx.r13);
921 READ_GREG(HV_X86_R14, pVCpu->cpum.GstCtx.r14);
922 READ_GREG(HV_X86_R15, pVCpu->cpum.GstCtx.r15);
923 }
924 }
925
926 /* RIP & Flags */
927 if (fWhat & CPUMCTX_EXTRN_RIP)
928 READ_GREG(HV_X86_RIP, pVCpu->cpum.GstCtx.rip);
929 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
930 READ_GREG(HV_X86_RFLAGS, pVCpu->cpum.GstCtx.rflags.u);
931
932 /* Segments */
933#define READ_SEG(a_SReg, a_enmName) \
934 do { \
935 READ_VMCS16_FIELD(VMX_VMCS16_GUEST_ ## a_enmName ## _SEL, (a_SReg).Sel); \
936 READ_VMCS32_FIELD(VMX_VMCS32_GUEST_ ## a_enmName ## _LIMIT, (a_SReg).u32Limit); \
937 READ_VMCS32_FIELD(VMX_VMCS32_GUEST_ ## a_enmName ## _ACCESS_RIGHTS, (a_SReg).Attr.u); \
938 READ_VMCS_FIELD(VMX_VMCS_GUEST_ ## a_enmName ## _BASE, (a_SReg).u64Base); \
939 (a_SReg).ValidSel = (a_SReg).Sel; \
940 } while (0)
941 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
942 {
943 if (fWhat & CPUMCTX_EXTRN_ES)
944 READ_SEG(pVCpu->cpum.GstCtx.es, ES);
945 if (fWhat & CPUMCTX_EXTRN_CS)
946 READ_SEG(pVCpu->cpum.GstCtx.cs, CS);
947 if (fWhat & CPUMCTX_EXTRN_SS)
948 READ_SEG(pVCpu->cpum.GstCtx.ss, SS);
949 if (fWhat & CPUMCTX_EXTRN_DS)
950 READ_SEG(pVCpu->cpum.GstCtx.ds, DS);
951 if (fWhat & CPUMCTX_EXTRN_FS)
952 READ_SEG(pVCpu->cpum.GstCtx.fs, FS);
953 if (fWhat & CPUMCTX_EXTRN_GS)
954 READ_SEG(pVCpu->cpum.GstCtx.gs, GS);
955 }
956
957 /* Descriptor tables and the task segment. */
958 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
959 {
960 if (fWhat & CPUMCTX_EXTRN_LDTR)
961 READ_SEG(pVCpu->cpum.GstCtx.ldtr, LDTR);
962
963 if (fWhat & CPUMCTX_EXTRN_TR)
964 {
965 /* AMD-V likes loading TR with in AVAIL state, whereas intel insists on BUSY. So,
966 avoid to trigger sanity assertions around the code, always fix this. */
967 READ_SEG(pVCpu->cpum.GstCtx.tr, TR);
968 switch (pVCpu->cpum.GstCtx.tr.Attr.n.u4Type)
969 {
970 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
971 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
972 break;
973 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
974 pVCpu->cpum.GstCtx.tr.Attr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
975 break;
976 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
977 pVCpu->cpum.GstCtx.tr.Attr.n.u4Type = X86_SEL_TYPE_SYS_286_TSS_BUSY;
978 break;
979 }
980 }
981 if (fWhat & CPUMCTX_EXTRN_IDTR)
982 {
983 READ_VMCS32_FIELD(VMX_VMCS32_GUEST_IDTR_LIMIT, pVCpu->cpum.GstCtx.idtr.cbIdt);
984 READ_VMCS_FIELD(VMX_VMCS_GUEST_IDTR_BASE, pVCpu->cpum.GstCtx.idtr.pIdt);
985 }
986 if (fWhat & CPUMCTX_EXTRN_GDTR)
987 {
988 READ_VMCS32_FIELD(VMX_VMCS32_GUEST_GDTR_LIMIT, pVCpu->cpum.GstCtx.gdtr.cbGdt);
989 READ_VMCS_FIELD(VMX_VMCS_GUEST_GDTR_BASE, pVCpu->cpum.GstCtx.gdtr.pGdt);
990 }
991 }
992
993 /* Control registers. */
994 bool fMaybeChangedMode = false;
995 bool fUpdateCr3 = false;
996 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
997 {
998 uint64_t u64CrTmp = 0;
999
1000 if (fWhat & CPUMCTX_EXTRN_CR0)
1001 {
1002 READ_GREG(HV_X86_CR0, u64CrTmp);
1003 if (pVCpu->cpum.GstCtx.cr0 != u64CrTmp)
1004 {
1005 CPUMSetGuestCR0(pVCpu, u64CrTmp);
1006 fMaybeChangedMode = true;
1007 }
1008 }
1009 if (fWhat & CPUMCTX_EXTRN_CR2)
1010 READ_GREG(HV_X86_CR2, pVCpu->cpum.GstCtx.cr2);
1011 if (fWhat & CPUMCTX_EXTRN_CR3)
1012 {
1013 READ_GREG(HV_X86_CR3, u64CrTmp);
1014 if (pVCpu->cpum.GstCtx.cr3 != u64CrTmp)
1015 {
1016 CPUMSetGuestCR3(pVCpu, u64CrTmp);
1017 fUpdateCr3 = true;
1018 }
1019
1020 /*
1021 * If the guest is in PAE mode, sync back the PDPE's into the guest state.
1022 * CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date.
1023 */
1024 if (CPUMIsGuestInPAEModeEx(&pVCpu->cpum.GstCtx))
1025 {
1026 X86PDPE aPaePdpes[4];
1027 READ_VMCS_FIELD(VMX_VMCS64_GUEST_PDPTE0_FULL, aPaePdpes[0].u);
1028 READ_VMCS_FIELD(VMX_VMCS64_GUEST_PDPTE1_FULL, aPaePdpes[1].u);
1029 READ_VMCS_FIELD(VMX_VMCS64_GUEST_PDPTE2_FULL, aPaePdpes[2].u);
1030 READ_VMCS_FIELD(VMX_VMCS64_GUEST_PDPTE3_FULL, aPaePdpes[3].u);
1031 if (memcmp(&aPaePdpes[0], &pVCpu->cpum.GstCtx.aPaePdpes[0], sizeof(aPaePdpes)))
1032 {
1033 memcpy(&pVCpu->cpum.GstCtx.aPaePdpes[0], &aPaePdpes[0], sizeof(aPaePdpes));
1034 fUpdateCr3 = true;
1035 }
1036 }
1037 }
1038 if (fWhat & CPUMCTX_EXTRN_CR4)
1039 {
1040 READ_GREG(HV_X86_CR4, u64CrTmp);
1041 u64CrTmp &= ~VMX_V_CR4_FIXED0;
1042
1043 if (pVCpu->cpum.GstCtx.cr4 != u64CrTmp)
1044 {
1045 CPUMSetGuestCR4(pVCpu, u64CrTmp);
1046 fMaybeChangedMode = true;
1047 }
1048 }
1049 }
1050
1051#if 0 /* Always done. */
1052 if (fWhat & CPUMCTX_EXTRN_APIC_TPR)
1053 {
1054 uint64_t u64Cr8 = 0;
1055
1056 READ_GREG(HV_X86_TPR, u64Cr8);
1057 APICSetTpr(pVCpu, u64Cr8 << 4);
1058 }
1059#endif
1060
1061 if (fWhat & CPUMCTX_EXTRN_XCRx)
1062 READ_GREG(HV_X86_XCR0, pVCpu->cpum.GstCtx.aXcr[0]);
1063
1064 /* Debug registers. */
1065 if (fWhat & CPUMCTX_EXTRN_DR7)
1066 {
1067 uint64_t u64Dr7;
1068 READ_GREG(HV_X86_DR7, u64Dr7);
1069 if (pVCpu->cpum.GstCtx.dr[7] != u64Dr7)
1070 CPUMSetGuestDR7(pVCpu, u64Dr7);
1071 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_DR7; /* Hack alert! Avoids asserting when processing CPUMCTX_EXTRN_DR0_DR3. */
1072 }
1073 if (fWhat & CPUMCTX_EXTRN_DR0_DR3)
1074 {
1075 uint64_t u64DrTmp;
1076
1077 READ_GREG(HV_X86_DR0, u64DrTmp);
1078 if (pVCpu->cpum.GstCtx.dr[0] != u64DrTmp)
1079 CPUMSetGuestDR0(pVCpu, u64DrTmp);
1080 READ_GREG(HV_X86_DR1, u64DrTmp);
1081 if (pVCpu->cpum.GstCtx.dr[1] != u64DrTmp)
1082 CPUMSetGuestDR1(pVCpu, u64DrTmp);
1083 READ_GREG(HV_X86_DR2, u64DrTmp);
1084 if (pVCpu->cpum.GstCtx.dr[2] != u64DrTmp)
1085 CPUMSetGuestDR2(pVCpu, u64DrTmp);
1086 READ_GREG(HV_X86_DR3, u64DrTmp);
1087 if (pVCpu->cpum.GstCtx.dr[3] != u64DrTmp)
1088 CPUMSetGuestDR3(pVCpu, u64DrTmp);
1089 }
1090 if (fWhat & CPUMCTX_EXTRN_DR6)
1091 {
1092 uint64_t u64Dr6;
1093 READ_GREG(HV_X86_DR6, u64Dr6);
1094 if (pVCpu->cpum.GstCtx.dr[6] != u64Dr6)
1095 CPUMSetGuestDR6(pVCpu, u64Dr6);
1096 }
1097
1098 if (fWhat & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX))
1099 {
1100 hrc = hv_vcpu_read_fpstate(pVCpu->nem.s.hVCpuId, &pVCpu->cpum.GstCtx.XState, sizeof(pVCpu->cpum.GstCtx.XState));
1101 if (hrc == HV_SUCCESS)
1102 { /* likely */ }
1103 else
1104 {
1105 STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateImport, x);
1106 return nemR3DarwinHvSts2Rc(hrc);
1107 }
1108 }
1109
1110 /* MSRs */
1111 if (fWhat & CPUMCTX_EXTRN_EFER)
1112 {
1113 uint64_t u64Efer;
1114
1115 READ_VMCS_FIELD(VMX_VMCS64_GUEST_EFER_FULL, u64Efer);
1116 if (u64Efer != pVCpu->cpum.GstCtx.msrEFER)
1117 {
1118 Log7(("NEM/%u: MSR EFER changed %RX64 -> %RX64\n", pVCpu->idCpu, pVCpu->cpum.GstCtx.msrEFER, u64Efer));
1119 if ((u64Efer ^ pVCpu->cpum.GstCtx.msrEFER) & MSR_K6_EFER_NXE)
1120 PGMNotifyNxeChanged(pVCpu, RT_BOOL(u64Efer & MSR_K6_EFER_NXE));
1121 pVCpu->cpum.GstCtx.msrEFER = u64Efer;
1122 fMaybeChangedMode = true;
1123 }
1124 }
1125
1126 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
1127 READ_MSR(MSR_K8_KERNEL_GS_BASE, pVCpu->cpum.GstCtx.msrKERNELGSBASE);
1128 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
1129 {
1130 uint64_t u64Tmp;
1131 READ_MSR(MSR_IA32_SYSENTER_EIP, u64Tmp);
1132 pVCpu->cpum.GstCtx.SysEnter.eip = u64Tmp;
1133 READ_MSR(MSR_IA32_SYSENTER_ESP, u64Tmp);
1134 pVCpu->cpum.GstCtx.SysEnter.esp = u64Tmp;
1135 READ_MSR(MSR_IA32_SYSENTER_CS, u64Tmp);
1136 pVCpu->cpum.GstCtx.SysEnter.cs = u64Tmp;
1137 }
1138 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
1139 {
1140 READ_MSR(MSR_K6_STAR, pVCpu->cpum.GstCtx.msrSTAR);
1141 READ_MSR(MSR_K8_LSTAR, pVCpu->cpum.GstCtx.msrLSTAR);
1142 READ_MSR(MSR_K8_CSTAR, pVCpu->cpum.GstCtx.msrCSTAR);
1143 READ_MSR(MSR_K8_SF_MASK, pVCpu->cpum.GstCtx.msrSFMASK);
1144 }
1145 if (fWhat & CPUMCTX_EXTRN_TSC_AUX)
1146 {
1147 PCPUMCTXMSRS pCtxMsrs = CPUMQueryGuestCtxMsrsPtr(pVCpu);
1148 READ_MSR(MSR_K8_TSC_AUX, pCtxMsrs->msr.TscAux);
1149 }
1150 if (fWhat & CPUMCTX_EXTRN_OTHER_MSRS)
1151 {
1152 /* Last Branch Record. */
1153 if (pVM->nem.s.fLbr)
1154 {
1155 PVMXVMCSINFOSHARED const pVmcsInfoShared = &pVCpu->nem.s.vmx.VmcsInfo;
1156 uint32_t const idFromIpMsrStart = pVM->nem.s.idLbrFromIpMsrFirst;
1157 uint32_t const idToIpMsrStart = pVM->nem.s.idLbrToIpMsrFirst;
1158 uint32_t const idInfoMsrStart = pVM->nem.s.idLbrInfoMsrFirst;
1159 uint32_t const cLbrStack = pVM->nem.s.idLbrFromIpMsrLast - pVM->nem.s.idLbrFromIpMsrFirst + 1;
1160 Assert(cLbrStack <= 32);
1161 for (uint32_t i = 0; i < cLbrStack; i++)
1162 {
1163 READ_MSR(idFromIpMsrStart + i, pVmcsInfoShared->au64LbrFromIpMsr[i]);
1164
1165 /* Some CPUs don't have a Branch-To-IP MSR (P4 and related Xeons). */
1166 if (idToIpMsrStart != 0)
1167 READ_MSR(idToIpMsrStart + i, pVmcsInfoShared->au64LbrToIpMsr[i]);
1168 if (idInfoMsrStart != 0)
1169 READ_MSR(idInfoMsrStart + i, pVmcsInfoShared->au64LbrInfoMsr[i]);
1170 }
1171
1172 READ_MSR(pVM->nem.s.idLbrTosMsr, pVmcsInfoShared->u64LbrTosMsr);
1173
1174 if (pVM->nem.s.idLerFromIpMsr)
1175 READ_MSR(pVM->nem.s.idLerFromIpMsr, pVmcsInfoShared->u64LerFromIpMsr);
1176 if (pVM->nem.s.idLerToIpMsr)
1177 READ_MSR(pVM->nem.s.idLerToIpMsr, pVmcsInfoShared->u64LerToIpMsr);
1178 }
1179 }
1180
1181 /* Almost done, just update extrn flags and maybe change PGM mode. */
1182 pVCpu->cpum.GstCtx.fExtrn &= ~fWhat;
1183 if (!(pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_ALL))
1184 pVCpu->cpum.GstCtx.fExtrn = 0;
1185
1186#ifdef LOG_ENABLED
1187 nemR3DarwinLogState(pVM, pVCpu);
1188#endif
1189
1190 /* Typical. */
1191 if (!fMaybeChangedMode && !fUpdateCr3)
1192 {
1193 STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateImport, x);
1194 return VINF_SUCCESS;
1195 }
1196
1197 /*
1198 * Slow.
1199 */
1200 if (fMaybeChangedMode)
1201 {
1202 int rc = PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER,
1203 false /* fForce */);
1204 AssertMsgReturn(rc == VINF_SUCCESS, ("rc=%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_NEM_IPE_1);
1205 }
1206
1207 if (fUpdateCr3)
1208 {
1209 int rc = PGMUpdateCR3(pVCpu, pVCpu->cpum.GstCtx.cr3);
1210 if (rc == VINF_SUCCESS)
1211 { /* likely */ }
1212 else
1213 AssertMsgFailedReturn(("rc=%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_NEM_IPE_2);
1214 }
1215
1216 STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateImport, x);
1217
1218 return VINF_SUCCESS;
1219#undef READ_GREG
1220#undef READ_VMCS_FIELD
1221#undef READ_VMCS32_FIELD
1222#undef READ_SEG
1223#undef READ_MSR
1224}
1225
1226
1227/**
1228 * State to pass between nemHCWinHandleMemoryAccess / nemR3WinWHvHandleMemoryAccess
1229 * and nemHCWinHandleMemoryAccessPageCheckerCallback.
1230 */
1231typedef struct NEMHCDARWINHMACPCCSTATE
1232{
1233 /** Input: Write access. */
1234 bool fWriteAccess;
1235 /** Output: Set if we did something. */
1236 bool fDidSomething;
1237 /** Output: Set it we should resume. */
1238 bool fCanResume;
1239} NEMHCDARWINHMACPCCSTATE;
1240
1241/**
1242 * @callback_method_impl{FNPGMPHYSNEMCHECKPAGE,
1243 * Worker for nemR3WinHandleMemoryAccess; pvUser points to a
1244 * NEMHCDARWINHMACPCCSTATE structure. }
1245 */
1246static DECLCALLBACK(int)
1247nemR3DarwinHandleMemoryAccessPageCheckerCallback(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)
1248{
1249 NEMHCDARWINHMACPCCSTATE *pState = (NEMHCDARWINHMACPCCSTATE *)pvUser;
1250 pState->fDidSomething = false;
1251 pState->fCanResume = false;
1252
1253 uint8_t u2State = pInfo->u2NemState;
1254
1255 /*
1256 * Consolidate current page state with actual page protection and access type.
1257 * We don't really consider downgrades here, as they shouldn't happen.
1258 */
1259 int rc;
1260 switch (u2State)
1261 {
1262 case NEM_DARWIN_PAGE_STATE_UNMAPPED:
1263 case NEM_DARWIN_PAGE_STATE_NOT_SET:
1264 if (pInfo->fNemProt == NEM_PAGE_PROT_NONE)
1265 {
1266 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #1\n", GCPhys));
1267 return VINF_SUCCESS;
1268 }
1269
1270 /* Don't bother remapping it if it's a write request to a non-writable page. */
1271 if ( pState->fWriteAccess
1272 && !(pInfo->fNemProt & NEM_PAGE_PROT_WRITE))
1273 {
1274 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #1w\n", GCPhys));
1275 return VINF_SUCCESS;
1276 }
1277
1278 /* Map the page. */
1279 rc = nemHCNativeSetPhysPage(pVM,
1280 pVCpu,
1281 GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
1282 GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
1283 pInfo->fNemProt,
1284 &u2State,
1285 true /*fBackingState*/);
1286 pInfo->u2NemState = u2State;
1287 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - synced => %s + %Rrc\n",
1288 GCPhys, g_apszPageStates[u2State], rc));
1289 pState->fDidSomething = true;
1290 pState->fCanResume = true;
1291 return rc;
1292
1293 case NEM_DARWIN_PAGE_STATE_READABLE:
1294 if ( !(pInfo->fNemProt & NEM_PAGE_PROT_WRITE)
1295 && (pInfo->fNemProt & (NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE)))
1296 {
1297 pState->fCanResume = true;
1298 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #2\n", GCPhys));
1299 return VINF_SUCCESS;
1300 }
1301 break;
1302
1303 case NEM_DARWIN_PAGE_STATE_WRITABLE:
1304 if (pInfo->fNemProt & NEM_PAGE_PROT_WRITE)
1305 {
1306 /* We get spurious EPT exit violations when everything is fine (#3a case) but can resume without issues here... */
1307 pState->fCanResume = true;
1308 if (pInfo->u2OldNemState == NEM_DARWIN_PAGE_STATE_WRITABLE)
1309 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #3a\n", GCPhys));
1310 else
1311 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #3b (%s -> %s)\n",
1312 GCPhys, g_apszPageStates[pInfo->u2OldNemState], g_apszPageStates[u2State]));
1313 return VINF_SUCCESS;
1314 }
1315
1316 break;
1317
1318 default:
1319 AssertLogRelMsgFailedReturn(("u2State=%#x\n", u2State), VERR_NEM_IPE_4);
1320 }
1321
1322 /*
1323 * Unmap and restart the instruction.
1324 * If this fails, which it does every so often, just unmap everything for now.
1325 */
1326 rc = nemR3DarwinUnmap(pVM, GCPhys, X86_PAGE_SIZE);
1327 if (RT_SUCCESS(rc))
1328 {
1329 pState->fDidSomething = true;
1330 pState->fCanResume = true;
1331 pInfo->u2NemState = NEM_DARWIN_PAGE_STATE_UNMAPPED;
1332 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
1333 Log5(("NEM GPA unmapped/exit: %RGp (was %s)\n", GCPhys, g_apszPageStates[u2State]));
1334 return VINF_SUCCESS;
1335 }
1336 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
1337 LogRel(("nemR3DarwinHandleMemoryAccessPageCheckerCallback/unmap: GCPhysDst=%RGp %s rc=%Rrc\n",
1338 GCPhys, g_apszPageStates[u2State], rc));
1339 return VERR_NEM_UNMAP_PAGES_FAILED;
1340}
1341
1342
1343DECL_FORCE_INLINE(bool) nemR3DarwinIsUnrestrictedGuest(PCVMCC pVM)
1344{
1345 RT_NOREF(pVM);
1346 return true;
1347}
1348
1349
1350DECL_FORCE_INLINE(bool) nemR3DarwinIsNestedPaging(PCVMCC pVM)
1351{
1352 RT_NOREF(pVM);
1353 return true;
1354}
1355
1356
1357DECL_FORCE_INLINE(bool) nemR3DarwinIsPreemptTimerUsed(PCVMCC pVM)
1358{
1359 RT_NOREF(pVM);
1360 return false;
1361}
1362
1363
1364#if 0 /* unused */
1365DECL_FORCE_INLINE(bool) nemR3DarwinIsVmxLbr(PCVMCC pVM)
1366{
1367 RT_NOREF(pVM);
1368 return false;
1369}
1370#endif
1371
1372
1373/*
1374 * Instantiate the code we share with ring-0.
1375 */
1376#define IN_NEM_DARWIN
1377//#define HMVMX_ALWAYS_TRAP_ALL_XCPTS
1378//#define HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
1379//#define HMVMX_ALWAYS_INTERCEPT_CR3_ACCESS
1380#define VCPU_2_VMXSTATE(a_pVCpu) (a_pVCpu)->nem.s
1381#define VCPU_2_VMXSTATS(a_pVCpu) (*(a_pVCpu)->nem.s.pVmxStats)
1382
1383#define VM_IS_VMX_UNRESTRICTED_GUEST(a_pVM) nemR3DarwinIsUnrestrictedGuest((a_pVM))
1384#define VM_IS_VMX_NESTED_PAGING(a_pVM) nemR3DarwinIsNestedPaging((a_pVM))
1385#define VM_IS_VMX_PREEMPT_TIMER_USED(a_pVM) nemR3DarwinIsPreemptTimerUsed((a_pVM))
1386#define VM_IS_VMX_LBR(a_pVM) nemR3DarwinIsVmxLbr((a_pVM))
1387
1388#define VMX_VMCS_WRITE_16(a_pVCpu, a_FieldEnc, a_Val) nemR3DarwinWriteVmcs16((a_pVCpu), (a_FieldEnc), (a_Val))
1389#define VMX_VMCS_WRITE_32(a_pVCpu, a_FieldEnc, a_Val) nemR3DarwinWriteVmcs32((a_pVCpu), (a_FieldEnc), (a_Val))
1390#define VMX_VMCS_WRITE_64(a_pVCpu, a_FieldEnc, a_Val) nemR3DarwinWriteVmcs64((a_pVCpu), (a_FieldEnc), (a_Val))
1391#define VMX_VMCS_WRITE_NW(a_pVCpu, a_FieldEnc, a_Val) nemR3DarwinWriteVmcs64((a_pVCpu), (a_FieldEnc), (a_Val))
1392
1393#define VMX_VMCS_READ_16(a_pVCpu, a_FieldEnc, a_pVal) nemR3DarwinReadVmcs16((a_pVCpu), (a_FieldEnc), (a_pVal))
1394#define VMX_VMCS_READ_32(a_pVCpu, a_FieldEnc, a_pVal) nemR3DarwinReadVmcs32((a_pVCpu), (a_FieldEnc), (a_pVal))
1395#define VMX_VMCS_READ_64(a_pVCpu, a_FieldEnc, a_pVal) nemR3DarwinReadVmcs64((a_pVCpu), (a_FieldEnc), (a_pVal))
1396#define VMX_VMCS_READ_NW(a_pVCpu, a_FieldEnc, a_pVal) nemR3DarwinReadVmcs64((a_pVCpu), (a_FieldEnc), (a_pVal))
1397
1398#include "../VMMAll/VMXAllTemplate.cpp.h"
1399
1400#undef VMX_VMCS_WRITE_16
1401#undef VMX_VMCS_WRITE_32
1402#undef VMX_VMCS_WRITE_64
1403#undef VMX_VMCS_WRITE_NW
1404
1405#undef VMX_VMCS_READ_16
1406#undef VMX_VMCS_READ_32
1407#undef VMX_VMCS_READ_64
1408#undef VMX_VMCS_READ_NW
1409
1410#undef VM_IS_VMX_PREEMPT_TIMER_USED
1411#undef VM_IS_VMX_NESTED_PAGING
1412#undef VM_IS_VMX_UNRESTRICTED_GUEST
1413#undef VCPU_2_VMXSTATS
1414#undef VCPU_2_VMXSTATE
1415
1416
1417/**
1418 * Exports the guest GP registers to HV for execution.
1419 *
1420 * @returns VBox status code.
1421 * @param pVCpu The cross context virtual CPU structure of the
1422 * calling EMT.
1423 */
1424static int nemR3DarwinExportGuestGprs(PVMCPUCC pVCpu)
1425{
1426#define WRITE_GREG(a_GReg, a_Value) \
1427 do \
1428 { \
1429 hv_return_t hrc = hv_vcpu_write_register(pVCpu->nem.s.hVCpuId, (a_GReg), (a_Value)); \
1430 if (RT_LIKELY(hrc == HV_SUCCESS)) \
1431 { /* likely */ } \
1432 else \
1433 return VERR_INTERNAL_ERROR; \
1434 } while(0)
1435
1436 uint64_t fCtxChanged = ASMAtomicUoReadU64(&pVCpu->nem.s.fCtxChanged);
1437 if (fCtxChanged & HM_CHANGED_GUEST_GPRS_MASK)
1438 {
1439 if (fCtxChanged & HM_CHANGED_GUEST_RAX)
1440 WRITE_GREG(HV_X86_RAX, pVCpu->cpum.GstCtx.rax);
1441 if (fCtxChanged & HM_CHANGED_GUEST_RCX)
1442 WRITE_GREG(HV_X86_RCX, pVCpu->cpum.GstCtx.rcx);
1443 if (fCtxChanged & HM_CHANGED_GUEST_RDX)
1444 WRITE_GREG(HV_X86_RDX, pVCpu->cpum.GstCtx.rdx);
1445 if (fCtxChanged & HM_CHANGED_GUEST_RBX)
1446 WRITE_GREG(HV_X86_RBX, pVCpu->cpum.GstCtx.rbx);
1447 if (fCtxChanged & HM_CHANGED_GUEST_RSP)
1448 WRITE_GREG(HV_X86_RSP, pVCpu->cpum.GstCtx.rsp);
1449 if (fCtxChanged & HM_CHANGED_GUEST_RBP)
1450 WRITE_GREG(HV_X86_RBP, pVCpu->cpum.GstCtx.rbp);
1451 if (fCtxChanged & HM_CHANGED_GUEST_RSI)
1452 WRITE_GREG(HV_X86_RSI, pVCpu->cpum.GstCtx.rsi);
1453 if (fCtxChanged & HM_CHANGED_GUEST_RDI)
1454 WRITE_GREG(HV_X86_RDI, pVCpu->cpum.GstCtx.rdi);
1455 if (fCtxChanged & HM_CHANGED_GUEST_R8_R15)
1456 {
1457 WRITE_GREG(HV_X86_R8, pVCpu->cpum.GstCtx.r8);
1458 WRITE_GREG(HV_X86_R9, pVCpu->cpum.GstCtx.r9);
1459 WRITE_GREG(HV_X86_R10, pVCpu->cpum.GstCtx.r10);
1460 WRITE_GREG(HV_X86_R11, pVCpu->cpum.GstCtx.r11);
1461 WRITE_GREG(HV_X86_R12, pVCpu->cpum.GstCtx.r12);
1462 WRITE_GREG(HV_X86_R13, pVCpu->cpum.GstCtx.r13);
1463 WRITE_GREG(HV_X86_R14, pVCpu->cpum.GstCtx.r14);
1464 WRITE_GREG(HV_X86_R15, pVCpu->cpum.GstCtx.r15);
1465 }
1466
1467 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_GPRS_MASK);
1468 }
1469
1470 if (fCtxChanged & HM_CHANGED_GUEST_CR2)
1471 {
1472 WRITE_GREG(HV_X86_CR2, pVCpu->cpum.GstCtx.cr2);
1473 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_CR2);
1474 }
1475
1476 return VINF_SUCCESS;
1477#undef WRITE_GREG
1478}
1479
1480
1481/**
1482 * Exports the guest debug registers into the guest-state applying any hypervisor
1483 * debug related states (hardware breakpoints from the debugger, etc.).
1484 *
1485 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
1486 *
1487 * @returns VBox status code.
1488 * @param pVCpu The cross context virtual CPU structure.
1489 * @param pVmxTransient The VMX-transient structure.
1490 */
1491static int nemR3DarwinExportDebugState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
1492{
1493 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1494
1495#ifdef VBOX_STRICT
1496 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
1497 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
1498 {
1499 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
1500 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
1501 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
1502 }
1503#endif
1504
1505 bool fSteppingDB = false;
1506 bool fInterceptMovDRx = false;
1507 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
1508 if (pVCpu->nem.s.fSingleInstruction)
1509 {
1510 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
1511 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
1512 {
1513 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
1514 Assert(fSteppingDB == false);
1515 }
1516 else
1517 {
1518 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
1519 pVCpu->nem.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
1520 pVCpu->nem.s.fClearTrapFlag = true;
1521 fSteppingDB = true;
1522 }
1523 }
1524
1525 uint64_t u64GuestDr7;
1526 if ( fSteppingDB
1527 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
1528 {
1529 /*
1530 * Use the combined guest and host DRx values found in the hypervisor register set
1531 * because the hypervisor debugger has breakpoints active or someone is single stepping
1532 * on the host side without a monitor trap flag.
1533 *
1534 * Note! DBGF expects a clean DR6 state before executing guest code.
1535 */
1536 if (!CPUMIsHyperDebugStateActive(pVCpu))
1537 {
1538 /*
1539 * Make sure the hypervisor values are up to date.
1540 */
1541 CPUMRecalcHyperDRx(pVCpu, UINT8_MAX /* no loading, please */);
1542
1543 CPUMR3NemActivateHyperDebugState(pVCpu);
1544
1545 Assert(CPUMIsHyperDebugStateActive(pVCpu));
1546 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
1547 }
1548
1549 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
1550 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
1551 pVCpu->nem.s.fUsingHyperDR7 = true;
1552 fInterceptMovDRx = true;
1553 }
1554 else
1555 {
1556 /*
1557 * If the guest has enabled debug registers, we need to load them prior to
1558 * executing guest code so they'll trigger at the right time.
1559 */
1560 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
1561 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
1562 {
1563 if (!CPUMIsGuestDebugStateActive(pVCpu))
1564 {
1565 CPUMR3NemActivateGuestDebugState(pVCpu);
1566
1567 Assert(CPUMIsGuestDebugStateActive(pVCpu));
1568 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
1569 }
1570 Assert(!fInterceptMovDRx);
1571 }
1572 else if (!CPUMIsGuestDebugStateActive(pVCpu))
1573 {
1574 /*
1575 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
1576 * must intercept #DB in order to maintain a correct DR6 guest value, and
1577 * because we need to intercept it to prevent nested #DBs from hanging the
1578 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
1579 */
1580 fInterceptMovDRx = true;
1581 }
1582
1583 /* Update DR7 with the actual guest value. */
1584 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
1585 pVCpu->nem.s.fUsingHyperDR7 = false;
1586 }
1587
1588 if (fInterceptMovDRx)
1589 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
1590 else
1591 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
1592
1593 /*
1594 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
1595 * monitor-trap flag and update our cache.
1596 */
1597 if (uProcCtls != pVmcsInfo->u32ProcCtls)
1598 {
1599 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
1600 AssertRC(rc);
1601 pVmcsInfo->u32ProcCtls = uProcCtls;
1602 }
1603
1604 /*
1605 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
1606 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
1607 *
1608 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
1609 */
1610 if (fSteppingDB)
1611 {
1612 Assert(pVCpu->nem.s.fSingleInstruction);
1613 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
1614
1615 uint32_t fIntrState = 0;
1616 int rc = nemR3DarwinReadVmcs32(pVCpu, VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
1617 AssertRC(rc);
1618
1619 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
1620 {
1621 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
1622 rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_GUEST_INT_STATE, fIntrState);
1623 AssertRC(rc);
1624 }
1625 }
1626
1627 /*
1628 * Store status of the shared guest/host debug state at the time of VM-entry.
1629 */
1630 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
1631 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
1632
1633 return VINF_SUCCESS;
1634}
1635
1636
1637/**
1638 * Converts the given CPUM externalized bitmask to the appropriate HM changed bitmask.
1639 *
1640 * @returns Bitmask of HM changed flags.
1641 * @param fCpumExtrn The CPUM extern bitmask.
1642 */
1643static uint64_t nemR3DarwinCpumExtrnToHmChanged(uint64_t fCpumExtrn)
1644{
1645 uint64_t fHmChanged = 0;
1646
1647 /* Invert to gt a mask of things which are kept in CPUM. */
1648 uint64_t fCpumIntern = ~fCpumExtrn;
1649
1650 if (fCpumIntern & CPUMCTX_EXTRN_GPRS_MASK)
1651 {
1652 if (fCpumIntern & CPUMCTX_EXTRN_RAX)
1653 fHmChanged |= HM_CHANGED_GUEST_RAX;
1654 if (fCpumIntern & CPUMCTX_EXTRN_RCX)
1655 fHmChanged |= HM_CHANGED_GUEST_RCX;
1656 if (fCpumIntern & CPUMCTX_EXTRN_RDX)
1657 fHmChanged |= HM_CHANGED_GUEST_RDX;
1658 if (fCpumIntern & CPUMCTX_EXTRN_RBX)
1659 fHmChanged |= HM_CHANGED_GUEST_RBX;
1660 if (fCpumIntern & CPUMCTX_EXTRN_RSP)
1661 fHmChanged |= HM_CHANGED_GUEST_RSP;
1662 if (fCpumIntern & CPUMCTX_EXTRN_RBP)
1663 fHmChanged |= HM_CHANGED_GUEST_RBP;
1664 if (fCpumIntern & CPUMCTX_EXTRN_RSI)
1665 fHmChanged |= HM_CHANGED_GUEST_RSI;
1666 if (fCpumIntern & CPUMCTX_EXTRN_RDI)
1667 fHmChanged |= HM_CHANGED_GUEST_RDI;
1668 if (fCpumIntern & CPUMCTX_EXTRN_R8_R15)
1669 fHmChanged |= HM_CHANGED_GUEST_R8_R15;
1670 }
1671
1672 /* RIP & Flags */
1673 if (fCpumIntern & CPUMCTX_EXTRN_RIP)
1674 fHmChanged |= HM_CHANGED_GUEST_RIP;
1675 if (fCpumIntern & CPUMCTX_EXTRN_RFLAGS)
1676 fHmChanged |= HM_CHANGED_GUEST_RFLAGS;
1677
1678 /* Segments */
1679 if (fCpumIntern & CPUMCTX_EXTRN_SREG_MASK)
1680 {
1681 if (fCpumIntern & CPUMCTX_EXTRN_ES)
1682 fHmChanged |= HM_CHANGED_GUEST_ES;
1683 if (fCpumIntern & CPUMCTX_EXTRN_CS)
1684 fHmChanged |= HM_CHANGED_GUEST_CS;
1685 if (fCpumIntern & CPUMCTX_EXTRN_SS)
1686 fHmChanged |= HM_CHANGED_GUEST_SS;
1687 if (fCpumIntern & CPUMCTX_EXTRN_DS)
1688 fHmChanged |= HM_CHANGED_GUEST_DS;
1689 if (fCpumIntern & CPUMCTX_EXTRN_FS)
1690 fHmChanged |= HM_CHANGED_GUEST_FS;
1691 if (fCpumIntern & CPUMCTX_EXTRN_GS)
1692 fHmChanged |= HM_CHANGED_GUEST_GS;
1693 }
1694
1695 /* Descriptor tables & task segment. */
1696 if (fCpumIntern & CPUMCTX_EXTRN_TABLE_MASK)
1697 {
1698 if (fCpumIntern & CPUMCTX_EXTRN_LDTR)
1699 fHmChanged |= HM_CHANGED_GUEST_LDTR;
1700 if (fCpumIntern & CPUMCTX_EXTRN_TR)
1701 fHmChanged |= HM_CHANGED_GUEST_TR;
1702 if (fCpumIntern & CPUMCTX_EXTRN_IDTR)
1703 fHmChanged |= HM_CHANGED_GUEST_IDTR;
1704 if (fCpumIntern & CPUMCTX_EXTRN_GDTR)
1705 fHmChanged |= HM_CHANGED_GUEST_GDTR;
1706 }
1707
1708 /* Control registers. */
1709 if (fCpumIntern & CPUMCTX_EXTRN_CR_MASK)
1710 {
1711 if (fCpumIntern & CPUMCTX_EXTRN_CR0)
1712 fHmChanged |= HM_CHANGED_GUEST_CR0;
1713 if (fCpumIntern & CPUMCTX_EXTRN_CR2)
1714 fHmChanged |= HM_CHANGED_GUEST_CR2;
1715 if (fCpumIntern & CPUMCTX_EXTRN_CR3)
1716 fHmChanged |= HM_CHANGED_GUEST_CR3;
1717 if (fCpumIntern & CPUMCTX_EXTRN_CR4)
1718 fHmChanged |= HM_CHANGED_GUEST_CR4;
1719 }
1720 if (fCpumIntern & CPUMCTX_EXTRN_APIC_TPR)
1721 fHmChanged |= HM_CHANGED_GUEST_APIC_TPR;
1722
1723 /* Debug registers. */
1724 if (fCpumIntern & CPUMCTX_EXTRN_DR0_DR3)
1725 fHmChanged |= HM_CHANGED_GUEST_DR0_DR3;
1726 if (fCpumIntern & CPUMCTX_EXTRN_DR6)
1727 fHmChanged |= HM_CHANGED_GUEST_DR6;
1728 if (fCpumIntern & CPUMCTX_EXTRN_DR7)
1729 fHmChanged |= HM_CHANGED_GUEST_DR7;
1730
1731 /* Floating point state. */
1732 if (fCpumIntern & CPUMCTX_EXTRN_X87)
1733 fHmChanged |= HM_CHANGED_GUEST_X87;
1734 if (fCpumIntern & CPUMCTX_EXTRN_SSE_AVX)
1735 fHmChanged |= HM_CHANGED_GUEST_SSE_AVX;
1736 if (fCpumIntern & CPUMCTX_EXTRN_OTHER_XSAVE)
1737 fHmChanged |= HM_CHANGED_GUEST_OTHER_XSAVE;
1738 if (fCpumIntern & CPUMCTX_EXTRN_XCRx)
1739 fHmChanged |= HM_CHANGED_GUEST_XCRx;
1740
1741 /* MSRs */
1742 if (fCpumIntern & CPUMCTX_EXTRN_EFER)
1743 fHmChanged |= HM_CHANGED_GUEST_EFER_MSR;
1744 if (fCpumIntern & CPUMCTX_EXTRN_KERNEL_GS_BASE)
1745 fHmChanged |= HM_CHANGED_GUEST_KERNEL_GS_BASE;
1746 if (fCpumIntern & CPUMCTX_EXTRN_SYSENTER_MSRS)
1747 fHmChanged |= HM_CHANGED_GUEST_SYSENTER_MSR_MASK;
1748 if (fCpumIntern & CPUMCTX_EXTRN_SYSCALL_MSRS)
1749 fHmChanged |= HM_CHANGED_GUEST_SYSCALL_MSRS;
1750 if (fCpumIntern & CPUMCTX_EXTRN_TSC_AUX)
1751 fHmChanged |= HM_CHANGED_GUEST_TSC_AUX;
1752 if (fCpumIntern & CPUMCTX_EXTRN_OTHER_MSRS)
1753 fHmChanged |= HM_CHANGED_GUEST_OTHER_MSRS;
1754
1755 return fHmChanged;
1756}
1757
1758
1759/**
1760 * Exports the guest state to HV for execution.
1761 *
1762 * @returns VBox status code.
1763 * @param pVM The cross context VM structure.
1764 * @param pVCpu The cross context virtual CPU structure of the
1765 * calling EMT.
1766 * @param pVmxTransient The transient VMX structure.
1767 */
1768static int nemR3DarwinExportGuestState(PVMCC pVM, PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
1769{
1770#define WRITE_GREG(a_GReg, a_Value) \
1771 do \
1772 { \
1773 hv_return_t hrc = hv_vcpu_write_register(pVCpu->nem.s.hVCpuId, (a_GReg), (a_Value)); \
1774 if (RT_LIKELY(hrc == HV_SUCCESS)) \
1775 { /* likely */ } \
1776 else \
1777 return VERR_INTERNAL_ERROR; \
1778 } while(0)
1779#define WRITE_VMCS_FIELD(a_Field, a_Value) \
1780 do \
1781 { \
1782 hv_return_t hrc = hv_vmx_vcpu_write_vmcs(pVCpu->nem.s.hVCpuId, (a_Field), (a_Value)); \
1783 if (RT_LIKELY(hrc == HV_SUCCESS)) \
1784 { /* likely */ } \
1785 else \
1786 return VERR_INTERNAL_ERROR; \
1787 } while(0)
1788#define WRITE_MSR(a_Msr, a_Value) \
1789 do \
1790 { \
1791 hv_return_t hrc = hv_vcpu_write_msr(pVCpu->nem.s.hVCpuId, (a_Msr), (a_Value)); \
1792 if (RT_LIKELY(hrc == HV_SUCCESS)) \
1793 { /* likely */ } \
1794 else \
1795 AssertFailedReturn(VERR_INTERNAL_ERROR); \
1796 } while(0)
1797
1798 RT_NOREF(pVM);
1799
1800#ifdef LOG_ENABLED
1801 nemR3DarwinLogState(pVM, pVCpu);
1802#endif
1803
1804 STAM_PROFILE_ADV_START(&pVCpu->nem.s.StatProfGstStateExport, x);
1805
1806 uint64_t const fWhat = ~pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_ALL;
1807 if (!fWhat)
1808 return VINF_SUCCESS;
1809
1810 pVCpu->nem.s.fCtxChanged |= nemR3DarwinCpumExtrnToHmChanged(pVCpu->cpum.GstCtx.fExtrn);
1811
1812 int rc = vmxHCExportGuestEntryExitCtls(pVCpu, pVmxTransient);
1813 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
1814
1815 rc = nemR3DarwinExportGuestGprs(pVCpu);
1816 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
1817
1818 rc = vmxHCExportGuestCR0(pVCpu, pVmxTransient);
1819 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
1820
1821 VBOXSTRICTRC rcStrict = vmxHCExportGuestCR3AndCR4(pVCpu, pVmxTransient);
1822 if (rcStrict == VINF_SUCCESS)
1823 { /* likely */ }
1824 else
1825 {
1826 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
1827 return VBOXSTRICTRC_VAL(rcStrict);
1828 }
1829
1830 rc = nemR3DarwinExportDebugState(pVCpu, pVmxTransient);
1831 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
1832
1833 vmxHCExportGuestXcptIntercepts(pVCpu, pVmxTransient);
1834 vmxHCExportGuestRip(pVCpu);
1835 //vmxHCExportGuestRsp(pVCpu);
1836 vmxHCExportGuestRflags(pVCpu, pVmxTransient);
1837
1838 rc = vmxHCExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
1839 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
1840
1841 if (fWhat & CPUMCTX_EXTRN_XCRx)
1842 {
1843 WRITE_GREG(HV_X86_XCR0, pVCpu->cpum.GstCtx.aXcr[0]);
1844 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_XCRx);
1845 }
1846
1847 if (fWhat & CPUMCTX_EXTRN_APIC_TPR)
1848 {
1849 Assert(pVCpu->nem.s.fCtxChanged & HM_CHANGED_GUEST_APIC_TPR);
1850 vmxHCExportGuestApicTpr(pVCpu, pVmxTransient);
1851
1852 rc = APICGetTpr(pVCpu, &pVmxTransient->u8GuestTpr, NULL /*pfPending*/, NULL /*pu8PendingIntr*/);
1853 AssertRC(rc);
1854
1855 WRITE_GREG(HV_X86_TPR, pVmxTransient->u8GuestTpr);
1856 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
1857 }
1858
1859 /* Debug registers. */
1860 if (fWhat & CPUMCTX_EXTRN_DR0_DR3)
1861 {
1862 WRITE_GREG(HV_X86_DR0, CPUMGetHyperDR0(pVCpu));
1863 WRITE_GREG(HV_X86_DR1, CPUMGetHyperDR1(pVCpu));
1864 WRITE_GREG(HV_X86_DR2, CPUMGetHyperDR2(pVCpu));
1865 WRITE_GREG(HV_X86_DR3, CPUMGetHyperDR3(pVCpu));
1866 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_DR0_DR3);
1867 }
1868 if (fWhat & CPUMCTX_EXTRN_DR6)
1869 {
1870 WRITE_GREG(HV_X86_DR6, CPUMGetHyperDR6(pVCpu));
1871 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_DR6);
1872 }
1873 if (fWhat & CPUMCTX_EXTRN_DR7)
1874 {
1875 WRITE_GREG(HV_X86_DR7, CPUMGetHyperDR7(pVCpu));
1876 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_DR7);
1877 }
1878
1879 if (fWhat & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE))
1880 {
1881 hv_return_t hrc = hv_vcpu_write_fpstate(pVCpu->nem.s.hVCpuId, &pVCpu->cpum.GstCtx.XState, sizeof(pVCpu->cpum.GstCtx.XState));
1882 if (hrc == HV_SUCCESS)
1883 { /* likely */ }
1884 else
1885 return nemR3DarwinHvSts2Rc(hrc);
1886
1887 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~(HM_CHANGED_GUEST_X87 | HM_CHANGED_GUEST_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE));
1888 }
1889
1890 /* MSRs */
1891 if (fWhat & CPUMCTX_EXTRN_EFER)
1892 {
1893 WRITE_VMCS_FIELD(VMX_VMCS64_GUEST_EFER_FULL, pVCpu->cpum.GstCtx.msrEFER);
1894 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
1895 }
1896 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
1897 {
1898 WRITE_MSR(MSR_K8_KERNEL_GS_BASE, pVCpu->cpum.GstCtx.msrKERNELGSBASE);
1899 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_KERNEL_GS_BASE);
1900 }
1901 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
1902 {
1903 WRITE_MSR(MSR_IA32_SYSENTER_CS, pVCpu->cpum.GstCtx.SysEnter.cs);
1904 WRITE_MSR(MSR_IA32_SYSENTER_EIP, pVCpu->cpum.GstCtx.SysEnter.eip);
1905 WRITE_MSR(MSR_IA32_SYSENTER_ESP, pVCpu->cpum.GstCtx.SysEnter.esp);
1906 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_MSR_MASK);
1907 }
1908 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
1909 {
1910 WRITE_MSR(MSR_K6_STAR, pVCpu->cpum.GstCtx.msrSTAR);
1911 WRITE_MSR(MSR_K8_LSTAR, pVCpu->cpum.GstCtx.msrLSTAR);
1912 WRITE_MSR(MSR_K8_CSTAR, pVCpu->cpum.GstCtx.msrCSTAR);
1913 WRITE_MSR(MSR_K8_SF_MASK, pVCpu->cpum.GstCtx.msrSFMASK);
1914 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSCALL_MSRS);
1915 }
1916 if (fWhat & CPUMCTX_EXTRN_TSC_AUX)
1917 {
1918 PCPUMCTXMSRS pCtxMsrs = CPUMQueryGuestCtxMsrsPtr(pVCpu);
1919
1920 WRITE_MSR(MSR_K8_TSC_AUX, pCtxMsrs->msr.TscAux);
1921 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_TSC_AUX);
1922 }
1923 if (fWhat & CPUMCTX_EXTRN_OTHER_MSRS)
1924 {
1925 /* Last Branch Record. */
1926 if (pVM->nem.s.fLbr)
1927 {
1928 PVMXVMCSINFOSHARED const pVmcsInfoShared = &pVCpu->nem.s.vmx.VmcsInfo;
1929 uint32_t const idFromIpMsrStart = pVM->nem.s.idLbrFromIpMsrFirst;
1930 uint32_t const idToIpMsrStart = pVM->nem.s.idLbrToIpMsrFirst;
1931 uint32_t const idInfoMsrStart = pVM->nem.s.idLbrInfoMsrFirst;
1932 uint32_t const cLbrStack = pVM->nem.s.idLbrFromIpMsrLast - pVM->nem.s.idLbrFromIpMsrFirst + 1;
1933 Assert(cLbrStack <= 32);
1934 for (uint32_t i = 0; i < cLbrStack; i++)
1935 {
1936 WRITE_MSR(idFromIpMsrStart + i, pVmcsInfoShared->au64LbrFromIpMsr[i]);
1937
1938 /* Some CPUs don't have a Branch-To-IP MSR (P4 and related Xeons). */
1939 if (idToIpMsrStart != 0)
1940 WRITE_MSR(idToIpMsrStart + i, pVmcsInfoShared->au64LbrToIpMsr[i]);
1941 if (idInfoMsrStart != 0)
1942 WRITE_MSR(idInfoMsrStart + i, pVmcsInfoShared->au64LbrInfoMsr[i]);
1943 }
1944
1945 WRITE_MSR(pVM->nem.s.idLbrTosMsr, pVmcsInfoShared->u64LbrTosMsr);
1946 if (pVM->nem.s.idLerFromIpMsr)
1947 WRITE_MSR(pVM->nem.s.idLerFromIpMsr, pVmcsInfoShared->u64LerFromIpMsr);
1948 if (pVM->nem.s.idLerToIpMsr)
1949 WRITE_MSR(pVM->nem.s.idLerToIpMsr, pVmcsInfoShared->u64LerToIpMsr);
1950 }
1951
1952 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
1953 }
1954
1955 hv_vcpu_invalidate_tlb(pVCpu->nem.s.hVCpuId);
1956 hv_vcpu_flush(pVCpu->nem.s.hVCpuId);
1957
1958 pVCpu->cpum.GstCtx.fExtrn |= CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_NEM;
1959
1960 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
1961 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~( HM_CHANGED_GUEST_HWVIRT
1962 | HM_CHANGED_VMX_GUEST_AUTO_MSRS
1963 | HM_CHANGED_VMX_GUEST_LAZY_MSRS
1964 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
1965
1966 STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateExport, x);
1967 return VINF_SUCCESS;
1968#undef WRITE_GREG
1969#undef WRITE_VMCS_FIELD
1970}
1971
1972
1973/**
1974 * Common worker for both nemR3DarwinHandleExit() and nemR3DarwinHandleExitDebug().
1975 *
1976 * @returns VBox strict status code.
1977 * @param pVM The cross context VM structure.
1978 * @param pVCpu The cross context virtual CPU structure of the
1979 * calling EMT.
1980 * @param pVmxTransient The transient VMX structure.
1981 */
1982DECLINLINE(int) nemR3DarwinHandleExitCommon(PVM pVM, PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
1983{
1984 uint32_t uExitReason;
1985 int rc = nemR3DarwinReadVmcs32(pVCpu, VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
1986 AssertRC(rc);
1987 pVmxTransient->fVmcsFieldsRead = 0;
1988 pVmxTransient->fIsNestedGuest = false;
1989 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
1990 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
1991
1992 if (RT_UNLIKELY(pVmxTransient->fVMEntryFailed))
1993 AssertLogRelMsgFailedReturn(("Running guest failed for CPU #%u: %#x %u\n",
1994 pVCpu->idCpu, pVmxTransient->uExitReason, vmxHCCheckGuestState(pVCpu, &pVCpu->nem.s.VmcsInfo)),
1995 VERR_NEM_IPE_0);
1996
1997 /** @todo Only copy the state on demand (the R0 VT-x code saves some stuff unconditionally and the VMX template assumes that
1998 * when handling exits). */
1999 rc = nemR3DarwinCopyStateFromHv(pVM, pVCpu, CPUMCTX_EXTRN_ALL);
2000 AssertRCReturn(rc, rc);
2001
2002 STAM_COUNTER_INC(&pVCpu->nem.s.pVmxStats->aStatExitReason[pVmxTransient->uExitReason & MASK_EXITREASON_STAT]);
2003 STAM_REL_COUNTER_INC(&pVCpu->nem.s.pVmxStats->StatExitAll);
2004 return VINF_SUCCESS;
2005}
2006
2007
2008/**
2009 * Handles an exit from hv_vcpu_run().
2010 *
2011 * @returns VBox strict status code.
2012 * @param pVM The cross context VM structure.
2013 * @param pVCpu The cross context virtual CPU structure of the
2014 * calling EMT.
2015 * @param pVmxTransient The transient VMX structure.
2016 */
2017static VBOXSTRICTRC nemR3DarwinHandleExit(PVM pVM, PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
2018{
2019 int rc = nemR3DarwinHandleExitCommon(pVM, pVCpu, pVmxTransient);
2020 AssertRCReturn(rc, rc);
2021
2022#ifndef HMVMX_USE_FUNCTION_TABLE
2023 return vmxHCHandleExit(pVCpu, pVmxTransient);
2024#else
2025 return g_aVMExitHandlers[pVmxTransient->uExitReason].pfn(pVCpu, pVmxTransient);
2026#endif
2027}
2028
2029
2030/**
2031 * Handles an exit from hv_vcpu_run() - debug runloop variant.
2032 *
2033 * @returns VBox strict status code.
2034 * @param pVM The cross context VM structure.
2035 * @param pVCpu The cross context virtual CPU structure of the
2036 * calling EMT.
2037 * @param pVmxTransient The transient VMX structure.
2038 * @param pDbgState The debug state structure.
2039 */
2040static VBOXSTRICTRC nemR3DarwinHandleExitDebug(PVM pVM, PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
2041{
2042 int rc = nemR3DarwinHandleExitCommon(pVM, pVCpu, pVmxTransient);
2043 AssertRCReturn(rc, rc);
2044
2045 return vmxHCRunDebugHandleExit(pVCpu, pVmxTransient, pDbgState);
2046}
2047
2048
2049/**
2050 * Worker for nemR3NativeInit that loads the Hypervisor.framework shared library.
2051 *
2052 * @returns VBox status code.
2053 * @param fForced Whether the HMForced flag is set and we should
2054 * fail if we cannot initialize.
2055 * @param pErrInfo Where to always return error info.
2056 */
2057static int nemR3DarwinLoadHv(bool fForced, PRTERRINFO pErrInfo)
2058{
2059 RTLDRMOD hMod = NIL_RTLDRMOD;
2060 static const char *s_pszHvPath = "/System/Library/Frameworks/Hypervisor.framework/Hypervisor";
2061
2062 int rc = RTLdrLoadEx(s_pszHvPath, &hMod, RTLDRLOAD_FLAGS_NO_UNLOAD | RTLDRLOAD_FLAGS_NO_SUFFIX, pErrInfo);
2063 if (RT_SUCCESS(rc))
2064 {
2065 for (unsigned i = 0; i < RT_ELEMENTS(g_aImports); i++)
2066 {
2067 int rc2 = RTLdrGetSymbol(hMod, g_aImports[i].pszName, (void **)g_aImports[i].ppfn);
2068 if (RT_SUCCESS(rc2))
2069 {
2070 if (g_aImports[i].fOptional)
2071 LogRel(("NEM: info: Found optional import Hypervisor!%s.\n",
2072 g_aImports[i].pszName));
2073 }
2074 else
2075 {
2076 *g_aImports[i].ppfn = NULL;
2077
2078 LogRel(("NEM: %s: Failed to import Hypervisor!%s: %Rrc\n",
2079 g_aImports[i].fOptional ? "info" : fForced ? "fatal" : "error",
2080 g_aImports[i].pszName, rc2));
2081 if (!g_aImports[i].fOptional)
2082 {
2083 if (RTErrInfoIsSet(pErrInfo))
2084 RTErrInfoAddF(pErrInfo, rc2, ", Hypervisor!%s", g_aImports[i].pszName);
2085 else
2086 rc = RTErrInfoSetF(pErrInfo, rc2, "Failed to import: Hypervisor!%s", g_aImports[i].pszName);
2087 Assert(RT_FAILURE(rc));
2088 }
2089 }
2090 }
2091 if (RT_SUCCESS(rc))
2092 {
2093 Assert(!RTErrInfoIsSet(pErrInfo));
2094 }
2095
2096 RTLdrClose(hMod);
2097 }
2098 else
2099 {
2100 RTErrInfoAddF(pErrInfo, rc, "Failed to load Hypervisor.framwork: %s: %Rrc", s_pszHvPath, rc);
2101 rc = VERR_NEM_INIT_FAILED;
2102 }
2103
2104 return rc;
2105}
2106
2107
2108/**
2109 * Read and initialize the global capabilities supported by this CPU.
2110 *
2111 * @returns VBox status code.
2112 */
2113static int nemR3DarwinCapsInit(void)
2114{
2115 RT_ZERO(g_HmMsrs);
2116
2117 hv_return_t hrc = hv_vmx_read_capability(HV_VMX_CAP_PINBASED, &g_HmMsrs.u.vmx.PinCtls.u);
2118 if (hrc == HV_SUCCESS)
2119 hrc = hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &g_HmMsrs.u.vmx.ProcCtls.u);
2120 if (hrc == HV_SUCCESS)
2121 hrc = hv_vmx_read_capability(HV_VMX_CAP_ENTRY, &g_HmMsrs.u.vmx.EntryCtls.u);
2122 if (hrc == HV_SUCCESS)
2123 hrc = hv_vmx_read_capability(HV_VMX_CAP_EXIT, &g_HmMsrs.u.vmx.ExitCtls.u);
2124 if (hrc == HV_SUCCESS)
2125 {
2126 hrc = hv_vmx_read_capability(HV_VMX_CAP_BASIC, &g_HmMsrs.u.vmx.u64Basic);
2127 if (hrc == HV_SUCCESS)
2128 {
2129 if (hrc == HV_SUCCESS)
2130 hrc = hv_vmx_read_capability(HV_VMX_CAP_MISC, &g_HmMsrs.u.vmx.u64Misc);
2131 if (hrc == HV_SUCCESS)
2132 hrc = hv_vmx_read_capability(HV_VMX_CAP_CR0_FIXED0, &g_HmMsrs.u.vmx.u64Cr0Fixed0);
2133 if (hrc == HV_SUCCESS)
2134 hrc = hv_vmx_read_capability(HV_VMX_CAP_CR0_FIXED1, &g_HmMsrs.u.vmx.u64Cr0Fixed1);
2135 if (hrc == HV_SUCCESS)
2136 hrc = hv_vmx_read_capability(HV_VMX_CAP_CR4_FIXED0, &g_HmMsrs.u.vmx.u64Cr4Fixed0);
2137 if (hrc == HV_SUCCESS)
2138 hrc = hv_vmx_read_capability(HV_VMX_CAP_CR4_FIXED1, &g_HmMsrs.u.vmx.u64Cr4Fixed1);
2139 if (hrc == HV_SUCCESS)
2140 hrc = hv_vmx_read_capability(HV_VMX_CAP_VMCS_ENUM, &g_HmMsrs.u.vmx.u64VmcsEnum);
2141 if ( hrc == HV_SUCCESS
2142 && RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_TRUE_CTLS))
2143 {
2144 hrc = hv_vmx_read_capability(HV_VMX_CAP_TRUE_PINBASED, &g_HmMsrs.u.vmx.TruePinCtls.u);
2145 if (hrc == HV_SUCCESS)
2146 hrc = hv_vmx_read_capability(HV_VMX_CAP_TRUE_PROCBASED, &g_HmMsrs.u.vmx.TrueProcCtls.u);
2147 if (hrc == HV_SUCCESS)
2148 hrc = hv_vmx_read_capability(HV_VMX_CAP_TRUE_ENTRY, &g_HmMsrs.u.vmx.TrueEntryCtls.u);
2149 if (hrc == HV_SUCCESS)
2150 hrc = hv_vmx_read_capability(HV_VMX_CAP_TRUE_EXIT, &g_HmMsrs.u.vmx.TrueExitCtls.u);
2151 }
2152 }
2153 else
2154 {
2155 /* Likely running on anything < 11.0 (BigSur) so provide some sensible defaults. */
2156 g_HmMsrs.u.vmx.u64Cr0Fixed0 = 0x80000021;
2157 g_HmMsrs.u.vmx.u64Cr0Fixed1 = 0xffffffff;
2158 g_HmMsrs.u.vmx.u64Cr4Fixed0 = 0x2000;
2159 g_HmMsrs.u.vmx.u64Cr4Fixed1 = 0x1767ff;
2160 hrc = HV_SUCCESS;
2161 }
2162 }
2163
2164 if ( hrc == HV_SUCCESS
2165 && g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2166 {
2167 hrc = hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &g_HmMsrs.u.vmx.ProcCtls2.u);
2168
2169 if ( hrc == HV_SUCCESS
2170 && g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & (VMX_PROC_CTLS2_EPT | VMX_PROC_CTLS2_VPID))
2171 {
2172 hrc = hv_vmx_read_capability(HV_VMX_CAP_EPT_VPID_CAP, &g_HmMsrs.u.vmx.u64EptVpidCaps);
2173 if (hrc != HV_SUCCESS)
2174 hrc = HV_SUCCESS; /* Probably just outdated OS. */
2175 }
2176
2177 g_HmMsrs.u.vmx.u64VmFunc = 0; /* No way to read that on macOS. */
2178 }
2179
2180 if (hrc == HV_SUCCESS)
2181 {
2182 /*
2183 * Check for EFER swapping support.
2184 */
2185 g_fHmVmxSupportsVmcsEfer = true; //(g_HmMsrs.u.vmx.EntryCtls.n.allowed1 & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
2186 //&& (g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_LOAD_EFER_MSR)
2187 //&& (g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_EFER_MSR);
2188 }
2189
2190 return nemR3DarwinHvSts2Rc(hrc);
2191}
2192
2193
2194/**
2195 * Sets up the LBR MSR ranges based on the host CPU.
2196 *
2197 * @returns VBox status code.
2198 * @param pVM The cross context VM structure.
2199 *
2200 * @sa hmR0VmxSetupLbrMsrRange
2201 */
2202static int nemR3DarwinSetupLbrMsrRange(PVMCC pVM)
2203{
2204 Assert(pVM->nem.s.fLbr);
2205 uint32_t idLbrFromIpMsrFirst;
2206 uint32_t idLbrFromIpMsrLast;
2207 uint32_t idLbrToIpMsrFirst;
2208 uint32_t idLbrToIpMsrLast;
2209 uint32_t idLbrInfoMsrFirst;
2210 uint32_t idLbrInfoMsrLast;
2211 uint32_t idLbrTosMsr;
2212 uint32_t idLbrSelectMsr;
2213 uint32_t idLerFromIpMsr;
2214 uint32_t idLerToIpMsr;
2215
2216 /*
2217 * Determine the LBR MSRs supported for this host CPU family and model.
2218 *
2219 * See Intel spec. 17.4.8 "LBR Stack".
2220 * See Intel "Model-Specific Registers" spec.
2221 */
2222 uint32_t const uFamilyModel = (g_CpumHostFeatures.s.uFamily << 8)
2223 | g_CpumHostFeatures.s.uModel;
2224 switch (uFamilyModel)
2225 {
2226 case 0x0f01: case 0x0f02:
2227 idLbrFromIpMsrFirst = MSR_P4_LASTBRANCH_0;
2228 idLbrFromIpMsrLast = MSR_P4_LASTBRANCH_3;
2229 idLbrToIpMsrFirst = 0x0;
2230 idLbrToIpMsrLast = 0x0;
2231 idLbrInfoMsrFirst = 0x0;
2232 idLbrInfoMsrLast = 0x0;
2233 idLbrTosMsr = MSR_P4_LASTBRANCH_TOS;
2234 idLbrSelectMsr = 0x0;
2235 idLerFromIpMsr = 0x0;
2236 idLerToIpMsr = 0x0;
2237 break;
2238
2239 case 0x065c: case 0x065f: case 0x064e: case 0x065e: case 0x068e:
2240 case 0x069e: case 0x0655: case 0x0666: case 0x067a: case 0x0667:
2241 case 0x066a: case 0x066c: case 0x067d: case 0x067e:
2242 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
2243 idLbrFromIpMsrLast = MSR_LASTBRANCH_31_FROM_IP;
2244 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
2245 idLbrToIpMsrLast = MSR_LASTBRANCH_31_TO_IP;
2246 idLbrInfoMsrFirst = MSR_LASTBRANCH_0_INFO;
2247 idLbrInfoMsrLast = MSR_LASTBRANCH_31_INFO;
2248 idLbrTosMsr = MSR_LASTBRANCH_TOS;
2249 idLbrSelectMsr = MSR_LASTBRANCH_SELECT;
2250 idLerFromIpMsr = MSR_LER_FROM_IP;
2251 idLerToIpMsr = MSR_LER_TO_IP;
2252 break;
2253
2254 case 0x063d: case 0x0647: case 0x064f: case 0x0656: case 0x063c:
2255 case 0x0645: case 0x0646: case 0x063f: case 0x062a: case 0x062d:
2256 case 0x063a: case 0x063e: case 0x061a: case 0x061e: case 0x061f:
2257 case 0x062e: case 0x0625: case 0x062c: case 0x062f:
2258 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
2259 idLbrFromIpMsrLast = MSR_LASTBRANCH_15_FROM_IP;
2260 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
2261 idLbrToIpMsrLast = MSR_LASTBRANCH_15_TO_IP;
2262 idLbrInfoMsrFirst = MSR_LASTBRANCH_0_INFO;
2263 idLbrInfoMsrLast = MSR_LASTBRANCH_15_INFO;
2264 idLbrTosMsr = MSR_LASTBRANCH_TOS;
2265 idLbrSelectMsr = MSR_LASTBRANCH_SELECT;
2266 idLerFromIpMsr = MSR_LER_FROM_IP;
2267 idLerToIpMsr = MSR_LER_TO_IP;
2268 break;
2269
2270 case 0x0617: case 0x061d: case 0x060f:
2271 idLbrFromIpMsrFirst = MSR_CORE2_LASTBRANCH_0_FROM_IP;
2272 idLbrFromIpMsrLast = MSR_CORE2_LASTBRANCH_3_FROM_IP;
2273 idLbrToIpMsrFirst = MSR_CORE2_LASTBRANCH_0_TO_IP;
2274 idLbrToIpMsrLast = MSR_CORE2_LASTBRANCH_3_TO_IP;
2275 idLbrInfoMsrFirst = 0x0;
2276 idLbrInfoMsrLast = 0x0;
2277 idLbrTosMsr = MSR_CORE2_LASTBRANCH_TOS;
2278 idLbrSelectMsr = 0x0;
2279 idLerFromIpMsr = 0x0;
2280 idLerToIpMsr = 0x0;
2281 break;
2282
2283 /* Atom and related microarchitectures we don't care about:
2284 case 0x0637: case 0x064a: case 0x064c: case 0x064d: case 0x065a:
2285 case 0x065d: case 0x061c: case 0x0626: case 0x0627: case 0x0635:
2286 case 0x0636: */
2287 /* All other CPUs: */
2288 default:
2289 {
2290 LogRelFunc(("Could not determine LBR stack size for the CPU model %#x\n", uFamilyModel));
2291 VMCC_GET_CPU_0(pVM)->nem.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_UNKNOWN;
2292 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2293 }
2294 }
2295
2296 /*
2297 * Validate.
2298 */
2299 uint32_t const cLbrStack = idLbrFromIpMsrLast - idLbrFromIpMsrFirst + 1;
2300 PCVMCPU pVCpu0 = VMCC_GET_CPU_0(pVM);
2301 AssertCompile( RT_ELEMENTS(pVCpu0->nem.s.vmx.VmcsInfo.au64LbrFromIpMsr)
2302 == RT_ELEMENTS(pVCpu0->nem.s.vmx.VmcsInfo.au64LbrToIpMsr));
2303 AssertCompile( RT_ELEMENTS(pVCpu0->nem.s.vmx.VmcsInfo.au64LbrFromIpMsr)
2304 == RT_ELEMENTS(pVCpu0->nem.s.vmx.VmcsInfo.au64LbrInfoMsr));
2305 if (cLbrStack > RT_ELEMENTS(pVCpu0->nem.s.vmx.VmcsInfo.au64LbrFromIpMsr))
2306 {
2307 LogRelFunc(("LBR stack size of the CPU (%u) exceeds our buffer size\n", cLbrStack));
2308 VMCC_GET_CPU_0(pVM)->nem.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_OVERFLOW;
2309 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2310 }
2311 NOREF(pVCpu0);
2312
2313 /*
2314 * Update the LBR info. to the VM struct. for use later.
2315 */
2316 pVM->nem.s.idLbrTosMsr = idLbrTosMsr;
2317 pVM->nem.s.idLbrSelectMsr = idLbrSelectMsr;
2318
2319 pVM->nem.s.idLbrFromIpMsrFirst = idLbrFromIpMsrFirst;
2320 pVM->nem.s.idLbrFromIpMsrLast = idLbrFromIpMsrLast;
2321
2322 pVM->nem.s.idLbrToIpMsrFirst = idLbrToIpMsrFirst;
2323 pVM->nem.s.idLbrToIpMsrLast = idLbrToIpMsrLast;
2324
2325 pVM->nem.s.idLbrInfoMsrFirst = idLbrInfoMsrFirst;
2326 pVM->nem.s.idLbrInfoMsrLast = idLbrInfoMsrLast;
2327
2328 pVM->nem.s.idLerFromIpMsr = idLerFromIpMsr;
2329 pVM->nem.s.idLerToIpMsr = idLerToIpMsr;
2330 return VINF_SUCCESS;
2331}
2332
2333
2334/**
2335 * Sets up pin-based VM-execution controls in the VMCS.
2336 *
2337 * @returns VBox status code.
2338 * @param pVCpu The cross context virtual CPU structure.
2339 * @param pVmcsInfo The VMCS info. object.
2340 */
2341static int nemR3DarwinVmxSetupVmcsPinCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2342{
2343 //PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2344 uint32_t fVal = g_HmMsrs.u.vmx.PinCtls.n.allowed0; /* Bits set here must always be set. */
2345 uint32_t const fZap = g_HmMsrs.u.vmx.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
2346
2347 if (g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
2348 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
2349
2350#if 0 /** @todo Use preemption timer */
2351 /* Enable the VMX-preemption timer. */
2352 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
2353 {
2354 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
2355 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
2356 }
2357
2358 /* Enable posted-interrupt processing. */
2359 if (pVM->hm.s.fPostedIntrs)
2360 {
2361 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
2362 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
2363 fVal |= VMX_PIN_CTLS_POSTED_INT;
2364 }
2365#endif
2366
2367 if ((fVal & fZap) != fVal)
2368 {
2369 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
2370 g_HmMsrs.u.vmx.PinCtls.n.allowed0, fVal, fZap));
2371 pVCpu->nem.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
2372 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2373 }
2374
2375 /* Commit it to the VMCS and update our cache. */
2376 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PIN_EXEC, fVal);
2377 AssertRC(rc);
2378 pVmcsInfo->u32PinCtls = fVal;
2379
2380 return VINF_SUCCESS;
2381}
2382
2383
2384/**
2385 * Sets up secondary processor-based VM-execution controls in the VMCS.
2386 *
2387 * @returns VBox status code.
2388 * @param pVCpu The cross context virtual CPU structure.
2389 * @param pVmcsInfo The VMCS info. object.
2390 */
2391static int nemR3DarwinVmxSetupVmcsProcCtls2(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2392{
2393 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2394 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
2395 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2396
2397 /* WBINVD causes a VM-exit. */
2398 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
2399 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
2400
2401 /* Enable the INVPCID instruction if we expose it to the guest and is supported
2402 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
2403 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
2404 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
2405 fVal |= VMX_PROC_CTLS2_INVPCID;
2406
2407#if 0 /** @todo */
2408 /* Enable VPID. */
2409 if (pVM->hmr0.s.vmx.fVpid)
2410 fVal |= VMX_PROC_CTLS2_VPID;
2411
2412 if (pVM->hm.s.fVirtApicRegs)
2413 {
2414 /* Enable APIC-register virtualization. */
2415 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
2416 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
2417
2418 /* Enable virtual-interrupt delivery. */
2419 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
2420 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
2421 }
2422
2423 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
2424 where the TPR shadow resides. */
2425 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
2426 * done dynamically. */
2427 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
2428 {
2429 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
2430 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
2431 }
2432#endif
2433
2434 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
2435 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
2436 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
2437 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
2438 fVal |= VMX_PROC_CTLS2_RDTSCP;
2439
2440 /* Enable Pause-Loop exiting. */
2441 if ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
2442 && pVM->nem.s.cPleGapTicks
2443 && pVM->nem.s.cPleWindowTicks)
2444 {
2445 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
2446
2447 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PLE_GAP, pVM->nem.s.cPleGapTicks); AssertRC(rc);
2448 rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PLE_WINDOW, pVM->nem.s.cPleWindowTicks); AssertRC(rc);
2449 }
2450
2451 if ((fVal & fZap) != fVal)
2452 {
2453 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
2454 g_HmMsrs.u.vmx.ProcCtls2.n.allowed0, fVal, fZap));
2455 pVCpu->nem.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
2456 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2457 }
2458
2459 /* Commit it to the VMCS and update our cache. */
2460 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
2461 AssertRC(rc);
2462 pVmcsInfo->u32ProcCtls2 = fVal;
2463
2464 return VINF_SUCCESS;
2465}
2466
2467
2468/**
2469 * Enables native access for the given MSR.
2470 *
2471 * @returns VBox status code.
2472 * @param pVCpu The cross context virtual CPU structure.
2473 * @param idMsr The MSR to enable native access for.
2474 */
2475static int nemR3DarwinMsrSetNative(PVMCPUCC pVCpu, uint32_t idMsr)
2476{
2477 hv_return_t hrc = hv_vcpu_enable_native_msr(pVCpu->nem.s.hVCpuId, idMsr, true /*enable*/);
2478 if (hrc == HV_SUCCESS)
2479 return VINF_SUCCESS;
2480
2481 return nemR3DarwinHvSts2Rc(hrc);
2482}
2483
2484
2485/**
2486 * Sets the MSR to managed for the given vCPU allowing the guest to access it.
2487 *
2488 * @returns VBox status code.
2489 * @param pVCpu The cross context virtual CPU structure.
2490 * @param idMsr The MSR to enable managed access for.
2491 * @param fMsrPerm The MSR permissions flags.
2492 */
2493static int nemR3DarwinMsrSetManaged(PVMCPUCC pVCpu, uint32_t idMsr, hv_msr_flags_t fMsrPerm)
2494{
2495 Assert(hv_vcpu_enable_managed_msr);
2496
2497 hv_return_t hrc = hv_vcpu_enable_managed_msr(pVCpu->nem.s.hVCpuId, idMsr, true /*enable*/);
2498 if (hrc == HV_SUCCESS)
2499 {
2500 hrc = hv_vcpu_set_msr_access(pVCpu->nem.s.hVCpuId, idMsr, fMsrPerm);
2501 if (hrc == HV_SUCCESS)
2502 return VINF_SUCCESS;
2503 }
2504
2505 return nemR3DarwinHvSts2Rc(hrc);
2506}
2507
2508
2509/**
2510 * Sets up the MSR permissions which don't change through the lifetime of the VM.
2511 *
2512 * @returns VBox status code.
2513 * @param pVCpu The cross context virtual CPU structure.
2514 * @param pVmcsInfo The VMCS info. object.
2515 */
2516static int nemR3DarwinSetupVmcsMsrPermissions(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2517{
2518 RT_NOREF(pVmcsInfo);
2519
2520 /*
2521 * The guest can access the following MSRs (read, write) without causing
2522 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
2523 */
2524 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2525 int rc;
2526 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_SYSENTER_CS); AssertRCReturn(rc, rc);
2527 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_SYSENTER_ESP); AssertRCReturn(rc, rc);
2528 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_SYSENTER_EIP); AssertRCReturn(rc, rc);
2529 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_GS_BASE); AssertRCReturn(rc, rc);
2530 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_FS_BASE); AssertRCReturn(rc, rc);
2531
2532 /*
2533 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
2534 * associated with then. We never need to intercept access (writes need to be
2535 * executed without causing a VM-exit, reads will #GP fault anyway).
2536 *
2537 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
2538 * read/write them. We swap the guest/host MSR value using the
2539 * auto-load/store MSR area.
2540 */
2541 if (pVM->cpum.ro.GuestFeatures.fIbpb)
2542 {
2543 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_PRED_CMD);
2544 AssertRCReturn(rc, rc);
2545 }
2546#if 0 /* Doesn't work. */
2547 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
2548 {
2549 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_FLUSH_CMD);
2550 AssertRCReturn(rc, rc);
2551 }
2552#endif
2553 if (pVM->cpum.ro.GuestFeatures.fIbrs)
2554 {
2555 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_SPEC_CTRL);
2556 AssertRCReturn(rc, rc);
2557 }
2558
2559 /*
2560 * Allow full read/write access for the following MSRs (mandatory for VT-x)
2561 * required for 64-bit guests.
2562 */
2563 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_LSTAR); AssertRCReturn(rc, rc);
2564 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K6_STAR); AssertRCReturn(rc, rc);
2565 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_SF_MASK); AssertRCReturn(rc, rc);
2566 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_KERNEL_GS_BASE); AssertRCReturn(rc, rc);
2567
2568 /* Required for enabling the RDTSCP instruction. */
2569 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_TSC_AUX); AssertRCReturn(rc, rc);
2570
2571 /* Last Branch Record. */
2572 if (pVM->nem.s.fLbr)
2573 {
2574 uint32_t const idFromIpMsrStart = pVM->nem.s.idLbrFromIpMsrFirst;
2575 uint32_t const idToIpMsrStart = pVM->nem.s.idLbrToIpMsrFirst;
2576 uint32_t const idInfoMsrStart = pVM->nem.s.idLbrInfoMsrFirst;
2577 uint32_t const cLbrStack = pVM->nem.s.idLbrFromIpMsrLast - pVM->nem.s.idLbrFromIpMsrFirst + 1;
2578 Assert(cLbrStack <= 32);
2579 for (uint32_t i = 0; i < cLbrStack; i++)
2580 {
2581 rc = nemR3DarwinMsrSetManaged(pVCpu, idFromIpMsrStart + i, HV_MSR_READ | HV_MSR_WRITE);
2582 AssertRCReturn(rc, rc);
2583
2584 /* Some CPUs don't have a Branch-To-IP MSR (P4 and related Xeons). */
2585 if (idToIpMsrStart != 0)
2586 {
2587 rc = nemR3DarwinMsrSetManaged(pVCpu, idToIpMsrStart + i, HV_MSR_READ | HV_MSR_WRITE);
2588 AssertRCReturn(rc, rc);
2589 }
2590
2591 if (idInfoMsrStart != 0)
2592 {
2593 rc = nemR3DarwinMsrSetManaged(pVCpu, idInfoMsrStart + i, HV_MSR_READ | HV_MSR_WRITE);
2594 AssertRCReturn(rc, rc);
2595 }
2596 }
2597
2598 rc = nemR3DarwinMsrSetManaged(pVCpu, pVM->nem.s.idLbrTosMsr, HV_MSR_READ | HV_MSR_WRITE);
2599 AssertRCReturn(rc, rc);
2600
2601 if (pVM->nem.s.idLerFromIpMsr)
2602 {
2603 rc = nemR3DarwinMsrSetManaged(pVCpu, pVM->nem.s.idLerFromIpMsr, HV_MSR_READ | HV_MSR_WRITE);
2604 AssertRCReturn(rc, rc);
2605 }
2606
2607 if (pVM->nem.s.idLerToIpMsr)
2608 {
2609 rc = nemR3DarwinMsrSetManaged(pVCpu, pVM->nem.s.idLerToIpMsr, HV_MSR_READ | HV_MSR_WRITE);
2610 AssertRCReturn(rc, rc);
2611 }
2612
2613 if (pVM->nem.s.idLbrSelectMsr)
2614 {
2615 rc = nemR3DarwinMsrSetManaged(pVCpu, pVM->nem.s.idLbrSelectMsr, HV_MSR_READ | HV_MSR_WRITE);
2616 AssertRCReturn(rc, rc);
2617 }
2618 }
2619
2620 return VINF_SUCCESS;
2621}
2622
2623
2624/**
2625 * Sets up processor-based VM-execution controls in the VMCS.
2626 *
2627 * @returns VBox status code.
2628 * @param pVCpu The cross context virtual CPU structure.
2629 * @param pVmcsInfo The VMCS info. object.
2630 */
2631static int nemR3DarwinVmxSetupVmcsProcCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2632{
2633 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
2634 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2635
2636 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
2637// | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
2638 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
2639 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
2640 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
2641 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
2642 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
2643
2644#ifdef HMVMX_ALWAYS_INTERCEPT_CR3_ACCESS
2645 fVal |= VMX_PROC_CTLS_CR3_LOAD_EXIT
2646 | VMX_PROC_CTLS_CR3_STORE_EXIT;
2647#endif
2648
2649 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
2650 if ( !(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
2651 || (g_HmMsrs.u.vmx.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
2652 {
2653 pVCpu->nem.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
2654 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2655 }
2656
2657 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
2658 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2659 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
2660
2661 if ((fVal & fZap) != fVal)
2662 {
2663 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
2664 g_HmMsrs.u.vmx.ProcCtls.n.allowed0, fVal, fZap));
2665 pVCpu->nem.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
2666 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2667 }
2668
2669 /* Commit it to the VMCS and update our cache. */
2670 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, fVal);
2671 AssertRC(rc);
2672 pVmcsInfo->u32ProcCtls = fVal;
2673
2674 /* Set up MSR permissions that don't change through the lifetime of the VM. */
2675 rc = nemR3DarwinSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
2676 AssertRCReturn(rc, rc);
2677
2678 /*
2679 * Set up secondary processor-based VM-execution controls
2680 * (we assume the CPU to always support it as we rely on unrestricted guest execution support).
2681 */
2682 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
2683 return nemR3DarwinVmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
2684}
2685
2686
2687/**
2688 * Sets up miscellaneous (everything other than Pin, Processor and secondary
2689 * Processor-based VM-execution) control fields in the VMCS.
2690 *
2691 * @returns VBox status code.
2692 * @param pVCpu The cross context virtual CPU structure.
2693 * @param pVmcsInfo The VMCS info. object.
2694 */
2695static int nemR3DarwinVmxSetupVmcsMiscCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2696{
2697 int rc = VINF_SUCCESS;
2698 //rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo); TODO
2699 if (RT_SUCCESS(rc))
2700 {
2701 uint64_t const u64Cr0Mask = vmxHCGetFixedCr0Mask(pVCpu);
2702 uint64_t const u64Cr4Mask = vmxHCGetFixedCr4Mask(pVCpu);
2703
2704 rc = nemR3DarwinWriteVmcs64(pVCpu, VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
2705 rc = nemR3DarwinWriteVmcs64(pVCpu, VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
2706
2707 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
2708 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
2709
2710 if (pVCpu->CTX_SUFF(pVM)->nem.s.fLbr)
2711 {
2712 rc = nemR3DarwinWriteVmcs64(pVCpu, VMX_VMCS64_GUEST_DEBUGCTL_FULL, MSR_IA32_DEBUGCTL_LBR);
2713 AssertRC(rc);
2714 }
2715 return VINF_SUCCESS;
2716 }
2717 else
2718 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
2719 return rc;
2720}
2721
2722
2723/**
2724 * Sets up the initial exception bitmap in the VMCS based on static conditions.
2725 *
2726 * We shall setup those exception intercepts that don't change during the
2727 * lifetime of the VM here. The rest are done dynamically while loading the
2728 * guest state.
2729 *
2730 * @param pVCpu The cross context virtual CPU structure.
2731 * @param pVmcsInfo The VMCS info. object.
2732 */
2733static void nemR3DarwinVmxSetupVmcsXcptBitmap(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2734{
2735 /*
2736 * The following exceptions are always intercepted:
2737 *
2738 * #AC - To prevent the guest from hanging the CPU and for dealing with
2739 * split-lock detecting host configs.
2740 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
2741 * recursive #DBs can cause a CPU hang.
2742 */
2743 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
2744 | RT_BIT(X86_XCPT_DB);
2745
2746 /* Commit it to the VMCS. */
2747 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
2748 AssertRC(rc);
2749
2750 /* Update our cache of the exception bitmap. */
2751 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
2752}
2753
2754
2755/**
2756 * Initialize the VMCS information field for the given vCPU.
2757 *
2758 * @returns VBox status code.
2759 * @param pVCpu The cross context virtual CPU structure of the
2760 * calling EMT.
2761 */
2762static int nemR3DarwinInitVmcs(PVMCPU pVCpu)
2763{
2764 int rc = nemR3DarwinVmxSetupVmcsPinCtls(pVCpu, &pVCpu->nem.s.VmcsInfo);
2765 if (RT_SUCCESS(rc))
2766 {
2767 rc = nemR3DarwinVmxSetupVmcsProcCtls(pVCpu, &pVCpu->nem.s.VmcsInfo);
2768 if (RT_SUCCESS(rc))
2769 {
2770 rc = nemR3DarwinVmxSetupVmcsMiscCtls(pVCpu, &pVCpu->nem.s.VmcsInfo);
2771 if (RT_SUCCESS(rc))
2772 {
2773 rc = nemR3DarwinReadVmcs32(pVCpu, VMX_VMCS32_CTRL_ENTRY, &pVCpu->nem.s.VmcsInfo.u32EntryCtls);
2774 if (RT_SUCCESS(rc))
2775 {
2776 rc = nemR3DarwinReadVmcs32(pVCpu, VMX_VMCS32_CTRL_EXIT, &pVCpu->nem.s.VmcsInfo.u32ExitCtls);
2777 if (RT_SUCCESS(rc))
2778 {
2779 nemR3DarwinVmxSetupVmcsXcptBitmap(pVCpu, &pVCpu->nem.s.VmcsInfo);
2780 return VINF_SUCCESS;
2781 }
2782 else
2783 LogRelFunc(("Failed to read the exit controls. rc=%Rrc\n", rc));
2784 }
2785 else
2786 LogRelFunc(("Failed to read the entry controls. rc=%Rrc\n", rc));
2787 }
2788 else
2789 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
2790 }
2791 else
2792 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
2793 }
2794 else
2795 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
2796
2797 return rc;
2798}
2799
2800
2801/**
2802 * Registers statistics for the given vCPU.
2803 *
2804 * @returns VBox status code.
2805 * @param pVM The cross context VM structure.
2806 * @param idCpu The CPU ID.
2807 * @param pNemCpu The NEM CPU structure.
2808 */
2809static int nemR3DarwinStatisticsRegister(PVM pVM, VMCPUID idCpu, PNEMCPU pNemCpu)
2810{
2811#define NEM_REG_STAT(a_pVar, a_enmType, s_enmVisibility, a_enmUnit, a_szNmFmt, a_szDesc) do { \
2812 int rc = STAMR3RegisterF(pVM, a_pVar, a_enmType, s_enmVisibility, a_enmUnit, a_szDesc, a_szNmFmt, idCpu); \
2813 AssertRC(rc); \
2814 } while (0)
2815#define NEM_REG_PROFILE(a_pVar, a_szNmFmt, a_szDesc) \
2816 NEM_REG_STAT(a_pVar, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, a_szNmFmt, a_szDesc)
2817#define NEM_REG_COUNTER(a, b, desc) NEM_REG_STAT(a, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, b, desc)
2818
2819 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR0Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR0", "CR0 read.");
2820 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR2Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR2", "CR2 read.");
2821 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR3Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR3", "CR3 read.");
2822 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR4Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR4", "CR4 read.");
2823 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR8Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR8", "CR8 read.");
2824 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR0Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR0", "CR0 write.");
2825 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR2Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR2", "CR2 write.");
2826 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR3Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR3", "CR3 write.");
2827 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR4Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR4", "CR4 write.");
2828 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR8Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR8", "CR8 write.");
2829
2830 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitAll, "/NEM/CPU%u/Exit/All", "Total exits (including nested-guest exits).");
2831
2832#ifdef VBOX_WITH_STATISTICS
2833 NEM_REG_PROFILE(&pNemCpu->StatProfGstStateImport, "/NEM/CPU%u/ImportGuestState", "Profiling of importing guest state from hardware after VM-exit.");
2834 NEM_REG_PROFILE(&pNemCpu->StatProfGstStateExport, "/NEM/CPU%u/ExportGuestState", "Profiling of exporting guest state from hardware after VM-exit.");
2835
2836 for (int j = 0; j < MAX_EXITREASON_STAT; j++)
2837 {
2838 const char *pszExitName = HMGetVmxExitName(j);
2839 if (pszExitName)
2840 {
2841 int rc = STAMR3RegisterF(pVM, &pNemCpu->pVmxStats->aStatExitReason[j], STAMTYPE_COUNTER, STAMVISIBILITY_USED,
2842 STAMUNIT_OCCURENCES, pszExitName, "/NEM/CPU%u/Exit/Reason/%02x", idCpu, j);
2843 AssertRCReturn(rc, rc);
2844 }
2845 }
2846#endif
2847
2848 return VINF_SUCCESS;
2849
2850#undef NEM_REG_COUNTER
2851#undef NEM_REG_PROFILE
2852#undef NEM_REG_STAT
2853}
2854
2855
2856/**
2857 * Displays the HM Last-Branch-Record info. for the guest.
2858 *
2859 * @param pVM The cross context VM structure.
2860 * @param pHlp The info helper functions.
2861 * @param pszArgs Arguments, ignored.
2862 */
2863static DECLCALLBACK(void) nemR3DarwinInfoLbr(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
2864{
2865 NOREF(pszArgs);
2866 PVMCPU pVCpu = VMMGetCpu(pVM);
2867 if (!pVCpu)
2868 pVCpu = pVM->apCpusR3[0];
2869
2870 Assert(pVM->nem.s.fLbr);
2871
2872 PCVMXVMCSINFOSHARED pVmcsInfoShared = &pVCpu->nem.s.vmx.VmcsInfo;
2873 uint32_t const cLbrStack = pVM->nem.s.idLbrFromIpMsrLast - pVM->nem.s.idLbrFromIpMsrFirst + 1;
2874
2875 /** @todo r=ramshankar: The index technically varies depending on the CPU, but
2876 * 0xf should cover everything we support thus far. Fix if necessary
2877 * later. */
2878 uint32_t const idxTopOfStack = pVmcsInfoShared->u64LbrTosMsr & 0xf;
2879 if (idxTopOfStack > cLbrStack)
2880 {
2881 pHlp->pfnPrintf(pHlp, "Top-of-stack LBR MSR seems corrupt (index=%u, msr=%#RX64) expected index < %u\n",
2882 idxTopOfStack, pVmcsInfoShared->u64LbrTosMsr, cLbrStack);
2883 return;
2884 }
2885
2886 /*
2887 * Dump the circular buffer of LBR records starting from the most recent record (contained in idxTopOfStack).
2888 */
2889 pHlp->pfnPrintf(pHlp, "CPU[%u]: LBRs (most-recent first)\n", pVCpu->idCpu);
2890 if (pVM->nem.s.idLerFromIpMsr)
2891 pHlp->pfnPrintf(pHlp, "LER: From IP=%#016RX64 - To IP=%#016RX64\n",
2892 pVmcsInfoShared->u64LerFromIpMsr, pVmcsInfoShared->u64LerToIpMsr);
2893 uint32_t idxCurrent = idxTopOfStack;
2894 Assert(idxTopOfStack < cLbrStack);
2895 Assert(RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr) <= cLbrStack);
2896 Assert(RT_ELEMENTS(pVmcsInfoShared->au64LbrToIpMsr) <= cLbrStack);
2897 for (;;)
2898 {
2899 if (pVM->nem.s.idLbrToIpMsrFirst)
2900 pHlp->pfnPrintf(pHlp, " Branch (%2u): From IP=%#016RX64 - To IP=%#016RX64 (Info: %#016RX64)\n", idxCurrent,
2901 pVmcsInfoShared->au64LbrFromIpMsr[idxCurrent],
2902 pVmcsInfoShared->au64LbrToIpMsr[idxCurrent],
2903 pVmcsInfoShared->au64LbrInfoMsr[idxCurrent]);
2904 else
2905 pHlp->pfnPrintf(pHlp, " Branch (%2u): LBR=%#RX64\n", idxCurrent, pVmcsInfoShared->au64LbrFromIpMsr[idxCurrent]);
2906
2907 idxCurrent = (idxCurrent - 1) % cLbrStack;
2908 if (idxCurrent == idxTopOfStack)
2909 break;
2910 }
2911}
2912
2913
2914/**
2915 * Try initialize the native API.
2916 *
2917 * This may only do part of the job, more can be done in
2918 * nemR3NativeInitAfterCPUM() and nemR3NativeInitCompleted().
2919 *
2920 * @returns VBox status code.
2921 * @param pVM The cross context VM structure.
2922 * @param fFallback Whether we're in fallback mode or use-NEM mode. In
2923 * the latter we'll fail if we cannot initialize.
2924 * @param fForced Whether the HMForced flag is set and we should
2925 * fail if we cannot initialize.
2926 */
2927int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced)
2928{
2929 AssertReturn(!pVM->nem.s.fCreatedVm, VERR_WRONG_ORDER);
2930
2931 /*
2932 * Some state init.
2933 */
2934 PCFGMNODE pCfgNem = CFGMR3GetChild(CFGMR3GetRoot(pVM), "NEM/");
2935
2936 /** @cfgm{/NEM/VmxPleGap, uint32_t, 0}
2937 * The pause-filter exiting gap in TSC ticks. When the number of ticks between
2938 * two successive PAUSE instructions exceeds VmxPleGap, the CPU considers the
2939 * latest PAUSE instruction to be start of a new PAUSE loop.
2940 */
2941 int rc = CFGMR3QueryU32Def(pCfgNem, "VmxPleGap", &pVM->nem.s.cPleGapTicks, 0);
2942 AssertRCReturn(rc, rc);
2943
2944 /** @cfgm{/NEM/VmxPleWindow, uint32_t, 0}
2945 * The pause-filter exiting window in TSC ticks. When the number of ticks
2946 * between the current PAUSE instruction and first PAUSE of a loop exceeds
2947 * VmxPleWindow, a VM-exit is triggered.
2948 *
2949 * Setting VmxPleGap and VmxPleGap to 0 disables pause-filter exiting.
2950 */
2951 rc = CFGMR3QueryU32Def(pCfgNem, "VmxPleWindow", &pVM->nem.s.cPleWindowTicks, 0);
2952 AssertRCReturn(rc, rc);
2953
2954 /** @cfgm{/NEM/VmxLbr, bool, false}
2955 * Whether to enable LBR for the guest. This is disabled by default as it's only
2956 * useful while debugging and enabling it causes a noticeable performance hit. */
2957 rc = CFGMR3QueryBoolDef(pCfgNem, "VmxLbr", &pVM->nem.s.fLbr, false);
2958 AssertRCReturn(rc, rc);
2959
2960 /*
2961 * Error state.
2962 * The error message will be non-empty on failure and 'rc' will be set too.
2963 */
2964 RTERRINFOSTATIC ErrInfo;
2965 PRTERRINFO pErrInfo = RTErrInfoInitStatic(&ErrInfo);
2966 rc = nemR3DarwinLoadHv(fForced, pErrInfo);
2967 if (RT_SUCCESS(rc))
2968 {
2969 if ( !hv_vcpu_enable_managed_msr
2970 && pVM->nem.s.fLbr)
2971 {
2972 LogRel(("NEM: LBR recording is disabled because the Hypervisor API misses hv_vcpu_enable_managed_msr/hv_vcpu_set_msr_access functionality\n"));
2973 pVM->nem.s.fLbr = false;
2974 }
2975
2976 if (hv_vcpu_run_until)
2977 {
2978 struct mach_timebase_info TimeInfo;
2979
2980 if (mach_timebase_info(&TimeInfo) == KERN_SUCCESS)
2981 {
2982 pVM->nem.s.cMachTimePerNs = RT_MIN(1, (double)TimeInfo.denom / (double)TimeInfo.numer);
2983 LogRel(("NEM: cMachTimePerNs=%llu (TimeInfo.numer=%u TimeInfo.denom=%u)\n",
2984 pVM->nem.s.cMachTimePerNs, TimeInfo.numer, TimeInfo.denom));
2985 }
2986 else
2987 hv_vcpu_run_until = NULL; /* To avoid running forever (TM asserts when the guest runs for longer than 4 seconds). */
2988 }
2989
2990 hv_return_t hrc = hv_vm_create(HV_VM_DEFAULT);
2991 if (hrc == HV_SUCCESS)
2992 {
2993 if (hv_vm_space_create)
2994 {
2995 hrc = hv_vm_space_create(&pVM->nem.s.uVmAsid);
2996 if (hrc == HV_SUCCESS)
2997 {
2998 LogRel(("NEM: Successfully created ASID: %u\n", pVM->nem.s.uVmAsid));
2999 pVM->nem.s.fCreatedAsid = true;
3000 }
3001 else
3002 LogRel(("NEM: Failed to create ASID for VM (hrc=%#x), continuing...\n", pVM->nem.s.uVmAsid));
3003 }
3004 pVM->nem.s.fCreatedVm = true;
3005
3006 /* Register release statistics */
3007 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
3008 {
3009 PNEMCPU pNemCpu = &pVM->apCpusR3[idCpu]->nem.s;
3010 PVMXSTATISTICS pVmxStats = (PVMXSTATISTICS)RTMemAllocZ(sizeof(*pVmxStats));
3011 if (RT_LIKELY(pVmxStats))
3012 {
3013 pNemCpu->pVmxStats = pVmxStats;
3014 rc = nemR3DarwinStatisticsRegister(pVM, idCpu, pNemCpu);
3015 AssertRC(rc);
3016 }
3017 else
3018 {
3019 rc = VERR_NO_MEMORY;
3020 break;
3021 }
3022 }
3023
3024 if (RT_SUCCESS(rc))
3025 {
3026 VM_SET_MAIN_EXECUTION_ENGINE(pVM, VM_EXEC_ENGINE_NATIVE_API);
3027 Log(("NEM: Marked active!\n"));
3028 PGMR3EnableNemMode(pVM);
3029 }
3030 }
3031 else
3032 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
3033 "hv_vm_create() failed: %#x", hrc);
3034 }
3035
3036 /*
3037 * We only fail if in forced mode, otherwise just log the complaint and return.
3038 */
3039 Assert(pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API || RTErrInfoIsSet(pErrInfo));
3040 if ( (fForced || !fFallback)
3041 && pVM->bMainExecutionEngine != VM_EXEC_ENGINE_NATIVE_API)
3042 return VMSetError(pVM, RT_SUCCESS_NP(rc) ? VERR_NEM_NOT_AVAILABLE : rc, RT_SRC_POS, "%s", pErrInfo->pszMsg);
3043
3044 if (pVM->nem.s.fLbr)
3045 {
3046 rc = DBGFR3InfoRegisterInternalEx(pVM, "lbr", "Dumps the NEM LBR info.", nemR3DarwinInfoLbr, DBGFINFO_FLAGS_ALL_EMTS);
3047 AssertRCReturn(rc, rc);
3048 }
3049
3050 if (RTErrInfoIsSet(pErrInfo))
3051 LogRel(("NEM: Not available: %s\n", pErrInfo->pszMsg));
3052 return VINF_SUCCESS;
3053}
3054
3055
3056/**
3057 * Worker to create the vCPU handle on the EMT running it later on (as required by HV).
3058 *
3059 * @returns VBox status code
3060 * @param pVM The VM handle.
3061 * @param pVCpu The vCPU handle.
3062 * @param idCpu ID of the CPU to create.
3063 */
3064static DECLCALLBACK(int) nemR3DarwinNativeInitVCpuOnEmt(PVM pVM, PVMCPU pVCpu, VMCPUID idCpu)
3065{
3066 hv_return_t hrc = hv_vcpu_create(&pVCpu->nem.s.hVCpuId, HV_VCPU_DEFAULT);
3067 if (hrc != HV_SUCCESS)
3068 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
3069 "Call to hv_vcpu_create failed on vCPU %u: %#x (%Rrc)", idCpu, hrc, nemR3DarwinHvSts2Rc(hrc));
3070
3071 if (idCpu == 0)
3072 {
3073 /* First call initializs the MSR structure holding the capabilities of the host CPU. */
3074 int rc = nemR3DarwinCapsInit();
3075 AssertRCReturn(rc, rc);
3076
3077 if (hv_vmx_vcpu_get_cap_write_vmcs)
3078 {
3079 /* Log the VMCS field write capabilities. */
3080 for (uint32_t i = 0; i < RT_ELEMENTS(g_aVmcsFieldsCap); i++)
3081 {
3082 uint64_t u64Allowed0 = 0;
3083 uint64_t u64Allowed1 = 0;
3084
3085 hrc = hv_vmx_vcpu_get_cap_write_vmcs(pVCpu->nem.s.hVCpuId, g_aVmcsFieldsCap[i].u32VmcsFieldId,
3086 &u64Allowed0, &u64Allowed1);
3087 if (hrc == HV_SUCCESS)
3088 {
3089 if (g_aVmcsFieldsCap[i].f64Bit)
3090 LogRel(("NEM: %s = (allowed_0=%#016RX64 allowed_1=%#016RX64)\n",
3091 g_aVmcsFieldsCap[i].pszVmcsField, u64Allowed0, u64Allowed1));
3092 else
3093 LogRel(("NEM: %s = (allowed_0=%#08RX32 allowed_1=%#08RX32)\n",
3094 g_aVmcsFieldsCap[i].pszVmcsField, (uint32_t)u64Allowed0, (uint32_t)u64Allowed1));
3095
3096 uint32_t cBits = g_aVmcsFieldsCap[i].f64Bit ? 64 : 32;
3097 for (uint32_t iBit = 0; iBit < cBits; iBit++)
3098 {
3099 bool fAllowed0 = RT_BOOL(u64Allowed0 & RT_BIT_64(iBit));
3100 bool fAllowed1 = RT_BOOL(u64Allowed1 & RT_BIT_64(iBit));
3101
3102 if (!fAllowed0 && !fAllowed1)
3103 LogRel(("NEM: Bit %02u = Must NOT be set\n", iBit));
3104 else if (!fAllowed0 && fAllowed1)
3105 LogRel(("NEM: Bit %02u = Can be set or not be set\n", iBit));
3106 else if (fAllowed0 && !fAllowed1)
3107 LogRel(("NEM: Bit %02u = UNDEFINED (AppleHV error)!\n", iBit));
3108 else if (fAllowed0 && fAllowed1)
3109 LogRel(("NEM: Bit %02u = MUST be set\n", iBit));
3110 else
3111 AssertFailed();
3112 }
3113 }
3114 else
3115 LogRel(("NEM: %s = failed to query (hrc=%d)\n", g_aVmcsFieldsCap[i].pszVmcsField, hrc));
3116 }
3117 }
3118 }
3119
3120 int rc = nemR3DarwinInitVmcs(pVCpu);
3121 AssertRCReturn(rc, rc);
3122
3123 if (pVM->nem.s.fCreatedAsid)
3124 {
3125 hrc = hv_vcpu_set_space(pVCpu->nem.s.hVCpuId, pVM->nem.s.uVmAsid);
3126 AssertReturn(hrc == HV_SUCCESS, VERR_NEM_VM_CREATE_FAILED);
3127 }
3128
3129 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
3130
3131 return VINF_SUCCESS;
3132}
3133
3134
3135/**
3136 * Worker to destroy the vCPU handle on the EMT running it later on (as required by HV).
3137 *
3138 * @returns VBox status code
3139 * @param pVCpu The vCPU handle.
3140 */
3141static DECLCALLBACK(int) nemR3DarwinNativeTermVCpuOnEmt(PVMCPU pVCpu)
3142{
3143 hv_return_t hrc = hv_vcpu_set_space(pVCpu->nem.s.hVCpuId, 0 /*asid*/);
3144 Assert(hrc == HV_SUCCESS);
3145
3146 hrc = hv_vcpu_destroy(pVCpu->nem.s.hVCpuId);
3147 Assert(hrc == HV_SUCCESS); RT_NOREF(hrc);
3148 return VINF_SUCCESS;
3149}
3150
3151
3152/**
3153 * Worker to setup the TPR shadowing feature if available on the CPU and the VM has an APIC enabled.
3154 *
3155 * @returns VBox status code
3156 * @param pVM The VM handle.
3157 * @param pVCpu The vCPU handle.
3158 */
3159static DECLCALLBACK(int) nemR3DarwinNativeInitTprShadowing(PVM pVM, PVMCPU pVCpu)
3160{
3161 PVMXVMCSINFO pVmcsInfo = &pVCpu->nem.s.VmcsInfo;
3162 uint32_t fVal = pVmcsInfo->u32ProcCtls;
3163
3164 /* Use TPR shadowing if supported by the CPU. */
3165 if ( PDMHasApic(pVM)
3166 && (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
3167 {
3168 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
3169 /* CR8 writes cause a VM-exit based on TPR threshold. */
3170 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
3171 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
3172 }
3173 else
3174 {
3175 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
3176 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
3177 }
3178
3179 /* Commit it to the VMCS and update our cache. */
3180 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, fVal);
3181 AssertRC(rc);
3182 pVmcsInfo->u32ProcCtls = fVal;
3183
3184 return VINF_SUCCESS;
3185}
3186
3187
3188/**
3189 * This is called after CPUMR3Init is done.
3190 *
3191 * @returns VBox status code.
3192 * @param pVM The VM handle..
3193 */
3194int nemR3NativeInitAfterCPUM(PVM pVM)
3195{
3196 /*
3197 * Validate sanity.
3198 */
3199 AssertReturn(!pVM->nem.s.fCreatedEmts, VERR_WRONG_ORDER);
3200 AssertReturn(pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API, VERR_WRONG_ORDER);
3201
3202 if (pVM->nem.s.fLbr)
3203 {
3204 int rc = nemR3DarwinSetupLbrMsrRange(pVM);
3205 AssertRCReturn(rc, rc);
3206 }
3207
3208 /*
3209 * Setup the EMTs.
3210 */
3211 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
3212 {
3213 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
3214
3215 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)nemR3DarwinNativeInitVCpuOnEmt, 3, pVM, pVCpu, idCpu);
3216 if (RT_FAILURE(rc))
3217 {
3218 /* Rollback. */
3219 while (idCpu--)
3220 VMR3ReqCallWait(pVM, idCpu, (PFNRT)nemR3DarwinNativeTermVCpuOnEmt, 1, pVCpu);
3221
3222 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "Call to hv_vcpu_create failed: %Rrc", rc);
3223 }
3224 }
3225
3226 pVM->nem.s.fCreatedEmts = true;
3227 return VINF_SUCCESS;
3228}
3229
3230
3231int nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
3232{
3233 if (enmWhat == VMINITCOMPLETED_RING3)
3234 {
3235 /* Now that PDM is initialized the APIC state is known in order to enable the TPR shadowing feature on all EMTs. */
3236 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
3237 {
3238 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
3239
3240 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)nemR3DarwinNativeInitTprShadowing, 2, pVM, pVCpu);
3241 if (RT_FAILURE(rc))
3242 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "Setting up TPR shadowing failed: %Rrc", rc);
3243 }
3244 }
3245 return VINF_SUCCESS;
3246}
3247
3248
3249int nemR3NativeTerm(PVM pVM)
3250{
3251 /*
3252 * Delete the VM.
3253 */
3254
3255 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu--)
3256 {
3257 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
3258
3259 /*
3260 * Need to do this or hv_vm_space_destroy() fails later on (on 10.15 at least). Could've been documented in
3261 * API reference so I wouldn't have to decompile the kext to find this out but we are talking
3262 * about Apple here unfortunately, API documentation is not their strong suit...
3263 * Would have been of course even better to just automatically drop the address space reference when the vCPU
3264 * gets destroyed.
3265 */
3266 hv_return_t hrc = hv_vcpu_set_space(pVCpu->nem.s.hVCpuId, 0 /*asid*/);
3267 Assert(hrc == HV_SUCCESS);
3268
3269 /*
3270 * Apple's documentation states that the vCPU should be destroyed
3271 * on the thread running the vCPU but as all the other EMTs are gone
3272 * at this point, destroying the VM would hang.
3273 *
3274 * We seem to be at luck here though as destroying apparently works
3275 * from EMT(0) as well.
3276 */
3277 hrc = hv_vcpu_destroy(pVCpu->nem.s.hVCpuId);
3278 Assert(hrc == HV_SUCCESS); RT_NOREF(hrc);
3279
3280 if (pVCpu->nem.s.pVmxStats)
3281 {
3282 RTMemFree(pVCpu->nem.s.pVmxStats);
3283 pVCpu->nem.s.pVmxStats = NULL;
3284 }
3285 }
3286
3287 pVM->nem.s.fCreatedEmts = false;
3288
3289 if (pVM->nem.s.fCreatedAsid)
3290 {
3291 hv_return_t hrc = hv_vm_space_destroy(pVM->nem.s.uVmAsid);
3292 Assert(hrc == HV_SUCCESS); RT_NOREF(hrc);
3293 pVM->nem.s.fCreatedAsid = false;
3294 }
3295
3296 if (pVM->nem.s.fCreatedVm)
3297 {
3298 hv_return_t hrc = hv_vm_destroy();
3299 if (hrc != HV_SUCCESS)
3300 LogRel(("NEM: hv_vm_destroy() failed with %#x\n", hrc));
3301
3302 pVM->nem.s.fCreatedVm = false;
3303 }
3304 return VINF_SUCCESS;
3305}
3306
3307
3308/**
3309 * VM reset notification.
3310 *
3311 * @param pVM The cross context VM structure.
3312 */
3313void nemR3NativeReset(PVM pVM)
3314{
3315 RT_NOREF(pVM);
3316}
3317
3318
3319/**
3320 * Reset CPU due to INIT IPI or hot (un)plugging.
3321 *
3322 * @param pVCpu The cross context virtual CPU structure of the CPU being
3323 * reset.
3324 * @param fInitIpi Whether this is the INIT IPI or hot (un)plugging case.
3325 */
3326void nemR3NativeResetCpu(PVMCPU pVCpu, bool fInitIpi)
3327{
3328 RT_NOREF(fInitIpi);
3329 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
3330}
3331
3332
3333/**
3334 * Runs the guest once until an exit occurs.
3335 *
3336 * @returns HV status code.
3337 * @param pVM The cross context VM structure.
3338 * @param pVCpu The cross context virtual CPU structure.
3339 * @param pVmxTransient The transient VMX execution structure.
3340 */
3341static hv_return_t nemR3DarwinRunGuest(PVM pVM, PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
3342{
3343 TMNotifyStartOfExecution(pVM, pVCpu);
3344
3345 Assert(!pVCpu->nem.s.fCtxChanged);
3346 hv_return_t hrc;
3347 if (hv_vcpu_run_until) /** @todo Configur the deadline dynamically based on when the next timer triggers. */
3348 hrc = hv_vcpu_run_until(pVCpu->nem.s.hVCpuId, mach_absolute_time() + 2 * RT_NS_1SEC_64 * pVM->nem.s.cMachTimePerNs);
3349 else
3350 hrc = hv_vcpu_run(pVCpu->nem.s.hVCpuId);
3351
3352 TMNotifyEndOfExecution(pVM, pVCpu, ASMReadTSC());
3353
3354 /*
3355 * Sync the TPR shadow with our APIC state.
3356 */
3357 if ( !pVmxTransient->fIsNestedGuest
3358 && (pVCpu->nem.s.VmcsInfo.u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
3359 {
3360 uint64_t u64Tpr;
3361 hv_return_t hrc2 = hv_vcpu_read_register(pVCpu->nem.s.hVCpuId, HV_X86_TPR, &u64Tpr);
3362 Assert(hrc2 == HV_SUCCESS); RT_NOREF(hrc2);
3363
3364 if (pVmxTransient->u8GuestTpr != (uint8_t)u64Tpr)
3365 {
3366 int rc = APICSetTpr(pVCpu, (uint8_t)u64Tpr);
3367 AssertRC(rc);
3368 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
3369 }
3370 }
3371
3372 return hrc;
3373}
3374
3375
3376/**
3377 * Prepares the VM to run the guest.
3378 *
3379 * @returns Strict VBox status code.
3380 * @param pVM The cross context VM structure.
3381 * @param pVCpu The cross context virtual CPU structure.
3382 * @param pVmxTransient The VMX transient state.
3383 * @param fSingleStepping Flag whether we run in single stepping mode.
3384 */
3385static VBOXSTRICTRC nemR3DarwinPreRunGuest(PVM pVM, PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, bool fSingleStepping)
3386{
3387 /*
3388 * Check and process force flag actions, some of which might require us to go back to ring-3.
3389 */
3390 VBOXSTRICTRC rcStrict = vmxHCCheckForceFlags(pVCpu, false /*fIsNestedGuest*/, fSingleStepping);
3391 if (rcStrict == VINF_SUCCESS)
3392 { /*likely */ }
3393 else
3394 return rcStrict;
3395
3396 /*
3397 * Do not execute in HV if the A20 isn't enabled.
3398 */
3399 if (PGMPhysIsA20Enabled(pVCpu))
3400 { /* likely */ }
3401 else
3402 {
3403 LogFlow(("NEM/%u: breaking: A20 disabled\n", pVCpu->idCpu));
3404 return VINF_EM_RESCHEDULE_REM;
3405 }
3406
3407 /*
3408 * Evaluate events to be injected into the guest.
3409 *
3410 * Events in TRPM can be injected without inspecting the guest state.
3411 * If any new events (interrupts/NMI) are pending currently, we try to set up the
3412 * guest to cause a VM-exit the next time they are ready to receive the event.
3413 */
3414 if (TRPMHasTrap(pVCpu))
3415 vmxHCTrpmTrapToPendingEvent(pVCpu);
3416
3417 uint32_t fIntrState;
3418 rcStrict = vmxHCEvaluatePendingEvent(pVCpu, &pVCpu->nem.s.VmcsInfo, false /*fIsNestedGuest*/, &fIntrState);
3419
3420 /*
3421 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
3422 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
3423 * also result in triple-faulting the VM.
3424 *
3425 * With nested-guests, the above does not apply since unrestricted guest execution is a
3426 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
3427 */
3428 rcStrict = vmxHCInjectPendingEvent(pVCpu, &pVCpu->nem.s.VmcsInfo, false /*fIsNestedGuest*/, fIntrState, fSingleStepping);
3429 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
3430 { /* likely */ }
3431 else
3432 return rcStrict;
3433
3434 int rc = nemR3DarwinExportGuestState(pVM, pVCpu, pVmxTransient);
3435 AssertRCReturn(rc, rc);
3436
3437 LogFlowFunc(("Running vCPU\n"));
3438 pVCpu->nem.s.Event.fPending = false;
3439 return VINF_SUCCESS;
3440}
3441
3442
3443/**
3444 * The normal runloop (no debugging features enabled).
3445 *
3446 * @returns Strict VBox status code.
3447 * @param pVM The cross context VM structure.
3448 * @param pVCpu The cross context virtual CPU structure.
3449 */
3450static VBOXSTRICTRC nemR3DarwinRunGuestNormal(PVM pVM, PVMCPU pVCpu)
3451{
3452 /*
3453 * The run loop.
3454 *
3455 * Current approach to state updating to use the sledgehammer and sync
3456 * everything every time. This will be optimized later.
3457 */
3458 VMXTRANSIENT VmxTransient;
3459 RT_ZERO(VmxTransient);
3460 VmxTransient.pVmcsInfo = &pVCpu->nem.s.VmcsInfo;
3461
3462 /*
3463 * Poll timers and run for a bit.
3464 */
3465 /** @todo See if we cannot optimize this TMTimerPollGIP by only redoing
3466 * the whole polling job when timers have changed... */
3467 uint64_t offDeltaIgnored;
3468 uint64_t const nsNextTimerEvt = TMTimerPollGIP(pVM, pVCpu, &offDeltaIgnored); NOREF(nsNextTimerEvt);
3469 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
3470 for (unsigned iLoop = 0;; iLoop++)
3471 {
3472 rcStrict = nemR3DarwinPreRunGuest(pVM, pVCpu, &VmxTransient, false /* fSingleStepping */);
3473 if (rcStrict != VINF_SUCCESS)
3474 break;
3475
3476 hv_return_t hrc = nemR3DarwinRunGuest(pVM, pVCpu, &VmxTransient);
3477 if (hrc == HV_SUCCESS)
3478 {
3479 /*
3480 * Deal with the message.
3481 */
3482 rcStrict = nemR3DarwinHandleExit(pVM, pVCpu, &VmxTransient);
3483 if (rcStrict == VINF_SUCCESS)
3484 { /* hopefully likely */ }
3485 else
3486 {
3487 LogFlow(("NEM/%u: breaking: nemR3DarwinHandleExit -> %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict) ));
3488 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnStatus);
3489 break;
3490 }
3491 }
3492 else
3493 {
3494 AssertLogRelMsgFailedReturn(("hv_vcpu_run()) failed for CPU #%u: %#x %u\n",
3495 pVCpu->idCpu, hrc, vmxHCCheckGuestState(pVCpu, &pVCpu->nem.s.VmcsInfo)),
3496 VERR_NEM_IPE_0);
3497 }
3498 } /* the run loop */
3499
3500 return rcStrict;
3501}
3502
3503
3504/**
3505 * Checks if any expensive dtrace probes are enabled and we should go to the
3506 * debug loop.
3507 *
3508 * @returns true if we should use debug loop, false if not.
3509 */
3510static bool nemR3DarwinAnyExpensiveProbesEnabled(void)
3511{
3512 /** @todo Check performance penalty when checking these over and over */
3513 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED() /* expensive too due to context */
3514 | VBOXVMM_XCPT_DE_ENABLED()
3515 | VBOXVMM_XCPT_DB_ENABLED()
3516 | VBOXVMM_XCPT_BP_ENABLED()
3517 | VBOXVMM_XCPT_OF_ENABLED()
3518 | VBOXVMM_XCPT_BR_ENABLED()
3519 | VBOXVMM_XCPT_UD_ENABLED()
3520 | VBOXVMM_XCPT_NM_ENABLED()
3521 | VBOXVMM_XCPT_DF_ENABLED()
3522 | VBOXVMM_XCPT_TS_ENABLED()
3523 | VBOXVMM_XCPT_NP_ENABLED()
3524 | VBOXVMM_XCPT_SS_ENABLED()
3525 | VBOXVMM_XCPT_GP_ENABLED()
3526 | VBOXVMM_XCPT_PF_ENABLED()
3527 | VBOXVMM_XCPT_MF_ENABLED()
3528 | VBOXVMM_XCPT_AC_ENABLED()
3529 | VBOXVMM_XCPT_XF_ENABLED()
3530 | VBOXVMM_XCPT_VE_ENABLED()
3531 | VBOXVMM_XCPT_SX_ENABLED()
3532 | VBOXVMM_INT_SOFTWARE_ENABLED()
3533 /* not available in R3 | VBOXVMM_INT_HARDWARE_ENABLED()*/
3534 ) != 0
3535 || ( VBOXVMM_INSTR_HALT_ENABLED()
3536 | VBOXVMM_INSTR_MWAIT_ENABLED()
3537 | VBOXVMM_INSTR_MONITOR_ENABLED()
3538 | VBOXVMM_INSTR_CPUID_ENABLED()
3539 | VBOXVMM_INSTR_INVD_ENABLED()
3540 | VBOXVMM_INSTR_WBINVD_ENABLED()
3541 | VBOXVMM_INSTR_INVLPG_ENABLED()
3542 | VBOXVMM_INSTR_RDTSC_ENABLED()
3543 | VBOXVMM_INSTR_RDTSCP_ENABLED()
3544 | VBOXVMM_INSTR_RDPMC_ENABLED()
3545 | VBOXVMM_INSTR_RDMSR_ENABLED()
3546 | VBOXVMM_INSTR_WRMSR_ENABLED()
3547 | VBOXVMM_INSTR_CRX_READ_ENABLED()
3548 | VBOXVMM_INSTR_CRX_WRITE_ENABLED()
3549 | VBOXVMM_INSTR_DRX_READ_ENABLED()
3550 | VBOXVMM_INSTR_DRX_WRITE_ENABLED()
3551 | VBOXVMM_INSTR_PAUSE_ENABLED()
3552 | VBOXVMM_INSTR_XSETBV_ENABLED()
3553 | VBOXVMM_INSTR_SIDT_ENABLED()
3554 | VBOXVMM_INSTR_LIDT_ENABLED()
3555 | VBOXVMM_INSTR_SGDT_ENABLED()
3556 | VBOXVMM_INSTR_LGDT_ENABLED()
3557 | VBOXVMM_INSTR_SLDT_ENABLED()
3558 | VBOXVMM_INSTR_LLDT_ENABLED()
3559 | VBOXVMM_INSTR_STR_ENABLED()
3560 | VBOXVMM_INSTR_LTR_ENABLED()
3561 | VBOXVMM_INSTR_GETSEC_ENABLED()
3562 | VBOXVMM_INSTR_RSM_ENABLED()
3563 | VBOXVMM_INSTR_RDRAND_ENABLED()
3564 | VBOXVMM_INSTR_RDSEED_ENABLED()
3565 | VBOXVMM_INSTR_XSAVES_ENABLED()
3566 | VBOXVMM_INSTR_XRSTORS_ENABLED()
3567 | VBOXVMM_INSTR_VMM_CALL_ENABLED()
3568 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED()
3569 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED()
3570 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED()
3571 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED()
3572 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED()
3573 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED()
3574 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED()
3575 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED()
3576 | VBOXVMM_INSTR_VMX_VMXON_ENABLED()
3577 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED()
3578 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED()
3579 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED()
3580 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED()
3581 ) != 0
3582 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED()
3583 | VBOXVMM_EXIT_HALT_ENABLED()
3584 | VBOXVMM_EXIT_MWAIT_ENABLED()
3585 | VBOXVMM_EXIT_MONITOR_ENABLED()
3586 | VBOXVMM_EXIT_CPUID_ENABLED()
3587 | VBOXVMM_EXIT_INVD_ENABLED()
3588 | VBOXVMM_EXIT_WBINVD_ENABLED()
3589 | VBOXVMM_EXIT_INVLPG_ENABLED()
3590 | VBOXVMM_EXIT_RDTSC_ENABLED()
3591 | VBOXVMM_EXIT_RDTSCP_ENABLED()
3592 | VBOXVMM_EXIT_RDPMC_ENABLED()
3593 | VBOXVMM_EXIT_RDMSR_ENABLED()
3594 | VBOXVMM_EXIT_WRMSR_ENABLED()
3595 | VBOXVMM_EXIT_CRX_READ_ENABLED()
3596 | VBOXVMM_EXIT_CRX_WRITE_ENABLED()
3597 | VBOXVMM_EXIT_DRX_READ_ENABLED()
3598 | VBOXVMM_EXIT_DRX_WRITE_ENABLED()
3599 | VBOXVMM_EXIT_PAUSE_ENABLED()
3600 | VBOXVMM_EXIT_XSETBV_ENABLED()
3601 | VBOXVMM_EXIT_SIDT_ENABLED()
3602 | VBOXVMM_EXIT_LIDT_ENABLED()
3603 | VBOXVMM_EXIT_SGDT_ENABLED()
3604 | VBOXVMM_EXIT_LGDT_ENABLED()
3605 | VBOXVMM_EXIT_SLDT_ENABLED()
3606 | VBOXVMM_EXIT_LLDT_ENABLED()
3607 | VBOXVMM_EXIT_STR_ENABLED()
3608 | VBOXVMM_EXIT_LTR_ENABLED()
3609 | VBOXVMM_EXIT_GETSEC_ENABLED()
3610 | VBOXVMM_EXIT_RSM_ENABLED()
3611 | VBOXVMM_EXIT_RDRAND_ENABLED()
3612 | VBOXVMM_EXIT_RDSEED_ENABLED()
3613 | VBOXVMM_EXIT_XSAVES_ENABLED()
3614 | VBOXVMM_EXIT_XRSTORS_ENABLED()
3615 | VBOXVMM_EXIT_VMM_CALL_ENABLED()
3616 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED()
3617 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED()
3618 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED()
3619 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED()
3620 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED()
3621 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED()
3622 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED()
3623 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED()
3624 | VBOXVMM_EXIT_VMX_VMXON_ENABLED()
3625 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED()
3626 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED()
3627 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED()
3628 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED()
3629 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED()
3630 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED()
3631 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED()
3632 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED()
3633 ) != 0;
3634}
3635
3636
3637/**
3638 * The debug runloop.
3639 *
3640 * @returns Strict VBox status code.
3641 * @param pVM The cross context VM structure.
3642 * @param pVCpu The cross context virtual CPU structure.
3643 */
3644static VBOXSTRICTRC nemR3DarwinRunGuestDebug(PVM pVM, PVMCPU pVCpu)
3645{
3646 /*
3647 * The run loop.
3648 *
3649 * Current approach to state updating to use the sledgehammer and sync
3650 * everything every time. This will be optimized later.
3651 */
3652 VMXTRANSIENT VmxTransient;
3653 RT_ZERO(VmxTransient);
3654 VmxTransient.pVmcsInfo = &pVCpu->nem.s.VmcsInfo;
3655
3656 bool const fSavedSingleInstruction = pVCpu->nem.s.fSingleInstruction;
3657 pVCpu->nem.s.fSingleInstruction = pVCpu->nem.s.fSingleInstruction || DBGFIsStepping(pVCpu);
3658 pVCpu->nem.s.fDebugWantRdTscExit = false;
3659 pVCpu->nem.s.fUsingDebugLoop = true;
3660
3661 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
3662 VMXRUNDBGSTATE DbgState;
3663 vmxHCRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
3664 vmxHCPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
3665
3666 /*
3667 * Poll timers and run for a bit.
3668 */
3669 /** @todo See if we cannot optimize this TMTimerPollGIP by only redoing
3670 * the whole polling job when timers have changed... */
3671 uint64_t offDeltaIgnored;
3672 uint64_t const nsNextTimerEvt = TMTimerPollGIP(pVM, pVCpu, &offDeltaIgnored); NOREF(nsNextTimerEvt);
3673 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
3674 for (unsigned iLoop = 0;; iLoop++)
3675 {
3676 bool fStepping = pVCpu->nem.s.fSingleInstruction;
3677
3678 /* Set up VM-execution controls the next two can respond to. */
3679 vmxHCPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
3680
3681 rcStrict = nemR3DarwinPreRunGuest(pVM, pVCpu, &VmxTransient, fStepping);
3682 if (rcStrict != VINF_SUCCESS)
3683 break;
3684
3685 /* Override any obnoxious code in the above call. */
3686 vmxHCPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
3687
3688 hv_return_t hrc = nemR3DarwinRunGuest(pVM, pVCpu, &VmxTransient);
3689 if (hrc == HV_SUCCESS)
3690 {
3691 /*
3692 * Deal with the message.
3693 */
3694 rcStrict = nemR3DarwinHandleExitDebug(pVM, pVCpu, &VmxTransient, &DbgState);
3695 if (rcStrict == VINF_SUCCESS)
3696 { /* hopefully likely */ }
3697 else
3698 {
3699 LogFlow(("NEM/%u: breaking: nemR3DarwinHandleExitDebug -> %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict) ));
3700 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnStatus);
3701 break;
3702 }
3703
3704 /*
3705 * Stepping: Did the RIP change, if so, consider it a single step.
3706 * Otherwise, make sure one of the TFs gets set.
3707 */
3708 if (fStepping)
3709 {
3710 int rc = vmxHCImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
3711 AssertRC(rc);
3712 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
3713 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
3714 {
3715 rcStrict = VINF_EM_DBG_STEPPED;
3716 break;
3717 }
3718 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
3719 }
3720 }
3721 else
3722 {
3723 AssertLogRelMsgFailedReturn(("hv_vcpu_run()) failed for CPU #%u: %#x %u\n",
3724 pVCpu->idCpu, hrc, vmxHCCheckGuestState(pVCpu, &pVCpu->nem.s.VmcsInfo)),
3725 VERR_NEM_IPE_0);
3726 }
3727 } /* the run loop */
3728
3729 /*
3730 * Clear the X86_EFL_TF if necessary.
3731 */
3732 if (pVCpu->nem.s.fClearTrapFlag)
3733 {
3734 int rc = vmxHCImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
3735 AssertRC(rc);
3736 pVCpu->nem.s.fClearTrapFlag = false;
3737 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
3738 }
3739
3740 pVCpu->nem.s.fUsingDebugLoop = false;
3741 pVCpu->nem.s.fDebugWantRdTscExit = false;
3742 pVCpu->nem.s.fSingleInstruction = fSavedSingleInstruction;
3743
3744 /* Restore all controls applied by vmxHCPreRunGuestDebugStateApply above. */
3745 return vmxHCRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
3746}
3747
3748
3749VBOXSTRICTRC nemR3NativeRunGC(PVM pVM, PVMCPU pVCpu)
3750{
3751 LogFlow(("NEM/%u: %04x:%08RX64 efl=%#08RX64 <=\n", pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags));
3752#ifdef LOG_ENABLED
3753 if (LogIs3Enabled())
3754 nemR3DarwinLogState(pVM, pVCpu);
3755#endif
3756
3757 AssertReturn(NEMR3CanExecuteGuest(pVM, pVCpu), VERR_NEM_IPE_9);
3758
3759 /*
3760 * Try switch to NEM runloop state.
3761 */
3762 if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED))
3763 { /* likely */ }
3764 else
3765 {
3766 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED);
3767 LogFlow(("NEM/%u: returning immediately because canceled\n", pVCpu->idCpu));
3768 return VINF_SUCCESS;
3769 }
3770
3771 VBOXSTRICTRC rcStrict;
3772 if ( !pVCpu->nem.s.fUseDebugLoop
3773 && !nemR3DarwinAnyExpensiveProbesEnabled()
3774 && !DBGFIsStepping(pVCpu)
3775 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
3776 rcStrict = nemR3DarwinRunGuestNormal(pVM, pVCpu);
3777 else
3778 rcStrict = nemR3DarwinRunGuestDebug(pVM, pVCpu);
3779
3780 if (rcStrict == VINF_EM_RAW_TO_R3)
3781 rcStrict = VINF_SUCCESS;
3782
3783 /*
3784 * Convert any pending HM events back to TRPM due to premature exits.
3785 *
3786 * This is because execution may continue from IEM and we would need to inject
3787 * the event from there (hence place it back in TRPM).
3788 */
3789 if (pVCpu->nem.s.Event.fPending)
3790 {
3791 vmxHCPendingEventToTrpmTrap(pVCpu);
3792 Assert(!pVCpu->nem.s.Event.fPending);
3793
3794 /* Clear the events from the VMCS. */
3795 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
3796 rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, 0); AssertRC(rc);
3797 }
3798
3799
3800 if (!VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM))
3801 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED);
3802
3803 if (pVCpu->cpum.GstCtx.fExtrn & (CPUMCTX_EXTRN_ALL))
3804 {
3805 /* Try anticipate what we might need. */
3806 uint64_t fImport = NEM_DARWIN_CPUMCTX_EXTRN_MASK_FOR_IEM;
3807 if ( (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST)
3808 || RT_FAILURE(rcStrict))
3809 fImport = CPUMCTX_EXTRN_ALL;
3810 else if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC | VMCPU_FF_INTERRUPT_APIC
3811 | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI))
3812 fImport |= IEM_CPUMCTX_EXTRN_XCPT_MASK;
3813
3814 if (pVCpu->cpum.GstCtx.fExtrn & fImport)
3815 {
3816 /* Only import what is external currently. */
3817 int rc2 = nemR3DarwinCopyStateFromHv(pVM, pVCpu, fImport);
3818 if (RT_SUCCESS(rc2))
3819 pVCpu->cpum.GstCtx.fExtrn &= ~fImport;
3820 else if (RT_SUCCESS(rcStrict))
3821 rcStrict = rc2;
3822 if (!(pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_ALL))
3823 {
3824 pVCpu->cpum.GstCtx.fExtrn = 0;
3825 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
3826 }
3827 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatImportOnReturn);
3828 }
3829 else
3830 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatImportOnReturnSkipped);
3831 }
3832 else
3833 {
3834 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatImportOnReturnSkipped);
3835 pVCpu->cpum.GstCtx.fExtrn = 0;
3836 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
3837 }
3838
3839 LogFlow(("NEM/%u: %04x:%08RX64 efl=%#08RX64 => %Rrc\n",
3840 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags, VBOXSTRICTRC_VAL(rcStrict) ));
3841 return rcStrict;
3842}
3843
3844
3845VMMR3_INT_DECL(bool) NEMR3CanExecuteGuest(PVM pVM, PVMCPU pVCpu)
3846{
3847 NOREF(pVM);
3848 return PGMPhysIsA20Enabled(pVCpu);
3849}
3850
3851
3852bool nemR3NativeSetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable)
3853{
3854 VMCPU_ASSERT_EMT(pVCpu);
3855 bool fOld = pVCpu->nem.s.fSingleInstruction;
3856 pVCpu->nem.s.fSingleInstruction = fEnable;
3857 pVCpu->nem.s.fUseDebugLoop = fEnable || pVM->nem.s.fUseDebugLoop;
3858 return fOld;
3859}
3860
3861
3862void nemR3NativeNotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags)
3863{
3864 LogFlowFunc(("pVM=%p pVCpu=%p fFlags=%#x\n", pVM, pVCpu, fFlags));
3865
3866 RT_NOREF(pVM, fFlags);
3867
3868 hv_return_t hrc = hv_vcpu_interrupt(&pVCpu->nem.s.hVCpuId, 1);
3869 if (hrc != HV_SUCCESS)
3870 LogRel(("NEM: hv_vcpu_interrupt(%u, 1) failed with %#x\n", pVCpu->nem.s.hVCpuId, hrc));
3871}
3872
3873
3874DECLHIDDEN(bool) nemR3NativeNotifyDebugEventChanged(PVM pVM, bool fUseDebugLoop)
3875{
3876 for (DBGFEVENTTYPE enmEvent = DBGFEVENT_EXIT_VMX_FIRST;
3877 !fUseDebugLoop && enmEvent <= DBGFEVENT_EXIT_VMX_LAST;
3878 enmEvent = (DBGFEVENTTYPE)(enmEvent + 1))
3879 fUseDebugLoop = DBGF_IS_EVENT_ENABLED(pVM, enmEvent);
3880
3881 return fUseDebugLoop;
3882}
3883
3884
3885DECLHIDDEN(bool) nemR3NativeNotifyDebugEventChangedPerCpu(PVM pVM, PVMCPU pVCpu, bool fUseDebugLoop)
3886{
3887 RT_NOREF(pVM, pVCpu);
3888 return fUseDebugLoop;
3889}
3890
3891
3892VMMR3_INT_DECL(int) NEMR3NotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvR3,
3893 uint8_t *pu2State, uint32_t *puNemRange)
3894{
3895 RT_NOREF(pVM, puNemRange);
3896
3897 Log5(("NEMR3NotifyPhysRamRegister: %RGp LB %RGp, pvR3=%p\n", GCPhys, cb, pvR3));
3898#if defined(VBOX_WITH_PGM_NEM_MODE)
3899 if (pvR3)
3900 {
3901 int rc = nemR3DarwinMap(pVM, GCPhys, pvR3, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
3902 if (RT_SUCCESS(rc))
3903 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
3904 else
3905 {
3906 LogRel(("NEMR3NotifyPhysRamRegister: GCPhys=%RGp LB %RGp pvR3=%p rc=%Rrc\n", GCPhys, cb, pvR3, rc));
3907 return VERR_NEM_MAP_PAGES_FAILED;
3908 }
3909 }
3910 return VINF_SUCCESS;
3911#else
3912 RT_NOREF(pVM, GCPhys, cb, pvR3);
3913 return VERR_NEM_MAP_PAGES_FAILED;
3914#endif
3915}
3916
3917
3918VMMR3_INT_DECL(bool) NEMR3IsMmio2DirtyPageTrackingSupported(PVM pVM)
3919{
3920 RT_NOREF(pVM);
3921 return false;
3922}
3923
3924
3925VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags,
3926 void *pvRam, void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange)
3927{
3928 RT_NOREF(pVM, puNemRange, pvRam, fFlags);
3929
3930 Log5(("NEMR3NotifyPhysMmioExMapEarly: %RGp LB %RGp fFlags=%#x pvRam=%p pvMmio2=%p pu2State=%p (%d)\n",
3931 GCPhys, cb, fFlags, pvRam, pvMmio2, pu2State, *pu2State));
3932
3933#if defined(VBOX_WITH_PGM_NEM_MODE)
3934 /*
3935 * Unmap the RAM we're replacing.
3936 */
3937 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE)
3938 {
3939 int rc = nemR3DarwinUnmap(pVM, GCPhys, cb);
3940 if (RT_SUCCESS(rc))
3941 { /* likely */ }
3942 else if (pvMmio2)
3943 LogRel(("NEMR3NotifyPhysMmioExMapEarly: GCPhys=%RGp LB %RGp fFlags=%#x: Unmap -> rc=%Rc(ignored)\n",
3944 GCPhys, cb, fFlags, rc));
3945 else
3946 {
3947 LogRel(("NEMR3NotifyPhysMmioExMapEarly: GCPhys=%RGp LB %RGp fFlags=%#x: Unmap -> rc=%Rrc\n",
3948 GCPhys, cb, fFlags, rc));
3949 return VERR_NEM_UNMAP_PAGES_FAILED;
3950 }
3951 }
3952
3953 /*
3954 * Map MMIO2 if any.
3955 */
3956 if (pvMmio2)
3957 {
3958 Assert(fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2);
3959 int rc = nemR3DarwinMap(pVM, GCPhys, pvMmio2, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
3960 if (RT_SUCCESS(rc))
3961 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
3962 else
3963 {
3964 LogRel(("NEMR3NotifyPhysMmioExMapEarly: GCPhys=%RGp LB %RGp fFlags=%#x pvMmio2=%p: Map -> rc=%Rrc\n",
3965 GCPhys, cb, fFlags, pvMmio2, rc));
3966 return VERR_NEM_MAP_PAGES_FAILED;
3967 }
3968 }
3969 else
3970 {
3971 Assert(!(fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2));
3972 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
3973 }
3974
3975#else
3976 RT_NOREF(pVM, GCPhys, cb, pvRam, pvMmio2);
3977 *pu2State = (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE) ? UINT8_MAX : NEM_DARWIN_PAGE_STATE_UNMAPPED;
3978#endif
3979 return VINF_SUCCESS;
3980}
3981
3982
3983VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags,
3984 void *pvRam, void *pvMmio2, uint32_t *puNemRange)
3985{
3986 RT_NOREF(pVM, GCPhys, cb, fFlags, pvRam, pvMmio2, puNemRange);
3987 return VINF_SUCCESS;
3988}
3989
3990
3991VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, void *pvRam,
3992 void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange)
3993{
3994 RT_NOREF(pVM, puNemRange);
3995
3996 Log5(("NEMR3NotifyPhysMmioExUnmap: %RGp LB %RGp fFlags=%#x pvRam=%p pvMmio2=%p pu2State=%p uNemRange=%#x (%#x)\n",
3997 GCPhys, cb, fFlags, pvRam, pvMmio2, pu2State, puNemRange, *puNemRange));
3998
3999 int rc = VINF_SUCCESS;
4000#if defined(VBOX_WITH_PGM_NEM_MODE)
4001 /*
4002 * Unmap the MMIO2 pages.
4003 */
4004 /** @todo If we implement aliasing (MMIO2 page aliased into MMIO range),
4005 * we may have more stuff to unmap even in case of pure MMIO... */
4006 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2)
4007 {
4008 rc = nemR3DarwinUnmap(pVM, GCPhys, cb);
4009 if (RT_FAILURE(rc))
4010 {
4011 LogRel2(("NEMR3NotifyPhysMmioExUnmap: GCPhys=%RGp LB %RGp fFlags=%#x: Unmap -> rc=%Rrc\n",
4012 GCPhys, cb, fFlags, rc));
4013 rc = VERR_NEM_UNMAP_PAGES_FAILED;
4014 }
4015 }
4016
4017 /*
4018 * Restore the RAM we replaced.
4019 */
4020 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE)
4021 {
4022 AssertPtr(pvRam);
4023 rc = nemR3DarwinMap(pVM, GCPhys, pvRam, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
4024 if (RT_SUCCESS(rc))
4025 { /* likely */ }
4026 else
4027 {
4028 LogRel(("NEMR3NotifyPhysMmioExUnmap: GCPhys=%RGp LB %RGp pvMmio2=%p rc=%Rrc\n", GCPhys, cb, pvMmio2, rc));
4029 rc = VERR_NEM_MAP_PAGES_FAILED;
4030 }
4031 if (pu2State)
4032 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
4033 }
4034 /* Mark the pages as unmapped if relevant. */
4035 else if (pu2State)
4036 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
4037
4038 RT_NOREF(pvMmio2);
4039#else
4040 RT_NOREF(pVM, GCPhys, cb, fFlags, pvRam, pvMmio2, pu2State);
4041 if (pu2State)
4042 *pu2State = UINT8_MAX;
4043 rc = VERR_NEM_UNMAP_PAGES_FAILED;
4044#endif
4045 return rc;
4046}
4047
4048
4049VMMR3_INT_DECL(int) NEMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t uNemRange,
4050 void *pvBitmap, size_t cbBitmap)
4051{
4052 RT_NOREF(pVM, GCPhys, cb, uNemRange, pvBitmap, cbBitmap);
4053 AssertFailed();
4054 return VERR_NOT_IMPLEMENTED;
4055}
4056
4057
4058VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages, uint32_t fFlags,
4059 uint8_t *pu2State, uint32_t *puNemRange)
4060{
4061 RT_NOREF(pVM, GCPhys, cb, pvPages, fFlags, puNemRange);
4062
4063 Log5(("nemR3NativeNotifyPhysRomRegisterEarly: %RGp LB %RGp pvPages=%p fFlags=%#x\n", GCPhys, cb, pvPages, fFlags));
4064 *pu2State = UINT8_MAX;
4065 *puNemRange = 0;
4066 return VINF_SUCCESS;
4067}
4068
4069
4070VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages,
4071 uint32_t fFlags, uint8_t *pu2State, uint32_t *puNemRange)
4072{
4073 Log5(("nemR3NativeNotifyPhysRomRegisterLate: %RGp LB %RGp pvPages=%p fFlags=%#x pu2State=%p (%d) puNemRange=%p (%#x)\n",
4074 GCPhys, cb, pvPages, fFlags, pu2State, *pu2State, puNemRange, *puNemRange));
4075 *pu2State = UINT8_MAX;
4076
4077#if defined(VBOX_WITH_PGM_NEM_MODE)
4078 /*
4079 * (Re-)map readonly.
4080 */
4081 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
4082 int rc = nemR3DarwinMap(pVM, GCPhys, pvPages, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE);
4083 if (RT_SUCCESS(rc))
4084 *pu2State = NEM_DARWIN_PAGE_STATE_READABLE;
4085 else
4086 {
4087 LogRel(("nemR3NativeNotifyPhysRomRegisterLate: GCPhys=%RGp LB %RGp pvPages=%p fFlags=%#x rc=%Rrc\n",
4088 GCPhys, cb, pvPages, fFlags, rc));
4089 return VERR_NEM_MAP_PAGES_FAILED;
4090 }
4091 RT_NOREF(pVM, fFlags, puNemRange);
4092 return VINF_SUCCESS;
4093#else
4094 RT_NOREF(pVM, GCPhys, cb, pvPages, fFlags, puNemRange);
4095 return VERR_NEM_MAP_PAGES_FAILED;
4096#endif
4097}
4098
4099
4100VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalDeregister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb,
4101 RTR3PTR pvMemR3, uint8_t *pu2State)
4102{
4103 RT_NOREF(pVM);
4104
4105 Log5(("NEMHCNotifyHandlerPhysicalDeregister: %RGp LB %RGp enmKind=%d pvMemR3=%p pu2State=%p (%d)\n",
4106 GCPhys, cb, enmKind, pvMemR3, pu2State, *pu2State));
4107
4108 *pu2State = UINT8_MAX;
4109#if defined(VBOX_WITH_PGM_NEM_MODE)
4110 if (pvMemR3)
4111 {
4112 int rc = nemR3DarwinMap(pVM, GCPhys, pvMemR3, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
4113 if (RT_SUCCESS(rc))
4114 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
4115 else
4116 AssertLogRelMsgFailed(("NEMHCNotifyHandlerPhysicalDeregister: nemR3DarwinMap(,%p,%RGp,%RGp,) -> %Rrc\n",
4117 pvMemR3, GCPhys, cb, rc));
4118 }
4119 RT_NOREF(enmKind);
4120#else
4121 RT_NOREF(pVM, enmKind, GCPhys, cb, pvMemR3);
4122 AssertFailed();
4123#endif
4124}
4125
4126
4127static int nemHCJustUnmapPage(PVMCC pVM, RTGCPHYS GCPhysDst, uint8_t *pu2State)
4128{
4129 if (*pu2State <= NEM_DARWIN_PAGE_STATE_UNMAPPED)
4130 {
4131 Log5(("nemHCJustUnmapPage: %RGp == unmapped\n", GCPhysDst));
4132 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
4133 return VINF_SUCCESS;
4134 }
4135
4136 int rc = nemR3DarwinUnmap(pVM, GCPhysDst & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK, X86_PAGE_SIZE);
4137 if (RT_SUCCESS(rc))
4138 {
4139 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
4140 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
4141 Log5(("nemHCJustUnmapPage: %RGp => unmapped\n", GCPhysDst));
4142 return VINF_SUCCESS;
4143 }
4144 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
4145 LogRel(("nemHCJustUnmapPage(%RGp): failed! rc=%Rrc\n",
4146 GCPhysDst, rc));
4147 return VERR_NEM_IPE_6;
4148}
4149
4150
4151VMMR3_INT_DECL(void) NEMR3NotifySetA20(PVMCPU pVCpu, bool fEnabled)
4152{
4153 Log(("NEMR3NotifySetA20: fEnabled=%RTbool\n", fEnabled));
4154 RT_NOREF(pVCpu, fEnabled);
4155}
4156
4157
4158void nemHCNativeNotifyHandlerPhysicalRegister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb)
4159{
4160 Log5(("nemHCNativeNotifyHandlerPhysicalRegister: %RGp LB %RGp enmKind=%d\n", GCPhys, cb, enmKind));
4161 NOREF(pVM); NOREF(enmKind); NOREF(GCPhys); NOREF(cb);
4162}
4163
4164
4165void nemHCNativeNotifyHandlerPhysicalModify(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld,
4166 RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM)
4167{
4168 Log5(("nemHCNativeNotifyHandlerPhysicalModify: %RGp LB %RGp -> %RGp enmKind=%d fRestoreAsRAM=%d\n",
4169 GCPhysOld, cb, GCPhysNew, enmKind, fRestoreAsRAM));
4170 NOREF(pVM); NOREF(enmKind); NOREF(GCPhysOld); NOREF(GCPhysNew); NOREF(cb); NOREF(fRestoreAsRAM);
4171}
4172
4173
4174int nemHCNativeNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
4175 PGMPAGETYPE enmType, uint8_t *pu2State)
4176{
4177 Log5(("nemHCNativeNotifyPhysPageAllocated: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
4178 GCPhys, HCPhys, fPageProt, enmType, *pu2State));
4179 RT_NOREF(HCPhys, fPageProt, enmType);
4180
4181 return nemHCJustUnmapPage(pVM, GCPhys, pu2State);
4182}
4183
4184
4185VMM_INT_DECL(void) NEMHCNotifyPhysPageProtChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, RTR3PTR pvR3, uint32_t fPageProt,
4186 PGMPAGETYPE enmType, uint8_t *pu2State)
4187{
4188 Log5(("NEMHCNotifyPhysPageProtChanged: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
4189 GCPhys, HCPhys, fPageProt, enmType, *pu2State));
4190 RT_NOREF(HCPhys, pvR3, fPageProt, enmType)
4191
4192 nemHCJustUnmapPage(pVM, GCPhys, pu2State);
4193}
4194
4195
4196VMM_INT_DECL(void) NEMHCNotifyPhysPageChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew,
4197 RTR3PTR pvNewR3, uint32_t fPageProt, PGMPAGETYPE enmType, uint8_t *pu2State)
4198{
4199 Log5(("NEMHCNotifyPhysPageChanged: %RGp HCPhys=%RHp->%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
4200 GCPhys, HCPhysPrev, HCPhysNew, fPageProt, enmType, *pu2State));
4201 RT_NOREF(HCPhysPrev, HCPhysNew, pvNewR3, fPageProt, enmType);
4202
4203 nemHCJustUnmapPage(pVM, GCPhys, pu2State);
4204}
4205
4206
4207/**
4208 * Interface for importing state on demand (used by IEM).
4209 *
4210 * @returns VBox status code.
4211 * @param pVCpu The cross context CPU structure.
4212 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
4213 */
4214VMM_INT_DECL(int) NEMImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat)
4215{
4216 LogFlowFunc(("pVCpu=%p fWhat=%RX64\n", pVCpu, fWhat));
4217 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatImportOnDemand);
4218
4219 return nemR3DarwinCopyStateFromHv(pVCpu->pVMR3, pVCpu, fWhat);
4220}
4221
4222
4223/**
4224 * Query the CPU tick counter and optionally the TSC_AUX MSR value.
4225 *
4226 * @returns VBox status code.
4227 * @param pVCpu The cross context CPU structure.
4228 * @param pcTicks Where to return the CPU tick count.
4229 * @param puAux Where to return the TSC_AUX register value.
4230 */
4231VMM_INT_DECL(int) NEMHCQueryCpuTick(PVMCPUCC pVCpu, uint64_t *pcTicks, uint32_t *puAux)
4232{
4233 LogFlowFunc(("pVCpu=%p pcTicks=%RX64 puAux=%RX32\n", pVCpu, pcTicks, puAux));
4234 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatQueryCpuTick);
4235
4236 int rc = nemR3DarwinMsrRead(pVCpu, MSR_IA32_TSC, pcTicks);
4237 if ( RT_SUCCESS(rc)
4238 && puAux)
4239 {
4240 if (pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_TSC_AUX)
4241 {
4242 uint64_t u64Aux;
4243 rc = nemR3DarwinMsrRead(pVCpu, MSR_K8_TSC_AUX, &u64Aux);
4244 if (RT_SUCCESS(rc))
4245 *puAux = (uint32_t)u64Aux;
4246 }
4247 else
4248 *puAux = CPUMGetGuestTscAux(pVCpu);
4249 }
4250
4251 return rc;
4252}
4253
4254
4255/**
4256 * Resumes CPU clock (TSC) on all virtual CPUs.
4257 *
4258 * This is called by TM when the VM is started, restored, resumed or similar.
4259 *
4260 * @returns VBox status code.
4261 * @param pVM The cross context VM structure.
4262 * @param pVCpu The cross context CPU structure of the calling EMT.
4263 * @param uPausedTscValue The TSC value at the time of pausing.
4264 */
4265VMM_INT_DECL(int) NEMHCResumeCpuTickOnAll(PVMCC pVM, PVMCPUCC pVCpu, uint64_t uPausedTscValue)
4266{
4267 LogFlowFunc(("pVM=%p pVCpu=%p uPausedTscValue=%RX64\n", pVCpu, uPausedTscValue));
4268 VMCPU_ASSERT_EMT_RETURN(pVCpu, VERR_VM_THREAD_NOT_EMT);
4269 AssertReturn(VM_IS_NEM_ENABLED(pVM), VERR_NEM_IPE_9);
4270
4271 hv_return_t hrc = hv_vm_sync_tsc(uPausedTscValue);
4272 if (RT_LIKELY(hrc == HV_SUCCESS))
4273 {
4274 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_TSC_AUX);
4275 return VINF_SUCCESS;
4276 }
4277
4278 return nemR3DarwinHvSts2Rc(hrc);
4279}
4280
4281
4282/**
4283 * Returns features supported by the NEM backend.
4284 *
4285 * @returns Flags of features supported by the native NEM backend.
4286 * @param pVM The cross context VM structure.
4287 */
4288VMM_INT_DECL(uint32_t) NEMHCGetFeatures(PVMCC pVM)
4289{
4290 RT_NOREF(pVM);
4291 /*
4292 * Apple's Hypervisor.framework is not supported if the CPU doesn't support nested paging
4293 * and unrestricted guest execution support so we can safely return these flags here always.
4294 */
4295 return NEM_FEAT_F_NESTED_PAGING | NEM_FEAT_F_FULL_GST_EXEC | NEM_FEAT_F_XSAVE_XRSTOR;
4296}
4297
4298
4299/** @page pg_nem_darwin NEM/darwin - Native Execution Manager, macOS.
4300 *
4301 * @todo Add notes as the implementation progresses...
4302 */
4303
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use