VirtualBox

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

Last change on this file since 97178 was 97174, checked in by vboxsync, 2 years ago

VMM/NEMR3Native-darwin: Addendum for r154132, unmapping doesn't unwedge the map. Check whether it would be possible to make it work when we set g_fAppleHvNoWX upfront by determining the macOS version, bugref:9044

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

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