VirtualBox

source: vbox/trunk/src/VBox/VMM/include/NEMInternal.h@ 91702

Last change on this file since 91702 was 91702, checked in by vboxsync, 4 years ago

VMM/NEM: More stats. Played with using WHvMapGpaRange again, but much too slow to use on a per-page basis. bugref:10118

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.2 KB
Line 
1/* $Id: NEMInternal.h 91702 2021-10-12 21:15:19Z vboxsync $ */
2/** @file
3 * NEM - Internal header file.
4 */
5
6/*
7 * Copyright (C) 2018-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef VMM_INCLUDED_SRC_include_NEMInternal_h
19#define VMM_INCLUDED_SRC_include_NEMInternal_h
20#ifndef RT_WITHOUT_PRAGMA_ONCE
21# pragma once
22#endif
23
24#include <VBox/cdefs.h>
25#include <VBox/types.h>
26#include <VBox/vmm/nem.h>
27#include <VBox/vmm/cpum.h> /* For CPUMCPUVENDOR. */
28#include <VBox/vmm/stam.h>
29#include <VBox/vmm/vmapi.h>
30#ifdef RT_OS_WINDOWS
31#include <iprt/nt/hyperv.h>
32#include <iprt/critsect.h>
33#endif
34
35RT_C_DECLS_BEGIN
36
37
38/** @defgroup grp_nem_int Internal
39 * @ingroup grp_nem
40 * @internal
41 * @{
42 */
43
44
45#ifdef RT_OS_WINDOWS
46/*
47 * Windows: Code configuration.
48 */
49# define NEM_WIN_USE_HYPERCALLS_FOR_PAGES
50//# define NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS /**< Applies to ring-3 code only. Useful for testing VID API. */
51//# define NEM_WIN_USE_OUR_OWN_RUN_API /**< Applies to ring-3 code only. Useful for testing VID API. */
52//# define NEM_WIN_WITH_RING0_RUNLOOP /**< Enables the ring-0 runloop. */
53//# define NEM_WIN_USE_RING0_RUNLOOP_BY_DEFAULT /**< For quickly testing ring-3 API without messing with CFGM. */
54# if defined(NEM_WIN_USE_OUR_OWN_RUN_API) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
55# error "NEM_WIN_USE_OUR_OWN_RUN_API requires NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS"
56# endif
57# if defined(NEM_WIN_USE_OUR_OWN_RUN_API) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES)
58# error "NEM_WIN_USE_OUR_OWN_RUN_API requires NEM_WIN_USE_HYPERCALLS_FOR_PAGES"
59# endif
60# if defined(NEM_WIN_WITH_RING0_RUNLOOP) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES)
61# error "NEM_WIN_WITH_RING0_RUNLOOP requires NEM_WIN_USE_HYPERCALLS_FOR_PAGES"
62# endif
63
64/**
65 * Windows VID I/O control information.
66 */
67typedef struct NEMWINIOCTL
68{
69 /** The I/O control function number. */
70 uint32_t uFunction;
71 uint32_t cbInput;
72 uint32_t cbOutput;
73} NEMWINIOCTL;
74
75/** @name Windows: Our two-bit physical page state for PGMPAGE
76 * @{ */
77# define NEM_WIN_PAGE_STATE_NOT_SET 0
78# define NEM_WIN_PAGE_STATE_UNMAPPED 1
79# define NEM_WIN_PAGE_STATE_READABLE 2
80# define NEM_WIN_PAGE_STATE_WRITABLE 3
81/** @} */
82
83/** Windows: Checks if a_GCPhys is subject to the limited A20 gate emulation. */
84# define NEM_WIN_IS_SUBJECT_TO_A20(a_GCPhys) ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K)
85/** Windows: Checks if a_GCPhys is relevant to the limited A20 gate emulation. */
86# define NEM_WIN_IS_RELEVANT_TO_A20(a_GCPhys) \
87 ( ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K) || ((RTGCPHYS)(a_GCPhys) < (RTGCPHYS)_64K) )
88
89/** The CPUMCTX_EXTRN_XXX mask for IEM. */
90# define NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM ( IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_NEM_WIN_INHIBIT_INT \
91 | CPUMCTX_EXTRN_NEM_WIN_INHIBIT_NMI )
92/** The CPUMCTX_EXTRN_XXX mask for IEM when raising exceptions. */
93# define NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM_XCPT (IEM_CPUMCTX_EXTRN_XCPT_MASK | NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM)
94
95/** @name Windows: Interrupt window flags (NEM_WIN_INTW_F_XXX).
96 * @{ */
97# define NEM_WIN_INTW_F_NMI UINT8_C(0x01)
98# define NEM_WIN_INTW_F_REGULAR UINT8_C(0x02)
99# define NEM_WIN_INTW_F_PRIO_MASK UINT8_C(0x3c)
100# define NEM_WIN_INTW_F_PRIO_SHIFT 2
101/** @} */
102
103#endif /* RT_OS_WINDOWS */
104
105
106/** Trick to make slickedit see the static functions in the template. */
107#ifndef IN_SLICKEDIT
108# define NEM_TMPL_STATIC static
109#else
110# define NEM_TMPL_STATIC
111#endif
112
113
114/**
115 * Generic NEM exit type enumeration for use with EMHistoryAddExit.
116 *
117 * On windows we've got two different set of exit types and they are both jumping
118 * around the place value wise, so EM can use their values.
119 *
120 * @note We only have exit types for exits not covered by EM here.
121 */
122typedef enum NEMEXITTYPE
123{
124 /* windows: */
125 NEMEXITTYPE_UNRECOVERABLE_EXCEPTION = 1,
126 NEMEXITTYPE_INVALID_VP_REGISTER_VALUE,
127 NEMEXITTYPE_INTTERRUPT_WINDOW,
128 NEMEXITTYPE_HALT,
129 NEMEXITTYPE_XCPT_UD,
130 NEMEXITTYPE_XCPT_DB,
131 NEMEXITTYPE_XCPT_BP,
132 NEMEXITTYPE_CANCELED,
133 NEMEXITTYPE_MEMORY_ACCESS
134} NEMEXITTYPE;
135
136
137/**
138 * NEM VM Instance data.
139 */
140typedef struct NEM
141{
142 /** NEM_MAGIC. */
143 uint32_t u32Magic;
144
145 /** Set if enabled. */
146 bool fEnabled;
147 /** Set if long mode guests are allowed. */
148 bool fAllow64BitGuests;
149#ifdef RT_OS_WINDOWS
150 /** Set if we've created the EMTs. */
151 bool fCreatedEmts : 1;
152 /** WHvRunVpExitReasonX64Cpuid is supported. */
153 bool fExtendedMsrExit : 1;
154 /** WHvRunVpExitReasonX64MsrAccess is supported. */
155 bool fExtendedCpuIdExit : 1;
156 /** WHvRunVpExitReasonException is supported. */
157 bool fExtendedXcptExit : 1;
158 /** Set if we're using the ring-0 API to do the work. */
159 bool fUseRing0Runloop : 1;
160 /** Set if we've started more than one CPU and cannot mess with A20. */
161 bool fA20Fixed : 1;
162 /** Set if A20 is enabled. */
163 bool fA20Enabled : 1;
164 /** The reported CPU vendor. */
165 CPUMCPUVENDOR enmCpuVendor;
166 /** Cache line flush size as a power of two. */
167 uint8_t cCacheLineFlushShift;
168 /** The result of WHvCapabilityCodeProcessorFeatures. */
169 union
170 {
171 /** 64-bit view. */
172 uint64_t u64;
173# ifdef _WINHVAPIDEFS_H_
174 /** Interpreed features. */
175 WHV_PROCESSOR_FEATURES u;
176# endif
177 } uCpuFeatures;
178
179 /** The partition handle. */
180# ifdef _WINHVAPIDEFS_H_
181 WHV_PARTITION_HANDLE
182# else
183 RTHCUINTPTR
184# endif
185 hPartition;
186 /** The device handle for the partition, for use with Vid APIs or direct I/O
187 * controls. */
188 RTR3PTR hPartitionDevice;
189 /** The Hyper-V partition ID. */
190 uint64_t idHvPartition;
191
192 /** Number of currently mapped pages. */
193 uint32_t volatile cMappedPages;
194# ifndef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
195 /** Max number of pages we dare map at once. */
196 uint32_t cMaxMappedPages;
197# endif
198 STAMCOUNTER StatMapPage;
199 STAMCOUNTER StatUnmapPage;
200# ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
201 STAMCOUNTER StatRemapPage;
202 STAMCOUNTER StatRemapPageFailed;
203# else
204 STAMCOUNTER StatUnmapAllPages;
205# endif
206 STAMCOUNTER StatMapPageFailed;
207 STAMCOUNTER StatUnmapPageFailed;
208
209# ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
210 /** Info about the VidGetHvPartitionId I/O control interface. */
211 NEMWINIOCTL IoCtlGetHvPartitionId;
212 /** Info about the VidGetPartitionProperty I/O control interface. */
213 NEMWINIOCTL IoCtlGetPartitionProperty;
214# endif
215# ifdef NEM_WIN_WITH_RING0_RUNLOOP
216 /** Info about the VidStartVirtualProcessor I/O control interface. */
217 NEMWINIOCTL IoCtlStartVirtualProcessor;
218 /** Info about the VidStopVirtualProcessor I/O control interface. */
219 NEMWINIOCTL IoCtlStopVirtualProcessor;
220 /** Info about the VidStopVirtualProcessor I/O control interface. */
221 NEMWINIOCTL IoCtlMessageSlotHandleAndGetNext;
222# endif
223
224 /** Statistics updated by NEMR0UpdateStatistics. */
225 struct
226 {
227 uint64_t cPagesAvailable;
228 uint64_t cPagesInUse;
229 } R0Stats;
230#endif /* RT_OS_WINDOWS */
231} NEM;
232/** Pointer to NEM VM instance data. */
233typedef NEM *PNEM;
234
235/** NEM::u32Magic value. */
236#define NEM_MAGIC UINT32_C(0x004d454e)
237/** NEM::u32Magic value after termination. */
238#define NEM_MAGIC_DEAD UINT32_C(0xdead1111)
239
240
241/**
242 * NEM VMCPU Instance data.
243 */
244typedef struct NEMCPU
245{
246 /** NEMCPU_MAGIC. */
247 uint32_t u32Magic;
248 /** Whether \#UD needs to be intercepted and presented to GIM. */
249 bool fGIMTrapXcptUD : 1;
250 /** Whether \#GP needs to be intercept for mesa driver workaround. */
251 bool fTrapXcptGpForLovelyMesaDrv: 1;
252#ifdef RT_OS_WINDOWS
253 /** The current state of the interrupt windows (NEM_WIN_INTW_F_XXX). */
254 uint8_t fCurrentInterruptWindows;
255 /** The desired state of the interrupt windows (NEM_WIN_INTW_F_XXX). */
256 uint8_t fDesiredInterruptWindows;
257 /** Last copy of HV_X64_VP_EXECUTION_STATE::InterruptShadow. */
258 bool fLastInterruptShadow : 1;
259# ifdef NEM_WIN_WITH_RING0_RUNLOOP
260 /** Pending VINF_NEM_FLUSH_TLB. */
261 int32_t rcPending;
262# else
263 uint32_t uPadding;
264# endif
265 /** The VID_MSHAGN_F_XXX flags.
266 * Either VID_MSHAGN_F_HANDLE_MESSAGE | VID_MSHAGN_F_GET_NEXT_MESSAGE or zero. */
267 uint32_t fHandleAndGetFlags;
268 /** What VidMessageSlotMap returns and is used for passing exit info. */
269 RTR3PTR pvMsgSlotMapping;
270 /** The windows thread handle. */
271 RTR3PTR hNativeThreadHandle;
272 /** Parameters for making Hyper-V hypercalls. */
273 union
274 {
275 uint8_t ab[64];
276 /** Arguments for NEMR0MapPages (HvCallMapGpaPages). */
277 struct
278 {
279 RTGCPHYS GCPhysSrc;
280 RTGCPHYS GCPhysDst; /**< Same as GCPhysSrc except maybe when the A20 gate is disabled. */
281 uint32_t cPages;
282 HV_MAP_GPA_FLAGS fFlags;
283 } MapPages;
284 /** Arguments for NEMR0UnmapPages (HvCallUnmapGpaPages). */
285 struct
286 {
287 RTGCPHYS GCPhys;
288 uint32_t cPages;
289 } UnmapPages;
290 /** Result from NEMR0QueryCpuTick. */
291 struct
292 {
293 uint64_t cTicks;
294 uint32_t uAux;
295 } QueryCpuTick;
296 /** Input and output for NEMR0DoExperiment. */
297 struct
298 {
299 uint32_t uItem;
300 bool fSuccess;
301 uint64_t uStatus;
302 uint64_t uLoValue;
303 uint64_t uHiValue;
304 } Experiment;
305 } Hypercall;
306 /** I/O control buffer, we always use this for I/O controls. */
307 union
308 {
309 uint8_t ab[64];
310 HV_PARTITION_ID idPartition;
311 HV_VP_INDEX idCpu;
312 struct
313 {
314 uint64_t enmProperty;
315 uint64_t uValue;
316 } GetProp;
317# ifdef VID_MSHAGN_F_GET_NEXT_MESSAGE
318 VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT MsgSlotHandleAndGetNext;
319# endif
320 } uIoCtlBuf;
321
322 /** @name Statistics
323 * @{ */
324 STAMCOUNTER StatExitPortIo;
325 STAMCOUNTER StatExitMemUnmapped;
326 STAMCOUNTER StatExitMemIntercept;
327 STAMCOUNTER StatExitHalt;
328 STAMCOUNTER StatExitInterruptWindow;
329 STAMCOUNTER StatExitCpuId;
330 STAMCOUNTER StatExitMsr;
331 STAMCOUNTER StatExitException;
332 STAMCOUNTER StatExitExceptionBp;
333 STAMCOUNTER StatExitExceptionDb;
334 STAMCOUNTER StatExitExceptionGp;
335 STAMCOUNTER StatExitExceptionGpMesa;
336 STAMCOUNTER StatExitExceptionUd;
337 STAMCOUNTER StatExitExceptionUdHandled;
338 STAMCOUNTER StatExitUnrecoverable;
339 STAMCOUNTER StatGetMsgTimeout;
340 STAMCOUNTER StatStopCpuSuccess;
341 STAMCOUNTER StatStopCpuPending;
342 STAMCOUNTER StatStopCpuPendingAlerts;
343 STAMCOUNTER StatStopCpuPendingOdd;
344 STAMCOUNTER StatCancelChangedState;
345 STAMCOUNTER StatCancelAlertedThread;
346 STAMCOUNTER StatBreakOnCancel;
347 STAMCOUNTER StatBreakOnFFPre;
348 STAMCOUNTER StatBreakOnFFPost;
349 STAMCOUNTER StatBreakOnStatus;
350 STAMCOUNTER StatImportOnDemand;
351 STAMCOUNTER StatImportOnReturn;
352 STAMCOUNTER StatImportOnReturnSkipped;
353 STAMCOUNTER StatQueryCpuTick;
354 /** @} */
355#endif /* RT_OS_WINDOWS */
356} NEMCPU;
357/** Pointer to NEM VMCPU instance data. */
358typedef NEMCPU *PNEMCPU;
359
360/** NEMCPU::u32Magic value. */
361#define NEMCPU_MAGIC UINT32_C(0x4d454e20)
362/** NEMCPU::u32Magic value after termination. */
363#define NEMCPU_MAGIC_DEAD UINT32_C(0xdead2222)
364
365
366#ifdef IN_RING0
367# ifdef RT_OS_WINDOWS
368/**
369 * Windows: Hypercall input/ouput page info.
370 */
371typedef struct NEMR0HYPERCALLDATA
372{
373 /** Host physical address of the hypercall input/output page. */
374 RTHCPHYS HCPhysPage;
375 /** Pointer to the hypercall input/output page. */
376 uint8_t *pbPage;
377 /** Handle to the memory object of the hypercall input/output page. */
378 RTR0MEMOBJ hMemObj;
379} NEMR0HYPERCALLDATA;
380/** Pointer to a Windows hypercall input/output page info. */
381typedef NEMR0HYPERCALLDATA *PNEMR0HYPERCALLDATA;
382# endif /* RT_OS_WINDOWS */
383
384/**
385 * NEM GVMCPU instance data.
386 */
387typedef struct NEMR0PERVCPU
388{
389# if defined(RT_OS_WINDOWS) && defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES)
390 /** Hypercall input/ouput page. */
391 NEMR0HYPERCALLDATA HypercallData;
392 /** Delta to add to convert a ring-0 pointer to a ring-3 one. */
393 uintptr_t offRing3ConversionDelta;
394# else
395 uint32_t uDummy;
396# endif
397} NEMR0PERVCPU;
398
399/**
400 * NEM GVM instance data.
401 */
402typedef struct NEMR0PERVM
403{
404# ifdef RT_OS_WINDOWS
405# ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
406 /** The partition ID. */
407 uint64_t idHvPartition;
408 /** I/O control context. */
409 PSUPR0IOCTLCTX pIoCtlCtx;
410 /** Info about the VidGetHvPartitionId I/O control interface. */
411 NEMWINIOCTL IoCtlGetHvPartitionId;
412 /** Info about the VidGetPartitionProperty I/O control interface. */
413 NEMWINIOCTL IoCtlGetPartitionProperty;
414# endif
415# ifdef NEM_WIN_WITH_RING0_RUNLOOP
416 /** Info about the VidStartVirtualProcessor I/O control interface. */
417 NEMWINIOCTL IoCtlStartVirtualProcessor;
418 /** Info about the VidStopVirtualProcessor I/O control interface. */
419 NEMWINIOCTL IoCtlStopVirtualProcessor;
420 /** Info about the VidStopVirtualProcessor I/O control interface. */
421 NEMWINIOCTL IoCtlMessageSlotHandleAndGetNext;
422 /** Whether we may use the ring-0 runloop or not. */
423 bool fMayUseRing0Runloop;
424# endif
425
426# ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
427 /** Hypercall input/ouput page for non-EMT. */
428 NEMR0HYPERCALLDATA HypercallData;
429 /** Critical section protecting use of HypercallData. */
430 RTCRITSECT HypercallDataCritSect;
431# endif
432
433# else
434 uint32_t uDummy;
435# endif
436} NEMR0PERVM;
437
438#endif /* IN_RING*/
439
440
441#ifdef IN_RING3
442int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced);
443int nemR3NativeInitAfterCPUM(PVM pVM);
444int nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat);
445int nemR3NativeTerm(PVM pVM);
446void nemR3NativeReset(PVM pVM);
447void nemR3NativeResetCpu(PVMCPU pVCpu, bool fInitIpi);
448VBOXSTRICTRC nemR3NativeRunGC(PVM pVM, PVMCPU pVCpu);
449bool nemR3NativeCanExecuteGuest(PVM pVM, PVMCPU pVCpu);
450bool nemR3NativeSetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable);
451void nemR3NativeNotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags);
452
453int nemR3NativeNotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb);
454int nemR3NativeNotifyPhysMmioExMap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, void *pvMmio2);
455int nemR3NativeNotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags);
456int nemR3NativeNotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags);
457int nemR3NativeNotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags);
458void nemR3NativeNotifySetA20(PVMCPU pVCpu, bool fEnabled);
459#endif
460
461void nemHCNativeNotifyHandlerPhysicalRegister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb);
462void nemHCNativeNotifyHandlerPhysicalDeregister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb,
463 int fRestoreAsRAM, bool fRestoreAsRAM2);
464void nemHCNativeNotifyHandlerPhysicalModify(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld,
465 RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM);
466int nemHCNativeNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
467 PGMPAGETYPE enmType, uint8_t *pu2State);
468void nemHCNativeNotifyPhysPageProtChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
469 PGMPAGETYPE enmType, uint8_t *pu2State);
470void nemHCNativeNotifyPhysPageChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew, uint32_t fPageProt,
471 PGMPAGETYPE enmType, uint8_t *pu2State);
472
473
474#ifdef RT_OS_WINDOWS
475/** Maximum number of pages we can map in a single NEMR0MapPages call. */
476# define NEM_MAX_MAP_PAGES ((PAGE_SIZE - RT_UOFFSETOF(HV_INPUT_MAP_GPA_PAGES, PageList)) / sizeof(HV_SPA_PAGE_NUMBER))
477/** Maximum number of pages we can unmap in a single NEMR0UnmapPages call. */
478# define NEM_MAX_UNMAP_PAGES 4095
479
480#endif
481/** @} */
482
483RT_C_DECLS_END
484
485#endif /* !VMM_INCLUDED_SRC_include_NEMInternal_h */
486
Note: See TracBrowser for help on using the repository browser.

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