VirtualBox

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

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

VMM/NEM/darwin: Use g_CpumHostFeatures. [build fix] bugref:10093

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