VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsThreadedRecompiler.cpp@ 99983

Last change on this file since 99983 was 99982, checked in by vboxsync, 23 months ago

VMM/IEM: More plotting on the IEM recompiler. bugref:10369

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: IEMAllInstructionsThreadedRecompiler.cpp 99982 2023-05-25 19:59:54Z vboxsync $ */
2/** @file
3 * IEM - Instruction Decoding and Emulation.
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#ifndef LOG_GROUP /* defined when included by tstIEMCheckMc.cpp */
33# define LOG_GROUP LOG_GROUP_IEM
34#endif
35#define VMCPU_INCL_CPUM_GST_CTX
36#include <VBox/vmm/iem.h>
37#include <VBox/vmm/cpum.h>
38#include <VBox/vmm/apic.h>
39#include <VBox/vmm/pdm.h>
40#include <VBox/vmm/pgm.h>
41#include <VBox/vmm/iom.h>
42#include <VBox/vmm/em.h>
43#include <VBox/vmm/hm.h>
44#include <VBox/vmm/nem.h>
45#include <VBox/vmm/gim.h>
46#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
47# include <VBox/vmm/em.h>
48# include <VBox/vmm/hm_svm.h>
49#endif
50#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
51# include <VBox/vmm/hmvmxinline.h>
52#endif
53#include <VBox/vmm/tm.h>
54#include <VBox/vmm/dbgf.h>
55#include <VBox/vmm/dbgftrace.h>
56#ifndef TST_IEM_CHECK_MC
57# include "IEMInternal.h"
58#endif
59#include <VBox/vmm/vmcc.h>
60#include <VBox/log.h>
61#include <VBox/err.h>
62#include <VBox/param.h>
63#include <VBox/dis.h>
64#include <VBox/disopcode-x86-amd64.h>
65#include <iprt/asm-math.h>
66#include <iprt/assert.h>
67#include <iprt/string.h>
68#include <iprt/x86.h>
69
70#ifndef TST_IEM_CHECK_MC
71# include "IEMInline.h"
72# include "IEMOpHlp.h"
73# include "IEMMc.h"
74#endif
75
76#include "IEMThreadedFunctions.h"
77
78
79/*
80 * Narrow down configs here to avoid wasting time on unused configs here.
81 */
82
83#ifndef IEM_WITH_CODE_TLB
84# error The code TLB must be enabled for the recompiler.
85#endif
86
87#ifndef IEM_WITH_DATA_TLB
88# error The data TLB must be enabled for the recompiler.
89#endif
90
91#ifndef IEM_WITH_SETJMP
92# error The setjmp approach must be enabled for the recompiler.
93#endif
94
95
96/*********************************************************************************************************************************
97* Structures and Typedefs *
98*********************************************************************************************************************************/
99/**
100 * A call for the threaded call table.
101 */
102typedef struct IEMTHRDEDCALLENTRY
103{
104 /** The function to call (IEMTHREADEDFUNCS). */
105 uint16_t enmFunction;
106 uint16_t uUnused0;
107
108 /** The opcode length. */
109 uint8_t cbOpcode;
110 /** The opcode chunk number.
111 * @note sketches for discontiguous opcode support */
112 uint8_t idxOpcodeChunk;
113 /** The offset into the opcode chunk of this function.
114 * @note sketches for discontiguous opcode support */
115 uint16_t offOpcodeChunk;
116
117 /** Generic parameters. */
118 uint64_t auParams[3];
119} IEMTHRDEDCALLENTRY;
120AssertCompileSize(IEMTHRDEDCALLENTRY, sizeof(uint64_t) * 4);
121/** Pointer to a threaded call entry. */
122typedef IEMTHRDEDCALLENTRY *PIEMTHRDEDCALLENTRY;
123/** Pointer to a const threaded call entry. */
124typedef IEMTHRDEDCALLENTRY const *PCIEMTHRDEDCALLENTRY;
125
126/** @name IEMTB_F_XXX - Translation block flags.
127 * @{ */
128#define IEMTB_F_MODE_MASK UINT32_C(0x00000007)
129#define IEMTB_F_MODE_X86_16BIT UINT32_C(0x00000001)
130#define IEMTB_F_MODE_X86_32BIT UINT32_C(0x00000002)
131#define IEMTB_F_MODE_X86_32BIT_FLAT UINT32_C(0x00000003)
132#define IEMTB_F_MODE_X86_64BIT UINT32_C(0x00000004)
133
134#define IEMTB_F_COMPILING RT_BIT_32(0)
135#define IEMTB_F_NATIVE RT_BIT_32(1)
136/** @} */
137
138/**
139 * Translation block.
140 */
141typedef struct IEMTB
142{
143 /** Next block with the same hash table entry. */
144 PIEMTB volatile pNext;
145 /** List on the local VCPU for blocks. */
146 RTLISTNODE LocalList;
147
148 /** @name What uniquely identifies the block.
149 * @{ */
150 RTGCPHYS GCPhysPc;
151 uint64_t uPc;
152 uint32_t fFlags;
153 union
154 {
155 struct
156 {
157 /** The CS base. */
158 uint32_t uCsBase;
159 /** The CS limit (UINT32_MAX for 64-bit code). */
160 uint32_t uCsLimit;
161 /** The CS selector value. */
162 uint16_t CS;
163 /**< Relevant X86DESCATTR_XXX bits. */
164 uint16_t fAttr;
165 } x86;
166 };
167 /** @} */
168
169 /** Number of bytes of opcodes covered by this block.
170 * @todo Support discontiguous chunks of opcodes in same block, though maybe
171 * restrict to the initial page or smth. */
172 uint32_t cbPC;
173
174 union
175 {
176 struct
177 {
178 /** Number of calls in paCalls. */
179 uint32_t cCalls;
180 /** Number of calls allocated. */
181 uint32_t cAllocated;
182 /** The call sequence table. */
183 PIEMTHRDEDCALLENTRY paCalls;
184 } Thrd;
185 };
186
187
188} IEMTB;
189
190
191/*********************************************************************************************************************************
192* Defined Constants And Macros *
193*********************************************************************************************************************************/
194#define g_apfnOneByteMap g_apfnIemThreadedRecompilerOneByteMap
195
196
197#undef IEM_MC_CALC_RM_EFF_ADDR
198#ifndef IEM_WITH_SETJMP
199# define IEM_MC_CALC_RM_EFF_ADDR(a_GCPtrEff, bRm, cbImm) \
200 uint64_t uEffAddrInfo; \
201 IEM_MC_RETURN_ON_FAILURE(iemOpHlpCalcRmEffAddrJmpEx(pVCpu, (bRm), (cbImm), &(a_GCPtrEff), &uEffAddrInfo))
202#else
203# define IEM_MC_CALC_RM_EFF_ADDR(a_GCPtrEff, bRm, cbImm) \
204 uint64_t uEffAddrInfo; \
205 ((a_GCPtrEff) = iemOpHlpCalcRmEffAddrJmpEx(pVCpu, (bRm), (cbImm), &uEffAddrInfo))
206#endif
207
208#define IEM_MC2_EMIT_CALL_1(a_enmFunction, a_uArg0) do { \
209 IEMTHREADEDFUNCS const enmFunctionCheck = a_enmFunction; RT_NOREF(enmFunctionCheck); \
210 uint64_t const uArg0Check = (a_uArg0); RT_NOREF(uArg0Check); \
211 \
212 PIEMTB const pTb = pVCpu->iem.s.pCurTbR3; \
213 PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
214 pCall->enmFunction = a_enmFunction; \
215 pCall->cbOpcode = IEM_GET_INSTR_LEN(pVCpu); \
216 pCall->auParams[0] = a_uArg0; \
217 pCall->auParams[1] = 0; \
218 pCall->auParams[2] = 0; \
219 } while (0)
220#define IEM_MC2_EMIT_CALL_2(a_enmFunction, a_uArg0, a_uArg1) do { \
221 IEMTHREADEDFUNCS const enmFunctionCheck = a_enmFunction; RT_NOREF(enmFunctionCheck); \
222 uint64_t const uArg0Check = (a_uArg0); RT_NOREF(uArg0Check); \
223 uint64_t const uArg1Check = (a_uArg1); RT_NOREF(uArg1Check); \
224 \
225 PIEMTB const pTb = pVCpu->iem.s.pCurTbR3; \
226 PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
227 pCall->enmFunction = a_enmFunction; \
228 pCall->cbOpcode = IEM_GET_INSTR_LEN(pVCpu); \
229 pCall->auParams[0] = a_uArg0; \
230 pCall->auParams[1] = a_uArg1; \
231 pCall->auParams[2] = 0; \
232 } while (0)
233#define IEM_MC2_EMIT_CALL_3(a_enmFunction, a_uArg0, a_uArg1, a_uArg2) do { \
234 IEMTHREADEDFUNCS const enmFunctionCheck = a_enmFunction; RT_NOREF(enmFunctionCheck); \
235 uint64_t const uArg0Check = (a_uArg0); RT_NOREF(uArg0Check); \
236 uint64_t const uArg1Check = (a_uArg1); RT_NOREF(uArg1Check); \
237 uint64_t const uArg2Check = (a_uArg2); RT_NOREF(uArg2Check); \
238 \
239 PIEMTB const pTb = pVCpu->iem.s.pCurTbR3; \
240 PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
241 pCall->enmFunction = a_enmFunction; \
242 pCall->cbOpcode = IEM_GET_INSTR_LEN(pVCpu); \
243 pCall->auParams[0] = a_uArg0; \
244 pCall->auParams[1] = a_uArg1; \
245 pCall->auParams[2] = a_uArg2; \
246 } while (0)
247
248
249/*
250 * IEM_MC_DEFER_TO_CIMPL_0 is easily wrapped up.
251 *
252 * Doing so will also take care of IEMOP_RAISE_DIVIDE_ERROR, IEMOP_RAISE_INVALID_LOCK_PREFIX,
253 * IEMOP_RAISE_INVALID_OPCODE and their users.
254 */
255#undef IEM_MC_DEFER_TO_CIMPL_0
256#define IEM_MC_DEFER_TO_CIMPL_0(a_pfnCImpl) iemThreadedRecompilerMcDeferToCImpl0(pVCpu, a_pfnCImpl)
257
258typedef IEM_CIMPL_DECL_TYPE_0(FNIEMCIMPL0);
259typedef FNIEMCIMPL0 *PFNIEMCIMPL0;
260
261DECLINLINE(VBOXSTRICTRC) iemThreadedRecompilerMcDeferToCImpl0(PVMCPUCC pVCpu, PFNIEMCIMPL0 pfnCImpl)
262{
263 return pfnCImpl(pVCpu, IEM_GET_INSTR_LEN(pVCpu));
264}
265
266/** @todo deal with IEM_MC_DEFER_TO_CIMPL_1, IEM_MC_DEFER_TO_CIMPL_2 and
267 * IEM_MC_DEFER_TO_CIMPL_3 as well. */
268
269/*
270 * Include the "annotated" IEMAllInstructions*.cpp.h files.
271 */
272#include "IEMThreadedInstructions.cpp.h"
273
274
275
276/*
277 * Real code.
278 */
279
280static VBOXSTRICTRC iemThreadedCompile(PVMCCV pVM, PVMCPUCC pVCpu)
281{
282 RT_NOREF(pVM, pVCpu, pTb);
283 return VERR_NOT_IMPLEMENTED;
284}
285
286
287static VBOXSTRICTRC iemThreadedCompileLongJumped(PVMCCV pVM, PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict)
288{
289 RT_NOREF(pVM, pVCpu);
290 return rcStrict;
291}
292
293
294static PIEMTB iemThreadedTbLookup(PVMCCV pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysPC, uint64_t uPc)
295{
296 RT_NOREF(pVM, pVCpu, GCPhysPC, uPc);
297 return NULL;
298}
299
300
301static VBOXSTRICTRC iemThreadedTbExec(PVMCCV pVM, PVMCPUCC pVCpu, PIEMTB pTb)
302{
303 RT_NOREF(pVM, pVCpu, pTb);
304 return VERR_NOT_IMPLEMENTED;
305}
306
307
308/**
309 * This is called when the PC doesn't match the current pbInstrBuf.
310 */
311static uint64_t iemGetPcWithPhysAndCodeMissed(PVMCPUCC pVCpu, uint64_t const uPc, PRTGCPHYS pPhys)
312{
313 /** @todo see iemOpcodeFetchBytesJmp */
314 pVCpu->iem.s.pbInstrBuf = NULL;
315
316 pVCpu->iem.s.offInstrNextByte = 0;
317 pVCpu->iem.s.offCurInstrStart = 0;
318 pVCpu->iem.s.cbInstrBuf = 0;
319 pVCpu->iem.s.cbInstrBufTotal = 0;
320
321}
322
323/** @todo need private inline decl for throw/nothrow matching IEM_WITH_SETJMP? */
324DECL_INLINE_THROW(uint64_t) iemGetPcWithPhysAndCode(PVMCPUCC pVCpu, PRTGCPHYS pPhys)
325{
326 Assert(pVCpu->cpum.GstCtx.cs.u64Base == 0 || pVCpu->iem.s.enmCpuMode != IEMMODE_64BIT);
327 uint64_t const uPc = pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base;
328 if (pVCpu->iem.s.pbInstrBuf)
329 {
330 uint64_t off = uPc - pVCpu->iem.s.uInstrBufPc;
331 if (off < pVCpu->iem.s.cbInstrBufTotal)
332 {
333 pVCpu->iem.s.offInstrNextByte = (uint32_t)off;
334 pVCpu->iem.s.offCurInstrStart = (uint16_t)off;
335 if ((uint16_t)off + 15 <= pVCpu->iem.s.cbInstrBufTotal)
336 pVCpu->iem.s.cbInstrBuf = (uint16_t)off + 15;
337 else
338 pVCpu->iem.s.cbInstrBuf = pVCpu->iem.s.cbInstrBufTotal;
339
340 *pPhys = pVCpu->iem.s.GCPhysInstrBuf + off;
341 return uPc;
342 }
343 }
344 return iemGetPcWithPhysAndCodeMissed(pVCpu, uPc, pPhys);
345}
346
347
348VMMDECL(VBOXSTRICTRC) IEMExecRecompilerThreaded(PVMCC pVM, PVMCPUCC pVCpu)
349{
350 /*
351 * Run-loop.
352 *
353 * If we're using setjmp/longjmp we combine all the catching here to avoid
354 * having to call setjmp for each block we're executing.
355 */
356 for (;;)
357 {
358 PIEMTB pTb = NULL;
359 VBOXSTRICTRC rcStrict;
360#ifdef IEM_WITH_SETJMP
361 IEM_TRY_SETJMP(pVCpu, rcStrict)
362#endif
363 {
364 for (;;)
365 {
366 /* Translate PC to physical address, we'll need this for both lookup and compilation. */
367 RTGCPHYS GCPhysPC;
368 uint64_t const uPC = iemGetPcWithPhysAndCode(pVCpu, &GCPhysPC);
369
370 pTb = iemThreadedTbLookup(pVM, pVCpu, GCPhysPC, uPc);
371 if (pTb)
372 rcStrict = iemThreadedTbExec(pVM, pVCpu, pTb);
373 else
374 rcStrict = iemThreadedCompile(pVM, pVCpu, GCPhysPC, uPc);
375 if (rcStrict == VINF_SUCCESS)
376 { /* likely */ }
377 else
378 return rcStrict;
379 }
380 }
381#ifdef IEM_WITH_SETJMP
382 IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
383 {
384 pVCpu->iem.s.cLongJumps++;
385 if (pTb)
386 return rcStrict;
387 return iemThreadedCompileLongJumped(pVM, pVCpu, rcStrict);
388 }
389 IEM_CATCH_LONGJMP_END(pVCpu);
390#endif
391 }
392}
393
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