VirtualBox

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

Last change on this file was 107922, checked in by vboxsync, 3 months ago

VMM/NEM/darwin/amd64: Translate HV error constants to string in messages.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette