VirtualBox

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

Last change on this file since 100111 was 100109, checked in by vboxsync, 18 months ago

VMM/IEM: Make it compile and link again with VBOX_WITH_IEM_RECOMPILER=1. bugref:10369

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.5 KB
Line 
1/* $Id: IEMAllInstructionsThreadedRecompiler.cpp 100109 2023-06-07 20:21:40Z 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
127
128/**
129 * Translation block.
130 */
131typedef struct IEMTB
132{
133 /** Next block with the same hash table entry. */
134 PIEMTB volatile pNext;
135 /** List on the local VCPU for blocks. */
136 RTLISTNODE LocalList;
137
138 /** @name What uniquely identifies the block.
139 * @{ */
140 RTGCPHYS GCPhysPc;
141 uint64_t uPc;
142 uint32_t fFlags;
143 union
144 {
145 struct
146 {
147 /** The CS base. */
148 uint32_t uCsBase;
149 /** The CS limit (UINT32_MAX for 64-bit code). */
150 uint32_t uCsLimit;
151 /** The CS selector value. */
152 uint16_t CS;
153 /**< Relevant X86DESCATTR_XXX bits. */
154 uint16_t fAttr;
155 } x86;
156 };
157 /** @} */
158
159 /** Number of bytes of opcodes covered by this block.
160 * @todo Support discontiguous chunks of opcodes in same block, though maybe
161 * restrict to the initial page or smth. */
162 uint32_t cbPC;
163
164 union
165 {
166 struct
167 {
168 /** Number of calls in paCalls. */
169 uint32_t cCalls;
170 /** Number of calls allocated. */
171 uint32_t cAllocated;
172 /** The call sequence table. */
173 PIEMTHRDEDCALLENTRY paCalls;
174 } Thrd;
175 };
176
177
178} IEMTB;
179
180
181/*********************************************************************************************************************************
182* Defined Constants And Macros *
183*********************************************************************************************************************************/
184#define g_apfnOneByteMap g_apfnIemThreadedRecompilerOneByteMap
185
186
187#undef IEM_MC_CALC_RM_EFF_ADDR
188#ifndef IEM_WITH_SETJMP
189# define IEM_MC_CALC_RM_EFF_ADDR(a_GCPtrEff, bRm, cbImm) \
190 uint64_t uEffAddrInfo; \
191 IEM_MC_RETURN_ON_FAILURE(iemOpHlpCalcRmEffAddrJmpEx(pVCpu, (bRm), (cbImm), &(a_GCPtrEff), &uEffAddrInfo))
192#else
193# define IEM_MC_CALC_RM_EFF_ADDR(a_GCPtrEff, bRm, cbImm) \
194 uint64_t uEffAddrInfo; \
195 ((a_GCPtrEff) = iemOpHlpCalcRmEffAddrJmpEx(pVCpu, (bRm), (cbImm), &uEffAddrInfo))
196#endif
197
198#define IEM_MC2_EMIT_CALL_1(a_enmFunction, a_uArg0) do { \
199 IEMTHREADEDFUNCS const enmFunctionCheck = a_enmFunction; RT_NOREF(enmFunctionCheck); \
200 uint64_t const uArg0Check = (a_uArg0); RT_NOREF(uArg0Check); \
201 \
202 PIEMTB const pTb = pVCpu->iem.s.pCurTbR3; \
203 PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
204 pCall->enmFunction = a_enmFunction; \
205 pCall->cbOpcode = IEM_GET_INSTR_LEN(pVCpu); \
206 pCall->auParams[0] = a_uArg0; \
207 pCall->auParams[1] = 0; \
208 pCall->auParams[2] = 0; \
209 } while (0)
210#define IEM_MC2_EMIT_CALL_2(a_enmFunction, a_uArg0, a_uArg1) do { \
211 IEMTHREADEDFUNCS const enmFunctionCheck = a_enmFunction; RT_NOREF(enmFunctionCheck); \
212 uint64_t const uArg0Check = (a_uArg0); RT_NOREF(uArg0Check); \
213 uint64_t const uArg1Check = (a_uArg1); RT_NOREF(uArg1Check); \
214 \
215 PIEMTB const pTb = pVCpu->iem.s.pCurTbR3; \
216 PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
217 pCall->enmFunction = a_enmFunction; \
218 pCall->cbOpcode = IEM_GET_INSTR_LEN(pVCpu); \
219 pCall->auParams[0] = a_uArg0; \
220 pCall->auParams[1] = a_uArg1; \
221 pCall->auParams[2] = 0; \
222 } while (0)
223#define IEM_MC2_EMIT_CALL_3(a_enmFunction, a_uArg0, a_uArg1, a_uArg2) do { \
224 IEMTHREADEDFUNCS const enmFunctionCheck = a_enmFunction; RT_NOREF(enmFunctionCheck); \
225 uint64_t const uArg0Check = (a_uArg0); RT_NOREF(uArg0Check); \
226 uint64_t const uArg1Check = (a_uArg1); RT_NOREF(uArg1Check); \
227 uint64_t const uArg2Check = (a_uArg2); RT_NOREF(uArg2Check); \
228 \
229 PIEMTB const pTb = pVCpu->iem.s.pCurTbR3; \
230 PIEMTHRDEDCALLENTRY const pCall = &pTb->Thrd.paCalls[pTb->Thrd.cCalls++]; \
231 pCall->enmFunction = a_enmFunction; \
232 pCall->cbOpcode = IEM_GET_INSTR_LEN(pVCpu); \
233 pCall->auParams[0] = a_uArg0; \
234 pCall->auParams[1] = a_uArg1; \
235 pCall->auParams[2] = a_uArg2; \
236 } while (0)
237
238
239/*
240 * IEM_MC_DEFER_TO_CIMPL_0 is easily wrapped up.
241 *
242 * Doing so will also take care of IEMOP_RAISE_DIVIDE_ERROR, IEMOP_RAISE_INVALID_LOCK_PREFIX,
243 * IEMOP_RAISE_INVALID_OPCODE and their users.
244 */
245#undef IEM_MC_DEFER_TO_CIMPL_0_RET
246#define IEM_MC_DEFER_TO_CIMPL_0_RET(a_fFlags, a_pfnCImpl) return iemThreadedRecompilerMcDeferToCImpl0(pVCpu, a_pfnCImpl)
247
248typedef IEM_CIMPL_DECL_TYPE_0(FNIEMCIMPL0);
249typedef FNIEMCIMPL0 *PFNIEMCIMPL0;
250
251DECLINLINE(VBOXSTRICTRC) iemThreadedRecompilerMcDeferToCImpl0(PVMCPUCC pVCpu, PFNIEMCIMPL0 pfnCImpl)
252{
253 return pfnCImpl(pVCpu, IEM_GET_INSTR_LEN(pVCpu));
254}
255
256/** @todo deal with IEM_MC_DEFER_TO_CIMPL_1, IEM_MC_DEFER_TO_CIMPL_2 and
257 * IEM_MC_DEFER_TO_CIMPL_3 as well. */
258
259/*
260 * Include the "annotated" IEMAllInstructions*.cpp.h files.
261 */
262#include "IEMThreadedInstructions.cpp.h"
263
264
265
266/*
267 * Real code.
268 */
269
270static VBOXSTRICTRC iemThreadedCompile(PVMCC pVM, PVMCPUCC pVCpu)
271{
272 RT_NOREF(pVM, pVCpu);
273 return VERR_NOT_IMPLEMENTED;
274}
275
276
277static VBOXSTRICTRC iemThreadedCompileLongJumped(PVMCC pVM, PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict)
278{
279 RT_NOREF(pVM, pVCpu);
280 return rcStrict;
281}
282
283
284static PIEMTB iemThreadedTbLookup(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysPC, uint64_t uPc)
285{
286 RT_NOREF(pVM, pVCpu, GCPhysPC, uPc);
287 return NULL;
288}
289
290
291static VBOXSTRICTRC iemThreadedTbExec(PVMCC pVM, PVMCPUCC pVCpu, PIEMTB pTb)
292{
293 RT_NOREF(pVM, pVCpu, pTb);
294 return VERR_NOT_IMPLEMENTED;
295}
296
297
298/**
299 * This is called when the PC doesn't match the current pbInstrBuf.
300 */
301static uint64_t iemGetPcWithPhysAndCodeMissed(PVMCPUCC pVCpu, uint64_t const uPc, PRTGCPHYS pPhys)
302{
303 /** @todo see iemOpcodeFetchBytesJmp */
304 pVCpu->iem.s.pbInstrBuf = NULL;
305
306 pVCpu->iem.s.offInstrNextByte = 0;
307 pVCpu->iem.s.offCurInstrStart = 0;
308 pVCpu->iem.s.cbInstrBuf = 0;
309 pVCpu->iem.s.cbInstrBufTotal = 0;
310
311 RT_NOREF(uPc, pPhys);
312 return 0;
313}
314
315
316/** @todo need private inline decl for throw/nothrow matching IEM_WITH_SETJMP? */
317DECL_INLINE_THROW(uint64_t) iemGetPcWithPhysAndCode(PVMCPUCC pVCpu, PRTGCPHYS pPhys)
318{
319 Assert(pVCpu->cpum.GstCtx.cs.u64Base == 0 || !IEM_IS_64BIT_CODE(pVCpu));
320 uint64_t const uPc = pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base;
321 if (pVCpu->iem.s.pbInstrBuf)
322 {
323 uint64_t off = uPc - pVCpu->iem.s.uInstrBufPc;
324 if (off < pVCpu->iem.s.cbInstrBufTotal)
325 {
326 pVCpu->iem.s.offInstrNextByte = (uint32_t)off;
327 pVCpu->iem.s.offCurInstrStart = (uint16_t)off;
328 if ((uint16_t)off + 15 <= pVCpu->iem.s.cbInstrBufTotal)
329 pVCpu->iem.s.cbInstrBuf = (uint16_t)off + 15;
330 else
331 pVCpu->iem.s.cbInstrBuf = pVCpu->iem.s.cbInstrBufTotal;
332
333 *pPhys = pVCpu->iem.s.GCPhysInstrBuf + off;
334 return uPc;
335 }
336 }
337 return iemGetPcWithPhysAndCodeMissed(pVCpu, uPc, pPhys);
338}
339
340
341VMMDECL(VBOXSTRICTRC) IEMExecRecompilerThreaded(PVMCC pVM, PVMCPUCC pVCpu)
342{
343 /*
344 * Init the execution environment.
345 */
346 iemInitExec(pVCpu, 0 /*fExecOpts*/);
347
348 /*
349 * Run-loop.
350 *
351 * If we're using setjmp/longjmp we combine all the catching here to avoid
352 * having to call setjmp for each block we're executing.
353 */
354 for (;;)
355 {
356 PIEMTB pTb = NULL;
357 VBOXSTRICTRC rcStrict;
358#ifdef IEM_WITH_SETJMP
359 IEM_TRY_SETJMP(pVCpu, rcStrict)
360#endif
361 {
362 for (;;)
363 {
364 /* Translate PC to physical address, we'll need this for both lookup and compilation. */
365 RTGCPHYS GCPhysPc;
366 uint64_t const uPc = iemGetPcWithPhysAndCode(pVCpu, &GCPhysPc);
367
368 pTb = iemThreadedTbLookup(pVM, pVCpu, GCPhysPc, uPc);
369 if (pTb)
370 rcStrict = iemThreadedTbExec(pVM, pVCpu, pTb);
371 else
372 rcStrict = iemThreadedCompile(pVM, pVCpu /*, GCPhysPc, uPc*/);
373 if (rcStrict == VINF_SUCCESS)
374 { /* likely */ }
375 else
376 return rcStrict;
377 }
378 }
379#ifdef IEM_WITH_SETJMP
380 IEM_CATCH_LONGJMP_BEGIN(pVCpu, rcStrict);
381 {
382 pVCpu->iem.s.cLongJumps++;
383 if (pTb)
384 return rcStrict;
385 return iemThreadedCompileLongJumped(pVM, pVCpu, rcStrict);
386 }
387 IEM_CATCH_LONGJMP_END(pVCpu);
388#endif
389 }
390}
391
Note: See TracBrowser for help on using the repository browser.

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