VirtualBox

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

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

VMM/{VMXAllTemplate.cpp.h,NEMR3Native-darwin.cpp}: Temporarily intercept all CR3 accesses to investigate an issue with 32bit guests where we seem to end up with an invalid page table root address under certain circumstances, bugref:9044 [typo]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 132.0 KB
Line 
1/* $Id: NEMR3Native-darwin.cpp 93586 2022-02-03 15:21:32Z vboxsync $ */
2/** @file
3 * NEM - Native execution manager, native ring-3 macOS backend using Hypervisor.framework.
4 *
5 * Log group 2: Exit logging.
6 * Log group 3: Log context on exit.
7 * Log group 5: Ring-3 memory management
8 */
9
10/*
11 * Copyright (C) 2020-2022 Oracle Corporation
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.virtualbox.org. This file is free software;
15 * you can redistribute it and/or modify it under the terms of the GNU
16 * General Public License (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 */
21
22
23/*********************************************************************************************************************************
24* Header Files *
25*********************************************************************************************************************************/
26#define LOG_GROUP LOG_GROUP_NEM
27#define VMCPU_INCL_CPUM_GST_CTX
28#include <VBox/vmm/nem.h>
29#include <VBox/vmm/iem.h>
30#include <VBox/vmm/em.h>
31#include <VBox/vmm/apic.h>
32#include <VBox/vmm/pdm.h>
33#include <VBox/vmm/hm.h>
34#include <VBox/vmm/hm_vmx.h>
35#include <VBox/vmm/dbgftrace.h>
36#include "VMXInternal.h"
37#include "NEMInternal.h"
38#include <VBox/vmm/vmcc.h>
39#include "dtrace/VBoxVMM.h"
40
41#include <iprt/asm.h>
42#include <iprt/ldr.h>
43#include <iprt/mem.h>
44#include <iprt/path.h>
45#include <iprt/string.h>
46#include <iprt/system.h>
47#include <iprt/utf16.h>
48
49
50/*********************************************************************************************************************************
51* Defined Constants And Macros *
52*********************************************************************************************************************************/
53/* No nested hwvirt (for now). */
54#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
55# undef VBOX_WITH_NESTED_HWVIRT_VMX
56#endif
57
58
59/** @name HV return codes.
60 * @{ */
61/** Operation was successful. */
62#define HV_SUCCESS 0
63/** An error occurred during operation. */
64#define HV_ERROR 0xfae94001
65/** The operation could not be completed right now, try again. */
66#define HV_BUSY 0xfae94002
67/** One of the parameters passed wis invalid. */
68#define HV_BAD_ARGUMENT 0xfae94003
69/** Not enough resources left to fulfill the operation. */
70#define HV_NO_RESOURCES 0xfae94005
71/** The device could not be found. */
72#define HV_NO_DEVICE 0xfae94006
73/** The operation is not supportd on this platform with this configuration. */
74#define HV_UNSUPPORTED 0xfae94007
75/** @} */
76
77
78/** @name HV memory protection flags.
79 * @{ */
80/** Memory is readable. */
81#define HV_MEMORY_READ RT_BIT_64(0)
82/** Memory is writeable. */
83#define HV_MEMORY_WRITE RT_BIT_64(1)
84/** Memory is executable. */
85#define HV_MEMORY_EXEC RT_BIT_64(2)
86/** @} */
87
88
89/** @name HV shadow VMCS protection flags.
90 * @{ */
91/** Shadow VMCS field is not accessible. */
92#define HV_SHADOW_VMCS_NONE 0
93/** Shadow VMCS fild is readable. */
94#define HV_SHADOW_VMCS_READ RT_BIT_64(0)
95/** Shadow VMCS field is writeable. */
96#define HV_SHADOW_VMCS_WRITE RT_BIT_64(1)
97/** @} */
98
99
100/** Default VM creation flags. */
101#define HV_VM_DEFAULT 0
102/** Default guest address space creation flags. */
103#define HV_VM_SPACE_DEFAULT 0
104/** Default vCPU creation flags. */
105#define HV_VCPU_DEFAULT 0
106
107#define HV_DEADLINE_FOREVER UINT64_MAX
108
109
110/*********************************************************************************************************************************
111* Structures and Typedefs *
112*********************************************************************************************************************************/
113
114/** HV return code type. */
115typedef uint32_t hv_return_t;
116/** HV capability bitmask. */
117typedef uint64_t hv_capability_t;
118/** Option bitmask type when creating a VM. */
119typedef uint64_t hv_vm_options_t;
120/** Option bitmask when creating a vCPU. */
121typedef uint64_t hv_vcpu_options_t;
122/** HV memory protection flags type. */
123typedef uint64_t hv_memory_flags_t;
124/** Shadow VMCS protection flags. */
125typedef uint64_t hv_shadow_flags_t;
126/** Guest physical address type. */
127typedef uint64_t hv_gpaddr_t;
128
129
130/**
131 * VMX Capability enumeration.
132 */
133typedef enum
134{
135 HV_VMX_CAP_PINBASED = 0,
136 HV_VMX_CAP_PROCBASED,
137 HV_VMX_CAP_PROCBASED2,
138 HV_VMX_CAP_ENTRY,
139 HV_VMX_CAP_EXIT,
140 HV_VMX_CAP_BASIC, /* Since 11.0 */
141 HV_VMX_CAP_TRUE_PINBASED, /* Since 11.0 */
142 HV_VMX_CAP_TRUE_PROCBASED, /* Since 11.0 */
143 HV_VMX_CAP_TRUE_ENTRY, /* Since 11.0 */
144 HV_VMX_CAP_TRUE_EXIT, /* Since 11.0 */
145 HV_VMX_CAP_MISC, /* Since 11.0 */
146 HV_VMX_CAP_CR0_FIXED0, /* Since 11.0 */
147 HV_VMX_CAP_CR0_FIXED1, /* Since 11.0 */
148 HV_VMX_CAP_CR4_FIXED0, /* Since 11.0 */
149 HV_VMX_CAP_CR4_FIXED1, /* Since 11.0 */
150 HV_VMX_CAP_VMCS_ENUM, /* Since 11.0 */
151 HV_VMX_CAP_EPT_VPID_CAP, /* Since 11.0 */
152 HV_VMX_CAP_PREEMPTION_TIMER = 32
153} hv_vmx_capability_t;
154
155
156/**
157 * HV x86 register enumeration.
158 */
159typedef enum
160{
161 HV_X86_RIP = 0,
162 HV_X86_RFLAGS,
163 HV_X86_RAX,
164 HV_X86_RCX,
165 HV_X86_RDX,
166 HV_X86_RBX,
167 HV_X86_RSI,
168 HV_X86_RDI,
169 HV_X86_RSP,
170 HV_X86_RBP,
171 HV_X86_R8,
172 HV_X86_R9,
173 HV_X86_R10,
174 HV_X86_R11,
175 HV_X86_R12,
176 HV_X86_R13,
177 HV_X86_R14,
178 HV_X86_R15,
179 HV_X86_CS,
180 HV_X86_SS,
181 HV_X86_DS,
182 HV_X86_ES,
183 HV_X86_FS,
184 HV_X86_GS,
185 HV_X86_IDT_BASE,
186 HV_X86_IDT_LIMIT,
187 HV_X86_GDT_BASE,
188 HV_X86_GDT_LIMIT,
189 HV_X86_LDTR,
190 HV_X86_LDT_BASE,
191 HV_X86_LDT_LIMIT,
192 HV_X86_LDT_AR,
193 HV_X86_TR,
194 HV_X86_TSS_BASE,
195 HV_X86_TSS_LIMIT,
196 HV_X86_TSS_AR,
197 HV_X86_CR0,
198 HV_X86_CR1,
199 HV_X86_CR2,
200 HV_X86_CR3,
201 HV_X86_CR4,
202 HV_X86_DR0,
203 HV_X86_DR1,
204 HV_X86_DR2,
205 HV_X86_DR3,
206 HV_X86_DR4,
207 HV_X86_DR5,
208 HV_X86_DR6,
209 HV_X86_DR7,
210 HV_X86_TPR,
211 HV_X86_XCR0,
212 HV_X86_REGISTERS_MAX
213} hv_x86_reg_t;
214
215
216typedef hv_return_t FN_HV_CAPABILITY(hv_capability_t capability, uint64_t *valu);
217typedef hv_return_t FN_HV_VM_CREATE(hv_vm_options_t flags);
218typedef hv_return_t FN_HV_VM_DESTROY(void);
219typedef hv_return_t FN_HV_VM_SPACE_CREATE(hv_vm_space_t *asid);
220typedef hv_return_t FN_HV_VM_SPACE_DESTROY(hv_vm_space_t asid);
221typedef hv_return_t FN_HV_VM_MAP(const void *uva, hv_gpaddr_t gpa, size_t size, hv_memory_flags_t flags);
222typedef hv_return_t FN_HV_VM_UNMAP(hv_gpaddr_t gpa, size_t size);
223typedef hv_return_t FN_HV_VM_PROTECT(hv_gpaddr_t gpa, size_t size, hv_memory_flags_t flags);
224typedef 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);
225typedef hv_return_t FN_HV_VM_UNMAP_SPACE(hv_vm_space_t asid, hv_gpaddr_t gpa, size_t size);
226typedef 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);
227typedef hv_return_t FN_HV_VM_SYNC_TSC(uint64_t tsc);
228
229typedef hv_return_t FN_HV_VCPU_CREATE(hv_vcpuid_t *vcpu, hv_vcpu_options_t flags);
230typedef hv_return_t FN_HV_VCPU_DESTROY(hv_vcpuid_t vcpu);
231typedef hv_return_t FN_HV_VCPU_SET_SPACE(hv_vcpuid_t vcpu, hv_vm_space_t asid);
232typedef hv_return_t FN_HV_VCPU_READ_REGISTER(hv_vcpuid_t vcpu, hv_x86_reg_t reg, uint64_t *value);
233typedef hv_return_t FN_HV_VCPU_WRITE_REGISTER(hv_vcpuid_t vcpu, hv_x86_reg_t reg, uint64_t value);
234typedef hv_return_t FN_HV_VCPU_READ_FPSTATE(hv_vcpuid_t vcpu, void *buffer, size_t size);
235typedef hv_return_t FN_HV_VCPU_WRITE_FPSTATE(hv_vcpuid_t vcpu, const void *buffer, size_t size);
236typedef hv_return_t FN_HV_VCPU_ENABLE_NATIVE_MSR(hv_vcpuid_t vcpu, uint32_t msr, bool enable);
237typedef hv_return_t FN_HV_VCPU_READ_MSR(hv_vcpuid_t vcpu, uint32_t msr, uint64_t *value);
238typedef hv_return_t FN_HV_VCPU_WRITE_MSR(hv_vcpuid_t vcpu, uint32_t msr, uint64_t value);
239typedef hv_return_t FN_HV_VCPU_FLUSH(hv_vcpuid_t vcpu);
240typedef hv_return_t FN_HV_VCPU_INVALIDATE_TLB(hv_vcpuid_t vcpu);
241typedef hv_return_t FN_HV_VCPU_RUN(hv_vcpuid_t vcpu);
242typedef hv_return_t FN_HV_VCPU_RUN_UNTIL(hv_vcpuid_t vcpu, uint64_t deadline);
243typedef hv_return_t FN_HV_VCPU_INTERRUPT(hv_vcpuid_t *vcpus, unsigned int vcpu_count);
244typedef hv_return_t FN_HV_VCPU_GET_EXEC_TIME(hv_vcpuid_t *vcpus, uint64_t *time);
245
246typedef hv_return_t FN_HV_VMX_VCPU_READ_VMCS(hv_vcpuid_t vcpu, uint32_t field, uint64_t *value);
247typedef hv_return_t FN_HV_VMX_VCPU_WRITE_VMCS(hv_vcpuid_t vcpu, uint32_t field, uint64_t value);
248
249typedef hv_return_t FN_HV_VMX_VCPU_READ_SHADOW_VMCS(hv_vcpuid_t vcpu, uint32_t field, uint64_t *value);
250typedef hv_return_t FN_HV_VMX_VCPU_WRITE_SHADOW_VMCS(hv_vcpuid_t vcpu, uint32_t field, uint64_t value);
251typedef hv_return_t FN_HV_VMX_VCPU_SET_SHADOW_ACCESS(hv_vcpuid_t vcpu, uint32_t field, hv_shadow_flags_t flags);
252
253typedef hv_return_t FN_HV_VMX_READ_CAPABILITY(hv_vmx_capability_t field, uint64_t *value);
254typedef hv_return_t FN_HV_VMX_VCPU_SET_APIC_ADDRESS(hv_vcpuid_t vcpu, hv_gpaddr_t gpa);
255
256/* Since 11.0 */
257typedef 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);
258
259
260/*********************************************************************************************************************************
261* Global Variables *
262*********************************************************************************************************************************/
263/** NEM_DARWIN_PAGE_STATE_XXX names. */
264NEM_TMPL_STATIC const char * const g_apszPageStates[4] = { "not-set", "unmapped", "readable", "writable" };
265/** MSRs. */
266static SUPHWVIRTMSRS g_HmMsrs;
267/** VMX: Set if swapping EFER is supported. */
268static bool g_fHmVmxSupportsVmcsEfer = false;
269/** @name APIs imported from Hypervisor.framework.
270 * @{ */
271static FN_HV_CAPABILITY *g_pfnHvCapability = NULL; /* Since 10.15 */
272static FN_HV_VM_CREATE *g_pfnHvVmCreate = NULL; /* Since 10.10 */
273static FN_HV_VM_DESTROY *g_pfnHvVmDestroy = NULL; /* Since 10.10 */
274static FN_HV_VM_SPACE_CREATE *g_pfnHvVmSpaceCreate = NULL; /* Since 10.15 */
275static FN_HV_VM_SPACE_DESTROY *g_pfnHvVmSpaceDestroy = NULL; /* Since 10.15 */
276static FN_HV_VM_MAP *g_pfnHvVmMap = NULL; /* Since 10.10 */
277static FN_HV_VM_UNMAP *g_pfnHvVmUnmap = NULL; /* Since 10.10 */
278static FN_HV_VM_PROTECT *g_pfnHvVmProtect = NULL; /* Since 10.10 */
279static FN_HV_VM_MAP_SPACE *g_pfnHvVmMapSpace = NULL; /* Since 10.15 */
280static FN_HV_VM_UNMAP_SPACE *g_pfnHvVmUnmapSpace = NULL; /* Since 10.15 */
281static FN_HV_VM_PROTECT_SPACE *g_pfnHvVmProtectSpace = NULL; /* Since 10.15 */
282static FN_HV_VM_SYNC_TSC *g_pfnHvVmSyncTsc = NULL; /* Since 10.10 */
283
284static FN_HV_VCPU_CREATE *g_pfnHvVCpuCreate = NULL; /* Since 10.10 */
285static FN_HV_VCPU_DESTROY *g_pfnHvVCpuDestroy = NULL; /* Since 10.10 */
286static FN_HV_VCPU_SET_SPACE *g_pfnHvVCpuSetSpace = NULL; /* Since 10.15 */
287static FN_HV_VCPU_READ_REGISTER *g_pfnHvVCpuReadRegister = NULL; /* Since 10.10 */
288static FN_HV_VCPU_WRITE_REGISTER *g_pfnHvVCpuWriteRegister = NULL; /* Since 10.10 */
289static FN_HV_VCPU_READ_FPSTATE *g_pfnHvVCpuReadFpState = NULL; /* Since 10.10 */
290static FN_HV_VCPU_WRITE_FPSTATE *g_pfnHvVCpuWriteFpState = NULL; /* Since 10.10 */
291static FN_HV_VCPU_ENABLE_NATIVE_MSR *g_pfnHvVCpuEnableNativeMsr = NULL; /* Since 10.10 */
292static FN_HV_VCPU_READ_MSR *g_pfnHvVCpuReadMsr = NULL; /* Since 10.10 */
293static FN_HV_VCPU_WRITE_MSR *g_pfnHvVCpuWriteMsr = NULL; /* Since 10.10 */
294static FN_HV_VCPU_FLUSH *g_pfnHvVCpuFlush = NULL; /* Since 10.10 */
295static FN_HV_VCPU_INVALIDATE_TLB *g_pfnHvVCpuInvalidateTlb = NULL; /* Since 10.10 */
296static FN_HV_VCPU_RUN *g_pfnHvVCpuRun = NULL; /* Since 10.10 */
297static FN_HV_VCPU_RUN_UNTIL *g_pfnHvVCpuRunUntil = NULL; /* Since 10.15 */
298static FN_HV_VCPU_INTERRUPT *g_pfnHvVCpuInterrupt = NULL; /* Since 10.10 */
299static FN_HV_VCPU_GET_EXEC_TIME *g_pfnHvVCpuGetExecTime = NULL; /* Since 10.10 */
300
301static FN_HV_VMX_READ_CAPABILITY *g_pfnHvVmxReadCapability = NULL; /* Since 10.10 */
302static FN_HV_VMX_VCPU_READ_VMCS *g_pfnHvVmxVCpuReadVmcs = NULL; /* Since 10.10 */
303static FN_HV_VMX_VCPU_WRITE_VMCS *g_pfnHvVmxVCpuWriteVmcs = NULL; /* Since 10.10 */
304static FN_HV_VMX_VCPU_READ_SHADOW_VMCS *g_pfnHvVmxVCpuReadShadowVmcs = NULL; /* Since 10.15 */
305static FN_HV_VMX_VCPU_WRITE_SHADOW_VMCS *g_pfnHvVmxVCpuWriteShadowVmcs = NULL; /* Since 10.15 */
306static FN_HV_VMX_VCPU_SET_SHADOW_ACCESS *g_pfnHvVmxVCpuSetShadowAccess = NULL; /* Since 10.15 */
307static FN_HV_VMX_VCPU_SET_APIC_ADDRESS *g_pfnHvVmxVCpuSetApicAddress = NULL; /* Since 10.10 */
308
309static FN_HV_VMX_VCPU_GET_CAP_WRITE_VMCS *g_pfnHvVmxVCpuGetCapWriteVmcs = NULL; /* Since 11.0 */
310/** @} */
311
312
313/**
314 * Import instructions.
315 */
316static const struct
317{
318 bool fOptional; /**< Set if import is optional. */
319 void **ppfn; /**< The function pointer variable. */
320 const char *pszName; /**< The function name. */
321} g_aImports[] =
322{
323#define NEM_DARWIN_IMPORT(a_fOptional, a_Pfn, a_Name) { (a_fOptional), (void **)&(a_Pfn), #a_Name }
324 NEM_DARWIN_IMPORT(true, g_pfnHvCapability, hv_capability),
325 NEM_DARWIN_IMPORT(false, g_pfnHvVmCreate, hv_vm_create),
326 NEM_DARWIN_IMPORT(false, g_pfnHvVmDestroy, hv_vm_destroy),
327 NEM_DARWIN_IMPORT(true, g_pfnHvVmSpaceCreate, hv_vm_space_create),
328 NEM_DARWIN_IMPORT(true, g_pfnHvVmSpaceDestroy, hv_vm_space_destroy),
329 NEM_DARWIN_IMPORT(false, g_pfnHvVmMap, hv_vm_map),
330 NEM_DARWIN_IMPORT(false, g_pfnHvVmUnmap, hv_vm_unmap),
331 NEM_DARWIN_IMPORT(false, g_pfnHvVmProtect, hv_vm_protect),
332 NEM_DARWIN_IMPORT(true, g_pfnHvVmMapSpace, hv_vm_map_space),
333 NEM_DARWIN_IMPORT(true, g_pfnHvVmUnmapSpace, hv_vm_unmap_space),
334 NEM_DARWIN_IMPORT(true, g_pfnHvVmProtectSpace, hv_vm_protect_space),
335 NEM_DARWIN_IMPORT(false, g_pfnHvVmSyncTsc, hv_vm_sync_tsc),
336
337 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuCreate, hv_vcpu_create),
338 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuDestroy, hv_vcpu_destroy),
339 NEM_DARWIN_IMPORT(true, g_pfnHvVCpuSetSpace, hv_vcpu_set_space),
340 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuReadRegister, hv_vcpu_read_register),
341 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuWriteRegister, hv_vcpu_write_register),
342 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuReadFpState, hv_vcpu_read_fpstate),
343 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuWriteFpState, hv_vcpu_write_fpstate),
344 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuEnableNativeMsr, hv_vcpu_enable_native_msr),
345 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuReadMsr, hv_vcpu_read_msr),
346 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuWriteMsr, hv_vcpu_write_msr),
347 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuFlush, hv_vcpu_flush),
348 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuInvalidateTlb, hv_vcpu_invalidate_tlb),
349 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuRun, hv_vcpu_run),
350 NEM_DARWIN_IMPORT(true, g_pfnHvVCpuRunUntil, hv_vcpu_run_until),
351 NEM_DARWIN_IMPORT(false, g_pfnHvVCpuInterrupt, hv_vcpu_interrupt),
352 NEM_DARWIN_IMPORT(true, g_pfnHvVCpuGetExecTime, hv_vcpu_get_exec_time),
353 NEM_DARWIN_IMPORT(false, g_pfnHvVmxReadCapability, hv_vmx_read_capability),
354 NEM_DARWIN_IMPORT(false, g_pfnHvVmxVCpuReadVmcs, hv_vmx_vcpu_read_vmcs),
355 NEM_DARWIN_IMPORT(false, g_pfnHvVmxVCpuWriteVmcs, hv_vmx_vcpu_write_vmcs),
356 NEM_DARWIN_IMPORT(true, g_pfnHvVmxVCpuReadShadowVmcs, hv_vmx_vcpu_read_shadow_vmcs),
357 NEM_DARWIN_IMPORT(true, g_pfnHvVmxVCpuWriteShadowVmcs, hv_vmx_vcpu_write_shadow_vmcs),
358 NEM_DARWIN_IMPORT(true, g_pfnHvVmxVCpuSetShadowAccess, hv_vmx_vcpu_set_shadow_access),
359 NEM_DARWIN_IMPORT(false, g_pfnHvVmxVCpuSetApicAddress, hv_vmx_vcpu_set_apic_address),
360 NEM_DARWIN_IMPORT(true, g_pfnHvVmxVCpuGetCapWriteVmcs, hv_vmx_vcpu_get_cap_write_vmcs)
361#undef NEM_DARWIN_IMPORT
362};
363
364
365/*
366 * Let the preprocessor alias the APIs to import variables for better autocompletion.
367 */
368#ifndef IN_SLICKEDIT
369# define hv_capability g_pfnHvCapability
370# define hv_vm_create g_pfnHvVmCreate
371# define hv_vm_destroy g_pfnHvVmDestroy
372# define hv_vm_space_create g_pfnHvVmSpaceCreate
373# define hv_vm_space_destroy g_pfnHvVmSpaceDestroy
374# define hv_vm_map g_pfnHvVmMap
375# define hv_vm_unmap g_pfnHvVmUnmap
376# define hv_vm_protect g_pfnHvVmProtect
377# define hv_vm_map_space g_pfnHvVmMapSpace
378# define hv_vm_unmap_space g_pfnHvVmUnmapSpace
379# define hv_vm_protect_space g_pfnHvVmProtectSpace
380# define hv_vm_sync_tsc g_pfnHvVmSyncTsc
381
382# define hv_vcpu_create g_pfnHvVCpuCreate
383# define hv_vcpu_destroy g_pfnHvVCpuDestroy
384# define hv_vcpu_set_space g_pfnHvVCpuSetSpace
385# define hv_vcpu_read_register g_pfnHvVCpuReadRegister
386# define hv_vcpu_write_register g_pfnHvVCpuWriteRegister
387# define hv_vcpu_read_fpstate g_pfnHvVCpuReadFpState
388# define hv_vcpu_write_fpstate g_pfnHvVCpuWriteFpState
389# define hv_vcpu_enable_native_msr g_pfnHvVCpuEnableNativeMsr
390# define hv_vcpu_read_msr g_pfnHvVCpuReadMsr
391# define hv_vcpu_write_msr g_pfnHvVCpuWriteMsr
392# define hv_vcpu_flush g_pfnHvVCpuFlush
393# define hv_vcpu_invalidate_tlb g_pfnHvVCpuInvalidateTlb
394# define hv_vcpu_run g_pfnHvVCpuRun
395# define hv_vcpu_run_until g_pfnHvVCpuRunUntil
396# define hv_vcpu_interrupt g_pfnHvVCpuInterrupt
397# define hv_vcpu_get_exec_time g_pfnHvVCpuGetExecTime
398
399# define hv_vmx_read_capability g_pfnHvVmxReadCapability
400# define hv_vmx_vcpu_read_vmcs g_pfnHvVmxVCpuReadVmcs
401# define hv_vmx_vcpu_write_vmcs g_pfnHvVmxVCpuWriteVmcs
402# define hv_vmx_vcpu_read_shadow_vmcs g_pfnHvVmxVCpuReadShadowVmcs
403# define hv_vmx_vcpu_write_shadow_vmcs g_pfnHvVmxVCpuWriteShadowVmcs
404# define hv_vmx_vcpu_set_shadow_access g_pfnHvVmxVCpuSetShadowAccess
405# define hv_vmx_vcpu_set_apic_address g_pfnHvVmxVCpuSetApicAddress
406
407# define hv_vmx_vcpu_get_cap_write_vmcs g_pfnHvVmxVCpuGetCapWriteVmcs
408#endif
409
410static const struct
411{
412 uint32_t u32VmcsFieldId; /**< The VMCS field identifier. */
413 const char *pszVmcsField; /**< The VMCS field name. */
414 bool f64Bit;
415} g_aVmcsFieldsCap[] =
416{
417#define NEM_DARWIN_VMCS64_FIELD_CAP(a_u32VmcsFieldId) { (a_u32VmcsFieldId), #a_u32VmcsFieldId, true }
418#define NEM_DARWIN_VMCS32_FIELD_CAP(a_u32VmcsFieldId) { (a_u32VmcsFieldId), #a_u32VmcsFieldId, false }
419
420 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PIN_EXEC),
421 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PROC_EXEC),
422 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_EXCEPTION_BITMAP),
423 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_EXIT),
424 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_ENTRY),
425 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PROC_EXEC2),
426 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PLE_GAP),
427 NEM_DARWIN_VMCS32_FIELD_CAP(VMX_VMCS32_CTRL_PLE_WINDOW),
428 NEM_DARWIN_VMCS64_FIELD_CAP(VMX_VMCS64_CTRL_TSC_OFFSET_FULL),
429 NEM_DARWIN_VMCS64_FIELD_CAP(VMX_VMCS64_GUEST_DEBUGCTL_FULL)
430#undef NEM_DARWIN_VMCS64_FIELD_CAP
431#undef NEM_DARWIN_VMCS32_FIELD_CAP
432};
433
434
435/*********************************************************************************************************************************
436* Internal Functions *
437*********************************************************************************************************************************/
438static void vmxHCImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo);
439
440/**
441 * Converts a HV return code to a VBox status code.
442 *
443 * @returns VBox status code.
444 * @param hrc The HV return code to convert.
445 */
446DECLINLINE(int) nemR3DarwinHvSts2Rc(hv_return_t hrc)
447{
448 if (hrc == HV_SUCCESS)
449 return VINF_SUCCESS;
450
451 switch (hrc)
452 {
453 case HV_ERROR: return VERR_INVALID_STATE;
454 case HV_BUSY: return VERR_RESOURCE_BUSY;
455 case HV_BAD_ARGUMENT: return VERR_INVALID_PARAMETER;
456 case HV_NO_RESOURCES: return VERR_OUT_OF_RESOURCES;
457 case HV_NO_DEVICE: return VERR_NOT_FOUND;
458 case HV_UNSUPPORTED: return VERR_NOT_SUPPORTED;
459 }
460
461 return VERR_IPE_UNEXPECTED_STATUS;
462}
463
464
465/**
466 * Unmaps the given guest physical address range (page aligned).
467 *
468 * @returns VBox status code.
469 * @param pVM The cross context VM structure.
470 * @param GCPhys The guest physical address to start unmapping at.
471 * @param cb The size of the range to unmap in bytes.
472 */
473DECLINLINE(int) nemR3DarwinUnmap(PVM pVM, RTGCPHYS GCPhys, size_t cb)
474{
475 LogFlowFunc(("Unmapping %RGp LB %zu\n", GCPhys, cb));
476 hv_return_t hrc;
477 if (pVM->nem.s.fCreatedAsid)
478 hrc = hv_vm_unmap_space(pVM->nem.s.uVmAsid, GCPhys, cb);
479 else
480 hrc = hv_vm_unmap(GCPhys, cb);
481 return nemR3DarwinHvSts2Rc(hrc);
482}
483
484
485/**
486 * Maps a given guest physical address range backed by the given memory with the given
487 * protection flags.
488 *
489 * @returns VBox status code.
490 * @param pVM The cross context VM structure.
491 * @param GCPhys The guest physical address to start mapping.
492 * @param pvRam The R3 pointer of the memory to back the range with.
493 * @param cb The size of the range, page aligned.
494 * @param fPageProt The page protection flags to use for this range, combination of NEM_PAGE_PROT_XXX
495 */
496DECLINLINE(int) nemR3DarwinMap(PVM pVM, RTGCPHYS GCPhys, void *pvRam, size_t cb, uint32_t fPageProt)
497{
498 LogFlowFunc(("Mapping %RGp LB %zu fProt=%#x\n", GCPhys, cb, fPageProt));
499
500 hv_memory_flags_t fHvMemProt = 0;
501 if (fPageProt & NEM_PAGE_PROT_READ)
502 fHvMemProt |= HV_MEMORY_READ;
503 if (fPageProt & NEM_PAGE_PROT_WRITE)
504 fHvMemProt |= HV_MEMORY_WRITE;
505 if (fPageProt & NEM_PAGE_PROT_EXECUTE)
506 fHvMemProt |= HV_MEMORY_EXEC;
507
508 hv_return_t hrc;
509 if (pVM->nem.s.fCreatedAsid)
510 hrc = hv_vm_map_space(pVM->nem.s.uVmAsid, pvRam, GCPhys, cb, fHvMemProt);
511 else
512 hrc = hv_vm_map(pvRam, GCPhys, cb, fHvMemProt);
513 return nemR3DarwinHvSts2Rc(hrc);
514}
515
516
517#if 0 /* unused */
518DECLINLINE(int) nemR3DarwinProtectPage(PVM pVM, RTGCPHYS GCPhys, size_t cb, uint32_t fPageProt)
519{
520 hv_memory_flags_t fHvMemProt = 0;
521 if (fPageProt & NEM_PAGE_PROT_READ)
522 fHvMemProt |= HV_MEMORY_READ;
523 if (fPageProt & NEM_PAGE_PROT_WRITE)
524 fHvMemProt |= HV_MEMORY_WRITE;
525 if (fPageProt & NEM_PAGE_PROT_EXECUTE)
526 fHvMemProt |= HV_MEMORY_EXEC;
527
528 if (pVM->nem.s.fCreatedAsid)
529 hrc = hv_vm_protect_space(pVM->nem.s.uVmAsid, GCPhys, cb, fHvMemProt);
530 else
531 hrc = hv_vm_protect(GCPhys, cb, fHvMemProt);
532
533 return nemR3DarwinHvSts2Rc(hrc);
534}
535#endif
536
537
538DECLINLINE(int) nemR3NativeGCPhys2R3PtrReadOnly(PVM pVM, RTGCPHYS GCPhys, const void **ppv)
539{
540 PGMPAGEMAPLOCK Lock;
541 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, ppv, &Lock);
542 if (RT_SUCCESS(rc))
543 PGMPhysReleasePageMappingLock(pVM, &Lock);
544 return rc;
545}
546
547
548DECLINLINE(int) nemR3NativeGCPhys2R3PtrWriteable(PVM pVM, RTGCPHYS GCPhys, void **ppv)
549{
550 PGMPAGEMAPLOCK Lock;
551 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhys, ppv, &Lock);
552 if (RT_SUCCESS(rc))
553 PGMPhysReleasePageMappingLock(pVM, &Lock);
554 return rc;
555}
556
557
558/**
559 * Worker that maps pages into Hyper-V.
560 *
561 * This is used by the PGM physical page notifications as well as the memory
562 * access VMEXIT handlers.
563 *
564 * @returns VBox status code.
565 * @param pVM The cross context VM structure.
566 * @param pVCpu The cross context virtual CPU structure of the
567 * calling EMT.
568 * @param GCPhysSrc The source page address.
569 * @param GCPhysDst The hyper-V destination page. This may differ from
570 * GCPhysSrc when A20 is disabled.
571 * @param fPageProt NEM_PAGE_PROT_XXX.
572 * @param pu2State Our page state (input/output).
573 * @param fBackingChanged Set if the page backing is being changed.
574 * @thread EMT(pVCpu)
575 */
576NEM_TMPL_STATIC int nemHCNativeSetPhysPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst,
577 uint32_t fPageProt, uint8_t *pu2State, bool fBackingChanged)
578{
579 /*
580 * Looks like we need to unmap a page before we can change the backing
581 * or even modify the protection. This is going to be *REALLY* efficient.
582 * PGM lends us two bits to keep track of the state here.
583 */
584 RT_NOREF(pVCpu);
585 uint8_t const u2OldState = *pu2State;
586 uint8_t const u2NewState = fPageProt & NEM_PAGE_PROT_WRITE ? NEM_DARWIN_PAGE_STATE_WRITABLE
587 : fPageProt & NEM_PAGE_PROT_READ ? NEM_DARWIN_PAGE_STATE_READABLE : NEM_DARWIN_PAGE_STATE_UNMAPPED;
588 if ( fBackingChanged
589 || u2NewState != u2OldState)
590 {
591 if (u2OldState > NEM_DARWIN_PAGE_STATE_UNMAPPED)
592 {
593 int rc = nemR3DarwinUnmap(pVM, GCPhysDst, X86_PAGE_SIZE);
594 if (RT_SUCCESS(rc))
595 {
596 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
597 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
598 if (u2NewState == NEM_DARWIN_PAGE_STATE_UNMAPPED)
599 {
600 Log5(("NEM GPA unmapped/set: %RGp (was %s)\n", GCPhysDst, g_apszPageStates[u2OldState]));
601 return VINF_SUCCESS;
602 }
603 }
604 else
605 {
606 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
607 LogRel(("nemHCNativeSetPhysPage/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
608 return VERR_NEM_INIT_FAILED;
609 }
610 }
611 }
612
613 /*
614 * Writeable mapping?
615 */
616 if (fPageProt & NEM_PAGE_PROT_WRITE)
617 {
618 void *pvPage;
619 int rc = nemR3NativeGCPhys2R3PtrWriteable(pVM, GCPhysSrc, &pvPage);
620 if (RT_SUCCESS(rc))
621 {
622 rc = nemR3DarwinMap(pVM, GCPhysDst, pvPage, X86_PAGE_SIZE, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
623 if (RT_SUCCESS(rc))
624 {
625 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
626 STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPage);
627 Log5(("NEM GPA mapped/set: %RGp %s (was %s)\n", GCPhysDst, g_apszPageStates[u2NewState], g_apszPageStates[u2OldState]));
628 return VINF_SUCCESS;
629 }
630 STAM_REL_COUNTER_INC(&pVM->nem.s.StatMapPageFailed);
631 LogRel(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst));
632 return VERR_NEM_INIT_FAILED;
633 }
634 LogRel(("nemHCNativeSetPhysPage/writable: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
635 return rc;
636 }
637
638 if (fPageProt & NEM_PAGE_PROT_READ)
639 {
640 const void *pvPage;
641 int rc = nemR3NativeGCPhys2R3PtrReadOnly(pVM, GCPhysSrc, &pvPage);
642 if (RT_SUCCESS(rc))
643 {
644 rc = nemR3DarwinMap(pVM, GCPhysDst, (void *)pvPage, X86_PAGE_SIZE, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE);
645 if (RT_SUCCESS(rc))
646 {
647 *pu2State = NEM_DARWIN_PAGE_STATE_READABLE;
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/readonly: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
654 return VERR_NEM_INIT_FAILED;
655 }
656 LogRel(("nemHCNativeSetPhysPage/readonly: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
657 return rc;
658 }
659
660 /* We already unmapped it above. */
661 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
662 return VINF_SUCCESS;
663}
664
665
666#ifdef LOG_ENABLED
667/**
668 * Logs the current CPU state.
669 */
670static void nemR3DarwinLogState(PVMCC pVM, PVMCPUCC pVCpu)
671{
672 if (LogIs3Enabled())
673 {
674#if 0
675 char szRegs[4096];
676 DBGFR3RegPrintf(pVM->pUVM, pVCpu->idCpu, &szRegs[0], sizeof(szRegs),
677 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n"
678 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n"
679 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n"
680 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n"
681 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n"
682 "cs={%04VR{cs} base=%016VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} cr0=%016VR{cr0}\n"
683 "ds={%04VR{ds} base=%016VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} cr2=%016VR{cr2}\n"
684 "es={%04VR{es} base=%016VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} cr3=%016VR{cr3}\n"
685 "fs={%04VR{fs} base=%016VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr4=%016VR{cr4}\n"
686 "gs={%04VR{gs} base=%016VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr8=%016VR{cr8}\n"
687 "ss={%04VR{ss} base=%016VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n"
688 "dr0=%016VR{dr0} dr1=%016VR{dr1} dr2=%016VR{dr2} dr3=%016VR{dr3}\n"
689 "dr6=%016VR{dr6} dr7=%016VR{dr7}\n"
690 "gdtr=%016VR{gdtr_base}:%04VR{gdtr_lim} idtr=%016VR{idtr_base}:%04VR{idtr_lim} rflags=%08VR{rflags}\n"
691 "ldtr={%04VR{ldtr} base=%016VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%08VR{ldtr_attr}}\n"
692 "tr ={%04VR{tr} base=%016VR{tr_base} limit=%08VR{tr_lim} flags=%08VR{tr_attr}}\n"
693 " sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n"
694 " efer=%016VR{efer}\n"
695 " pat=%016VR{pat}\n"
696 " sf_mask=%016VR{sf_mask}\n"
697 "krnl_gs_base=%016VR{krnl_gs_base}\n"
698 " lstar=%016VR{lstar}\n"
699 " star=%016VR{star} cstar=%016VR{cstar}\n"
700 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n"
701 );
702
703 char szInstr[256];
704 DBGFR3DisasInstrEx(pVM->pUVM, pVCpu->idCpu, 0, 0,
705 DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,
706 szInstr, sizeof(szInstr), NULL);
707 Log3(("%s%s\n", szRegs, szInstr));
708#else
709 RT_NOREF(pVM, pVCpu);
710#endif
711 }
712}
713#endif /* LOG_ENABLED */
714
715
716DECLINLINE(int) nemR3DarwinReadVmcs16(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint16_t *pData)
717{
718 uint64_t u64Data;
719 hv_return_t hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, &u64Data);
720 if (RT_LIKELY(hrc == HV_SUCCESS))
721 {
722 *pData = (uint16_t)u64Data;
723 return VINF_SUCCESS;
724 }
725
726 return nemR3DarwinHvSts2Rc(hrc);
727}
728
729
730DECLINLINE(int) nemR3DarwinReadVmcs32(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint32_t *pData)
731{
732 uint64_t u64Data;
733 hv_return_t hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, &u64Data);
734 if (RT_LIKELY(hrc == HV_SUCCESS))
735 {
736 *pData = (uint32_t)u64Data;
737 return VINF_SUCCESS;
738 }
739
740 return nemR3DarwinHvSts2Rc(hrc);
741}
742
743
744DECLINLINE(int) nemR3DarwinReadVmcs64(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint64_t *pData)
745{
746 hv_return_t hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, pData);
747 if (RT_LIKELY(hrc == HV_SUCCESS))
748 return VINF_SUCCESS;
749
750 return nemR3DarwinHvSts2Rc(hrc);
751}
752
753
754DECLINLINE(int) nemR3DarwinWriteVmcs16(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint16_t u16Val)
755{
756 hv_return_t hrc = hv_vmx_vcpu_write_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, u16Val);
757 if (RT_LIKELY(hrc == HV_SUCCESS))
758 return VINF_SUCCESS;
759
760 return nemR3DarwinHvSts2Rc(hrc);
761}
762
763
764DECLINLINE(int) nemR3DarwinWriteVmcs32(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint32_t u32Val)
765{
766 hv_return_t hrc = hv_vmx_vcpu_write_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, u32Val);
767 if (RT_LIKELY(hrc == HV_SUCCESS))
768 return VINF_SUCCESS;
769
770 return nemR3DarwinHvSts2Rc(hrc);
771}
772
773
774DECLINLINE(int) nemR3DarwinWriteVmcs64(PVMCPUCC pVCpu, uint32_t uFieldEnc, uint64_t u64Val)
775{
776 hv_return_t hrc = hv_vmx_vcpu_write_vmcs(pVCpu->nem.s.hVCpuId, uFieldEnc, u64Val);
777 if (RT_LIKELY(hrc == HV_SUCCESS))
778 return VINF_SUCCESS;
779
780 return nemR3DarwinHvSts2Rc(hrc);
781}
782
783DECLINLINE(int) nemR3DarwinMsrRead(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t *pu64Val)
784{
785 hv_return_t hrc = hv_vcpu_read_msr(pVCpu->nem.s.hVCpuId, idMsr, pu64Val);
786 if (RT_LIKELY(hrc == HV_SUCCESS))
787 return VINF_SUCCESS;
788
789 return nemR3DarwinHvSts2Rc(hrc);
790}
791
792#if 0 /*unused*/
793DECLINLINE(int) nemR3DarwinMsrWrite(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t u64Val)
794{
795 hv_return_t hrc = hv_vcpu_write_msr(pVCpu->nem.s.hVCpuId, idMsr, u64Val);
796 if (RT_LIKELY(hrc == HV_SUCCESS))
797 return VINF_SUCCESS;
798
799 return nemR3DarwinHvSts2Rc(hrc);
800}
801#endif
802
803static int nemR3DarwinCopyStateFromHv(PVMCC pVM, PVMCPUCC pVCpu, uint64_t fWhat)
804{
805#define READ_GREG(a_GReg, a_Value) \
806 do \
807 { \
808 hrc = hv_vcpu_read_register(pVCpu->nem.s.hVCpuId, (a_GReg), &(a_Value)); \
809 if (RT_LIKELY(hrc == HV_SUCCESS)) \
810 { /* likely */ } \
811 else \
812 return VERR_INTERNAL_ERROR; \
813 } while(0)
814#define READ_VMCS_FIELD(a_Field, a_Value) \
815 do \
816 { \
817 hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, (a_Field), &(a_Value)); \
818 if (RT_LIKELY(hrc == HV_SUCCESS)) \
819 { /* likely */ } \
820 else \
821 return VERR_INTERNAL_ERROR; \
822 } while(0)
823#define READ_VMCS16_FIELD(a_Field, a_Value) \
824 do \
825 { \
826 uint64_t u64Data; \
827 hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, (a_Field), &u64Data); \
828 if (RT_LIKELY(hrc == HV_SUCCESS)) \
829 { (a_Value) = (uint16_t)u64Data; } \
830 else \
831 return VERR_INTERNAL_ERROR; \
832 } while(0)
833#define READ_VMCS32_FIELD(a_Field, a_Value) \
834 do \
835 { \
836 uint64_t u64Data; \
837 hrc = hv_vmx_vcpu_read_vmcs(pVCpu->nem.s.hVCpuId, (a_Field), &u64Data); \
838 if (RT_LIKELY(hrc == HV_SUCCESS)) \
839 { (a_Value) = (uint32_t)u64Data; } \
840 else \
841 return VERR_INTERNAL_ERROR; \
842 } while(0)
843#define READ_MSR(a_Msr, a_Value) \
844 do \
845 { \
846 hrc = hv_vcpu_read_msr(pVCpu->nem.s.hVCpuId, (a_Msr), &(a_Value)); \
847 if (RT_LIKELY(hrc == HV_SUCCESS)) \
848 { /* likely */ } \
849 else \
850 AssertFailedReturn(VERR_INTERNAL_ERROR); \
851 } while(0)
852
853 STAM_PROFILE_ADV_START(&pVCpu->nem.s.StatProfGstStateImport, x);
854
855 RT_NOREF(pVM);
856 fWhat &= pVCpu->cpum.GstCtx.fExtrn;
857
858 if (fWhat & (CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI))
859 vmxHCImportGuestIntrState(pVCpu, &pVCpu->nem.s.VmcsInfo);
860
861 /* GPRs */
862 hv_return_t hrc;
863 if (fWhat & CPUMCTX_EXTRN_GPRS_MASK)
864 {
865 if (fWhat & CPUMCTX_EXTRN_RAX)
866 READ_GREG(HV_X86_RAX, pVCpu->cpum.GstCtx.rax);
867 if (fWhat & CPUMCTX_EXTRN_RCX)
868 READ_GREG(HV_X86_RCX, pVCpu->cpum.GstCtx.rcx);
869 if (fWhat & CPUMCTX_EXTRN_RDX)
870 READ_GREG(HV_X86_RDX, pVCpu->cpum.GstCtx.rdx);
871 if (fWhat & CPUMCTX_EXTRN_RBX)
872 READ_GREG(HV_X86_RBX, pVCpu->cpum.GstCtx.rbx);
873 if (fWhat & CPUMCTX_EXTRN_RSP)
874 READ_GREG(HV_X86_RSP, pVCpu->cpum.GstCtx.rsp);
875 if (fWhat & CPUMCTX_EXTRN_RBP)
876 READ_GREG(HV_X86_RBP, pVCpu->cpum.GstCtx.rbp);
877 if (fWhat & CPUMCTX_EXTRN_RSI)
878 READ_GREG(HV_X86_RSI, pVCpu->cpum.GstCtx.rsi);
879 if (fWhat & CPUMCTX_EXTRN_RDI)
880 READ_GREG(HV_X86_RDI, pVCpu->cpum.GstCtx.rdi);
881 if (fWhat & CPUMCTX_EXTRN_R8_R15)
882 {
883 READ_GREG(HV_X86_R8, pVCpu->cpum.GstCtx.r8);
884 READ_GREG(HV_X86_R9, pVCpu->cpum.GstCtx.r9);
885 READ_GREG(HV_X86_R10, pVCpu->cpum.GstCtx.r10);
886 READ_GREG(HV_X86_R11, pVCpu->cpum.GstCtx.r11);
887 READ_GREG(HV_X86_R12, pVCpu->cpum.GstCtx.r12);
888 READ_GREG(HV_X86_R13, pVCpu->cpum.GstCtx.r13);
889 READ_GREG(HV_X86_R14, pVCpu->cpum.GstCtx.r14);
890 READ_GREG(HV_X86_R15, pVCpu->cpum.GstCtx.r15);
891 }
892 }
893
894 /* RIP & Flags */
895 if (fWhat & CPUMCTX_EXTRN_RIP)
896 READ_GREG(HV_X86_RIP, pVCpu->cpum.GstCtx.rip);
897 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
898 READ_GREG(HV_X86_RFLAGS, pVCpu->cpum.GstCtx.rflags.u);
899
900 /* Segments */
901#define READ_SEG(a_SReg, a_enmName) \
902 do { \
903 READ_VMCS16_FIELD(VMX_VMCS16_GUEST_ ## a_enmName ## _SEL, (a_SReg).Sel); \
904 READ_VMCS32_FIELD(VMX_VMCS32_GUEST_ ## a_enmName ## _LIMIT, (a_SReg).u32Limit); \
905 READ_VMCS32_FIELD(VMX_VMCS32_GUEST_ ## a_enmName ## _ACCESS_RIGHTS, (a_SReg).Attr.u); \
906 READ_VMCS_FIELD(VMX_VMCS_GUEST_ ## a_enmName ## _BASE, (a_SReg).u64Base); \
907 (a_SReg).ValidSel = (a_SReg).Sel; \
908 } while (0)
909 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
910 {
911 if (fWhat & CPUMCTX_EXTRN_ES)
912 READ_SEG(pVCpu->cpum.GstCtx.es, ES);
913 if (fWhat & CPUMCTX_EXTRN_CS)
914 READ_SEG(pVCpu->cpum.GstCtx.cs, CS);
915 if (fWhat & CPUMCTX_EXTRN_SS)
916 READ_SEG(pVCpu->cpum.GstCtx.ss, SS);
917 if (fWhat & CPUMCTX_EXTRN_DS)
918 READ_SEG(pVCpu->cpum.GstCtx.ds, DS);
919 if (fWhat & CPUMCTX_EXTRN_FS)
920 READ_SEG(pVCpu->cpum.GstCtx.fs, FS);
921 if (fWhat & CPUMCTX_EXTRN_GS)
922 READ_SEG(pVCpu->cpum.GstCtx.gs, GS);
923 }
924
925 /* Descriptor tables and the task segment. */
926 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
927 {
928 if (fWhat & CPUMCTX_EXTRN_LDTR)
929 READ_SEG(pVCpu->cpum.GstCtx.ldtr, LDTR);
930
931 if (fWhat & CPUMCTX_EXTRN_TR)
932 {
933 /* AMD-V likes loading TR with in AVAIL state, whereas intel insists on BUSY. So,
934 avoid to trigger sanity assertions around the code, always fix this. */
935 READ_SEG(pVCpu->cpum.GstCtx.tr, TR);
936 switch (pVCpu->cpum.GstCtx.tr.Attr.n.u4Type)
937 {
938 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
939 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
940 break;
941 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
942 pVCpu->cpum.GstCtx.tr.Attr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
943 break;
944 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
945 pVCpu->cpum.GstCtx.tr.Attr.n.u4Type = X86_SEL_TYPE_SYS_286_TSS_BUSY;
946 break;
947 }
948 }
949 if (fWhat & CPUMCTX_EXTRN_IDTR)
950 {
951 READ_VMCS32_FIELD(VMX_VMCS32_GUEST_IDTR_LIMIT, pVCpu->cpum.GstCtx.idtr.cbIdt);
952 READ_VMCS_FIELD(VMX_VMCS_GUEST_IDTR_BASE, pVCpu->cpum.GstCtx.idtr.pIdt);
953 }
954 if (fWhat & CPUMCTX_EXTRN_GDTR)
955 {
956 READ_VMCS32_FIELD(VMX_VMCS32_GUEST_GDTR_LIMIT, pVCpu->cpum.GstCtx.gdtr.cbGdt);
957 READ_VMCS_FIELD(VMX_VMCS_GUEST_GDTR_BASE, pVCpu->cpum.GstCtx.gdtr.pGdt);
958 }
959 }
960
961 /* Control registers. */
962 bool fMaybeChangedMode = false;
963 bool fUpdateCr3 = false;
964 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
965 {
966 uint64_t u64CrTmp = 0;
967
968 if (fWhat & CPUMCTX_EXTRN_CR0)
969 {
970 READ_GREG(HV_X86_CR0, u64CrTmp);
971 if (pVCpu->cpum.GstCtx.cr0 != u64CrTmp)
972 {
973 CPUMSetGuestCR0(pVCpu, u64CrTmp);
974 fMaybeChangedMode = true;
975 }
976 }
977 if (fWhat & CPUMCTX_EXTRN_CR2)
978 READ_GREG(HV_X86_CR2, pVCpu->cpum.GstCtx.cr2);
979 if (fWhat & CPUMCTX_EXTRN_CR3)
980 {
981 READ_GREG(HV_X86_CR3, u64CrTmp);
982 if (pVCpu->cpum.GstCtx.cr3 != u64CrTmp)
983 {
984 CPUMSetGuestCR3(pVCpu, u64CrTmp);
985 fUpdateCr3 = true;
986 }
987 }
988 if (fWhat & CPUMCTX_EXTRN_CR4)
989 {
990 READ_GREG(HV_X86_CR4, u64CrTmp);
991 u64CrTmp &= ~VMX_V_CR4_FIXED0;
992
993 if (pVCpu->cpum.GstCtx.cr4 != u64CrTmp)
994 {
995 CPUMSetGuestCR4(pVCpu, u64CrTmp);
996 fMaybeChangedMode = true;
997 }
998 }
999 }
1000
1001#if 0 /* Always done. */
1002 if (fWhat & CPUMCTX_EXTRN_APIC_TPR)
1003 {
1004 uint64_t u64Cr8 = 0;
1005
1006 READ_GREG(HV_X86_TPR, u64Cr8);
1007 APICSetTpr(pVCpu, u64Cr8 << 4);
1008 }
1009#endif
1010
1011 if (fWhat & CPUMCTX_EXTRN_XCRx)
1012 READ_GREG(HV_X86_XCR0, pVCpu->cpum.GstCtx.aXcr[0]);
1013
1014 /* Debug registers. */
1015 if (fWhat & CPUMCTX_EXTRN_DR7)
1016 {
1017 uint64_t u64Dr7;
1018 READ_GREG(HV_X86_DR7, u64Dr7);
1019 if (pVCpu->cpum.GstCtx.dr[7] != u64Dr7)
1020 CPUMSetGuestDR7(pVCpu, u64Dr7);
1021 pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_DR7; /* Hack alert! Avoids asserting when processing CPUMCTX_EXTRN_DR0_DR3. */
1022 }
1023 if (fWhat & CPUMCTX_EXTRN_DR0_DR3)
1024 {
1025 uint64_t u64DrTmp;
1026
1027 READ_GREG(HV_X86_DR0, u64DrTmp);
1028 if (pVCpu->cpum.GstCtx.dr[0] != u64DrTmp)
1029 CPUMSetGuestDR0(pVCpu, u64DrTmp);
1030 READ_GREG(HV_X86_DR1, u64DrTmp);
1031 if (pVCpu->cpum.GstCtx.dr[1] != u64DrTmp)
1032 CPUMSetGuestDR1(pVCpu, u64DrTmp);
1033 READ_GREG(HV_X86_DR2, u64DrTmp);
1034 if (pVCpu->cpum.GstCtx.dr[2] != u64DrTmp)
1035 CPUMSetGuestDR2(pVCpu, u64DrTmp);
1036 READ_GREG(HV_X86_DR3, u64DrTmp);
1037 if (pVCpu->cpum.GstCtx.dr[3] != u64DrTmp)
1038 CPUMSetGuestDR3(pVCpu, u64DrTmp);
1039 }
1040 if (fWhat & CPUMCTX_EXTRN_DR6)
1041 {
1042 uint64_t u64Dr6;
1043 READ_GREG(HV_X86_DR6, u64Dr6);
1044 if (pVCpu->cpum.GstCtx.dr[6] != u64Dr6)
1045 CPUMSetGuestDR6(pVCpu, u64Dr6);
1046 }
1047
1048 if (fWhat & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX))
1049 {
1050 hrc = hv_vcpu_read_fpstate(pVCpu->nem.s.hVCpuId, &pVCpu->cpum.GstCtx.XState, sizeof(pVCpu->cpum.GstCtx.XState));
1051 if (hrc == HV_SUCCESS)
1052 { /* likely */ }
1053 else
1054 {
1055 STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateImport, x);
1056 return nemR3DarwinHvSts2Rc(hrc);
1057 }
1058 }
1059
1060 /* MSRs */
1061 if (fWhat & CPUMCTX_EXTRN_EFER)
1062 {
1063 uint64_t u64Efer;
1064
1065 READ_VMCS_FIELD(VMX_VMCS64_GUEST_EFER_FULL, u64Efer);
1066 if (u64Efer != pVCpu->cpum.GstCtx.msrEFER)
1067 {
1068 Log7(("NEM/%u: MSR EFER changed %RX64 -> %RX64\n", pVCpu->idCpu, pVCpu->cpum.GstCtx.msrEFER, u64Efer));
1069 if ((u64Efer ^ pVCpu->cpum.GstCtx.msrEFER) & MSR_K6_EFER_NXE)
1070 PGMNotifyNxeChanged(pVCpu, RT_BOOL(u64Efer & MSR_K6_EFER_NXE));
1071 pVCpu->cpum.GstCtx.msrEFER = u64Efer;
1072 fMaybeChangedMode = true;
1073 }
1074 }
1075
1076 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
1077 READ_MSR(MSR_K8_KERNEL_GS_BASE, pVCpu->cpum.GstCtx.msrKERNELGSBASE);
1078 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
1079 {
1080 uint64_t u64Tmp;
1081 READ_MSR(MSR_IA32_SYSENTER_EIP, u64Tmp);
1082 pVCpu->cpum.GstCtx.SysEnter.eip = u64Tmp;
1083 READ_MSR(MSR_IA32_SYSENTER_ESP, u64Tmp);
1084 pVCpu->cpum.GstCtx.SysEnter.esp = u64Tmp;
1085 READ_MSR(MSR_IA32_SYSENTER_CS, u64Tmp);
1086 pVCpu->cpum.GstCtx.SysEnter.cs = u64Tmp;
1087 }
1088 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
1089 {
1090 READ_MSR(MSR_K6_STAR, pVCpu->cpum.GstCtx.msrSTAR);
1091 READ_MSR(MSR_K8_LSTAR, pVCpu->cpum.GstCtx.msrLSTAR);
1092 READ_MSR(MSR_K8_CSTAR, pVCpu->cpum.GstCtx.msrCSTAR);
1093 READ_MSR(MSR_K8_SF_MASK, pVCpu->cpum.GstCtx.msrSFMASK);
1094 }
1095#if 0
1096 if (fWhat & CPUMCTX_EXTRN_OTHER_MSRS)
1097 {
1098 Assert(aenmNames[iReg] == WHvX64RegisterApicBase);
1099 const uint64_t uOldBase = APICGetBaseMsrNoCheck(pVCpu);
1100 if (aValues[iReg].Reg64 != uOldBase)
1101 {
1102 Log7(("NEM/%u: MSR APICBase changed %RX64 -> %RX64 (%RX64)\n",
1103 pVCpu->idCpu, uOldBase, aValues[iReg].Reg64, aValues[iReg].Reg64 ^ uOldBase));
1104 int rc2 = APICSetBaseMsr(pVCpu, aValues[iReg].Reg64);
1105 AssertLogRelMsg(rc2 == VINF_SUCCESS, ("%Rrc %RX64\n", rc2, aValues[iReg].Reg64));
1106 }
1107 iReg++;
1108
1109 GET_REG64_LOG7(pVCpu->cpum.GstCtx.msrPAT, WHvX64RegisterPat, "MSR PAT");
1110#if 0 /*def LOG_ENABLED*/ /** @todo something's wrong with HvX64RegisterMtrrCap? (AMD) */
1111 GET_REG64_LOG7(pVCpu->cpum.GstCtx.msrPAT, WHvX64RegisterMsrMtrrCap);
1112#endif
1113 PCPUMCTXMSRS pCtxMsrs = CPUMQueryGuestCtxMsrsPtr(pVCpu);
1114 GET_REG64_LOG7(pCtxMsrs->msr.MtrrDefType, WHvX64RegisterMsrMtrrDefType, "MSR MTRR_DEF_TYPE");
1115 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix64K_00000, WHvX64RegisterMsrMtrrFix64k00000, "MSR MTRR_FIX_64K_00000");
1116 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix16K_80000, WHvX64RegisterMsrMtrrFix16k80000, "MSR MTRR_FIX_16K_80000");
1117 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix16K_A0000, WHvX64RegisterMsrMtrrFix16kA0000, "MSR MTRR_FIX_16K_A0000");
1118 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix4K_C0000, WHvX64RegisterMsrMtrrFix4kC0000, "MSR MTRR_FIX_4K_C0000");
1119 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix4K_C8000, WHvX64RegisterMsrMtrrFix4kC8000, "MSR MTRR_FIX_4K_C8000");
1120 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix4K_D0000, WHvX64RegisterMsrMtrrFix4kD0000, "MSR MTRR_FIX_4K_D0000");
1121 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix4K_D8000, WHvX64RegisterMsrMtrrFix4kD8000, "MSR MTRR_FIX_4K_D8000");
1122 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix4K_E0000, WHvX64RegisterMsrMtrrFix4kE0000, "MSR MTRR_FIX_4K_E0000");
1123 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix4K_E8000, WHvX64RegisterMsrMtrrFix4kE8000, "MSR MTRR_FIX_4K_E8000");
1124 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix4K_F0000, WHvX64RegisterMsrMtrrFix4kF0000, "MSR MTRR_FIX_4K_F0000");
1125 GET_REG64_LOG7(pCtxMsrs->msr.MtrrFix4K_F8000, WHvX64RegisterMsrMtrrFix4kF8000, "MSR MTRR_FIX_4K_F8000");
1126 GET_REG64_LOG7(pCtxMsrs->msr.TscAux, WHvX64RegisterTscAux, "MSR TSC_AUX");
1127 /** @todo look for HvX64RegisterIa32MiscEnable and HvX64RegisterIa32FeatureControl? */
1128 }
1129#endif
1130
1131 /* Almost done, just update extrn flags and maybe change PGM mode. */
1132 pVCpu->cpum.GstCtx.fExtrn &= ~fWhat;
1133 if (!(pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_ALL))
1134 pVCpu->cpum.GstCtx.fExtrn = 0;
1135
1136#ifdef LOG_ENABLED
1137 nemR3DarwinLogState(pVM, pVCpu);
1138#endif
1139
1140 /* Typical. */
1141 if (!fMaybeChangedMode && !fUpdateCr3)
1142 {
1143 STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateImport, x);
1144 return VINF_SUCCESS;
1145 }
1146
1147 /*
1148 * Slow.
1149 */
1150 if (fMaybeChangedMode)
1151 {
1152 int rc = PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER,
1153 false /* fForce */);
1154 AssertMsgReturn(rc == VINF_SUCCESS, ("rc=%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_NEM_IPE_1);
1155 }
1156
1157 if (fUpdateCr3)
1158 {
1159 int rc = PGMUpdateCR3(pVCpu, pVCpu->cpum.GstCtx.cr3);
1160 if (rc == VINF_SUCCESS)
1161 { /* likely */ }
1162 else
1163 AssertMsgFailedReturn(("rc=%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_NEM_IPE_2);
1164 }
1165
1166 STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateImport, x);
1167
1168 return VINF_SUCCESS;
1169#undef READ_GREG
1170#undef READ_VMCS_FIELD
1171#undef READ_VMCS32_FIELD
1172#undef READ_SEG
1173#undef READ_MSR
1174}
1175
1176
1177/**
1178 * State to pass between nemHCWinHandleMemoryAccess / nemR3WinWHvHandleMemoryAccess
1179 * and nemHCWinHandleMemoryAccessPageCheckerCallback.
1180 */
1181typedef struct NEMHCDARWINHMACPCCSTATE
1182{
1183 /** Input: Write access. */
1184 bool fWriteAccess;
1185 /** Output: Set if we did something. */
1186 bool fDidSomething;
1187 /** Output: Set it we should resume. */
1188 bool fCanResume;
1189} NEMHCDARWINHMACPCCSTATE;
1190
1191/**
1192 * @callback_method_impl{FNPGMPHYSNEMCHECKPAGE,
1193 * Worker for nemR3WinHandleMemoryAccess; pvUser points to a
1194 * NEMHCDARWINHMACPCCSTATE structure. }
1195 */
1196static DECLCALLBACK(int)
1197nemR3DarwinHandleMemoryAccessPageCheckerCallback(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)
1198{
1199 NEMHCDARWINHMACPCCSTATE *pState = (NEMHCDARWINHMACPCCSTATE *)pvUser;
1200 pState->fDidSomething = false;
1201 pState->fCanResume = false;
1202
1203 uint8_t u2State = pInfo->u2NemState;
1204
1205 /*
1206 * Consolidate current page state with actual page protection and access type.
1207 * We don't really consider downgrades here, as they shouldn't happen.
1208 */
1209 int rc;
1210 switch (u2State)
1211 {
1212 case NEM_DARWIN_PAGE_STATE_UNMAPPED:
1213 case NEM_DARWIN_PAGE_STATE_NOT_SET:
1214 if (pInfo->fNemProt == NEM_PAGE_PROT_NONE)
1215 {
1216 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #1\n", GCPhys));
1217 return VINF_SUCCESS;
1218 }
1219
1220 /* Don't bother remapping it if it's a write request to a non-writable page. */
1221 if ( pState->fWriteAccess
1222 && !(pInfo->fNemProt & NEM_PAGE_PROT_WRITE))
1223 {
1224 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #1w\n", GCPhys));
1225 return VINF_SUCCESS;
1226 }
1227
1228 /* Map the page. */
1229 rc = nemHCNativeSetPhysPage(pVM,
1230 pVCpu,
1231 GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
1232 GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
1233 pInfo->fNemProt,
1234 &u2State,
1235 true /*fBackingState*/);
1236 pInfo->u2NemState = u2State;
1237 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - synced => %s + %Rrc\n",
1238 GCPhys, g_apszPageStates[u2State], rc));
1239 pState->fDidSomething = true;
1240 pState->fCanResume = true;
1241 return rc;
1242
1243 case NEM_DARWIN_PAGE_STATE_READABLE:
1244 if ( !(pInfo->fNemProt & NEM_PAGE_PROT_WRITE)
1245 && (pInfo->fNemProt & (NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE)))
1246 {
1247 pState->fCanResume = true;
1248 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #2\n", GCPhys));
1249 return VINF_SUCCESS;
1250 }
1251 break;
1252
1253 case NEM_DARWIN_PAGE_STATE_WRITABLE:
1254 if (pInfo->fNemProt & NEM_PAGE_PROT_WRITE)
1255 {
1256 /* We get spurious EPT exit violations when everything is fine (#3a case) but can resume without issues here... */
1257 pState->fCanResume = true;
1258 if (pInfo->u2OldNemState == NEM_DARWIN_PAGE_STATE_WRITABLE)
1259 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #3a\n", GCPhys));
1260 else
1261 Log4(("nemR3DarwinHandleMemoryAccessPageCheckerCallback: %RGp - #3b (%s -> %s)\n",
1262 GCPhys, g_apszPageStates[pInfo->u2OldNemState], g_apszPageStates[u2State]));
1263 return VINF_SUCCESS;
1264 }
1265
1266 break;
1267
1268 default:
1269 AssertLogRelMsgFailedReturn(("u2State=%#x\n", u2State), VERR_NEM_IPE_4);
1270 }
1271
1272 /*
1273 * Unmap and restart the instruction.
1274 * If this fails, which it does every so often, just unmap everything for now.
1275 */
1276 rc = nemR3DarwinUnmap(pVM, GCPhys, X86_PAGE_SIZE);
1277 if (RT_SUCCESS(rc))
1278 {
1279 pState->fDidSomething = true;
1280 pState->fCanResume = true;
1281 pInfo->u2NemState = NEM_DARWIN_PAGE_STATE_UNMAPPED;
1282 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
1283 Log5(("NEM GPA unmapped/exit: %RGp (was %s)\n", GCPhys, g_apszPageStates[u2State]));
1284 return VINF_SUCCESS;
1285 }
1286 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
1287 LogRel(("nemR3DarwinHandleMemoryAccessPageCheckerCallback/unmap: GCPhysDst=%RGp %s rc=%Rrc\n",
1288 GCPhys, g_apszPageStates[u2State], rc));
1289 return VERR_NEM_UNMAP_PAGES_FAILED;
1290}
1291
1292
1293DECL_FORCE_INLINE(bool) nemR3DarwinIsUnrestrictedGuest(PCVMCC pVM)
1294{
1295 RT_NOREF(pVM);
1296 return true;
1297}
1298
1299
1300DECL_FORCE_INLINE(bool) nemR3DarwinIsNestedPaging(PCVMCC pVM)
1301{
1302 RT_NOREF(pVM);
1303 return true;
1304}
1305
1306
1307DECL_FORCE_INLINE(bool) nemR3DarwinIsPreemptTimerUsed(PCVMCC pVM)
1308{
1309 RT_NOREF(pVM);
1310 return false;
1311}
1312
1313
1314#if 0 /* unused */
1315DECL_FORCE_INLINE(bool) nemR3DarwinIsVmxLbr(PCVMCC pVM)
1316{
1317 RT_NOREF(pVM);
1318 return false;
1319}
1320#endif
1321
1322
1323/*
1324 * Instantiate the code we share with ring-0.
1325 */
1326#define IN_NEM_DARWIN
1327//#define HMVMX_ALWAYS_TRAP_ALL_XCPTS
1328//#define HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
1329#define HMVMX_ALWAYS_INTERCEPT_CR3_ACCESS /* Temporary to investigate an issue with 32bit guests whete seem to end up with an invalid page table root address. */
1330#define VCPU_2_VMXSTATE(a_pVCpu) (a_pVCpu)->nem.s
1331#define VCPU_2_VMXSTATS(a_pVCpu) (*(a_pVCpu)->nem.s.pVmxStats)
1332
1333#define VM_IS_VMX_UNRESTRICTED_GUEST(a_pVM) nemR3DarwinIsUnrestrictedGuest((a_pVM))
1334#define VM_IS_VMX_NESTED_PAGING(a_pVM) nemR3DarwinIsNestedPaging((a_pVM))
1335#define VM_IS_VMX_PREEMPT_TIMER_USED(a_pVM) nemR3DarwinIsPreemptTimerUsed((a_pVM))
1336#define VM_IS_VMX_LBR(a_pVM) nemR3DarwinIsVmxLbr((a_pVM))
1337
1338#define VMX_VMCS_WRITE_16(a_pVCpu, a_FieldEnc, a_Val) nemR3DarwinWriteVmcs16((a_pVCpu), (a_FieldEnc), (a_Val))
1339#define VMX_VMCS_WRITE_32(a_pVCpu, a_FieldEnc, a_Val) nemR3DarwinWriteVmcs32((a_pVCpu), (a_FieldEnc), (a_Val))
1340#define VMX_VMCS_WRITE_64(a_pVCpu, a_FieldEnc, a_Val) nemR3DarwinWriteVmcs64((a_pVCpu), (a_FieldEnc), (a_Val))
1341#define VMX_VMCS_WRITE_NW(a_pVCpu, a_FieldEnc, a_Val) nemR3DarwinWriteVmcs64((a_pVCpu), (a_FieldEnc), (a_Val))
1342
1343#define VMX_VMCS_READ_16(a_pVCpu, a_FieldEnc, a_pVal) nemR3DarwinReadVmcs16((a_pVCpu), (a_FieldEnc), (a_pVal))
1344#define VMX_VMCS_READ_32(a_pVCpu, a_FieldEnc, a_pVal) nemR3DarwinReadVmcs32((a_pVCpu), (a_FieldEnc), (a_pVal))
1345#define VMX_VMCS_READ_64(a_pVCpu, a_FieldEnc, a_pVal) nemR3DarwinReadVmcs64((a_pVCpu), (a_FieldEnc), (a_pVal))
1346#define VMX_VMCS_READ_NW(a_pVCpu, a_FieldEnc, a_pVal) nemR3DarwinReadVmcs64((a_pVCpu), (a_FieldEnc), (a_pVal))
1347
1348#include "../VMMAll/VMXAllTemplate.cpp.h"
1349
1350#undef VMX_VMCS_WRITE_16
1351#undef VMX_VMCS_WRITE_32
1352#undef VMX_VMCS_WRITE_64
1353#undef VMX_VMCS_WRITE_NW
1354
1355#undef VMX_VMCS_READ_16
1356#undef VMX_VMCS_READ_32
1357#undef VMX_VMCS_READ_64
1358#undef VMX_VMCS_READ_NW
1359
1360#undef VM_IS_VMX_PREEMPT_TIMER_USED
1361#undef VM_IS_VMX_NESTED_PAGING
1362#undef VM_IS_VMX_UNRESTRICTED_GUEST
1363#undef VCPU_2_VMXSTATS
1364#undef VCPU_2_VMXSTATE
1365
1366
1367/**
1368 * Exports the guest GP registers to HV for execution.
1369 *
1370 * @returns VBox status code.
1371 * @param pVCpu The cross context virtual CPU structure of the
1372 * calling EMT.
1373 */
1374static int nemR3DarwinExportGuestGprs(PVMCPUCC pVCpu)
1375{
1376#define WRITE_GREG(a_GReg, a_Value) \
1377 do \
1378 { \
1379 hv_return_t hrc = hv_vcpu_write_register(pVCpu->nem.s.hVCpuId, (a_GReg), (a_Value)); \
1380 if (RT_LIKELY(hrc == HV_SUCCESS)) \
1381 { /* likely */ } \
1382 else \
1383 return VERR_INTERNAL_ERROR; \
1384 } while(0)
1385
1386 uint64_t fCtxChanged = ASMAtomicUoReadU64(&pVCpu->nem.s.fCtxChanged);
1387 if (fCtxChanged & HM_CHANGED_GUEST_GPRS_MASK)
1388 {
1389 if (fCtxChanged & HM_CHANGED_GUEST_RAX)
1390 WRITE_GREG(HV_X86_RAX, pVCpu->cpum.GstCtx.rax);
1391 if (fCtxChanged & HM_CHANGED_GUEST_RCX)
1392 WRITE_GREG(HV_X86_RCX, pVCpu->cpum.GstCtx.rcx);
1393 if (fCtxChanged & HM_CHANGED_GUEST_RDX)
1394 WRITE_GREG(HV_X86_RDX, pVCpu->cpum.GstCtx.rdx);
1395 if (fCtxChanged & HM_CHANGED_GUEST_RBX)
1396 WRITE_GREG(HV_X86_RBX, pVCpu->cpum.GstCtx.rbx);
1397 if (fCtxChanged & HM_CHANGED_GUEST_RSP)
1398 WRITE_GREG(HV_X86_RSP, pVCpu->cpum.GstCtx.rsp);
1399 if (fCtxChanged & HM_CHANGED_GUEST_RBP)
1400 WRITE_GREG(HV_X86_RBP, pVCpu->cpum.GstCtx.rbp);
1401 if (fCtxChanged & HM_CHANGED_GUEST_RSI)
1402 WRITE_GREG(HV_X86_RSI, pVCpu->cpum.GstCtx.rsi);
1403 if (fCtxChanged & HM_CHANGED_GUEST_RDI)
1404 WRITE_GREG(HV_X86_RDI, pVCpu->cpum.GstCtx.rdi);
1405 if (fCtxChanged & HM_CHANGED_GUEST_R8_R15)
1406 {
1407 WRITE_GREG(HV_X86_R8, pVCpu->cpum.GstCtx.r8);
1408 WRITE_GREG(HV_X86_R9, pVCpu->cpum.GstCtx.r9);
1409 WRITE_GREG(HV_X86_R10, pVCpu->cpum.GstCtx.r10);
1410 WRITE_GREG(HV_X86_R11, pVCpu->cpum.GstCtx.r11);
1411 WRITE_GREG(HV_X86_R12, pVCpu->cpum.GstCtx.r12);
1412 WRITE_GREG(HV_X86_R13, pVCpu->cpum.GstCtx.r13);
1413 WRITE_GREG(HV_X86_R14, pVCpu->cpum.GstCtx.r14);
1414 WRITE_GREG(HV_X86_R15, pVCpu->cpum.GstCtx.r15);
1415 }
1416
1417 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_GPRS_MASK);
1418 }
1419
1420 if (fCtxChanged & HM_CHANGED_GUEST_CR2)
1421 {
1422 WRITE_GREG(HV_X86_CR2, pVCpu->cpum.GstCtx.cr2);
1423 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_CR2);
1424 }
1425
1426 return VINF_SUCCESS;
1427#undef WRITE_GREG
1428}
1429
1430
1431/**
1432 * Converts the given CPUM externalized bitmask to the appropriate HM changed bitmask.
1433 *
1434 * @returns Bitmask of HM changed flags.
1435 * @param fCpumExtrn The CPUM extern bitmask.
1436 */
1437static uint64_t nemR3DarwinCpumExtrnToHmChanged(uint64_t fCpumExtrn)
1438{
1439 uint64_t fHmChanged = 0;
1440
1441 /* Invert to gt a mask of things which are kept in CPUM. */
1442 uint64_t fCpumIntern = ~fCpumExtrn;
1443
1444 if (fCpumIntern & CPUMCTX_EXTRN_GPRS_MASK)
1445 {
1446 if (fCpumIntern & CPUMCTX_EXTRN_RAX)
1447 fHmChanged |= HM_CHANGED_GUEST_RAX;
1448 if (fCpumIntern & CPUMCTX_EXTRN_RCX)
1449 fHmChanged |= HM_CHANGED_GUEST_RCX;
1450 if (fCpumIntern & CPUMCTX_EXTRN_RDX)
1451 fHmChanged |= HM_CHANGED_GUEST_RDX;
1452 if (fCpumIntern & CPUMCTX_EXTRN_RBX)
1453 fHmChanged |= HM_CHANGED_GUEST_RBX;
1454 if (fCpumIntern & CPUMCTX_EXTRN_RSP)
1455 fHmChanged |= HM_CHANGED_GUEST_RSP;
1456 if (fCpumIntern & CPUMCTX_EXTRN_RBP)
1457 fHmChanged |= HM_CHANGED_GUEST_RBP;
1458 if (fCpumIntern & CPUMCTX_EXTRN_RSI)
1459 fHmChanged |= HM_CHANGED_GUEST_RSI;
1460 if (fCpumIntern & CPUMCTX_EXTRN_RDI)
1461 fHmChanged |= HM_CHANGED_GUEST_RDI;
1462 if (fCpumIntern & CPUMCTX_EXTRN_R8_R15)
1463 fHmChanged |= HM_CHANGED_GUEST_R8_R15;
1464 }
1465
1466 /* RIP & Flags */
1467 if (fCpumIntern & CPUMCTX_EXTRN_RIP)
1468 fHmChanged |= HM_CHANGED_GUEST_RIP;
1469 if (fCpumIntern & CPUMCTX_EXTRN_RFLAGS)
1470 fHmChanged |= HM_CHANGED_GUEST_RFLAGS;
1471
1472 /* Segments */
1473 if (fCpumIntern & CPUMCTX_EXTRN_SREG_MASK)
1474 {
1475 if (fCpumIntern & CPUMCTX_EXTRN_ES)
1476 fHmChanged |= HM_CHANGED_GUEST_ES;
1477 if (fCpumIntern & CPUMCTX_EXTRN_CS)
1478 fHmChanged |= HM_CHANGED_GUEST_CS;
1479 if (fCpumIntern & CPUMCTX_EXTRN_SS)
1480 fHmChanged |= HM_CHANGED_GUEST_SS;
1481 if (fCpumIntern & CPUMCTX_EXTRN_DS)
1482 fHmChanged |= HM_CHANGED_GUEST_DS;
1483 if (fCpumIntern & CPUMCTX_EXTRN_FS)
1484 fHmChanged |= HM_CHANGED_GUEST_FS;
1485 if (fCpumIntern & CPUMCTX_EXTRN_GS)
1486 fHmChanged |= HM_CHANGED_GUEST_GS;
1487 }
1488
1489 /* Descriptor tables & task segment. */
1490 if (fCpumIntern & CPUMCTX_EXTRN_TABLE_MASK)
1491 {
1492 if (fCpumIntern & CPUMCTX_EXTRN_LDTR)
1493 fHmChanged |= HM_CHANGED_GUEST_LDTR;
1494 if (fCpumIntern & CPUMCTX_EXTRN_TR)
1495 fHmChanged |= HM_CHANGED_GUEST_TR;
1496 if (fCpumIntern & CPUMCTX_EXTRN_IDTR)
1497 fHmChanged |= HM_CHANGED_GUEST_IDTR;
1498 if (fCpumIntern & CPUMCTX_EXTRN_GDTR)
1499 fHmChanged |= HM_CHANGED_GUEST_GDTR;
1500 }
1501
1502 /* Control registers. */
1503 if (fCpumIntern & CPUMCTX_EXTRN_CR_MASK)
1504 {
1505 if (fCpumIntern & CPUMCTX_EXTRN_CR0)
1506 fHmChanged |= HM_CHANGED_GUEST_CR0;
1507 if (fCpumIntern & CPUMCTX_EXTRN_CR2)
1508 fHmChanged |= HM_CHANGED_GUEST_CR2;
1509 if (fCpumIntern & CPUMCTX_EXTRN_CR3)
1510 fHmChanged |= HM_CHANGED_GUEST_CR3;
1511 if (fCpumIntern & CPUMCTX_EXTRN_CR4)
1512 fHmChanged |= HM_CHANGED_GUEST_CR4;
1513 }
1514 if (fCpumIntern & CPUMCTX_EXTRN_APIC_TPR)
1515 fHmChanged |= HM_CHANGED_GUEST_APIC_TPR;
1516
1517 /* Debug registers. */
1518 if (fCpumIntern & CPUMCTX_EXTRN_DR0_DR3)
1519 fHmChanged |= HM_CHANGED_GUEST_DR0_DR3;
1520 if (fCpumIntern & CPUMCTX_EXTRN_DR6)
1521 fHmChanged |= HM_CHANGED_GUEST_DR6;
1522 if (fCpumIntern & CPUMCTX_EXTRN_DR7)
1523 fHmChanged |= HM_CHANGED_GUEST_DR7;
1524
1525 /* Floating point state. */
1526 if (fCpumIntern & CPUMCTX_EXTRN_X87)
1527 fHmChanged |= HM_CHANGED_GUEST_X87;
1528 if (fCpumIntern & CPUMCTX_EXTRN_SSE_AVX)
1529 fHmChanged |= HM_CHANGED_GUEST_SSE_AVX;
1530 if (fCpumIntern & CPUMCTX_EXTRN_OTHER_XSAVE)
1531 fHmChanged |= HM_CHANGED_GUEST_OTHER_XSAVE;
1532 if (fCpumIntern & CPUMCTX_EXTRN_XCRx)
1533 fHmChanged |= HM_CHANGED_GUEST_XCRx;
1534
1535 /* MSRs */
1536 if (fCpumIntern & CPUMCTX_EXTRN_EFER)
1537 fHmChanged |= HM_CHANGED_GUEST_EFER_MSR;
1538 if (fCpumIntern & CPUMCTX_EXTRN_KERNEL_GS_BASE)
1539 fHmChanged |= HM_CHANGED_GUEST_KERNEL_GS_BASE;
1540 if (fCpumIntern & CPUMCTX_EXTRN_SYSENTER_MSRS)
1541 fHmChanged |= HM_CHANGED_GUEST_SYSENTER_MSR_MASK;
1542 if (fCpumIntern & CPUMCTX_EXTRN_SYSCALL_MSRS)
1543 fHmChanged |= HM_CHANGED_GUEST_SYSCALL_MSRS;
1544 if (fCpumIntern & CPUMCTX_EXTRN_TSC_AUX)
1545 fHmChanged |= HM_CHANGED_GUEST_TSC_AUX;
1546 if (fCpumIntern & CPUMCTX_EXTRN_OTHER_MSRS)
1547 fHmChanged |= HM_CHANGED_GUEST_OTHER_MSRS;
1548
1549 return fHmChanged;
1550}
1551
1552
1553/**
1554 * Exports the guest state to HV for execution.
1555 *
1556 * @returns VBox status code.
1557 * @param pVM The cross context VM structure.
1558 * @param pVCpu The cross context virtual CPU structure of the
1559 * calling EMT.
1560 * @param pVmxTransient The transient VMX structure.
1561 */
1562static int nemR3DarwinExportGuestState(PVMCC pVM, PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
1563{
1564#define WRITE_GREG(a_GReg, a_Value) \
1565 do \
1566 { \
1567 hv_return_t hrc = hv_vcpu_write_register(pVCpu->nem.s.hVCpuId, (a_GReg), (a_Value)); \
1568 if (RT_LIKELY(hrc == HV_SUCCESS)) \
1569 { /* likely */ } \
1570 else \
1571 return VERR_INTERNAL_ERROR; \
1572 } while(0)
1573#define WRITE_VMCS_FIELD(a_Field, a_Value) \
1574 do \
1575 { \
1576 hv_return_t hrc = hv_vmx_vcpu_write_vmcs(pVCpu->nem.s.hVCpuId, (a_Field), (a_Value)); \
1577 if (RT_LIKELY(hrc == HV_SUCCESS)) \
1578 { /* likely */ } \
1579 else \
1580 return VERR_INTERNAL_ERROR; \
1581 } while(0)
1582#define WRITE_MSR(a_Msr, a_Value) \
1583 do \
1584 { \
1585 hv_return_t hrc = hv_vcpu_write_msr(pVCpu->nem.s.hVCpuId, (a_Msr), (a_Value)); \
1586 if (RT_LIKELY(hrc == HV_SUCCESS)) \
1587 { /* likely */ } \
1588 else \
1589 AssertFailedReturn(VERR_INTERNAL_ERROR); \
1590 } while(0)
1591
1592 RT_NOREF(pVM);
1593
1594#ifdef LOG_ENABLED
1595 nemR3DarwinLogState(pVM, pVCpu);
1596#endif
1597
1598 STAM_PROFILE_ADV_START(&pVCpu->nem.s.StatProfGstStateExport, x);
1599
1600 uint64_t const fWhat = ~pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_ALL;
1601 if (!fWhat)
1602 return VINF_SUCCESS;
1603
1604 pVCpu->nem.s.fCtxChanged |= nemR3DarwinCpumExtrnToHmChanged(pVCpu->cpum.GstCtx.fExtrn);
1605
1606 int rc = vmxHCExportGuestEntryExitCtls(pVCpu, pVmxTransient);
1607 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
1608
1609 rc = nemR3DarwinExportGuestGprs(pVCpu);
1610 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
1611
1612 rc = vmxHCExportGuestCR0(pVCpu, pVmxTransient);
1613 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
1614
1615 VBOXSTRICTRC rcStrict = vmxHCExportGuestCR3AndCR4(pVCpu, pVmxTransient);
1616 if (rcStrict == VINF_SUCCESS)
1617 { /* likely */ }
1618 else
1619 {
1620 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
1621 return VBOXSTRICTRC_VAL(rcStrict);
1622 }
1623
1624 vmxHCExportGuestXcptIntercepts(pVCpu, pVmxTransient);
1625 vmxHCExportGuestRip(pVCpu);
1626 //vmxHCExportGuestRsp(pVCpu);
1627 vmxHCExportGuestRflags(pVCpu, pVmxTransient);
1628
1629 rc = vmxHCExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
1630 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
1631
1632 if (fWhat & CPUMCTX_EXTRN_XCRx)
1633 {
1634 WRITE_GREG(HV_X86_XCR0, pVCpu->cpum.GstCtx.aXcr[0]);
1635 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_XCRx);
1636 }
1637
1638 if (fWhat & CPUMCTX_EXTRN_APIC_TPR)
1639 {
1640 Assert(pVCpu->nem.s.fCtxChanged & HM_CHANGED_GUEST_APIC_TPR);
1641 vmxHCExportGuestApicTpr(pVCpu, pVmxTransient);
1642
1643 rc = APICGetTpr(pVCpu, &pVmxTransient->u8GuestTpr, NULL /*pfPending*/, NULL /*pu8PendingIntr*/);
1644 AssertRC(rc);
1645
1646 WRITE_GREG(HV_X86_TPR, pVmxTransient->u8GuestTpr);
1647 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
1648 }
1649
1650 /* Debug registers. */
1651 if (fWhat & CPUMCTX_EXTRN_DR0_DR3)
1652 {
1653 WRITE_GREG(HV_X86_DR0, pVCpu->cpum.GstCtx.dr[0]); // CPUMGetHyperDR0(pVCpu));
1654 WRITE_GREG(HV_X86_DR1, pVCpu->cpum.GstCtx.dr[1]); // CPUMGetHyperDR1(pVCpu));
1655 WRITE_GREG(HV_X86_DR2, pVCpu->cpum.GstCtx.dr[2]); // CPUMGetHyperDR2(pVCpu));
1656 WRITE_GREG(HV_X86_DR3, pVCpu->cpum.GstCtx.dr[3]); // CPUMGetHyperDR3(pVCpu));
1657 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_DR0_DR3);
1658 }
1659 if (fWhat & CPUMCTX_EXTRN_DR6)
1660 {
1661 WRITE_GREG(HV_X86_DR6, pVCpu->cpum.GstCtx.dr[6]); // CPUMGetHyperDR6(pVCpu));
1662 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_DR6);
1663 }
1664 if (fWhat & CPUMCTX_EXTRN_DR7)
1665 {
1666 WRITE_GREG(HV_X86_DR7, pVCpu->cpum.GstCtx.dr[7]); // CPUMGetHyperDR7(pVCpu));
1667 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_DR7);
1668 }
1669
1670 if (fWhat & (CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE))
1671 {
1672 hv_return_t hrc = hv_vcpu_write_fpstate(pVCpu->nem.s.hVCpuId, &pVCpu->cpum.GstCtx.XState, sizeof(pVCpu->cpum.GstCtx.XState));
1673 if (hrc == HV_SUCCESS)
1674 { /* likely */ }
1675 else
1676 return nemR3DarwinHvSts2Rc(hrc);
1677
1678 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~(HM_CHANGED_GUEST_X87 | HM_CHANGED_GUEST_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE));
1679 }
1680
1681 /* MSRs */
1682 if (fWhat & CPUMCTX_EXTRN_EFER)
1683 {
1684 WRITE_VMCS_FIELD(VMX_VMCS64_GUEST_EFER_FULL, pVCpu->cpum.GstCtx.msrEFER);
1685 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
1686 }
1687 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
1688 {
1689 WRITE_MSR(MSR_K8_KERNEL_GS_BASE, pVCpu->cpum.GstCtx.msrKERNELGSBASE);
1690 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_KERNEL_GS_BASE);
1691 }
1692 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
1693 {
1694 WRITE_MSR(MSR_IA32_SYSENTER_CS, pVCpu->cpum.GstCtx.SysEnter.cs);
1695 WRITE_MSR(MSR_IA32_SYSENTER_EIP, pVCpu->cpum.GstCtx.SysEnter.eip);
1696 WRITE_MSR(MSR_IA32_SYSENTER_ESP, pVCpu->cpum.GstCtx.SysEnter.esp);
1697 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_MSR_MASK);
1698 }
1699 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
1700 {
1701 WRITE_MSR(MSR_K6_STAR, pVCpu->cpum.GstCtx.msrSTAR);
1702 WRITE_MSR(MSR_K8_LSTAR, pVCpu->cpum.GstCtx.msrLSTAR);
1703 WRITE_MSR(MSR_K8_CSTAR, pVCpu->cpum.GstCtx.msrCSTAR);
1704 WRITE_MSR(MSR_K8_SF_MASK, pVCpu->cpum.GstCtx.msrSFMASK);
1705 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSCALL_MSRS);
1706 }
1707 if (fWhat & CPUMCTX_EXTRN_OTHER_MSRS)
1708 {
1709#if 0
1710 hv_return_t hrc = hv_vmx_vcpu_set_apic_address(pVCpu->nem.s.hVCpuId, APICGetBaseMsrNoCheck(pVCpu) & PAGE_BASE_GC_MASK);
1711 if (RT_UNLIKELY(hrc != HV_SUCCESS))
1712 return nemR3DarwinHvSts2Rc(hrc);
1713#endif
1714
1715 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
1716
1717#if 0
1718 ADD_REG64(WHvX64RegisterPat, pVCpu->cpum.GstCtx.msrPAT);
1719#if 0 /** @todo check if WHvX64RegisterMsrMtrrCap works here... */
1720 ADD_REG64(WHvX64RegisterMsrMtrrCap, CPUMGetGuestIa32MtrrCap(pVCpu));
1721#endif
1722 PCPUMCTXMSRS pCtxMsrs = CPUMQueryGuestCtxMsrsPtr(pVCpu);
1723 ADD_REG64(WHvX64RegisterMsrMtrrDefType, pCtxMsrs->msr.MtrrDefType);
1724 ADD_REG64(WHvX64RegisterMsrMtrrFix64k00000, pCtxMsrs->msr.MtrrFix64K_00000);
1725 ADD_REG64(WHvX64RegisterMsrMtrrFix16k80000, pCtxMsrs->msr.MtrrFix16K_80000);
1726 ADD_REG64(WHvX64RegisterMsrMtrrFix16kA0000, pCtxMsrs->msr.MtrrFix16K_A0000);
1727 ADD_REG64(WHvX64RegisterMsrMtrrFix4kC0000, pCtxMsrs->msr.MtrrFix4K_C0000);
1728 ADD_REG64(WHvX64RegisterMsrMtrrFix4kC8000, pCtxMsrs->msr.MtrrFix4K_C8000);
1729 ADD_REG64(WHvX64RegisterMsrMtrrFix4kD0000, pCtxMsrs->msr.MtrrFix4K_D0000);
1730 ADD_REG64(WHvX64RegisterMsrMtrrFix4kD8000, pCtxMsrs->msr.MtrrFix4K_D8000);
1731 ADD_REG64(WHvX64RegisterMsrMtrrFix4kE0000, pCtxMsrs->msr.MtrrFix4K_E0000);
1732 ADD_REG64(WHvX64RegisterMsrMtrrFix4kE8000, pCtxMsrs->msr.MtrrFix4K_E8000);
1733 ADD_REG64(WHvX64RegisterMsrMtrrFix4kF0000, pCtxMsrs->msr.MtrrFix4K_F0000);
1734 ADD_REG64(WHvX64RegisterMsrMtrrFix4kF8000, pCtxMsrs->msr.MtrrFix4K_F8000);
1735 ADD_REG64(WHvX64RegisterTscAux, pCtxMsrs->msr.TscAux);
1736#if 0 /** @todo these registers aren't available? Might explain something.. .*/
1737 const CPUMCPUVENDOR enmCpuVendor = CPUMGetHostCpuVendor(pVM);
1738 if (enmCpuVendor != CPUMCPUVENDOR_AMD)
1739 {
1740 ADD_REG64(HvX64RegisterIa32MiscEnable, pCtxMsrs->msr.MiscEnable);
1741 ADD_REG64(HvX64RegisterIa32FeatureControl, CPUMGetGuestIa32FeatureControl(pVCpu));
1742 }
1743#endif
1744#endif
1745 }
1746
1747 WRITE_VMCS_FIELD(VMX_VMCS64_GUEST_DEBUGCTL_FULL, 0 /*MSR_IA32_DEBUGCTL_LBR*/);
1748
1749 hv_vcpu_invalidate_tlb(pVCpu->nem.s.hVCpuId);
1750 hv_vcpu_flush(pVCpu->nem.s.hVCpuId);
1751
1752 pVCpu->cpum.GstCtx.fExtrn |= CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_NEM;
1753
1754 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
1755 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~(
1756 HM_CHANGED_GUEST_TSC_AUX
1757 | HM_CHANGED_GUEST_HWVIRT
1758 | HM_CHANGED_VMX_GUEST_AUTO_MSRS
1759 | HM_CHANGED_VMX_GUEST_LAZY_MSRS
1760 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
1761
1762 STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateExport, x);
1763 return VINF_SUCCESS;
1764#undef WRITE_GREG
1765#undef WRITE_VMCS_FIELD
1766}
1767
1768
1769/**
1770 * Handles an exit from hv_vcpu_run().
1771 *
1772 * @returns VBox strict status code.
1773 * @param pVM The cross context VM structure.
1774 * @param pVCpu The cross context virtual CPU structure of the
1775 * calling EMT.
1776 * @param pVmxTransient The transient VMX structure.
1777 */
1778static VBOXSTRICTRC nemR3DarwinHandleExit(PVM pVM, PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
1779{
1780 uint32_t uExitReason;
1781 int rc = nemR3DarwinReadVmcs32(pVCpu, VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
1782 AssertRC(rc);
1783 pVmxTransient->fVmcsFieldsRead = 0;
1784 pVmxTransient->fIsNestedGuest = false;
1785 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
1786 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
1787
1788 if (RT_UNLIKELY(pVmxTransient->fVMEntryFailed))
1789 AssertLogRelMsgFailedReturn(("Running guest failed for CPU #%u: %#x %u\n",
1790 pVCpu->idCpu, pVmxTransient->uExitReason, vmxHCCheckGuestState(pVCpu, &pVCpu->nem.s.VmcsInfo)),
1791 VERR_NEM_IPE_0);
1792
1793 /** @todo Only copy the state on demand (the R0 VT-x code saves some stuff unconditionally and the VMX template assumes that
1794 * when handling exits). */
1795 rc = nemR3DarwinCopyStateFromHv(pVM, pVCpu, CPUMCTX_EXTRN_ALL);
1796 AssertRCReturn(rc, rc);
1797
1798 STAM_COUNTER_INC(&pVCpu->nem.s.pVmxStats->aStatExitReason[pVmxTransient->uExitReason & MASK_EXITREASON_STAT]);
1799 STAM_REL_COUNTER_INC(&pVCpu->nem.s.pVmxStats->StatExitAll);
1800
1801#ifndef HMVMX_USE_FUNCTION_TABLE
1802 return vmxHCHandleExit(pVCpu, pVmxTransient);
1803#else
1804 return g_aVMExitHandlers[pVmxTransient->uExitReason].pfn(pVCpu, pVmxTransient);
1805#endif
1806}
1807
1808
1809/**
1810 * Worker for nemR3NativeInit that loads the Hypervisor.framework shared library.
1811 *
1812 * @returns VBox status code.
1813 * @param fForced Whether the HMForced flag is set and we should
1814 * fail if we cannot initialize.
1815 * @param pErrInfo Where to always return error info.
1816 */
1817static int nemR3DarwinLoadHv(bool fForced, PRTERRINFO pErrInfo)
1818{
1819 RTLDRMOD hMod = NIL_RTLDRMOD;
1820 static const char *s_pszHvPath = "/System/Library/Frameworks/Hypervisor.framework/Hypervisor";
1821
1822 int rc = RTLdrLoadEx(s_pszHvPath, &hMod, RTLDRLOAD_FLAGS_NO_UNLOAD | RTLDRLOAD_FLAGS_NO_SUFFIX, pErrInfo);
1823 if (RT_SUCCESS(rc))
1824 {
1825 for (unsigned i = 0; i < RT_ELEMENTS(g_aImports); i++)
1826 {
1827 int rc2 = RTLdrGetSymbol(hMod, g_aImports[i].pszName, (void **)g_aImports[i].ppfn);
1828 if (RT_SUCCESS(rc2))
1829 {
1830 if (g_aImports[i].fOptional)
1831 LogRel(("NEM: info: Found optional import Hypervisor!%s.\n",
1832 g_aImports[i].pszName));
1833 }
1834 else
1835 {
1836 *g_aImports[i].ppfn = NULL;
1837
1838 LogRel(("NEM: %s: Failed to import Hypervisor!%s: %Rrc\n",
1839 g_aImports[i].fOptional ? "info" : fForced ? "fatal" : "error",
1840 g_aImports[i].pszName, rc2));
1841 if (!g_aImports[i].fOptional)
1842 {
1843 if (RTErrInfoIsSet(pErrInfo))
1844 RTErrInfoAddF(pErrInfo, rc2, ", Hypervisor!%s", g_aImports[i].pszName);
1845 else
1846 rc = RTErrInfoSetF(pErrInfo, rc2, "Failed to import: Hypervisor!%s", g_aImports[i].pszName);
1847 Assert(RT_FAILURE(rc));
1848 }
1849 }
1850 }
1851 if (RT_SUCCESS(rc))
1852 {
1853 Assert(!RTErrInfoIsSet(pErrInfo));
1854 }
1855
1856 RTLdrClose(hMod);
1857 }
1858 else
1859 {
1860 RTErrInfoAddF(pErrInfo, rc, "Failed to load Hypervisor.framwork: %s: %Rrc", s_pszHvPath, rc);
1861 rc = VERR_NEM_INIT_FAILED;
1862 }
1863
1864 return rc;
1865}
1866
1867
1868/**
1869 * Read and initialize the global capabilities supported by this CPU.
1870 *
1871 * @returns VBox status code.
1872 */
1873static int nemR3DarwinCapsInit(void)
1874{
1875 RT_ZERO(g_HmMsrs);
1876
1877 hv_return_t hrc = hv_vmx_read_capability(HV_VMX_CAP_PINBASED, &g_HmMsrs.u.vmx.PinCtls.u);
1878 if (hrc == HV_SUCCESS)
1879 hrc = hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &g_HmMsrs.u.vmx.ProcCtls.u);
1880 if (hrc == HV_SUCCESS)
1881 hrc = hv_vmx_read_capability(HV_VMX_CAP_ENTRY, &g_HmMsrs.u.vmx.EntryCtls.u);
1882 if (hrc == HV_SUCCESS)
1883 hrc = hv_vmx_read_capability(HV_VMX_CAP_EXIT, &g_HmMsrs.u.vmx.ExitCtls.u);
1884 if (hrc == HV_SUCCESS)
1885 {
1886 hrc = hv_vmx_read_capability(HV_VMX_CAP_BASIC, &g_HmMsrs.u.vmx.u64Basic);
1887 if (hrc == HV_SUCCESS)
1888 {
1889 if (hrc == HV_SUCCESS)
1890 hrc = hv_vmx_read_capability(HV_VMX_CAP_MISC, &g_HmMsrs.u.vmx.u64Misc);
1891 if (hrc == HV_SUCCESS)
1892 hrc = hv_vmx_read_capability(HV_VMX_CAP_CR0_FIXED0, &g_HmMsrs.u.vmx.u64Cr0Fixed0);
1893 if (hrc == HV_SUCCESS)
1894 hrc = hv_vmx_read_capability(HV_VMX_CAP_CR0_FIXED1, &g_HmMsrs.u.vmx.u64Cr0Fixed1);
1895 if (hrc == HV_SUCCESS)
1896 hrc = hv_vmx_read_capability(HV_VMX_CAP_CR4_FIXED0, &g_HmMsrs.u.vmx.u64Cr4Fixed0);
1897 if (hrc == HV_SUCCESS)
1898 hrc = hv_vmx_read_capability(HV_VMX_CAP_CR4_FIXED1, &g_HmMsrs.u.vmx.u64Cr4Fixed1);
1899 if (hrc == HV_SUCCESS)
1900 hrc = hv_vmx_read_capability(HV_VMX_CAP_VMCS_ENUM, &g_HmMsrs.u.vmx.u64VmcsEnum);
1901 if ( hrc == HV_SUCCESS
1902 && RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_TRUE_CTLS))
1903 {
1904 hrc = hv_vmx_read_capability(HV_VMX_CAP_TRUE_PINBASED, &g_HmMsrs.u.vmx.TruePinCtls.u);
1905 if (hrc == HV_SUCCESS)
1906 hrc = hv_vmx_read_capability(HV_VMX_CAP_TRUE_PROCBASED, &g_HmMsrs.u.vmx.TrueProcCtls.u);
1907 if (hrc == HV_SUCCESS)
1908 hrc = hv_vmx_read_capability(HV_VMX_CAP_TRUE_ENTRY, &g_HmMsrs.u.vmx.TrueEntryCtls.u);
1909 if (hrc == HV_SUCCESS)
1910 hrc = hv_vmx_read_capability(HV_VMX_CAP_TRUE_EXIT, &g_HmMsrs.u.vmx.TrueExitCtls.u);
1911 }
1912 }
1913 else
1914 {
1915 /* Likely running on anything < 11.0 (BigSur) so provide some sensible defaults. */
1916 g_HmMsrs.u.vmx.u64Cr0Fixed0 = 0x80000021;
1917 g_HmMsrs.u.vmx.u64Cr0Fixed1 = 0xffffffff;
1918 g_HmMsrs.u.vmx.u64Cr4Fixed0 = 0x2000;
1919 g_HmMsrs.u.vmx.u64Cr4Fixed1 = 0x1767ff;
1920 hrc = HV_SUCCESS;
1921 }
1922 }
1923
1924 if ( hrc == HV_SUCCESS
1925 && g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
1926 {
1927 hrc = hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &g_HmMsrs.u.vmx.ProcCtls2.u);
1928
1929 if ( hrc == HV_SUCCESS
1930 && g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & (VMX_PROC_CTLS2_EPT | VMX_PROC_CTLS2_VPID))
1931 {
1932 hrc = hv_vmx_read_capability(HV_VMX_CAP_EPT_VPID_CAP, &g_HmMsrs.u.vmx.u64EptVpidCaps);
1933 if (hrc != HV_SUCCESS)
1934 hrc = HV_SUCCESS; /* Probably just outdated OS. */
1935 }
1936
1937 g_HmMsrs.u.vmx.u64VmFunc = 0; /* No way to read that on macOS. */
1938 }
1939
1940 if (hrc == HV_SUCCESS)
1941 {
1942 /*
1943 * Check for EFER swapping support.
1944 */
1945 g_fHmVmxSupportsVmcsEfer = true; //(g_HmMsrs.u.vmx.EntryCtls.n.allowed1 & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
1946 //&& (g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_LOAD_EFER_MSR)
1947 //&& (g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_EFER_MSR);
1948 }
1949
1950 return nemR3DarwinHvSts2Rc(hrc);
1951}
1952
1953
1954/**
1955 * Sets up pin-based VM-execution controls in the VMCS.
1956 *
1957 * @returns VBox status code.
1958 * @param pVCpu The cross context virtual CPU structure.
1959 * @param pVmcsInfo The VMCS info. object.
1960 */
1961static int nemR3DarwinVmxSetupVmcsPinCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
1962{
1963 //PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1964 uint32_t fVal = g_HmMsrs.u.vmx.PinCtls.n.allowed0; /* Bits set here must always be set. */
1965 uint32_t const fZap = g_HmMsrs.u.vmx.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
1966
1967 if (g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
1968 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
1969
1970#if 0 /** @todo Use preemption timer */
1971 /* Enable the VMX-preemption timer. */
1972 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
1973 {
1974 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
1975 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
1976 }
1977
1978 /* Enable posted-interrupt processing. */
1979 if (pVM->hm.s.fPostedIntrs)
1980 {
1981 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
1982 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
1983 fVal |= VMX_PIN_CTLS_POSTED_INT;
1984 }
1985#endif
1986
1987 if ((fVal & fZap) != fVal)
1988 {
1989 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
1990 g_HmMsrs.u.vmx.PinCtls.n.allowed0, fVal, fZap));
1991 pVCpu->nem.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
1992 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1993 }
1994
1995 /* Commit it to the VMCS and update our cache. */
1996 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PIN_EXEC, fVal);
1997 AssertRC(rc);
1998 pVmcsInfo->u32PinCtls = fVal;
1999
2000 return VINF_SUCCESS;
2001}
2002
2003
2004/**
2005 * Sets up secondary processor-based VM-execution controls in the VMCS.
2006 *
2007 * @returns VBox status code.
2008 * @param pVCpu The cross context virtual CPU structure.
2009 * @param pVmcsInfo The VMCS info. object.
2010 */
2011static int nemR3DarwinVmxSetupVmcsProcCtls2(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2012{
2013 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2014 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
2015 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2016
2017 /* WBINVD causes a VM-exit. */
2018 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
2019 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
2020
2021 /* Enable the INVPCID instruction if we expose it to the guest and is supported
2022 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
2023 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
2024 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
2025 fVal |= VMX_PROC_CTLS2_INVPCID;
2026
2027#if 0 /** @todo */
2028 /* Enable VPID. */
2029 if (pVM->hmr0.s.vmx.fVpid)
2030 fVal |= VMX_PROC_CTLS2_VPID;
2031
2032 if (pVM->hm.s.fVirtApicRegs)
2033 {
2034 /* Enable APIC-register virtualization. */
2035 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
2036 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
2037
2038 /* Enable virtual-interrupt delivery. */
2039 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
2040 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
2041 }
2042
2043 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
2044 where the TPR shadow resides. */
2045 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
2046 * done dynamically. */
2047 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
2048 {
2049 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
2050 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
2051 }
2052#endif
2053
2054 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
2055 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
2056 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
2057 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
2058 fVal |= VMX_PROC_CTLS2_RDTSCP;
2059
2060#if 0
2061 /* Enable Pause-Loop exiting. */
2062 if ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
2063 && pVM->hm.s.vmx.cPleGapTicks
2064 && pVM->hm.s.vmx.cPleWindowTicks)
2065 {
2066 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
2067
2068 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks); AssertRC(rc);
2069 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks); AssertRC(rc);
2070 }
2071#endif
2072
2073 if ((fVal & fZap) != fVal)
2074 {
2075 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
2076 g_HmMsrs.u.vmx.ProcCtls2.n.allowed0, fVal, fZap));
2077 pVCpu->nem.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
2078 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2079 }
2080
2081 /* Commit it to the VMCS and update our cache. */
2082 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
2083 AssertRC(rc);
2084 pVmcsInfo->u32ProcCtls2 = fVal;
2085
2086 return VINF_SUCCESS;
2087}
2088
2089
2090/**
2091 * Enables native access for the given MSR.
2092 *
2093 * @returns VBox status code.
2094 * @param pVCpu The cross context virtual CPU structure.
2095 * @param idMsr The MSR to enable native access for.
2096 */
2097static int nemR3DarwinMsrSetNative(PVMCPUCC pVCpu, uint32_t idMsr)
2098{
2099 hv_return_t hrc = hv_vcpu_enable_native_msr(pVCpu->nem.s.hVCpuId, idMsr, true /*enable*/);
2100 if (hrc == HV_SUCCESS)
2101 return VINF_SUCCESS;
2102
2103 return nemR3DarwinHvSts2Rc(hrc);
2104}
2105
2106
2107/**
2108 * Sets up the MSR permissions which don't change through the lifetime of the VM.
2109 *
2110 * @returns VBox status code.
2111 * @param pVCpu The cross context virtual CPU structure.
2112 * @param pVmcsInfo The VMCS info. object.
2113 */
2114static int nemR3DarwinSetupVmcsMsrPermissions(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2115{
2116 RT_NOREF(pVmcsInfo);
2117
2118 /*
2119 * The guest can access the following MSRs (read, write) without causing
2120 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
2121 */
2122 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2123 int rc;
2124 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_SYSENTER_CS); AssertRCReturn(rc, rc);
2125 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_SYSENTER_ESP); AssertRCReturn(rc, rc);
2126 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_SYSENTER_EIP); AssertRCReturn(rc, rc);
2127 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_GS_BASE); AssertRCReturn(rc, rc);
2128 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_FS_BASE); AssertRCReturn(rc, rc);
2129
2130 /*
2131 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
2132 * associated with then. We never need to intercept access (writes need to be
2133 * executed without causing a VM-exit, reads will #GP fault anyway).
2134 *
2135 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
2136 * read/write them. We swap the guest/host MSR value using the
2137 * auto-load/store MSR area.
2138 */
2139 if (pVM->cpum.ro.GuestFeatures.fIbpb)
2140 {
2141 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_PRED_CMD);
2142 AssertRCReturn(rc, rc);
2143 }
2144#if 0 /* Doesn't work. */
2145 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
2146 {
2147 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_FLUSH_CMD);
2148 AssertRCReturn(rc, rc);
2149 }
2150#endif
2151 if (pVM->cpum.ro.GuestFeatures.fIbrs)
2152 {
2153 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_IA32_SPEC_CTRL);
2154 AssertRCReturn(rc, rc);
2155 }
2156
2157 /*
2158 * Allow full read/write access for the following MSRs (mandatory for VT-x)
2159 * required for 64-bit guests.
2160 */
2161 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_LSTAR); AssertRCReturn(rc, rc);
2162 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K6_STAR); AssertRCReturn(rc, rc);
2163 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_SF_MASK); AssertRCReturn(rc, rc);
2164 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_KERNEL_GS_BASE); AssertRCReturn(rc, rc);
2165
2166 /* Required for enabling the RDTSCP instruction. */
2167 rc = nemR3DarwinMsrSetNative(pVCpu, MSR_K8_TSC_AUX); AssertRCReturn(rc, rc);
2168
2169 return VINF_SUCCESS;
2170}
2171
2172
2173/**
2174 * Sets up processor-based VM-execution controls in the VMCS.
2175 *
2176 * @returns VBox status code.
2177 * @param pVCpu The cross context virtual CPU structure.
2178 * @param pVmcsInfo The VMCS info. object.
2179 */
2180static int nemR3DarwinVmxSetupVmcsProcCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2181{
2182 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
2183 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2184
2185 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
2186// | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
2187 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
2188 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
2189 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
2190 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
2191 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
2192
2193#ifdef HMVMX_ALWAYS_INTERCEPT_CR3_ACCESS
2194 fVal |= VMX_PROC_CTLS_CR3_LOAD_EXIT
2195 | VMX_PROC_CTLS_CR3_STORE_EXIT;
2196#endif
2197
2198 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
2199 if ( !(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
2200 || (g_HmMsrs.u.vmx.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
2201 {
2202 pVCpu->nem.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
2203 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2204 }
2205
2206 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
2207 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2208 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
2209
2210 if ((fVal & fZap) != fVal)
2211 {
2212 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
2213 g_HmMsrs.u.vmx.ProcCtls.n.allowed0, fVal, fZap));
2214 pVCpu->nem.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
2215 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2216 }
2217
2218 /* Commit it to the VMCS and update our cache. */
2219 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, fVal);
2220 AssertRC(rc);
2221 pVmcsInfo->u32ProcCtls = fVal;
2222
2223 /* Set up MSR permissions that don't change through the lifetime of the VM. */
2224 rc = nemR3DarwinSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
2225 AssertRCReturn(rc, rc);
2226
2227 /*
2228 * Set up secondary processor-based VM-execution controls
2229 * (we assume the CPU to always support it as we rely on unrestricted guest execution support).
2230 */
2231 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
2232 return nemR3DarwinVmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
2233}
2234
2235
2236/**
2237 * Sets up miscellaneous (everything other than Pin, Processor and secondary
2238 * Processor-based VM-execution) control fields in the VMCS.
2239 *
2240 * @returns VBox status code.
2241 * @param pVCpu The cross context virtual CPU structure.
2242 * @param pVmcsInfo The VMCS info. object.
2243 */
2244static int nemR3DarwinVmxSetupVmcsMiscCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2245{
2246 int rc = VINF_SUCCESS;
2247 //rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo); TODO
2248 if (RT_SUCCESS(rc))
2249 {
2250 uint64_t const u64Cr0Mask = vmxHCGetFixedCr0Mask(pVCpu);
2251 uint64_t const u64Cr4Mask = vmxHCGetFixedCr4Mask(pVCpu);
2252
2253 rc = nemR3DarwinWriteVmcs64(pVCpu, VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
2254 rc = nemR3DarwinWriteVmcs64(pVCpu, VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
2255
2256 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
2257 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
2258
2259#if 0 /** @todo */
2260 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fLbr)
2261 {
2262 rc = VMXWriteVmcsNw(VMX_VMCS64_GUEST_DEBUGCTL_FULL, MSR_IA32_DEBUGCTL_LBR);
2263 AssertRC(rc);
2264 }
2265#endif
2266 return VINF_SUCCESS;
2267 }
2268 else
2269 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
2270 return rc;
2271}
2272
2273
2274/**
2275 * Sets up the initial exception bitmap in the VMCS based on static conditions.
2276 *
2277 * We shall setup those exception intercepts that don't change during the
2278 * lifetime of the VM here. The rest are done dynamically while loading the
2279 * guest state.
2280 *
2281 * @param pVCpu The cross context virtual CPU structure.
2282 * @param pVmcsInfo The VMCS info. object.
2283 */
2284static void nemR3DarwinVmxSetupVmcsXcptBitmap(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
2285{
2286 /*
2287 * The following exceptions are always intercepted:
2288 *
2289 * #AC - To prevent the guest from hanging the CPU and for dealing with
2290 * split-lock detecting host configs.
2291 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
2292 * recursive #DBs can cause a CPU hang.
2293 */
2294 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
2295 | RT_BIT(X86_XCPT_DB);
2296
2297 /* Commit it to the VMCS. */
2298 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
2299 AssertRC(rc);
2300
2301 /* Update our cache of the exception bitmap. */
2302 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
2303}
2304
2305
2306/**
2307 * Initialize the VMCS information field for the given vCPU.
2308 *
2309 * @returns VBox status code.
2310 * @param pVCpu The cross context virtual CPU structure of the
2311 * calling EMT.
2312 */
2313static int nemR3DarwinInitVmcs(PVMCPU pVCpu)
2314{
2315 int rc = nemR3DarwinVmxSetupVmcsPinCtls(pVCpu, &pVCpu->nem.s.VmcsInfo);
2316 if (RT_SUCCESS(rc))
2317 {
2318 rc = nemR3DarwinVmxSetupVmcsProcCtls(pVCpu, &pVCpu->nem.s.VmcsInfo);
2319 if (RT_SUCCESS(rc))
2320 {
2321 rc = nemR3DarwinVmxSetupVmcsMiscCtls(pVCpu, &pVCpu->nem.s.VmcsInfo);
2322 if (RT_SUCCESS(rc))
2323 {
2324 rc = nemR3DarwinReadVmcs32(pVCpu, VMX_VMCS32_CTRL_ENTRY, &pVCpu->nem.s.VmcsInfo.u32EntryCtls);
2325 if (RT_SUCCESS(rc))
2326 {
2327 rc = nemR3DarwinReadVmcs32(pVCpu, VMX_VMCS32_CTRL_EXIT, &pVCpu->nem.s.VmcsInfo.u32ExitCtls);
2328 if (RT_SUCCESS(rc))
2329 {
2330 nemR3DarwinVmxSetupVmcsXcptBitmap(pVCpu, &pVCpu->nem.s.VmcsInfo);
2331 return VINF_SUCCESS;
2332 }
2333 else
2334 LogRelFunc(("Failed to read the exit controls. rc=%Rrc\n", rc));
2335 }
2336 else
2337 LogRelFunc(("Failed to read the entry controls. rc=%Rrc\n", rc));
2338 }
2339 else
2340 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
2341 }
2342 else
2343 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
2344 }
2345 else
2346 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
2347
2348 return rc;
2349}
2350
2351
2352/**
2353 * Registers statistics for the given vCPU.
2354 *
2355 * @returns VBox status code.
2356 * @param pVM The cross context VM structure.
2357 * @param idCpu The CPU ID.
2358 * @param pNemCpu The NEM CPU structure.
2359 */
2360static int nemR3DarwinStatisticsRegister(PVM pVM, VMCPUID idCpu, PNEMCPU pNemCpu)
2361{
2362#define NEM_REG_STAT(a_pVar, a_enmType, s_enmVisibility, a_enmUnit, a_szNmFmt, a_szDesc) do { \
2363 int rc = STAMR3RegisterF(pVM, a_pVar, a_enmType, s_enmVisibility, a_enmUnit, a_szDesc, a_szNmFmt, idCpu); \
2364 AssertRC(rc); \
2365 } while (0)
2366#define NEM_REG_PROFILE(a_pVar, a_szNmFmt, a_szDesc) \
2367 NEM_REG_STAT(a_pVar, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, a_szNmFmt, a_szDesc)
2368#define NEM_REG_COUNTER(a, b, desc) NEM_REG_STAT(a, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, b, desc)
2369
2370 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR0Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR0", "CR0 read.");
2371 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR2Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR2", "CR2 read.");
2372 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR3Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR3", "CR3 read.");
2373 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR4Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR4", "CR4 read.");
2374 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR8Read, "/NEM/CPU%u/Exit/Instr/CR-Read/CR8", "CR8 read.");
2375 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR0Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR0", "CR0 write.");
2376 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR2Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR2", "CR2 write.");
2377 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR3Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR3", "CR3 write.");
2378 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR4Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR4", "CR4 write.");
2379 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR8Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR8", "CR8 write.");
2380
2381 NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitAll, "/NEM/CPU%u/Exit/All", "Total exits (including nested-guest exits).");
2382
2383#ifdef VBOX_WITH_STATISTICS
2384 NEM_REG_PROFILE(&pNemCpu->StatProfGstStateImport, "/NEM/CPU%u/ImportGuestState", "Profiling of importing guest state from hardware after VM-exit.");
2385 NEM_REG_PROFILE(&pNemCpu->StatProfGstStateExport, "/NEM/CPU%u/ExportGuestState", "Profiling of exporting guest state from hardware after VM-exit.");
2386
2387 for (int j = 0; j < MAX_EXITREASON_STAT; j++)
2388 {
2389 const char *pszExitName = HMGetVmxExitName(j);
2390 if (pszExitName)
2391 {
2392 int rc = STAMR3RegisterF(pVM, &pNemCpu->pVmxStats->aStatExitReason[j], STAMTYPE_COUNTER, STAMVISIBILITY_USED,
2393 STAMUNIT_OCCURENCES, pszExitName, "/NEM/CPU%u/Exit/Reason/%02x", idCpu, j);
2394 AssertRCReturn(rc, rc);
2395 }
2396 }
2397#endif
2398
2399 return VINF_SUCCESS;
2400
2401#undef NEM_REG_COUNTER
2402#undef NEM_REG_PROFILE
2403#undef NEM_REG_STAT
2404}
2405
2406
2407/**
2408 * Try initialize the native API.
2409 *
2410 * This may only do part of the job, more can be done in
2411 * nemR3NativeInitAfterCPUM() and nemR3NativeInitCompleted().
2412 *
2413 * @returns VBox status code.
2414 * @param pVM The cross context VM structure.
2415 * @param fFallback Whether we're in fallback mode or use-NEM mode. In
2416 * the latter we'll fail if we cannot initialize.
2417 * @param fForced Whether the HMForced flag is set and we should
2418 * fail if we cannot initialize.
2419 */
2420int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced)
2421{
2422 AssertReturn(!pVM->nem.s.fCreatedVm, VERR_WRONG_ORDER);
2423
2424 /*
2425 * Some state init.
2426 */
2427
2428 /*
2429 * Error state.
2430 * The error message will be non-empty on failure and 'rc' will be set too.
2431 */
2432 RTERRINFOSTATIC ErrInfo;
2433 PRTERRINFO pErrInfo = RTErrInfoInitStatic(&ErrInfo);
2434 int rc = nemR3DarwinLoadHv(fForced, pErrInfo);
2435 if (RT_SUCCESS(rc))
2436 {
2437 hv_return_t hrc = hv_vm_create(HV_VM_DEFAULT);
2438 if (hrc == HV_SUCCESS)
2439 {
2440 if (hv_vm_space_create)
2441 {
2442 hrc = hv_vm_space_create(&pVM->nem.s.uVmAsid);
2443 if (hrc == HV_SUCCESS)
2444 {
2445 LogRel(("NEM: Successfully created ASID: %u\n", pVM->nem.s.uVmAsid));
2446 pVM->nem.s.fCreatedAsid = true;
2447 }
2448 else
2449 LogRel(("NEM: Failed to create ASID for VM (hrc=%#x), continuing...\n", pVM->nem.s.uVmAsid));
2450 }
2451 pVM->nem.s.fCreatedVm = true;
2452
2453 /* Register release statistics */
2454 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2455 {
2456 PNEMCPU pNemCpu = &pVM->apCpusR3[idCpu]->nem.s;
2457 PVMXSTATISTICS pVmxStats = (PVMXSTATISTICS)RTMemAllocZ(sizeof(*pVmxStats));
2458 if (RT_LIKELY(pVmxStats))
2459 {
2460 pNemCpu->pVmxStats = pVmxStats;
2461 rc = nemR3DarwinStatisticsRegister(pVM, idCpu, pNemCpu);
2462 AssertRC(rc);
2463 }
2464 else
2465 {
2466 rc = VERR_NO_MEMORY;
2467 break;
2468 }
2469 }
2470
2471 if (RT_SUCCESS(rc))
2472 {
2473 VM_SET_MAIN_EXECUTION_ENGINE(pVM, VM_EXEC_ENGINE_NATIVE_API);
2474 Log(("NEM: Marked active!\n"));
2475 PGMR3EnableNemMode(pVM);
2476 }
2477 }
2478 else
2479 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
2480 "hv_vm_create() failed: %#x", hrc);
2481 }
2482
2483 /*
2484 * We only fail if in forced mode, otherwise just log the complaint and return.
2485 */
2486 Assert(pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API || RTErrInfoIsSet(pErrInfo));
2487 if ( (fForced || !fFallback)
2488 && pVM->bMainExecutionEngine != VM_EXEC_ENGINE_NATIVE_API)
2489 return VMSetError(pVM, RT_SUCCESS_NP(rc) ? VERR_NEM_NOT_AVAILABLE : rc, RT_SRC_POS, "%s", pErrInfo->pszMsg);
2490
2491 if (RTErrInfoIsSet(pErrInfo))
2492 LogRel(("NEM: Not available: %s\n", pErrInfo->pszMsg));
2493 return VINF_SUCCESS;
2494}
2495
2496
2497/**
2498 * Worker to create the vCPU handle on the EMT running it later on (as required by HV).
2499 *
2500 * @returns VBox status code
2501 * @param pVM The VM handle.
2502 * @param pVCpu The vCPU handle.
2503 * @param idCpu ID of the CPU to create.
2504 */
2505static DECLCALLBACK(int) nemR3DarwinNativeInitVCpuOnEmt(PVM pVM, PVMCPU pVCpu, VMCPUID idCpu)
2506{
2507 hv_return_t hrc = hv_vcpu_create(&pVCpu->nem.s.hVCpuId, HV_VCPU_DEFAULT);
2508 if (hrc != HV_SUCCESS)
2509 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
2510 "Call to hv_vcpu_create failed on vCPU %u: %#x (%Rrc)", idCpu, hrc, nemR3DarwinHvSts2Rc(hrc));
2511
2512 if (idCpu == 0)
2513 {
2514 /* First call initializs the MSR structure holding the capabilities of the host CPU. */
2515 int rc = nemR3DarwinCapsInit();
2516 AssertRCReturn(rc, rc);
2517
2518 if (hv_vmx_vcpu_get_cap_write_vmcs)
2519 {
2520 /* Log the VMCS field write capabilities. */
2521 for (uint32_t i = 0; i < RT_ELEMENTS(g_aVmcsFieldsCap); i++)
2522 {
2523 uint64_t u64Allowed0 = 0;
2524 uint64_t u64Allowed1 = 0;
2525
2526 hrc = hv_vmx_vcpu_get_cap_write_vmcs(pVCpu->nem.s.hVCpuId, g_aVmcsFieldsCap[i].u32VmcsFieldId,
2527 &u64Allowed0, &u64Allowed1);
2528 if (hrc == HV_SUCCESS)
2529 {
2530 if (g_aVmcsFieldsCap[i].f64Bit)
2531 LogRel(("NEM: %s = (allowed_0=%#016RX64 allowed_1=%#016RX64)\n",
2532 g_aVmcsFieldsCap[i].pszVmcsField, u64Allowed0, u64Allowed1));
2533 else
2534 LogRel(("NEM: %s = (allowed_0=%#08RX32 allowed_1=%#08RX32)\n",
2535 g_aVmcsFieldsCap[i].pszVmcsField, (uint32_t)u64Allowed0, (uint32_t)u64Allowed1));
2536
2537 uint32_t cBits = g_aVmcsFieldsCap[i].f64Bit ? 64 : 32;
2538 for (uint32_t iBit = 0; iBit < cBits; iBit++)
2539 {
2540 bool fAllowed0 = RT_BOOL(u64Allowed0 & RT_BIT_64(iBit));
2541 bool fAllowed1 = RT_BOOL(u64Allowed1 & RT_BIT_64(iBit));
2542
2543 if (!fAllowed0 && !fAllowed1)
2544 LogRel(("NEM: Bit %02u = Must NOT be set\n", iBit));
2545 else if (!fAllowed0 && fAllowed1)
2546 LogRel(("NEM: Bit %02u = Can be set or not be set\n", iBit));
2547 else if (fAllowed0 && !fAllowed1)
2548 LogRel(("NEM: Bit %02u = UNDEFINED (AppleHV error)!\n", iBit));
2549 else if (fAllowed0 && fAllowed1)
2550 LogRel(("NEM: Bit %02u = MUST be set\n", iBit));
2551 else
2552 AssertFailed();
2553 }
2554 }
2555 else
2556 LogRel(("NEM: %s = failed to query (hrc=%d)\n", g_aVmcsFieldsCap[i].pszVmcsField, hrc));
2557 }
2558 }
2559 }
2560
2561 int rc = nemR3DarwinInitVmcs(pVCpu);
2562 AssertRCReturn(rc, rc);
2563
2564 if (pVM->nem.s.fCreatedAsid)
2565 {
2566 hrc = hv_vcpu_set_space(pVCpu->nem.s.hVCpuId, pVM->nem.s.uVmAsid);
2567 AssertReturn(hrc == HV_SUCCESS, VERR_NEM_VM_CREATE_FAILED);
2568 }
2569
2570 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
2571
2572 return VINF_SUCCESS;
2573}
2574
2575
2576/**
2577 * Worker to destroy the vCPU handle on the EMT running it later on (as required by HV).
2578 *
2579 * @returns VBox status code
2580 * @param pVCpu The vCPU handle.
2581 */
2582static DECLCALLBACK(int) nemR3DarwinNativeTermVCpuOnEmt(PVMCPU pVCpu)
2583{
2584 hv_return_t hrc = hv_vcpu_set_space(pVCpu->nem.s.hVCpuId, 0 /*asid*/);
2585 Assert(hrc == HV_SUCCESS);
2586
2587 hrc = hv_vcpu_destroy(pVCpu->nem.s.hVCpuId);
2588 Assert(hrc == HV_SUCCESS); RT_NOREF(hrc);
2589 return VINF_SUCCESS;
2590}
2591
2592
2593/**
2594 * Worker to setup the TPR shadowing feature if available on the CPU and the VM has an APIC enabled.
2595 *
2596 * @returns VBox status code
2597 * @param pVM The VM handle.
2598 * @param pVCpu The vCPU handle.
2599 */
2600static DECLCALLBACK(int) nemR3DarwinNativeInitTprShadowing(PVM pVM, PVMCPU pVCpu)
2601{
2602 PVMXVMCSINFO pVmcsInfo = &pVCpu->nem.s.VmcsInfo;
2603 uint32_t fVal = pVmcsInfo->u32ProcCtls;
2604
2605 /* Use TPR shadowing if supported by the CPU. */
2606 if ( PDMHasApic(pVM)
2607 && (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
2608 {
2609 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
2610 /* CR8 writes cause a VM-exit based on TPR threshold. */
2611 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
2612 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
2613 }
2614 else
2615 {
2616 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
2617 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
2618 }
2619
2620 /* Commit it to the VMCS and update our cache. */
2621 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, fVal);
2622 AssertRC(rc);
2623 pVmcsInfo->u32ProcCtls = fVal;
2624
2625 return VINF_SUCCESS;
2626}
2627
2628
2629/**
2630 * This is called after CPUMR3Init is done.
2631 *
2632 * @returns VBox status code.
2633 * @param pVM The VM handle..
2634 */
2635int nemR3NativeInitAfterCPUM(PVM pVM)
2636{
2637 /*
2638 * Validate sanity.
2639 */
2640 AssertReturn(!pVM->nem.s.fCreatedEmts, VERR_WRONG_ORDER);
2641 AssertReturn(pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API, VERR_WRONG_ORDER);
2642
2643 /*
2644 * Setup the EMTs.
2645 */
2646 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2647 {
2648 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
2649
2650 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)nemR3DarwinNativeInitVCpuOnEmt, 3, pVM, pVCpu, idCpu);
2651 if (RT_FAILURE(rc))
2652 {
2653 /* Rollback. */
2654 while (idCpu--)
2655 VMR3ReqCallWait(pVM, idCpu, (PFNRT)nemR3DarwinNativeTermVCpuOnEmt, 1, pVCpu);
2656
2657 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "Call to hv_vcpu_create failed: %Rrc", rc);
2658 }
2659 }
2660
2661 pVM->nem.s.fCreatedEmts = true;
2662 return VINF_SUCCESS;
2663}
2664
2665
2666int nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
2667{
2668 if (enmWhat == VMINITCOMPLETED_RING3)
2669 {
2670 /* Now that PDM is initialized the APIC state is known in order to enable the TPR shadowing feature on all EMTs. */
2671 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2672 {
2673 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
2674
2675 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)nemR3DarwinNativeInitTprShadowing, 2, pVM, pVCpu);
2676 if (RT_FAILURE(rc))
2677 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "Setting up TPR shadowing failed: %Rrc", rc);
2678 }
2679 }
2680 return VINF_SUCCESS;
2681}
2682
2683
2684int nemR3NativeTerm(PVM pVM)
2685{
2686 /*
2687 * Delete the VM.
2688 */
2689
2690 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu--)
2691 {
2692 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
2693
2694 /*
2695 * Need to do this or hv_vm_space_destroy() fails later on (on 10.15 at least). Could've been documented in
2696 * API reference so I wouldn't have to decompile the kext to find this out but we are talking
2697 * about Apple here unfortunately, API documentation is not their strong suit...
2698 * Would have been of course even better to just automatically drop the address space reference when the vCPU
2699 * gets destroyed.
2700 */
2701 hv_return_t hrc = hv_vcpu_set_space(pVCpu->nem.s.hVCpuId, 0 /*asid*/);
2702 Assert(hrc == HV_SUCCESS);
2703
2704 /*
2705 * Apple's documentation states that the vCPU should be destroyed
2706 * on the thread running the vCPU but as all the other EMTs are gone
2707 * at this point, destroying the VM would hang.
2708 *
2709 * We seem to be at luck here though as destroying apparently works
2710 * from EMT(0) as well.
2711 */
2712 hrc = hv_vcpu_destroy(pVCpu->nem.s.hVCpuId);
2713 Assert(hrc == HV_SUCCESS); RT_NOREF(hrc);
2714
2715 if (pVCpu->nem.s.pVmxStats)
2716 {
2717 RTMemFree(pVCpu->nem.s.pVmxStats);
2718 pVCpu->nem.s.pVmxStats = NULL;
2719 }
2720 }
2721
2722 pVM->nem.s.fCreatedEmts = false;
2723
2724 if (pVM->nem.s.fCreatedAsid)
2725 {
2726 hv_return_t hrc = hv_vm_space_destroy(pVM->nem.s.uVmAsid);
2727 Assert(hrc == HV_SUCCESS); RT_NOREF(hrc);
2728 pVM->nem.s.fCreatedAsid = false;
2729 }
2730
2731 if (pVM->nem.s.fCreatedVm)
2732 {
2733 hv_return_t hrc = hv_vm_destroy();
2734 if (hrc != HV_SUCCESS)
2735 LogRel(("NEM: hv_vm_destroy() failed with %#x\n", hrc));
2736
2737 pVM->nem.s.fCreatedVm = false;
2738 }
2739 return VINF_SUCCESS;
2740}
2741
2742
2743/**
2744 * VM reset notification.
2745 *
2746 * @param pVM The cross context VM structure.
2747 */
2748void nemR3NativeReset(PVM pVM)
2749{
2750 RT_NOREF(pVM);
2751}
2752
2753
2754/**
2755 * Reset CPU due to INIT IPI or hot (un)plugging.
2756 *
2757 * @param pVCpu The cross context virtual CPU structure of the CPU being
2758 * reset.
2759 * @param fInitIpi Whether this is the INIT IPI or hot (un)plugging case.
2760 */
2761void nemR3NativeResetCpu(PVMCPU pVCpu, bool fInitIpi)
2762{
2763 RT_NOREF(fInitIpi);
2764 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
2765}
2766
2767
2768VBOXSTRICTRC nemR3NativeRunGC(PVM pVM, PVMCPU pVCpu)
2769{
2770 LogFlow(("NEM/%u: %04x:%08RX64 efl=%#08RX64 <=\n", pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags));
2771#ifdef LOG_ENABLED
2772 if (LogIs3Enabled())
2773 nemR3DarwinLogState(pVM, pVCpu);
2774#endif
2775
2776 AssertReturn(NEMR3CanExecuteGuest(pVM, pVCpu), VERR_NEM_IPE_9);
2777
2778 /*
2779 * Try switch to NEM runloop state.
2780 */
2781 if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED))
2782 { /* likely */ }
2783 else
2784 {
2785 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED);
2786 LogFlow(("NEM/%u: returning immediately because canceled\n", pVCpu->idCpu));
2787 return VINF_SUCCESS;
2788 }
2789
2790 /*
2791 * The run loop.
2792 *
2793 * Current approach to state updating to use the sledgehammer and sync
2794 * everything every time. This will be optimized later.
2795 */
2796
2797 VMXTRANSIENT VmxTransient;
2798 RT_ZERO(VmxTransient);
2799 VmxTransient.pVmcsInfo = &pVCpu->nem.s.VmcsInfo;
2800
2801 /*
2802 * Poll timers and run for a bit.
2803 */
2804 /** @todo See if we cannot optimize this TMTimerPollGIP by only redoing
2805 * the whole polling job when timers have changed... */
2806 uint64_t offDeltaIgnored;
2807 uint64_t const nsNextTimerEvt = TMTimerPollGIP(pVM, pVCpu, &offDeltaIgnored); NOREF(nsNextTimerEvt);
2808
2809 const bool fSingleStepping = DBGFIsStepping(pVCpu);
2810 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2811 for (unsigned iLoop = 0;; iLoop++)
2812 {
2813 /*
2814 * Check and process force flag actions, some of which might require us to go back to ring-3.
2815 */
2816 rcStrict = vmxHCCheckForceFlags(pVCpu, false /*fIsNestedGuest*/, fSingleStepping);
2817 if (rcStrict == VINF_SUCCESS)
2818 { /*likely */ }
2819 else
2820 {
2821 if (rcStrict == VINF_EM_RAW_TO_R3)
2822 rcStrict = VINF_SUCCESS;
2823 break;
2824 }
2825
2826 /*
2827 * Do not execute in HV if the A20 isn't enabled.
2828 */
2829 if (PGMPhysIsA20Enabled(pVCpu))
2830 { /* likely */ }
2831 else
2832 {
2833 rcStrict = VINF_EM_RESCHEDULE_REM;
2834 LogFlow(("NEM/%u: breaking: A20 disabled\n", pVCpu->idCpu));
2835 break;
2836 }
2837
2838 /*
2839 * Evaluate events to be injected into the guest.
2840 *
2841 * Events in TRPM can be injected without inspecting the guest state.
2842 * If any new events (interrupts/NMI) are pending currently, we try to set up the
2843 * guest to cause a VM-exit the next time they are ready to receive the event.
2844 */
2845 if (TRPMHasTrap(pVCpu))
2846 vmxHCTrpmTrapToPendingEvent(pVCpu);
2847
2848 uint32_t fIntrState;
2849 rcStrict = vmxHCEvaluatePendingEvent(pVCpu, &pVCpu->nem.s.VmcsInfo, false /*fIsNestedGuest*/, &fIntrState);
2850
2851 /*
2852 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
2853 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
2854 * also result in triple-faulting the VM.
2855 *
2856 * With nested-guests, the above does not apply since unrestricted guest execution is a
2857 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
2858 */
2859 rcStrict = vmxHCInjectPendingEvent(pVCpu, &pVCpu->nem.s.VmcsInfo, false /*fIsNestedGuest*/, fIntrState, fSingleStepping);
2860 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
2861 { /* likely */ }
2862 else
2863 {
2864 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fSingleStepping),
2865 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
2866 break;
2867 }
2868
2869 int rc = nemR3DarwinExportGuestState(pVM, pVCpu, &VmxTransient);
2870 AssertRCReturn(rc, rc);
2871
2872 LogFlowFunc(("Running vCPU\n"));
2873 pVCpu->nem.s.Event.fPending = false;
2874
2875 TMNotifyStartOfExecution(pVM, pVCpu);
2876
2877 Assert(!pVCpu->nem.s.fCtxChanged);
2878 hv_return_t hrc;
2879 if (hv_vcpu_run_until)
2880 hrc = hv_vcpu_run_until(pVCpu->nem.s.hVCpuId, HV_DEADLINE_FOREVER);
2881 else
2882 hrc = hv_vcpu_run(pVCpu->nem.s.hVCpuId);
2883
2884 TMNotifyEndOfExecution(pVM, pVCpu, ASMReadTSC());
2885
2886 /*
2887 * Sync the TPR shadow with our APIC state.
2888 */
2889 if ( !VmxTransient.fIsNestedGuest
2890 && (pVCpu->nem.s.VmcsInfo.u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
2891 {
2892 uint64_t u64Tpr;
2893 hrc = hv_vcpu_read_register(pVCpu->nem.s.hVCpuId, HV_X86_TPR, &u64Tpr);
2894 Assert(hrc == HV_SUCCESS);
2895
2896 if (VmxTransient.u8GuestTpr != (uint8_t)u64Tpr)
2897 {
2898 rc = APICSetTpr(pVCpu, (uint8_t)u64Tpr);
2899 AssertRC(rc);
2900 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
2901 }
2902 }
2903
2904 if (hrc == HV_SUCCESS)
2905 {
2906 /*
2907 * Deal with the message.
2908 */
2909 rcStrict = nemR3DarwinHandleExit(pVM, pVCpu, &VmxTransient);
2910 if (rcStrict == VINF_SUCCESS)
2911 { /* hopefully likely */ }
2912 else
2913 {
2914 LogFlow(("NEM/%u: breaking: nemR3DarwinHandleExit -> %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict) ));
2915 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnStatus);
2916 break;
2917 }
2918 //Assert(!pVCpu->cpum.GstCtx.fExtrn);
2919 }
2920 else
2921 {
2922 AssertLogRelMsgFailedReturn(("hv_vcpu_run()) failed for CPU #%u: %#x %u\n",
2923 pVCpu->idCpu, hrc, vmxHCCheckGuestState(pVCpu, &pVCpu->nem.s.VmcsInfo)),
2924 VERR_NEM_IPE_0);
2925 }
2926 } /* the run loop */
2927
2928
2929 /*
2930 * Convert any pending HM events back to TRPM due to premature exits.
2931 *
2932 * This is because execution may continue from IEM and we would need to inject
2933 * the event from there (hence place it back in TRPM).
2934 */
2935 if (pVCpu->nem.s.Event.fPending)
2936 {
2937 vmxHCPendingEventToTrpmTrap(pVCpu);
2938 Assert(!pVCpu->nem.s.Event.fPending);
2939
2940 /* Clear the events from the VMCS. */
2941 int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
2942 rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, 0); AssertRC(rc);
2943 }
2944
2945
2946 if (!VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM))
2947 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED);
2948
2949 if (pVCpu->cpum.GstCtx.fExtrn & (CPUMCTX_EXTRN_ALL))
2950 {
2951 /* Try anticipate what we might need. */
2952 uint64_t fImport = NEM_DARWIN_CPUMCTX_EXTRN_MASK_FOR_IEM;
2953 if ( (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST)
2954 || RT_FAILURE(rcStrict))
2955 fImport = CPUMCTX_EXTRN_ALL;
2956 else if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC | VMCPU_FF_INTERRUPT_APIC
2957 | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI))
2958 fImport |= IEM_CPUMCTX_EXTRN_XCPT_MASK;
2959
2960 if (pVCpu->cpum.GstCtx.fExtrn & fImport)
2961 {
2962 /* Only import what is external currently. */
2963 int rc2 = nemR3DarwinCopyStateFromHv(pVM, pVCpu, fImport);
2964 if (RT_SUCCESS(rc2))
2965 pVCpu->cpum.GstCtx.fExtrn &= ~fImport;
2966 else if (RT_SUCCESS(rcStrict))
2967 rcStrict = rc2;
2968 if (!(pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_ALL))
2969 {
2970 pVCpu->cpum.GstCtx.fExtrn = 0;
2971 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
2972 }
2973 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatImportOnReturn);
2974 }
2975 else
2976 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatImportOnReturnSkipped);
2977 }
2978 else
2979 {
2980 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatImportOnReturnSkipped);
2981 pVCpu->cpum.GstCtx.fExtrn = 0;
2982 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
2983 }
2984
2985 LogFlow(("NEM/%u: %04x:%08RX64 efl=%#08RX64 => %Rrc\n",
2986 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags, VBOXSTRICTRC_VAL(rcStrict) ));
2987 return rcStrict;
2988}
2989
2990
2991VMMR3_INT_DECL(bool) NEMR3CanExecuteGuest(PVM pVM, PVMCPU pVCpu)
2992{
2993 NOREF(pVM);
2994 return PGMPhysIsA20Enabled(pVCpu);
2995}
2996
2997
2998bool nemR3NativeSetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable)
2999{
3000 NOREF(pVM); NOREF(pVCpu); NOREF(fEnable);
3001 return false;
3002}
3003
3004
3005/**
3006 * Forced flag notification call from VMEmt.h.
3007 *
3008 * This is only called when pVCpu is in the VMCPUSTATE_STARTED_EXEC_NEM state.
3009 *
3010 * @param pVM The cross context VM structure.
3011 * @param pVCpu The cross context virtual CPU structure of the CPU
3012 * to be notified.
3013 * @param fFlags Notification flags, VMNOTIFYFF_FLAGS_XXX.
3014 */
3015void nemR3NativeNotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags)
3016{
3017 LogFlowFunc(("pVM=%p pVCpu=%p fFlags=%#x\n", pVM, pVCpu, fFlags));
3018
3019 RT_NOREF(pVM, fFlags);
3020
3021 hv_return_t hrc = hv_vcpu_interrupt(&pVCpu->nem.s.hVCpuId, 1);
3022 if (hrc != HV_SUCCESS)
3023 LogRel(("NEM: hv_vcpu_interrupt(%u, 1) failed with %#x\n", pVCpu->nem.s.hVCpuId, hrc));
3024}
3025
3026
3027VMMR3_INT_DECL(int) NEMR3NotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvR3,
3028 uint8_t *pu2State, uint32_t *puNemRange)
3029{
3030 RT_NOREF(pVM, puNemRange);
3031
3032 Log5(("NEMR3NotifyPhysRamRegister: %RGp LB %RGp, pvR3=%p\n", GCPhys, cb, pvR3));
3033#if defined(VBOX_WITH_PGM_NEM_MODE)
3034 if (pvR3)
3035 {
3036 int rc = nemR3DarwinMap(pVM, GCPhys, pvR3, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
3037 if (RT_SUCCESS(rc))
3038 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
3039 else
3040 {
3041 LogRel(("NEMR3NotifyPhysRamRegister: GCPhys=%RGp LB %RGp pvR3=%p rc=%Rrc\n", GCPhys, cb, pvR3, rc));
3042 return VERR_NEM_MAP_PAGES_FAILED;
3043 }
3044 }
3045 return VINF_SUCCESS;
3046#else
3047 RT_NOREF(pVM, GCPhys, cb, pvR3);
3048 return VERR_NEM_MAP_PAGES_FAILED;
3049#endif
3050}
3051
3052
3053VMMR3_INT_DECL(bool) NEMR3IsMmio2DirtyPageTrackingSupported(PVM pVM)
3054{
3055 RT_NOREF(pVM);
3056 return false;
3057}
3058
3059
3060VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags,
3061 void *pvRam, void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange)
3062{
3063 RT_NOREF(pVM, puNemRange, pvRam, fFlags);
3064
3065 Log5(("NEMR3NotifyPhysMmioExMapEarly: %RGp LB %RGp fFlags=%#x pvRam=%p pvMmio2=%p pu2State=%p (%d)\n",
3066 GCPhys, cb, fFlags, pvRam, pvMmio2, pu2State, *pu2State));
3067
3068#if defined(VBOX_WITH_PGM_NEM_MODE)
3069 /*
3070 * Unmap the RAM we're replacing.
3071 */
3072 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE)
3073 {
3074 int rc = nemR3DarwinUnmap(pVM, GCPhys, cb);
3075 if (RT_SUCCESS(rc))
3076 { /* likely */ }
3077 else if (pvMmio2)
3078 LogRel(("NEMR3NotifyPhysMmioExMapEarly: GCPhys=%RGp LB %RGp fFlags=%#x: Unmap -> rc=%Rc(ignored)\n",
3079 GCPhys, cb, fFlags, rc));
3080 else
3081 {
3082 LogRel(("NEMR3NotifyPhysMmioExMapEarly: GCPhys=%RGp LB %RGp fFlags=%#x: Unmap -> rc=%Rrc\n",
3083 GCPhys, cb, fFlags, rc));
3084 return VERR_NEM_UNMAP_PAGES_FAILED;
3085 }
3086 }
3087
3088 /*
3089 * Map MMIO2 if any.
3090 */
3091 if (pvMmio2)
3092 {
3093 Assert(fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2);
3094 int rc = nemR3DarwinMap(pVM, GCPhys, pvMmio2, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
3095 if (RT_SUCCESS(rc))
3096 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
3097 else
3098 {
3099 LogRel(("NEMR3NotifyPhysMmioExMapEarly: GCPhys=%RGp LB %RGp fFlags=%#x pvMmio2=%p: Map -> rc=%Rrc\n",
3100 GCPhys, cb, fFlags, pvMmio2, rc));
3101 return VERR_NEM_MAP_PAGES_FAILED;
3102 }
3103 }
3104 else
3105 {
3106 Assert(!(fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2));
3107 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
3108 }
3109
3110#else
3111 RT_NOREF(pVM, GCPhys, cb, pvRam, pvMmio2);
3112 *pu2State = (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE) ? UINT8_MAX : NEM_DARWIN_PAGE_STATE_UNMAPPED;
3113#endif
3114 return VINF_SUCCESS;
3115}
3116
3117
3118VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags,
3119 void *pvRam, void *pvMmio2, uint32_t *puNemRange)
3120{
3121 RT_NOREF(pVM, GCPhys, cb, fFlags, pvRam, pvMmio2, puNemRange);
3122 return VINF_SUCCESS;
3123}
3124
3125
3126VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, void *pvRam,
3127 void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange)
3128{
3129 RT_NOREF(pVM, puNemRange);
3130
3131 Log5(("NEMR3NotifyPhysMmioExUnmap: %RGp LB %RGp fFlags=%#x pvRam=%p pvMmio2=%p pu2State=%p uNemRange=%#x (%#x)\n",
3132 GCPhys, cb, fFlags, pvRam, pvMmio2, pu2State, puNemRange, *puNemRange));
3133
3134 int rc = VINF_SUCCESS;
3135#if defined(VBOX_WITH_PGM_NEM_MODE)
3136 /*
3137 * Unmap the MMIO2 pages.
3138 */
3139 /** @todo If we implement aliasing (MMIO2 page aliased into MMIO range),
3140 * we may have more stuff to unmap even in case of pure MMIO... */
3141 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2)
3142 {
3143 rc = nemR3DarwinUnmap(pVM, GCPhys, cb);
3144 if (RT_FAILURE(rc))
3145 {
3146 LogRel2(("NEMR3NotifyPhysMmioExUnmap: GCPhys=%RGp LB %RGp fFlags=%#x: Unmap -> rc=%Rrc\n",
3147 GCPhys, cb, fFlags, rc));
3148 rc = VERR_NEM_UNMAP_PAGES_FAILED;
3149 }
3150 }
3151
3152 /*
3153 * Restore the RAM we replaced.
3154 */
3155 if (fFlags & NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE)
3156 {
3157 AssertPtr(pvRam);
3158 rc = nemR3DarwinMap(pVM, GCPhys, pvRam, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
3159 if (RT_SUCCESS(rc))
3160 { /* likely */ }
3161 else
3162 {
3163 LogRel(("NEMR3NotifyPhysMmioExUnmap: GCPhys=%RGp LB %RGp pvMmio2=%p rc=%Rrc\n", GCPhys, cb, pvMmio2, rc));
3164 rc = VERR_NEM_MAP_PAGES_FAILED;
3165 }
3166 if (pu2State)
3167 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
3168 }
3169 /* Mark the pages as unmapped if relevant. */
3170 else if (pu2State)
3171 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
3172
3173 RT_NOREF(pvMmio2);
3174#else
3175 RT_NOREF(pVM, GCPhys, cb, fFlags, pvRam, pvMmio2, pu2State);
3176 if (pu2State)
3177 *pu2State = UINT8_MAX;
3178 rc = VERR_NEM_UNMAP_PAGES_FAILED;
3179#endif
3180 return rc;
3181}
3182
3183
3184VMMR3_INT_DECL(int) NEMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t uNemRange,
3185 void *pvBitmap, size_t cbBitmap)
3186{
3187 RT_NOREF(pVM, GCPhys, cb, uNemRange, pvBitmap, cbBitmap);
3188 AssertFailed();
3189 return VERR_NOT_IMPLEMENTED;
3190}
3191
3192
3193VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages, uint32_t fFlags,
3194 uint8_t *pu2State, uint32_t *puNemRange)
3195{
3196 RT_NOREF(pVM, GCPhys, cb, pvPages, fFlags, puNemRange);
3197
3198 Log5(("nemR3NativeNotifyPhysRomRegisterEarly: %RGp LB %RGp pvPages=%p fFlags=%#x\n", GCPhys, cb, pvPages, fFlags));
3199 *pu2State = UINT8_MAX;
3200 *puNemRange = 0;
3201 return VINF_SUCCESS;
3202}
3203
3204
3205VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages,
3206 uint32_t fFlags, uint8_t *pu2State, uint32_t *puNemRange)
3207{
3208 Log5(("nemR3NativeNotifyPhysRomRegisterLate: %RGp LB %RGp pvPages=%p fFlags=%#x pu2State=%p (%d) puNemRange=%p (%#x)\n",
3209 GCPhys, cb, pvPages, fFlags, pu2State, *pu2State, puNemRange, *puNemRange));
3210 *pu2State = UINT8_MAX;
3211
3212#if defined(VBOX_WITH_PGM_NEM_MODE)
3213 /*
3214 * (Re-)map readonly.
3215 */
3216 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
3217 int rc = nemR3DarwinMap(pVM, GCPhys, pvPages, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE);
3218 if (RT_SUCCESS(rc))
3219 *pu2State = NEM_DARWIN_PAGE_STATE_READABLE;
3220 else
3221 {
3222 LogRel(("nemR3NativeNotifyPhysRomRegisterLate: GCPhys=%RGp LB %RGp pvPages=%p fFlags=%#x rc=%Rrc\n",
3223 GCPhys, cb, pvPages, fFlags, rc));
3224 return VERR_NEM_MAP_PAGES_FAILED;
3225 }
3226 RT_NOREF(pVM, fFlags, puNemRange);
3227 return VINF_SUCCESS;
3228#else
3229 RT_NOREF(pVM, GCPhys, cb, pvPages, fFlags, puNemRange);
3230 return VERR_NEM_MAP_PAGES_FAILED;
3231#endif
3232}
3233
3234
3235VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalDeregister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb,
3236 RTR3PTR pvMemR3, uint8_t *pu2State)
3237{
3238 RT_NOREF(pVM);
3239
3240 Log5(("NEMHCNotifyHandlerPhysicalDeregister: %RGp LB %RGp enmKind=%d pvMemR3=%p pu2State=%p (%d)\n",
3241 GCPhys, cb, enmKind, pvMemR3, pu2State, *pu2State));
3242
3243 *pu2State = UINT8_MAX;
3244#if defined(VBOX_WITH_PGM_NEM_MODE)
3245 if (pvMemR3)
3246 {
3247 int rc = nemR3DarwinMap(pVM, GCPhys, pvMemR3, cb, NEM_PAGE_PROT_READ | NEM_PAGE_PROT_WRITE | NEM_PAGE_PROT_EXECUTE);
3248 if (RT_SUCCESS(rc))
3249 *pu2State = NEM_DARWIN_PAGE_STATE_WRITABLE;
3250 else
3251 AssertLogRelMsgFailed(("NEMHCNotifyHandlerPhysicalDeregister: nemR3DarwinMap(,%p,%RGp,%RGp,) -> %Rrc\n",
3252 pvMemR3, GCPhys, cb, rc));
3253 }
3254 RT_NOREF(enmKind);
3255#else
3256 RT_NOREF(pVM, enmKind, GCPhys, cb, pvMemR3);
3257 AssertFailed();
3258#endif
3259}
3260
3261
3262static int nemHCJustUnmapPage(PVMCC pVM, RTGCPHYS GCPhysDst, uint8_t *pu2State)
3263{
3264 if (*pu2State <= NEM_DARWIN_PAGE_STATE_UNMAPPED)
3265 {
3266 Log5(("nemHCJustUnmapPage: %RGp == unmapped\n", GCPhysDst));
3267 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
3268 return VINF_SUCCESS;
3269 }
3270
3271 int rc = nemR3DarwinUnmap(pVM, GCPhysDst & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK, X86_PAGE_SIZE);
3272 if (RT_SUCCESS(rc))
3273 {
3274 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPage);
3275 *pu2State = NEM_DARWIN_PAGE_STATE_UNMAPPED;
3276 Log5(("nemHCJustUnmapPage: %RGp => unmapped\n", GCPhysDst));
3277 return VINF_SUCCESS;
3278 }
3279 STAM_REL_COUNTER_INC(&pVM->nem.s.StatUnmapPageFailed);
3280 LogRel(("nemHCJustUnmapPage(%RGp): failed! rc=%Rrc\n",
3281 GCPhysDst, rc));
3282 return VERR_NEM_IPE_6;
3283}
3284
3285
3286/**
3287 * Called when the A20 state changes.
3288 *
3289 * @param pVCpu The CPU the A20 state changed on.
3290 * @param fEnabled Whether it was enabled (true) or disabled.
3291 */
3292VMMR3_INT_DECL(void) NEMR3NotifySetA20(PVMCPU pVCpu, bool fEnabled)
3293{
3294 Log(("NEMR3NotifySetA20: fEnabled=%RTbool\n", fEnabled));
3295 RT_NOREF(pVCpu, fEnabled);
3296}
3297
3298
3299void nemHCNativeNotifyHandlerPhysicalRegister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb)
3300{
3301 Log5(("nemHCNativeNotifyHandlerPhysicalRegister: %RGp LB %RGp enmKind=%d\n", GCPhys, cb, enmKind));
3302 NOREF(pVM); NOREF(enmKind); NOREF(GCPhys); NOREF(cb);
3303}
3304
3305
3306void nemHCNativeNotifyHandlerPhysicalModify(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld,
3307 RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM)
3308{
3309 Log5(("nemHCNativeNotifyHandlerPhysicalModify: %RGp LB %RGp -> %RGp enmKind=%d fRestoreAsRAM=%d\n",
3310 GCPhysOld, cb, GCPhysNew, enmKind, fRestoreAsRAM));
3311 NOREF(pVM); NOREF(enmKind); NOREF(GCPhysOld); NOREF(GCPhysNew); NOREF(cb); NOREF(fRestoreAsRAM);
3312}
3313
3314
3315int nemHCNativeNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
3316 PGMPAGETYPE enmType, uint8_t *pu2State)
3317{
3318 Log5(("nemHCNativeNotifyPhysPageAllocated: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
3319 GCPhys, HCPhys, fPageProt, enmType, *pu2State));
3320 RT_NOREF(HCPhys, fPageProt, enmType);
3321
3322 return nemHCJustUnmapPage(pVM, GCPhys, pu2State);
3323}
3324
3325
3326VMM_INT_DECL(void) NEMHCNotifyPhysPageProtChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, RTR3PTR pvR3, uint32_t fPageProt,
3327 PGMPAGETYPE enmType, uint8_t *pu2State)
3328{
3329 Log5(("NEMHCNotifyPhysPageProtChanged: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
3330 GCPhys, HCPhys, fPageProt, enmType, *pu2State));
3331 RT_NOREF(HCPhys, pvR3, fPageProt, enmType)
3332
3333 nemHCJustUnmapPage(pVM, GCPhys, pu2State);
3334}
3335
3336
3337VMM_INT_DECL(void) NEMHCNotifyPhysPageChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew,
3338 RTR3PTR pvNewR3, uint32_t fPageProt, PGMPAGETYPE enmType, uint8_t *pu2State)
3339{
3340 Log5(("NEMHCNotifyPhysPageChanged: %RGp HCPhys=%RHp->%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
3341 GCPhys, HCPhysPrev, HCPhysNew, fPageProt, enmType, *pu2State));
3342 RT_NOREF(HCPhysPrev, HCPhysNew, pvNewR3, fPageProt, enmType);
3343
3344 nemHCJustUnmapPage(pVM, GCPhys, pu2State);
3345}
3346
3347
3348/**
3349 * Interface for importing state on demand (used by IEM).
3350 *
3351 * @returns VBox status code.
3352 * @param pVCpu The cross context CPU structure.
3353 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
3354 */
3355VMM_INT_DECL(int) NEMImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat)
3356{
3357 LogFlowFunc(("pVCpu=%p fWhat=%RX64\n", pVCpu, fWhat));
3358 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatImportOnDemand);
3359
3360 return nemR3DarwinCopyStateFromHv(pVCpu->pVMR3, pVCpu, fWhat);
3361}
3362
3363
3364/**
3365 * Query the CPU tick counter and optionally the TSC_AUX MSR value.
3366 *
3367 * @returns VBox status code.
3368 * @param pVCpu The cross context CPU structure.
3369 * @param pcTicks Where to return the CPU tick count.
3370 * @param puAux Where to return the TSC_AUX register value.
3371 */
3372VMM_INT_DECL(int) NEMHCQueryCpuTick(PVMCPUCC pVCpu, uint64_t *pcTicks, uint32_t *puAux)
3373{
3374 LogFlowFunc(("pVCpu=%p pcTicks=%RX64 puAux=%RX32\n", pVCpu, pcTicks, puAux));
3375 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatQueryCpuTick);
3376
3377 int rc = nemR3DarwinMsrRead(pVCpu, MSR_IA32_TSC, pcTicks);
3378 if ( RT_SUCCESS(rc)
3379 && puAux)
3380 {
3381 if (pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_TSC_AUX)
3382 {
3383 /** @todo Why the heck is puAux a uint32_t?. */
3384 uint64_t u64Aux;
3385 rc = nemR3DarwinMsrRead(pVCpu, MSR_K8_TSC_AUX, &u64Aux);
3386 if (RT_SUCCESS(rc))
3387 *puAux = (uint32_t)u64Aux;
3388 }
3389 else
3390 *puAux = CPUMGetGuestTscAux(pVCpu);
3391 }
3392
3393 return rc;
3394}
3395
3396
3397/**
3398 * Resumes CPU clock (TSC) on all virtual CPUs.
3399 *
3400 * This is called by TM when the VM is started, restored, resumed or similar.
3401 *
3402 * @returns VBox status code.
3403 * @param pVM The cross context VM structure.
3404 * @param pVCpu The cross context CPU structure of the calling EMT.
3405 * @param uPausedTscValue The TSC value at the time of pausing.
3406 */
3407VMM_INT_DECL(int) NEMHCResumeCpuTickOnAll(PVMCC pVM, PVMCPUCC pVCpu, uint64_t uPausedTscValue)
3408{
3409 LogFlowFunc(("pVM=%p pVCpu=%p uPausedTscValue=%RX64\n", pVCpu, uPausedTscValue));
3410 VMCPU_ASSERT_EMT_RETURN(pVCpu, VERR_VM_THREAD_NOT_EMT);
3411 AssertReturn(VM_IS_NEM_ENABLED(pVM), VERR_NEM_IPE_9);
3412
3413 hv_return_t hrc = hv_vm_sync_tsc(uPausedTscValue);
3414 if (RT_LIKELY(hrc == HV_SUCCESS))
3415 {
3416 ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_TSC_AUX);
3417 return VINF_SUCCESS;
3418 }
3419
3420 return nemR3DarwinHvSts2Rc(hrc);
3421}
3422
3423
3424/**
3425 * Returns features supported by the NEM backend.
3426 *
3427 * @returns Flags of features supported by the native NEM backend.
3428 * @param pVM The cross context VM structure.
3429 */
3430VMM_INT_DECL(uint32_t) NEMHCGetFeatures(PVMCC pVM)
3431{
3432 RT_NOREF(pVM);
3433 /*
3434 * Apple's Hypervisor.framework is not supported if the CPU doesn't support nested paging
3435 * and unrestricted guest execution support so we can safely return these flags here always.
3436 */
3437 return NEM_FEAT_F_NESTED_PAGING | NEM_FEAT_F_FULL_GST_EXEC | NEM_FEAT_F_XSAVE_XRSTOR;
3438}
3439
3440
3441/** @page pg_nem_darwin NEM/darwin - Native Execution Manager, macOS.
3442 *
3443 * @todo Add notes as the implementation progresses...
3444 */
3445
Note: See TracBrowser for help on using the repository browser.

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