VirtualBox

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

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

VMM/{VMXAllTemplate.cpp.h,NEMR3Native-darwin}: Add code to allow for single stepping and sharing the guest's DRx state with th hypervisor debugger (hardware breakpoints, etc.), bugref:9044

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