summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/include/EMInternal.h
blob: 38af73fdc40587346b232a07c5670ecadcea8c55 (plain)
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-2022 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 */