VirtualBox

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

Last change on this file since 97106 was 97106, checked in by vboxsync, 3 years ago

VMM/NEMR3Native-darwin: A test for which a proeprly signed build is required, bugref:9044

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

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