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