VirtualBox

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

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

VMM/NEMR3Native-darwin: Fix syncing the APIC TPR/CR8 register, fixes booting the amd64 Win10 install image, bugref:9044

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

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