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
|
/* $Id: EMInternal.h $ */
/** @file
* EM - Internal header file.
*/
/*
* Copyright (C) 2006-2023 Oracle and/or its affiliates.
*
* This file is part of VirtualBox base platform packages, as
* available from https://www.virtualbox.org.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, in version 3 of the
* License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses>.
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#ifndef VMM_INCLUDED_SRC_include_EMInternal_h
#define VMM_INCLUDED_SRC_include_EMInternal_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif
#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <VBox/vmm/em.h>
#include <VBox/vmm/stam.h>
#include <VBox/dis.h>
#include <VBox/vmm/pdmcritsect.h>
#include <iprt/avl.h>
#include <iprt/setjmp-without-sigmask.h>
RT_C_DECLS_BEGIN
/** @defgroup grp_em_int Internal
* @ingroup grp_em
* @internal
* @{
*/
/** The saved state version. */
#define EM_SAVED_STATE_VERSION 5
#define EM_SAVED_STATE_VERSION_PRE_IEM 4
#define EM_SAVED_STATE_VERSION_PRE_MWAIT 3
#define EM_SAVED_STATE_VERSION_PRE_SMP 2
/** @name MWait state flags.
* @{
*/
/** MWait activated. */
#define EMMWAIT_FLAG_ACTIVE RT_BIT(0)
/** MWait will continue when an interrupt is pending even when IF=0. */
#define EMMWAIT_FLAG_BREAKIRQIF0 RT_BIT(1)
/** Monitor instruction was executed previously. */
#define EMMWAIT_FLAG_MONITOR_ACTIVE RT_BIT(2)
/** @} */
/** EM time slice in ms; used for capping execution time. */
#define EM_TIME_SLICE 100
/**
* Cli node structure
*/
typedef struct CLISTAT
{
/** The key is the cli address. */
AVLGCPTRNODECORE Core;
#if HC_ARCH_BITS == 32 && !defined(RT_OS_WINDOWS)
/** Padding. */
uint32_t u32Padding;
#endif
/** Occurrences. */
STAMCOUNTER Counter;
} CLISTAT, *PCLISTAT;
#ifdef IN_RING3
AssertCompileMemberAlignment(CLISTAT, Counter, 8);
#endif
/**
* Exit history entry.
*
* @remarks We could perhaps trim this down a little bit by assuming uFlatPC
* only needs 48 bits (currently true but will change) and stuffing
* the flags+type in the available 16 bits made available. The
* timestamp could likewise be shortened to accomodate the index, or
* we might skip the index entirely. However, since we will have to
* deal with 56-bit wide PC address before long, there's not point.
*
* On the upside, there are unused bits in both uFlagsAndType and the
* idxSlot fields if needed for anything.
*/
typedef struct EMEXITENTRY
{
/** The flat PC (CS:EIP/RIP) address of the exit.
* UINT64_MAX if not available. */
uint64_t uFlatPC;
/** The EMEXIT_MAKE_FLAGS_AND_TYPE */
uint32_t uFlagsAndType;
/** The index into the exit slot hash table.
* UINT32_MAX if too many collisions and not entered into it. */
uint32_t idxSlot;
/** The TSC timestamp of the exit.
* This is 0 if not timestamped. */
uint64_t uTimestamp;
} EMEXITENTRY;
/** Pointer to an exit history entry. */
typedef EMEXITENTRY *PEMEXITENTRY;
/** Pointer to a const exit history entry. */
typedef EMEXITENTRY const *PCEMEXITENTRY;
/**
* EM VM Instance data.
*/
typedef struct EM
{
/** Whether IEM executes everything. */
bool fIemExecutesAll;
/** Whether a triple fault triggers a guru. */
bool fGuruOnTripleFault;
/** Alignment padding. */
bool afPadding[2];
/** Id of the VCPU that last executed code in the recompiler. */
VMCPUID idLastRemCpu;
} EM;
/** Pointer to EM VM instance data. */
typedef EM *PEM;
/**
* EM VMCPU Instance data.
*/
typedef struct EMCPU
{
/** Execution Manager State. */
EMSTATE volatile enmState;
/** The state prior to the suspending of the VM. */
EMSTATE enmPrevState;
/** Set if hypercall instruction VMMCALL (AMD) & VMCALL (Intel) are enabled.
* GIM sets this and the execution managers queries it. Not saved, as GIM
* takes care of that bit too. */
bool fHypercallEnabled;
/** Explicit padding. */
uint8_t abPadding0[3];
/** The number of instructions we've executed in IEM since switching to the
* EMSTATE_IEM_THEN_REM state. */
uint32_t cIemThenRemInstructions;
/** Start of the current time slice in ms. */
uint64_t u64TimeSliceStart;
/** Start of the current time slice in thread execution time (ms). */
uint64_t u64TimeSliceStartExec;
/** Current time slice value. */
uint64_t u64TimeSliceExec;
/** Pending ring-3 I/O port access (VINF_EM_PENDING_R3_IOPORT_READ / VINF_EM_PENDING_R3_IOPORT_WRITE). */
struct
{
RTIOPORT uPort; /**< The I/O port number.*/
uint8_t cbValue; /**< The value size in bytes. Zero when not pending. */
uint8_t cbInstr; /**< The instruction length. */
uint32_t uValue; /**< The value to write. */
} PendingIoPortAccess;
/** MWait halt state. */
struct
{
uint32_t fWait; /**< Type of mwait; see EMMWAIT_FLAG_*. */
uint32_t u32Padding;
RTGCPTR uMWaitRAX; /**< MWAIT hints. */
RTGCPTR uMWaitRCX; /**< MWAIT extensions. */
RTGCPTR uMonitorRAX; /**< Monitored address. */
RTGCPTR uMonitorRCX; /**< Monitor extension. */
RTGCPTR uMonitorRDX; /**< Monitor hint. */
} MWait;
#if 0
/** Make sure the jmp_buf is at a 32-byte boundrary. */
uint64_t au64Padding1[4];
#endif
union
{
/** Padding used in the other rings.
* This must be larger than jmp_buf on any supported platform. */
char achPaddingFatalLongJump[256];
#ifdef IN_RING3
/** Long buffer jump for fatal VM errors.
* It will jump to before the outer EM loop is entered. */
jmp_buf FatalLongJump;
#endif
} u;
/** For saving stack space, the disassembler state is allocated here instead of
* on the stack. */
DISCPUSTATE DisState;
/** @name Execution profiling.
* @{ */
STAMPROFILE StatForcedActions;
STAMPROFILE StatHalted;
STAMPROFILEADV StatCapped;
STAMPROFILEADV StatHMEntry;
STAMPROFILE StatHMExec;
STAMPROFILE StatIEMEmu;
STAMPROFILE StatIEMThenREM;
STAMPROFILEADV StatNEMEntry;
STAMPROFILE StatNEMExec;
STAMPROFILE StatREMEmu;
STAMPROFILE StatREMExec;
STAMPROFILE StatREMSync;
STAMPROFILEADV StatREMTotal;
STAMPROFILE StatRAWExec;
STAMPROFILEADV StatRAWEntry;
STAMPROFILEADV StatRAWTail;
STAMPROFILEADV StatRAWTotal;
STAMPROFILEADV StatTotal;
/** @} */
/** R3: Profiling of emR3RawExecuteIOInstruction. */
STAMPROFILE StatIOEmu;
STAMCOUNTER StatIoRestarted;
STAMCOUNTER StatIoIem;
/** R3: Profiling of emR3RawPrivileged. */
STAMPROFILE StatPrivEmu;
/** R3: Number of times emR3HmExecute is called. */
STAMCOUNTER StatHMExecuteCalled;
/** R3: Number of times emR3NEMExecute is called. */
STAMCOUNTER StatNEMExecuteCalled;
/** Align the next member at a 32-byte boundrary. */
uint64_t au64Padding2[1+2];
/** Exit history table (6KB). */
EMEXITENTRY aExitHistory[256];
/** Where to store the next exit history entry.
* Since aExitHistory is 256 items longs, we'll just increment this and
* mask it when using it. That help the readers detect whether we've
* wrapped around or not. */
uint64_t iNextExit;
/** Index into aExitRecords set by EMHistoryExec when returning to ring-3.
* This is UINT16_MAX if not armed. */
uint16_t volatile idxContinueExitRec;
/** Whether exit optimizations are enabled or not (in general). */
bool fExitOptimizationEnabled : 1;
/** Whether exit optimizations are enabled for ring-0 (in general). */
bool fExitOptimizationEnabledR0 : 1;
/** Whether exit optimizations are enabled for ring-0 when preemption is disabled. */
bool fExitOptimizationEnabledR0PreemptDisabled : 1;
/** Explicit padding. */
bool fPadding2;
/** Max number of instructions to execute. */
uint16_t cHistoryExecMaxInstructions;
/** Min number of instructions to execute while probing. */
uint16_t cHistoryProbeMinInstructions;
/** Max number of instructions to execute without an exit before giving up probe. */
uint16_t cHistoryProbeMaxInstructionsWithoutExit;
uint16_t uPadding3;
/** Number of exit records in use. */
uint32_t cExitRecordUsed;
/** Profiling the EMHistoryExec when executing (not probing). */
STAMPROFILE StatHistoryExec;
/** Number of saved exits. */
STAMCOUNTER StatHistoryExecSavedExits;
/** Number of instructions executed by EMHistoryExec. */
STAMCOUNTER StatHistoryExecInstructions;
uint64_t uPadding4;
/** Number of instructions executed by EMHistoryExec when probing. */
STAMCOUNTER StatHistoryProbeInstructions;
/** Number of times probing resulted in EMEXITACTION_NORMAL_PROBED. */
STAMCOUNTER StatHistoryProbedNormal;
/** Number of times probing resulted in EMEXITACTION_EXEC_WITH_MAX. */
STAMCOUNTER StatHistoryProbedExecWithMax;
/** Number of times probing resulted in ring-3 continuation. */
STAMCOUNTER StatHistoryProbedToRing3;
/** Profiling the EMHistoryExec when probing.*/
STAMPROFILE StatHistoryProbe;
/** Hit statistics for each lookup step. */
STAMCOUNTER aStatHistoryRecHits[16];
/** Type change statistics for each lookup step. */
STAMCOUNTER aStatHistoryRecTypeChanged[16];
/** Replacement statistics for each lookup step. */
STAMCOUNTER aStatHistoryRecReplaced[16];
/** New record statistics for each lookup step. */
STAMCOUNTER aStatHistoryRecNew[16];
/** Exit records (32KB). (Aligned on 32 byte boundrary.) */
EMEXITREC aExitRecords[1024];
} EMCPU;
/** Pointer to EM VM instance data. */
typedef EMCPU *PEMCPU;
/** @} */
int emR3InitDbg(PVM pVM);
int emR3HmExecute(PVM pVM, PVMCPU pVCpu, bool *pfFFDone);
VBOXSTRICTRC emR3NemExecute(PVM pVM, PVMCPU pVCpu, bool *pfFFDone);
int emR3RawExecute(PVM pVM, PVMCPU pVCpu, bool *pfFFDone);
EMSTATE emR3Reschedule(PVM pVM, PVMCPU pVCpu);
int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc);
VBOXSTRICTRC emR3HighPriorityPostForcedActions(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rc);
int emR3RawResumeHyper(PVM pVM, PVMCPU pVCpu);
int emR3RawStep(PVM pVM, PVMCPU pVCpu);
VBOXSTRICTRC emR3NemSingleInstruction(PVM pVM, PVMCPU pVCpu, uint32_t fFlags);
int emR3SingleStepExecRem(PVM pVM, PVMCPU pVCpu, uint32_t cIterations);
bool emR3IsExecutionAllowed(PVM pVM, PVMCPU pVCpu);
VBOXSTRICTRC emR3ExecutePendingIoPortWrite(PVM pVM, PVMCPU pVCpu);
VBOXSTRICTRC emR3ExecutePendingIoPortRead(PVM pVM, PVMCPU pVCpu);
VBOXSTRICTRC emR3ExecuteSplitLockInstruction(PVM pVM, PVMCPU pVCpu);
RT_C_DECLS_END
#endif /* !VMM_INCLUDED_SRC_include_EMInternal_h */
|