VirtualBox

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

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

VMM/HMVMXR0: Working on streamlining CPU state importing from the VMCS. This does cause quite some code bloat (release linux from 93950 to 132120 text bytes), but it is hopefully worth it. This should also provide some basis for addressing the @todo in nemR3DarwinHandleExitCommon (NEM/darwin) where the code imports the entire state for every exit. [build fix]

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

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