VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/cpu/cidet-core.cpp@ 107381

Last change on this file since 107381 was 106061, checked in by vboxsync, 5 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 90.9 KB
Line 
1/* $Id: cidet-core.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * CPU Instruction Decoding & Execution Tests - Simple Instructions.
4 */
5
6/*
7 * Copyright (C) 2014-2024 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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Defined Constants And Macros *
40*********************************************************************************************************************************/
41#define CIDET_INSTR_TEST_OP_FLAG(a_pInstr, a_fFlag) \
42 ( ((a_pInstr)->afOperands[0] & (a_fFlag)) \
43 || ((a_pInstr)->afOperands[1] & (a_fFlag)) \
44 || ( (a_pInstr)->cOperands > 2 \
45 && ( ((a_pInstr)->afOperands[2] & (a_fFlag)) \
46 || ((a_pInstr)->afOperands[3] & (a_fFlag)) ) ) )
47
48#define CIDET_INSTR_TEST_OP_MASK_VALUE(a_pInstr, a_fMask, a_fValue) \
49 ( ((a_pInstr)->afOperands[0] & (a_fMask)) == (a_fValue) \
50 || ((a_pInstr)->afOperands[1] & (a_fMask)) == (a_fValue) \
51 || ( (a_pInstr)->cOperands > 2 \
52 && ( ((a_pInstr)->afOperands[2] & (a_fMask)) == (a_fValue) \
53 || ((a_pInstr)->afOperands[3] & (a_fMask)) == (a_fValue) ) ) )
54
55/** @def CIDET_DPRINTF
56 * Debug printf. */
57#if 1 //def DEBUG_bird
58# define CIDET_DPRINTF(a) do { RTPrintf a; } while (0)
59# define CIDET_DPRINTF_ENABLED
60#else
61# define CIDET_DPRINTF(a) do { } while (0)
62#endif
63
64/** @def CIDET_DEBUG_DISAS
65 * Enables instruction disassembly. */
66#if defined(DOXYGEN_RUNNING)
67# define CIDET_DEBUG_DISAS 1
68#endif
69
70
71/*********************************************************************************************************************************
72* Header Files *
73*********************************************************************************************************************************/
74#include "cidet.h"
75
76#include <iprt/assert.h>
77#include <iprt/rand.h>
78#include <iprt/param.h>
79#include <iprt/string.h>
80#include <iprt/errcore.h>
81#if defined(CIDET_DPRINTF_ENABLED) || defined(CIDET_DEBUG_DISAS)
82# include <VBox/dis.h>
83# include <iprt/stream.h>
84#endif
85
86
87/*********************************************************************************************************************************
88* Global Variables *
89*********************************************************************************************************************************/
90/** For translating CIDET_OF_Z_XXX values (after shifting). */
91uint16_t const g_acbCidetOfSizes[] =
92{
93 /* [CIDET_OF_Z_NONE] = */ 0,
94 /* [CIDET_OF_Z_BYTE] = */ 1,
95 /* [CIDET_OF_Z_WORD] = */ 2,
96 /* [CIDET_OF_Z_DWORD] = */ 4,
97 /* [CIDET_OF_Z_QWORD] = */ 8,
98 /* [CIDET_OF_Z_TBYTE] = */ 10,
99 /* [CIDET_OF_Z_OWORD] = */ 16,
100 /* [CIDET_OF_Z_YWORD] = */ 32,
101 /* [CIDET_OF_Z_ZWORD] = */ 64,
102 /* [CIDET_OF_Z_VAR_WDQ] = */ UINT16_MAX,
103 /* [0xa] = */ 0,
104 /* [0xb] = */ 0,
105 /* [0xc] = */ 0,
106 /* [0xd] = */ 0,
107 /* [0xe] = */ 0,
108 /* [CIDET_OF_Z_SPECIAL] = */ UINT16_MAX - 1,
109};
110
111
112/** Converts operand sizes in bytes to 64-bit masks. */
113static const uint64_t g_au64ByteSizeToMask[] =
114{
115 UINT64_C(0x0000000000000000),
116 UINT64_C(0x00000000000000ff),
117 UINT64_C(0x000000000000ffff),
118 UINT64_C(0x0000000000ffffff),
119 UINT64_C(0x00000000ffffffff),
120 UINT64_C(0x000000ffffffffff),
121 UINT64_C(0x0000ffffffffffff),
122 UINT64_C(0x00ffffffffffffff),
123 UINT64_C(0xffffffffffffffff),
124};
125
126/** Converts operand sizes in bytes to 64-bit signed max values. */
127static const int64_t g_ai64ByteSizeToMax[] =
128{
129 INT64_C(0x0000000000000000),
130 INT64_C(0x000000000000007f),
131 INT64_C(0x0000000000007fff),
132 INT64_C(0x00000000007fffff),
133 INT64_C(0x000000007fffffff),
134 INT64_C(0x0000007fffffffff),
135 INT64_C(0x00007fffffffffff),
136 INT64_C(0x007fffffffffffff),
137 INT64_C(0x7fffffffffffffff),
138};
139
140
141static bool CidetInstrHasMrmMemOperand(PCCIDETINSTR pInstr)
142{
143 return CIDET_INSTR_TEST_OP_FLAG(pInstr, CIDET_OF_M_RM_ONLY_M);
144}
145
146
147static bool CidetInstrHasMrmRegOperand(PCCIDETINSTR pInstr)
148{
149 return CIDET_INSTR_TEST_OP_FLAG(pInstr, CIDET_OF_M_RM_ONLY_R);
150}
151
152
153static bool CidetInstrRespondsToOperandSizePrefixes(PCCIDETINSTR pInstr)
154{
155 return CIDET_INSTR_TEST_OP_MASK_VALUE(pInstr, CIDET_OF_Z_MASK, CIDET_OF_Z_VAR_WDQ);
156}
157
158
159
160
161int CidetCoreInit(PCIDETCORE pThis, RTRAND hRand)
162{
163 AssertPtr(pThis);
164 AssertPtr(hRand);
165
166 RT_ZERO(*pThis);
167 pThis->u32Magic = CIDETCORE_MAGIC;
168 pThis->hRand = hRand;
169 return VINF_SUCCESS;
170}
171
172
173void CidetCoreDelete(PCIDETCORE pThis)
174{
175 AssertPtr(pThis); Assert(pThis->u32Magic == CIDETCORE_MAGIC);
176
177 RTRandAdvDestroy(pThis->hRand);
178 RT_ZERO(*pThis);
179}
180
181
182/**
183 * Report a test failure via CIDET::pfnFailure
184 *
185 * @returns false
186 * @param pThis Pointer to the core structure.
187 * @param pszFormat Format string containing failure details.
188 * @param va Arguments referenced in @a pszFormat.
189 */
190static int CidetCoreSetErrorV(PCIDETCORE pThis, const char *pszFormat, va_list va)
191{
192 pThis->pfnFailure(pThis, pszFormat, va);
193 return false;
194}
195
196
197/**
198 * Report a test failure via CIDET::pfnFailure
199 *
200 * @returns false
201 * @param pThis Pointer to the core structure.
202 * @param pszFormat Format string containing failure details.
203 * @param ... Arguments referenced in @a pszFormat.
204 */
205static bool CidetCoreSetError(PCIDETCORE pThis, const char *pszFormat, ...)
206{
207 va_list va;
208 va_start(va, pszFormat);
209 CidetCoreSetErrorV(pThis, pszFormat, va);
210 va_end(va);
211 return false;
212}
213
214
215/**
216 * Get a signed random number, with a given number of significant bytes.
217 *
218 * @returns Random number.
219 * @param pThis Pointer to the core structure.
220 * @param cbSignificant The number of significant bytes.
221 */
222static int64_t CidetCoreGetRandS64(PCIDETCORE pThis, uint8_t cbSignificant)
223{
224 int64_t iVal = RTRandAdvS64(pThis->hRand);
225 switch (cbSignificant)
226 {
227 case 1: return (int8_t)iVal;
228 case 2: return (int16_t)iVal;
229 case 4: return (int32_t)iVal;
230 case 8: return iVal;
231 default:
232 AssertReleaseFailed();
233 return iVal;
234 }
235}
236
237
238/**
239 * Get an unsigned random number, with a given number of significant bytes.
240 *
241 * @returns Random number.
242 * @param pThis Pointer to the core structure.
243 * @param cbSignificant The number of significant bytes.
244 */
245static uint64_t CidetCoreGetRandU64(PCIDETCORE pThis, uint8_t cbSignificant)
246{
247 Assert(cbSignificant == 1 || cbSignificant == 2 || cbSignificant == 4 || cbSignificant == 8);
248
249 uint64_t uVal = RTRandAdvU64(pThis->hRand);
250 uVal &= g_au64ByteSizeToMask[cbSignificant];
251
252 return uVal;
253}
254
255
256
257static void CidetCoreInitializeCtxTemplate(PCIDETCORE pThis)
258{
259 pThis->InTemplateCtx.rip = UINT64_MAX;
260 pThis->InTemplateCtx.rfl = X86_EFL_1 | X86_EFL_ID | X86_EFL_IF;
261
262 unsigned i = RT_ELEMENTS(pThis->InTemplateCtx.aGRegs);
263 if (CIDETMODE_IS_LM(pThis->bMode))
264 while (i-- > 0)
265 pThis->InTemplateCtx.aGRegs[i] = UINT64_C(0x3fefcc00daba005d)
266 | ((uint64_t)i << 32)
267 | ((uint32_t)i << 8);
268 else
269 while (i-- > 0)
270 pThis->InTemplateCtx.aGRegs[i] = UINT64_C(0xfada009b)
271 | ((uint32_t)i << 12)
272 | ((uint32_t)i << 8);
273 i = RT_ELEMENTS(pThis->InTemplateCtx.aSRegs);
274 while (i-- > 0)
275 pThis->InTemplateCtx.aSRegs[i] = 0; /* Front end sets these afterwards. */
276 pThis->InTemplateCtx.cr2 = 0;
277#ifndef CIDET_REDUCED_CTX
278 pThis->InTemplateCtx.tr = 0;
279 pThis->InTemplateCtx.ldtr = 0;
280 pThis->InTemplateCtx.cr0 = 0;
281 pThis->InTemplateCtx.cr3 = 0;
282 pThis->InTemplateCtx.cr4 = 0;
283 pThis->InTemplateCtx.cr8 = 0;
284#endif
285 pThis->InTemplateCtx.fIgnoredRFlags = 0;
286 pThis->InTemplateCtx.uXcpt = UINT32_MAX;
287 pThis->InTemplateCtx.uErr = UINT64_MAX;
288 pThis->InTemplateCtx.fTrickyStack = false;
289}
290
291
292/**
293 * Sets the target mode.
294 *
295 * Caller must set up default selector values after calling this function.
296 *
297 * @returns VBox status code.
298 * @param pThis Pointer to the core structure.
299 * @param bMode The new mode.
300 */
301int CidetCoreSetTargetMode(PCIDETCORE pThis, uint8_t bMode)
302{
303 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == CIDETCORE_MAGIC, VERR_INVALID_HANDLE);
304 switch (bMode)
305 {
306 //case CIDETMODE_RM:
307 //case CIDETMODE_PE_16:
308 //case CIDETMODE_PE_32:
309 //case CIDETMODE_PE_V86:
310 //case CIDETMODE_PP_16:
311 case CIDETMODE_PP_32:
312 //case CIDETMODE_PP_V86:
313 //case CIDETMODE_PAE_16:
314 case CIDETMODE_PAE_32:
315 //case CIDETMODE_PAE_V86:
316 //case CIDETMODE_LM_S16:
317 //case CIDETMODE_LM_32:
318 case CIDETMODE_LM_64:
319 break;
320 default:
321 return VERR_NOT_IMPLEMENTED;
322 }
323 pThis->bMode = bMode;
324 CidetCoreInitializeCtxTemplate(pThis);
325 return VINF_SUCCESS;
326}
327
328#if 0 /* unused */
329static bool CidetCoreIsEncodingCompatibleWithInstruction(PCIDETCORE pThis)
330{
331 RT_NOREF_PV(pThis);
332 return true;
333}
334#endif
335
336/**
337 * Selects the next address size mode.
338 *
339 * @returns @c true if done, @c false if the next wheel needs to be moved.
340 * @param pThis The core state structure.
341 */
342static bool cidetCoreSetupNextBaseEncoding_AddressSize(PCIDETCORE pThis)
343{
344 if (pThis->fAddrSizePrf)
345 {
346 /*
347 * Reset to default.
348 */
349 pThis->cbAddrMode = CIDETMODE_GET_BYTE_COUNT(pThis->bMode);
350 pThis->fAddrSizePrf = false;
351 }
352 else
353 {
354 /*
355 * The other addressing size.
356 */
357 if (CIDETMODE_IS_64BIT(pThis->bMode))
358 pThis->cbAddrMode = 4;
359 else if (CIDETMODE_IS_32BIT(pThis->bMode))
360 pThis->cbAddrMode = 2;
361 else
362 {
363 AssertRelease(CIDETMODE_IS_16BIT(pThis->bMode));
364 pThis->cbAddrMode = 2;
365 }
366 pThis->fAddrSizePrf = true;
367 }
368 return pThis->fAddrSizePrf;
369}
370
371
372/**
373 * Selects the first REG encoding.
374 *
375 * @param pThis The core state structure.
376 */
377static void cidetCoreSetupFirstBaseEncoding_MrmReg(PCIDETCORE pThis)
378{
379 pThis->aOperands[pThis->idxMrmRegOp].iReg = 0;
380 pThis->aOperands[pThis->idxMrmRegOp].fIsMem = false;
381 pThis->aOperands[pThis->idxMrmRegOp].fIsRipRelative = false;
382 pThis->aOperands[pThis->idxMrmRegOp].fIsHighByteRegister = false;
383 pThis->aOperands[pThis->idxMrmRegOp].cbMemDisp = 0;
384 pThis->aOperands[pThis->idxMrmRegOp].iMemBaseReg = UINT8_MAX;
385 pThis->aOperands[pThis->idxMrmRegOp].iMemIndexReg = UINT8_MAX;
386 pThis->aOperands[pThis->idxMrmRegOp].uMemScale = 1;
387 pThis->aOperands[pThis->idxMrmRegOp].iEffSeg = UINT8_MAX;
388 pThis->bModRm &= ~X86_MODRM_REG_MASK;
389 pThis->fRexR = false;
390}
391
392
393/**
394 * Selects the next REG (ModR/M) encoding.
395 *
396 * @returns @c true if done, @c false if the next wheel needs to be moved.
397 * @param pThis The core state structure.
398 * @param iReg The value of MODRM.REG /w REX.R applied.
399 */
400static bool cidetCoreSetupNextBaseEncoding_MrmReg(PCIDETCORE pThis, uint8_t iReg)
401{
402 Assert(pThis->idxMrmRegOp < RT_ELEMENTS(pThis->aOperands) && !pThis->aOperands[pThis->idxMrmRegOp].fIsMem);
403 Assert(iReg < 16);
404
405 /*
406 * Clear the collision flags here because of the byte register kludge.
407 */
408 pThis->fHasRegCollisionDirect = false;
409 pThis->fHasRegCollisionMemBase = false;
410 pThis->fHasRegCollisionMemIndex = false;
411 pThis->fHasRegCollisionMem = false;
412
413 /*
414 * Clear the REX prefix and high byte register tracking too. ASSUMES MrmReg is after MrmRmMod.
415 */
416 Assert(!pThis->fNoRexPrefixMrmRm);
417 Assert(!pThis->fHasHighByteRegInMrmRm);
418 pThis->fNoRexPrefixMrmReg = false;
419 pThis->fNoRexPrefix = false;
420 pThis->fHasHighByteRegInMrmReg = false;
421 pThis->aOperands[pThis->idxMrmRegOp].fIsHighByteRegister = false;
422
423 /*
424 * Special kludge for ah, ch, dh, bh, spl, bpl, sil, and dil.
425 * Needs extra care in 64-bit mode and special collision detection code.
426 */
427 CIDET_DPRINTF(("aOperands[%u].cb=%u fGpr=%u iReg=%d fRex=%d fRexW=%u fRexX=%u fRexB=%u fRexR=%d\n",
428 pThis->idxMrmRegOp, pThis->aOperands[pThis->idxMrmRegOp].cb, CIDET_OF_K_IS_GPR(pThis->fMrmRegOp), iReg,
429 pThis->fRex, pThis->fRexW, pThis->fRexX, pThis->fRexB, pThis->fRexR));
430 if ( pThis->aOperands[pThis->idxMrmRegOp].cb == 1
431 && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp)
432 && iReg >= 3
433 && ( iReg <= 6
434 || (CIDETMODE_IS_64BIT(pThis->bMode) && iReg == 7 && !pThis->fRex)) )
435
436 {
437 if (!pThis->fRex && iReg >= 4 && CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fNoRexPrefix)
438 {
439 /* The AMD64 low variants: spl, bpl, sil and dil. */
440 pThis->fRex = true;
441 pThis->fHasStackRegInMrmReg = iReg == X86_GREG_xSP;
442
443 /* Check for collisions. */
444 if (pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands))
445 {
446 Assert(!pThis->fHasHighByteRegInMrmRm);
447 if (!pThis->aOperands[pThis->idxMrmRmOp].fIsMem)
448 pThis->fHasRegCollisionDirect = CIDET_OF_K_IS_GPR(pThis->fMrmRmOp)
449 && iReg == pThis->aOperands[pThis->idxMrmRmOp].iReg;
450 else
451 {
452 Assert(!pThis->fUsesVexIndexRegs || pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg == UINT8_MAX);
453
454 pThis->fHasRegCollisionMemBase = iReg == pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg;
455 pThis->fHasRegCollisionMemIndex = iReg == pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg;
456 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase || pThis->fHasRegCollisionMemIndex;
457 }
458 }
459 }
460 else
461 {
462 /* Next register: ah, ch, dh and bh. */
463 iReg++;
464 pThis->aOperands[pThis->idxMrmRegOp].iReg = iReg;
465 pThis->bModRm &= ~X86_MODRM_REG_MASK;
466 pThis->bModRm |= (iReg & X86_MODRM_REG_SMASK) << X86_MODRM_REG_SHIFT;
467 pThis->fRex = false;
468 pThis->fRexR = false;
469 pThis->fNoRexPrefixMrmReg = true;
470 pThis->fNoRexPrefix = true;
471 pThis->fHasHighByteRegInMrmReg = true;
472 pThis->fHasStackRegInMrmReg = false;
473 pThis->aOperands[pThis->idxMrmRegOp].fIsHighByteRegister = true;
474 Assert(!pThis->fRexW); Assert(!pThis->fRexX); Assert(!pThis->fRexB);
475
476 /* Check for collisions. */
477 if (pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands))
478 {
479 if (!pThis->aOperands[pThis->idxMrmRmOp].fIsMem)
480 pThis->fHasRegCollisionDirect = CIDET_OF_K_IS_GPR(pThis->fMrmRmOp)
481 && ( ( pThis->aOperands[pThis->idxMrmRmOp].cb == 1
482 && iReg == pThis->aOperands[pThis->idxMrmRmOp].iReg
483 && pThis->fHasHighByteRegInMrmRm)
484 || ( pThis->aOperands[pThis->idxMrmRmOp].cb > 1
485 && iReg - 4 == pThis->aOperands[pThis->idxMrmRmOp].iReg));
486 else
487 {
488 Assert(!pThis->fUsesVexIndexRegs || pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg == UINT8_MAX);
489
490 pThis->fHasRegCollisionMemBase = iReg - 4 == pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg;
491 pThis->fHasRegCollisionMemIndex = iReg - 4 == pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg;
492 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase || pThis->fHasRegCollisionMemIndex;
493 }
494 }
495 }
496 return true;
497 }
498
499 Assert(!pThis->fRex || (iReg == 7 && CIDETMODE_IS_64BIT(pThis->bMode)));
500 pThis->fRex = false;
501
502 /*
503 * Next register.
504 */
505 iReg = (iReg + 1) & (CIDETMODE_IS_64BIT(pThis->bMode) ? 15 : 7);
506
507 pThis->aOperands[pThis->idxMrmRegOp].iReg = iReg;
508 pThis->bModRm &= ~X86_MODRM_REG_MASK;
509 pThis->bModRm |= (iReg & X86_MODRM_REG_SMASK) << X86_MODRM_REG_SHIFT;
510 pThis->fRexR = iReg >= 8;
511 pThis->fHasStackRegInMrmReg = iReg == X86_GREG_xSP && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp);
512
513 /*
514 * Register collision detection.
515 */
516 if (pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands))
517 {
518 if (!pThis->aOperands[pThis->idxMrmRmOp].fIsMem)
519 pThis->fHasRegCollisionDirect = iReg == pThis->aOperands[pThis->idxMrmRmOp].iReg
520 && CIDET_OF_K_IS_SAME(pThis->fMrmRmOp, pThis->fMrmRegOp);
521 else if (CIDET_OF_K_IS_GPR(pThis->fMrmRegOp))
522 {
523 Assert(!pThis->fUsesVexIndexRegs || pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg == UINT8_MAX);
524 pThis->fHasRegCollisionMemBase = iReg == pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg;
525 pThis->fHasRegCollisionMemIndex = iReg == pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg;
526 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase || pThis->fHasRegCollisionMemIndex;
527 }
528 }
529 Assert(!pThis->fSib);
530
531 return iReg != 0;
532}
533
534
535/**
536 * Selects the next MOD & R/M encoding, 16-bit addressing variant.
537 *
538 * @param pThis The core state structure.
539 * @param iReg The value of MODRM.REG /w REX.R applied.
540 */
541static void cidetCoreSetupFirstBaseEncoding_MrmRmMod_16bit(PCIDETCORE pThis, uint8_t iReg)
542{
543 if (CidetInstrHasMrmRegOperand(pThis->pCurInstr))
544 {
545 pThis->aOperands[pThis->idxMrmRmOp].iReg = 0;
546 pThis->aOperands[pThis->idxMrmRmOp].fIsMem = false;
547 pThis->aOperands[pThis->idxMrmRmOp].fIsRipRelative = false;
548 pThis->aOperands[pThis->idxMrmRmOp].fIsHighByteRegister = false;
549 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 0;
550 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = UINT8_MAX;
551 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = UINT8_MAX;
552 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 1;
553 pThis->aOperands[pThis->idxMrmRmOp].iEffSeg = UINT8_MAX;
554 pThis->bModRm &= ~(X86_MODRM_RM_MASK | X86_MODRM_MOD_MASK);
555 pThis->bModRm |= 3 << X86_MODRM_MOD_SHIFT;
556 pThis->fRexB = false;
557 pThis->fRexX = false;
558 pThis->fHasMemoryOperand = false;
559 pThis->fHasRegCollisionDirect = iReg == 0
560 && CIDET_OF_K_IS_SAME(pThis->fMrmRmOp, pThis->fMrmRegOp);
561 pThis->fHasRegCollisionMem = false;
562 pThis->fHasRegCollisionMemBase = false;
563 pThis->fHasRegCollisionMemIndex = false;
564 pThis->fHasStackRegInMrmRmBase = false;
565 }
566 else
567 {
568 Assert(CidetInstrHasMrmMemOperand(pThis->pCurInstr));
569 pThis->aOperands[pThis->idxMrmRmOp].iReg = UINT8_MAX;
570 pThis->aOperands[pThis->idxMrmRmOp].fIsMem = true;
571 pThis->aOperands[pThis->idxMrmRmOp].fIsRipRelative = false;
572 pThis->aOperands[pThis->idxMrmRmOp].fIsHighByteRegister = false;
573 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 0;
574 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = X86_GREG_xBX;
575 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = X86_GREG_xSI;
576 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 1;
577 pThis->aOperands[pThis->idxMrmRmOp].iEffSeg = UINT8_MAX;
578 pThis->bModRm &= ~(X86_MODRM_RM_MASK | X86_MODRM_MOD_MASK);
579 pThis->fRexB = false;
580 pThis->fRexX = false;
581 pThis->fHasMemoryOperand = true;
582 pThis->fHasRegCollisionDirect = false;
583 iReg -= pThis->fHasHighByteRegInMrmReg * 4;
584 pThis->fHasRegCollisionMemBase = iReg == X86_GREG_xBX && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp);
585 pThis->fHasRegCollisionMemIndex = iReg == X86_GREG_xSI && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp);
586 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase || pThis->fHasRegCollisionMemIndex;
587 pThis->fHasStackRegInMrmRmBase = false;
588 }
589}
590
591
592/**
593 * Selects the next MOD & R/M encoding, 16-bit addressing variant.
594 *
595 * @returns @c true if done, @c false if the next wheel needs to be moved.
596 * @param pThis The core state structure.
597 * @param iReg The value of MODRM.REG /w REX.R applied.
598 */
599static bool cidetCoreSetupNextBaseEncoding_MrmRmMod_16bit(PCIDETCORE pThis, uint8_t iReg)
600{
601 AssertRelease(!pThis->fRexB);
602 AssertRelease(!pThis->fRexX);
603 uint8_t iRm = pThis->bModRm & X86_MODRM_RM_MASK;
604 uint8_t iMod = (pThis->bModRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK;
605 if (iMod == 3)
606 {
607 /*
608 * Register access mode.
609 */
610 Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && !pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
611 Assert(!pThis->fHasMemoryOperand);
612 Assert(!pThis->fHasRegCollisionMem);
613 Assert(!pThis->fHasRegCollisionMemBase);
614 Assert(!pThis->fHasRegCollisionMemIndex);
615 if (iRm < 7)
616 {
617 iRm++;
618 pThis->aOperands[pThis->idxMrmRmOp].iReg = iRm;
619 pThis->bModRm &= ~X86_MODRM_RM_MASK;
620 pThis->bModRm |= iRm;
621 pThis->fHasRegCollisionDirect = iRm == iReg
622 && CIDET_OF_K_IS_SAME(pThis->fMrmRmOp, pThis->fMrmRegOp);
623 pThis->fHasStackRegInMrmRmBase = iRm == X86_GREG_xSP && CIDET_OF_K_IS_GPR(pThis->fMrmRmOp);
624 return true;
625 }
626
627 /* If no memory modes, we're done. */
628 if (!CidetInstrHasMrmMemOperand(pThis->pCurInstr))
629 {
630 cidetCoreSetupFirstBaseEncoding_MrmRmMod_16bit(pThis, iReg);
631 return false;
632 }
633
634 /* Next mode: 16-bit memory addressing without displacement. */
635 pThis->aOperands[pThis->idxMrmRmOp].fIsMem = true;
636 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 0;
637 iMod = 0;
638 }
639 else
640 {
641 /*
642 * Memory access mode.
643 */
644 Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
645 Assert(pThis->fHasMemoryOperand);
646 if (iRm < 7)
647 {
648 iRm++;
649 switch (iRm)
650 {
651 case 1:
652 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = X86_GREG_xBX;
653 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = X86_GREG_xDI;
654 break;
655 case 2:
656 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = X86_GREG_xBP;
657 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = X86_GREG_xSI;
658 break;
659 case 3:
660 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = X86_GREG_xBP;
661 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = X86_GREG_xDI;
662 break;
663 case 4:
664 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = UINT8_MAX;
665 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = X86_GREG_xSI;
666 break;
667 case 5:
668 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = UINT8_MAX;
669 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = X86_GREG_xDI;
670 break;
671 case 6:
672 if (iMod == 0)
673 {
674 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 2;
675 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = UINT8_MAX;
676 }
677 else
678 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = X86_GREG_xBP;
679 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = UINT8_MAX;
680 break;
681 case 7:
682 if (iMod == 0)
683 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 0;
684 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = X86_GREG_xBX;
685 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = UINT8_MAX;
686 break;
687 default: AssertReleaseFailed();
688 }
689 pThis->bModRm &= ~X86_MODRM_RM_MASK;
690 pThis->bModRm |= iRm;
691 if (CIDET_OF_K_IS_GPR(pThis->fMrmRegOp))
692 {
693 iReg -= pThis->fHasHighByteRegInMrmReg * 4;
694 pThis->fHasRegCollisionMemBase = iReg == pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg;
695 pThis->fHasRegCollisionMemIndex = iReg == pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg;
696 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase || pThis->fHasRegCollisionMemIndex;
697 }
698 return true;
699 }
700
701 /* Last mode? */
702 if (iMod >= 2)
703 {
704 cidetCoreSetupFirstBaseEncoding_MrmRmMod_16bit(pThis, iReg);
705 return false;
706 }
707
708 /* Next memory addressing mode (if any). */
709 iMod++;
710 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp++;
711 }
712 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = X86_GREG_xBX;
713 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = X86_GREG_xSI;
714 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 1;
715 pThis->bModRm &= ~(X86_MODRM_RM_MASK | X86_MODRM_MOD_MASK);
716 pThis->bModRm |= iMod << X86_MODRM_MOD_SHIFT;
717 pThis->fHasMemoryOperand = true;
718 pThis->fHasRegCollisionDirect = false;
719 pThis->fHasStackRegInMrmRmBase = false;
720 if (CIDET_OF_K_IS_GPR(pThis->fMrmRmOp))
721 {
722 iReg -= pThis->fHasHighByteRegInMrmReg * 4;
723 pThis->fHasRegCollisionMemBase = iReg == X86_GREG_xBX;
724 pThis->fHasRegCollisionMemIndex = iReg == X86_GREG_xSI;
725 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase || pThis->fHasRegCollisionMemIndex;
726 }
727 return true;
728}
729
730
731/**
732 * Selects the first MOD & R/M encoding, 32-bit and 64-bit addressing variant.
733 *
734 * @param pThis The core state structure.
735 * @param iReg The value of MODRM.REG /w REX.R applied.
736 * @param f64Bit Set if 64-bit, clear if 32-bit.
737 */
738static void cidetCoreSetupFirstBaseEncoding_MrmRmMod_32bit64bit(PCIDETCORE pThis, uint8_t iReg, bool f64Bit)
739{
740 RT_NOREF_PV(f64Bit);
741 if (CidetInstrHasMrmRegOperand(pThis->pCurInstr))
742 {
743 pThis->aOperands[pThis->idxMrmRmOp].iReg = 0;
744 pThis->aOperands[pThis->idxMrmRmOp].fIsMem = false;
745 pThis->aOperands[pThis->idxMrmRmOp].fIsRipRelative = false;
746 pThis->aOperands[pThis->idxMrmRmOp].fIsHighByteRegister = false;
747 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 0;
748 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = UINT8_MAX;
749 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = UINT8_MAX;
750 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 1;
751 pThis->aOperands[pThis->idxMrmRmOp].iEffSeg = UINT8_MAX;
752 pThis->bModRm &= ~(X86_MODRM_RM_MASK | X86_MODRM_MOD_MASK);
753 pThis->bModRm |= 3 << X86_MODRM_MOD_SHIFT;
754 pThis->fRexB = false;
755 pThis->fRexX = false;
756 pThis->fHasMemoryOperand = false;
757 pThis->fHasRegCollisionDirect = iReg == 0
758 && CIDET_OF_K_IS_SAME(pThis->fMrmRmOp, pThis->fMrmRegOp);
759 pThis->fHasRegCollisionMem = false;
760 pThis->fHasRegCollisionMemBase = false;
761 pThis->fHasRegCollisionMemIndex = false;
762 pThis->fHasStackRegInMrmRmBase = false;
763 }
764 else
765 {
766 Assert(CidetInstrHasMrmMemOperand(pThis->pCurInstr));
767 pThis->aOperands[pThis->idxMrmRmOp].iReg = UINT8_MAX;
768 pThis->aOperands[pThis->idxMrmRmOp].fIsMem = true;
769 pThis->aOperands[pThis->idxMrmRmOp].fIsRipRelative = false;
770 pThis->aOperands[pThis->idxMrmRmOp].fIsHighByteRegister = false;
771 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 0;
772 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = 0;
773 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = UINT8_MAX;
774 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 1;
775 pThis->aOperands[pThis->idxMrmRmOp].iEffSeg = UINT8_MAX;
776 pThis->bModRm &= ~(X86_MODRM_RM_MASK | X86_MODRM_MOD_MASK);
777 pThis->fRexB = false;
778 pThis->fRexX = false;
779 pThis->fHasMemoryOperand = true;
780 pThis->fHasRegCollisionDirect = false;
781 pThis->fHasRegCollisionMemIndex = false;
782 pThis->fHasRegCollisionMemBase = iReg == pThis->fHasHighByteRegInMrmReg * 4 && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp);
783 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase;
784 pThis->fHasStackRegInMrmRmBase = false;
785 }
786}
787
788
789/**
790 * Selects the next MOD & R/M encoding, 32-bit and 64-bit addressing variant.
791 *
792 * @returns @c true if done, @c false if the next wheel needs to be moved.
793 * @param pThis The core state structure.
794 * @param iReg The value of MODRM.REG /w REX.R applied.
795 * @param f64Bit Set if 64-bit, clear if 32-bit.
796 */
797static bool cidetCoreSetupNextBaseEncoding_MrmRmMod_32bit64bit(PCIDETCORE pThis, uint8_t iReg, bool f64Bit)
798{
799 AssertRelease(!pThis->fRexX || CIDETMODE_IS_64BIT(pThis->bMode));
800 AssertRelease(!pThis->fRexB || CIDETMODE_IS_64BIT(pThis->bMode));
801 uint8_t iRm = (pThis->bModRm & X86_MODRM_RM_MASK) + pThis->fRexB * 8;
802 uint8_t iMod = (pThis->bModRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK;
803 if (iMod == 3)
804 {
805 /*
806 * Register access mode.
807 */
808 Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && !pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
809 Assert(!pThis->fHasMemoryOperand);
810 Assert(!pThis->fHasRegCollisionMem);
811 Assert(!pThis->fHasRegCollisionMemBase);
812 Assert(!pThis->fHasRegCollisionMemIndex);
813
814 if (CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fRexX && !pThis->fNoRexPrefix) /* should be ignored. */
815 {
816 pThis->fRexX = true;
817 return true;
818 }
819
820 /* Reset the byte register kludges variables. */
821 pThis->aOperands[pThis->idxMrmRmOp].fIsHighByteRegister = false;
822 pThis->fHasHighByteRegInMrmRm = false;
823 pThis->fNoRexPrefixMrmRm = false;
824 pThis->fNoRexPrefix = pThis->fNoRexPrefixMrmReg;
825
826 if (iRm < (CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fNoRexPrefix ? 15 : 7))
827 {
828 /*
829 * Byte register kludge.
830 */
831 if ( pThis->aOperands[pThis->idxMrmRmOp].cb == 1
832 && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp)
833 && iRm >= 3
834 && ( iRm <= 6
835 || (iRm == 7 && CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fRexX) ) )
836 {
837 if (!pThis->fRexX && iRm >= 4 && CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fNoRexPrefix)
838 {
839 /* The AMD64 low variants: spl, bpl, sil and dil. (Using fRexX here as REG covers fRex.) */
840 pThis->fRexX = true;
841 pThis->fHasRegCollisionDirect = CIDET_OF_K_IS_GPR(pThis->fMrmRegOp)
842 && iRm == iReg - pThis->fHasHighByteRegInMrmReg * 4;
843 pThis->fHasStackRegInMrmRmBase = iRm == X86_GREG_xSP && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp);
844 }
845 else
846 {
847 /* Next register: ah, ch, dh and bh. */
848 iRm++;
849 pThis->aOperands[pThis->idxMrmRmOp].iReg = iRm;
850 pThis->bModRm &= ~X86_MODRM_RM_MASK;
851 pThis->bModRm |= iRm & X86_MODRM_RM_MASK;
852 pThis->fRexB = false;
853 pThis->fRexX = false;
854 if (!pThis->fRexR && !pThis->fRexW && !pThis->fRex)
855 {
856 pThis->fNoRexPrefixMrmRm = true;
857 pThis->fNoRexPrefix = true;
858 pThis->fHasHighByteRegInMrmRm = true;
859 pThis->aOperands[pThis->idxMrmRmOp].fIsHighByteRegister = true;
860 pThis->fHasRegCollisionDirect = CIDET_OF_K_IS_GPR(pThis->fMrmRegOp)
861 && iRm - 4 == iReg - pThis->fHasHighByteRegInMrmReg * 4;
862 pThis->fHasStackRegInMrmRmBase = false;
863
864 }
865 else
866 {
867 /* Can't do the high stuff, so do the spl, bpl, sil and dil variation instead.
868 Note! We don't set the RexX yet since the base register or operand width holds it down. */
869 pThis->fHasRegCollisionDirect = CIDET_OF_K_IS_GPR(pThis->fMrmRegOp)
870 && iRm == iReg - pThis->fHasHighByteRegInMrmReg * 4;
871 pThis->fHasStackRegInMrmRmBase = iRm == X86_GREG_xSP && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp);
872 }
873 }
874 }
875 /*
876 * Normal register.
877 */
878 else
879 {
880 iRm++;
881 pThis->aOperands[pThis->idxMrmRmOp].iReg = iRm;
882 pThis->bModRm &= ~X86_MODRM_RM_MASK;
883 pThis->bModRm |= iRm & X86_MODRM_RM_MASK;
884 pThis->fRexB = iRm >= 8;
885 pThis->fRexX = false;
886 pThis->fHasRegCollisionDirect = iRm == iReg && CIDET_OF_K_IS_SAME(pThis->fMrmRmOp, pThis->fMrmRegOp);
887 pThis->fHasStackRegInMrmRmBase = iRm == X86_GREG_xSP && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp);
888 }
889 return true;
890 }
891
892 /* If no memory modes, we're done. */
893 if (!CidetInstrHasMrmMemOperand(pThis->pCurInstr))
894 {
895 cidetCoreSetupFirstBaseEncoding_MrmRmMod_32bit64bit(pThis, iReg, f64Bit);
896 return false;
897 }
898
899 /* Next mode: 32-bit/64-bit memory addressing without displacement. */
900 pThis->aOperands[pThis->idxMrmRmOp].fIsMem = true;
901 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 0;
902 iMod = 0;
903 }
904 else
905 {
906 /*
907 * Memory access mode.
908 */
909 Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
910 Assert(pThis->fHasMemoryOperand);
911 Assert(!pThis->fHasStackRegInMrmRmBase);
912 if (iRm < (CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fNoRexPrefix ? 15 : 7))
913 {
914 iRm++;
915 if (iRm == 12)
916 iRm++; /* Leave REX.B=1 to the next-sib-base function. */
917 if (iRm == 4)
918 {
919 /* SIB */
920 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = 0;
921 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = 0;
922 pThis->fSib = true;
923 pThis->bSib = 0;
924 }
925 else if ((iRm & 7) == 5 && iMod == 0)
926 {
927 /* Absolute or wrt rip addressing. */
928 pThis->aOperands[pThis->idxMrmRmOp].fIsRipRelative = CIDETMODE_IS_64BIT(pThis->bMode);
929 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = UINT8_MAX;
930 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = UINT8_MAX;
931 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 4;
932 }
933 else
934 {
935 if ((iRm & 7) == 6 && iMod == 0)
936 {
937 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 0;
938 pThis->aOperands[pThis->idxMrmRmOp].fIsRipRelative = false;
939 }
940 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = iRm;
941 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = UINT8_MAX;
942 }
943 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 1;
944 pThis->bModRm &= ~X86_MODRM_RM_MASK;
945 pThis->bModRm |= iRm & X86_MODRM_RM_MASK;
946 pThis->fRexB = iRm >= 8;
947 pThis->fRexX = false;
948 if (CIDET_OF_K_IS_GPR(pThis->fMrmRegOp))
949 {
950 iReg -= pThis->fHasHighByteRegInMrmReg * 4;
951 pThis->fHasRegCollisionMemBase = iReg == pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg;
952 pThis->fHasRegCollisionMemIndex = iReg == pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg;
953 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase || pThis->fHasRegCollisionMemIndex;
954 }
955 return true;
956 }
957
958 /* Last mode? */
959 if (iMod >= 2)
960 {
961 cidetCoreSetupFirstBaseEncoding_MrmRmMod_32bit64bit(pThis, iReg, f64Bit);
962 return false;
963 }
964
965 /* Next memory addressing mode (if any). */
966 iMod++;
967 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = iMod == 1 ? 1 : 4;
968 }
969 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = 0;
970 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = UINT8_MAX;
971 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 1;
972 pThis->bModRm &= ~(X86_MODRM_RM_MASK | X86_MODRM_MOD_MASK);
973 pThis->bModRm |= iMod << X86_MODRM_MOD_SHIFT;
974 pThis->fRexB = false;
975 pThis->fRexX = false;
976 pThis->fHasMemoryOperand = true;
977 pThis->fHasRegCollisionDirect = false;
978 pThis->fHasRegCollisionMemIndex = false;
979 pThis->fHasRegCollisionMemBase = iReg == pThis->fHasHighByteRegInMrmReg * 4
980 && CIDET_OF_K_IS_GPR(pThis->fMrmRmOp);
981 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase;
982 pThis->fHasStackRegInMrmRmBase = false;
983 return true;
984}
985
986
987/**
988 * Selects the next MOD & R/M encoding.
989 *
990 * @returns @c true if done, @c false if the next wheel needs to be moved.
991 * @param pThis The core state structure.
992 * @param iReg The value of MODRM.REG /w REX.R applied.
993 */
994static bool cidetCoreSetupNextBaseEncoding_MrmRmMod(PCIDETCORE pThis, uint8_t iReg)
995{
996 if (pThis->cbAddrMode == 2)
997 return cidetCoreSetupNextBaseEncoding_MrmRmMod_16bit(pThis, iReg);
998 if (pThis->cbAddrMode == 4)
999 return cidetCoreSetupNextBaseEncoding_MrmRmMod_32bit64bit(pThis, iReg, false);
1000 if (pThis->cbAddrMode == 8)
1001 return cidetCoreSetupNextBaseEncoding_MrmRmMod_32bit64bit(pThis, iReg, true);
1002 AssertReleaseFailedReturn(false);
1003}
1004
1005
1006
1007/**
1008 * Selects the next SIB base register (/ encoding).
1009 *
1010 * @returns @c true if done, @c false if the next wheel needs to be moved.
1011 * @param pThis The core state structure.
1012 * @param iReg The value of MODRM.REG /w REX.R applied.
1013 */
1014static bool cidetCoreSetupNextBaseEncoding_SibBase(PCIDETCORE pThis, uint8_t iReg)
1015{
1016 AssertRelease(!pThis->fRexB || CIDETMODE_IS_64BIT(pThis->bMode));
1017
1018 uint8_t iBase = (pThis->bSib & X86_SIB_BASE_MASK) + pThis->fRexB * 8;
1019 iBase = (iBase + 1) & (CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fNoRexPrefix ? 15 : 7);
1020
1021 if ((iBase & 7) == 5 && (pThis->bModRm & X86_MODRM_MOD_MASK) == 0)
1022 {
1023 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 4;
1024 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = UINT8_MAX;
1025 }
1026 else
1027 {
1028 if ((iBase & 7) == 6 && (pThis->bModRm & X86_MODRM_MOD_MASK) == 0)
1029 pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp = 0;
1030 pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg = iBase;
1031 }
1032 pThis->bSib &= ~X86_SIB_BASE_MASK;
1033 pThis->bSib |= iBase & X86_SIB_BASE_MASK;
1034 pThis->fRexB = iBase >= 8;
1035 pThis->fHasRegCollisionMemBase = pThis->aOperands[pThis->idxMrmRmOp].iMemBaseReg
1036 == iReg - pThis->fHasHighByteRegInMrmReg * 4
1037 && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp);
1038 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase || pThis->fHasRegCollisionMemIndex;
1039 pThis->fHasStackRegInMrmRmBase = iBase == X86_GREG_xSP;
1040
1041 return iBase != 0;
1042}
1043
1044
1045/**
1046 * Selects the next SIB index register (/ encoding).
1047 *
1048 * @returns @c true if done, @c false if the next wheel needs to be moved.
1049 * @param pThis The core state structure.
1050 * @param iReg The value of MODRM.REG /w REX.R applied.
1051 */
1052static bool cidetCoreSetupNextBaseEncoding_SibIndex(PCIDETCORE pThis, uint8_t iReg)
1053{
1054 AssertRelease(!pThis->fRexX || CIDETMODE_IS_64BIT(pThis->bMode));
1055 Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
1056
1057 uint8_t iIndex = ((pThis->bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) + pThis->fRexX * 8;
1058 iIndex = (iIndex + 1) & (CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fNoRexPrefix ? 15 : 7);
1059
1060 if (iIndex == 4 && !pThis->fUsesVexIndexRegs)
1061 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = UINT8_MAX;
1062 else
1063 pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg = iIndex;
1064 pThis->bSib &= ~X86_SIB_INDEX_MASK;
1065 pThis->bSib |= (iIndex & X86_SIB_INDEX_SMASK) << X86_SIB_INDEX_SHIFT;
1066 pThis->fRexX = iIndex >= 8;
1067 pThis->fHasRegCollisionMemIndex = pThis->aOperands[pThis->idxMrmRmOp].iMemIndexReg
1068 == iReg - pThis->fHasHighByteRegInMrmReg * 4
1069 && ( !pThis->fUsesVexIndexRegs
1070 ? CIDET_OF_K_IS_GPR(pThis->fMrmRegOp) : CIDET_OF_K_IS_VRX(pThis->fMrmRegOp) );
1071 pThis->fHasRegCollisionMem = pThis->fHasRegCollisionMemBase || pThis->fHasRegCollisionMemIndex;
1072
1073 return iIndex != 0;
1074}
1075
1076
1077/**
1078 * Selects the next SIB scale.
1079 *
1080 * @returns @c true if done, @c false if the next wheel needs to be moved.
1081 * @param pThis The core state structure.
1082 * @param iReg The value of MODRM.REG /w REX.R applied.
1083 */
1084static bool cidetCoreSetupNextBaseEncoding_SibScale(PCIDETCORE pThis, uint8_t iReg)
1085{
1086 RT_NOREF_PV(iReg);
1087 switch ((pThis->bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK)
1088 {
1089 case 0:
1090 pThis->bSib |= 1 << X86_SIB_SCALE_SHIFT;
1091 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 2;
1092 return true;
1093 case 1:
1094 pThis->bSib &= ~X86_SIB_SCALE_MASK;
1095 pThis->bSib |= 2 << X86_SIB_SCALE_SHIFT;
1096 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 4;
1097 return true;
1098 case 2:
1099 pThis->bSib |= 3 << X86_SIB_SCALE_SHIFT;
1100 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 8;
1101 return true;
1102 case 3:
1103 pThis->bSib &= ~X86_SIB_SCALE_MASK;
1104 pThis->aOperands[pThis->idxMrmRmOp].uMemScale = 1;
1105 return false;
1106
1107 default: AssertReleaseFailedReturn(false);
1108 }
1109}
1110
1111
1112/**
1113 * Selects the next segment prefix.
1114 *
1115 * @returns @c true if done, @c false if the next wheel needs to be moved.
1116 * @param pThis The core state structure.
1117 */
1118static bool cidetCoreSetupNextBaseEncoding_SegmentPrefix(PCIDETCORE pThis)
1119{
1120 if ( pThis->fHasMemoryOperand
1121 && (pThis->fTestCfg & CIDET_TESTCFG_SEG_PRF_MASK))
1122 {
1123 switch (pThis->uSegPrf)
1124 {
1125 case X86_SREG_COUNT:
1126 pThis->uSegPrf = X86_SREG_ES;
1127 if (pThis->fTestCfg & CIDET_TESTCFG_SEG_PRF_ES)
1128 return true;
1129 RT_FALL_THRU();
1130 case X86_SREG_ES:
1131 pThis->uSegPrf = X86_SREG_CS;
1132 if (pThis->fTestCfg & CIDET_TESTCFG_SEG_PRF_CS)
1133 return true;
1134 RT_FALL_THRU();
1135 case X86_SREG_CS:
1136 pThis->uSegPrf = X86_SREG_SS;
1137 if (pThis->fTestCfg & CIDET_TESTCFG_SEG_PRF_SS)
1138 return true;
1139 RT_FALL_THRU();
1140 case X86_SREG_SS:
1141 pThis->uSegPrf = X86_SREG_DS;
1142 if (pThis->fTestCfg & CIDET_TESTCFG_SEG_PRF_DS)
1143 return true;
1144 RT_FALL_THRU();
1145 case X86_SREG_DS:
1146 pThis->uSegPrf = X86_SREG_FS;
1147 if (pThis->fTestCfg & CIDET_TESTCFG_SEG_PRF_FS)
1148 return true;
1149 RT_FALL_THRU();
1150 case X86_SREG_FS:
1151 pThis->uSegPrf = X86_SREG_GS;
1152 if (pThis->fTestCfg & CIDET_TESTCFG_SEG_PRF_GS)
1153 return true;
1154 RT_FALL_THRU();
1155 case X86_SREG_GS:
1156 break;
1157 default: AssertReleaseFailedBreak();
1158 }
1159 pThis->uSegPrf = X86_SREG_COUNT;
1160 }
1161 return false;
1162}
1163
1164
1165/**
1166 * Updates the variable sized operands.
1167 *
1168 * @param pThis The core state structure.
1169 */
1170static void cidetCoreUpdateOperandSizes(PCIDETCORE pThis)
1171{
1172 uint8_t iOp = pThis->cOperands;
1173 while (iOp-- > 0)
1174 pThis->aOperands[iOp].cb = (uint8_t)CidetCoreGetOperandSize(pThis, iOp);
1175}
1176
1177
1178/**
1179 * Selects the next operand size.
1180 *
1181 * @returns @c true if done, @c false if the next wheel needs to be moved.
1182 * @param pThis The core state structure.
1183 */
1184static bool cidetCoreSetupNextBaseEncoding_OperandSize(PCIDETCORE pThis)
1185{
1186 if (CidetInstrRespondsToOperandSizePrefixes(pThis->pCurInstr))
1187 {
1188 if (CIDETMODE_IS_64BIT(pThis->bMode))
1189 {
1190 switch (pThis->fOpSizePrf + pThis->fRexW * 2)
1191 {
1192 case 0:
1193 pThis->fOpSizePrf = true;
1194 cidetCoreUpdateOperandSizes(pThis);
1195 return true;
1196 case 1:
1197 pThis->fOpSizePrf = false;
1198 if (pThis->fNoRexPrefix)
1199 break;
1200 pThis->fRexW = true;
1201 cidetCoreUpdateOperandSizes(pThis);
1202 return true;
1203 case 2:
1204 pThis->fOpSizePrf = true; /* check that it's ignored. */
1205 cidetCoreUpdateOperandSizes(pThis);
1206 return true;
1207 default:
1208 AssertReleaseFailedBreak();
1209 case 3:
1210 break;
1211 }
1212 }
1213 else
1214 {
1215 if (!pThis->fOpSizePrf)
1216 {
1217 pThis->fOpSizePrf = true;
1218 cidetCoreUpdateOperandSizes(pThis);
1219 return true;
1220 }
1221 }
1222 pThis->fRexW = false;
1223 pThis->fOpSizePrf = false;
1224 cidetCoreUpdateOperandSizes(pThis);
1225 }
1226 return false;
1227}
1228
1229
1230static bool CidetCoreSetupNextBaseEncoding(PCIDETCORE pThis)
1231{
1232 if (pThis->fUsesModRm)
1233 {
1234 /*
1235 * The wheels are lined up as follows:
1236 * 1. Address size prefix.
1237 * 2. MODRM.MOD
1238 * 3. MODRM.REG + REX.R
1239 * 4. MODRM.R/M + REX.B
1240 * 5. SIB - MODRM.R/M == 4 && MODRM.MOD != 3:
1241 * 5a) SIB.BASE + REX.B
1242 * 5b) SIB.INDEX + REX.X
1243 * 5c) SIB.SCALE
1244 * 6. Segment prefix overrides if applicable and supported (memory).
1245 * 7. Operand size prefix and REX.W if applicable.
1246 */
1247 if (cidetCoreSetupNextBaseEncoding_OperandSize(pThis))
1248 return true;
1249 if (cidetCoreSetupNextBaseEncoding_SegmentPrefix(pThis))
1250 return true;
1251
1252 /* The ModR/M register value for collision detection. */
1253 uint8_t iReg = ((pThis->bModRm >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) + pThis->fRexR * 8;
1254
1255 if (pThis->fSib)
1256 {
1257 AssertRelease(pThis->fHasMemoryOperand);
1258 if (cidetCoreSetupNextBaseEncoding_SibScale(pThis, iReg))
1259 return true;
1260 if (cidetCoreSetupNextBaseEncoding_SibIndex(pThis, iReg))
1261 return true;
1262 if (cidetCoreSetupNextBaseEncoding_SibBase(pThis, iReg))
1263 return true;
1264 Assert(pThis->bSib == 0);
1265 pThis->fSib = false;
1266 }
1267
1268 if (cidetCoreSetupNextBaseEncoding_MrmRmMod(pThis, iReg))
1269 return true;
1270 if (cidetCoreSetupNextBaseEncoding_MrmReg(pThis, iReg))
1271 return true;
1272 if (cidetCoreSetupNextBaseEncoding_AddressSize(pThis))
1273 return true;
1274 }
1275 else
1276 AssertFailedReturn(false);
1277 return false;
1278}
1279
1280
1281static bool CidetCoreSetupFirstBaseEncoding(PCIDETCORE pThis)
1282{
1283 /*
1284 * Reset all the knobs and wheels.
1285 */
1286 pThis->fSib = false;
1287 pThis->uSegPrf = X86_SREG_COUNT;
1288 pThis->fAddrSizePrf = false;
1289 pThis->fOpSizePrf = false;
1290 pThis->fRexW = false;
1291 pThis->fRexR = false;
1292 pThis->fRexX = false;
1293 pThis->fRexB = false;
1294 pThis->fRex = false;
1295 pThis->bModRm = 0;
1296 pThis->bSib = 0;
1297
1298 /* Indicators. */
1299 pThis->cbAddrMode = CIDETMODE_GET_BYTE_COUNT(pThis->bMode);
1300 pThis->fHasMemoryOperand = false;
1301 pThis->fHasRegCollisionMem = false;
1302 pThis->fHasRegCollisionMemBase = false;
1303 pThis->fHasRegCollisionMemIndex = false;
1304 pThis->fHasStackRegInMrmRmBase = false;
1305
1306 /*
1307 * Now, drill down on the instruction encoding.
1308 */
1309 if (pThis->pCurInstr->fFlags & CIDET_IF_MODRM)
1310 {
1311 Assert(pThis->fUsesModRm == true);
1312 cidetCoreSetupFirstBaseEncoding_MrmReg(pThis);
1313 if (pThis->cbAddrMode == 2)
1314 cidetCoreSetupFirstBaseEncoding_MrmRmMod_16bit(pThis, 0);
1315 else if (pThis->cbAddrMode == 4)
1316 cidetCoreSetupFirstBaseEncoding_MrmRmMod_32bit64bit(pThis, 0, false);
1317 else if (pThis->cbAddrMode == 8)
1318 cidetCoreSetupFirstBaseEncoding_MrmRmMod_32bit64bit(pThis, 0, true);
1319 else
1320 AssertReleaseFailedReturn(false);
1321 }
1322 else
1323 AssertFailedReturn(false);
1324 return true;
1325}
1326
1327
1328/**
1329 * The next memory operand configuration.
1330 *
1331 * @returns true if new one to test, false if we've reached end already.
1332 * @param pThis The core state structure.
1333 */
1334static bool CidetCoreSetupNextMemoryOperandConfig(PCIDETCORE pThis)
1335{
1336 RT_NOREF_PV(pThis);
1337 return false;
1338}
1339
1340
1341/**
1342 * Sets up the first memory operand configuration and counts memory operands.
1343 *
1344 * @returns true on success, false if no data buffers configured or failure.
1345 * @param pThis The core state structure.
1346 */
1347static bool CidetCoreSetupFirstMemoryOperandConfig(PCIDETCORE pThis)
1348{
1349 pThis->cMemoryOperands = 0;
1350 PCIDETBUF pDataBuf = &pThis->DataBuf;
1351 uint8_t idxOp = pThis->cOperands;
1352 while (idxOp-- > 0)
1353 if (!pThis->aOperands[idxOp].fIsMem)
1354 pThis->aOperands[idxOp].pDataBuf = NULL;
1355 else
1356 {
1357 if (RT_UNLIKELY(!pThis->cDataBufConfigs))
1358 return false;
1359
1360 pDataBuf->idxCfg = 0;
1361 pDataBuf->pCfg = &pThis->paDataBufConfigs[0];
1362 pDataBuf->off = 0;
1363 pDataBuf->cb = pThis->aOperands[idxOp].cb;
1364 pDataBuf->cbSegLimit = UINT16_MAX;
1365 pDataBuf->offSegBase = 0;
1366 pDataBuf->fActive = false;
1367 pDataBuf->idxOp = idxOp;
1368 pDataBuf->fXcptAfterInstruction = false;
1369 pDataBuf->enmExpectXcpt = kCidetExpectXcpt_None;
1370 pThis->aOperands[idxOp].pDataBuf = pDataBuf;
1371 pThis->cMemoryOperands++;
1372 pDataBuf++;
1373 }
1374
1375 /** @todo implement more than one memory operand. */
1376 AssertReleaseReturn(pThis->cMemoryOperands <= 1, false);
1377 return true;
1378}
1379
1380
1381/**
1382 * The next code buffer configuration.
1383 *
1384 * @returns true if new one to test, false if we've reached end already.
1385 * @param pThis The core state structure.
1386 */
1387static bool CidetCoreSetupNextCodeBufferConfig(PCIDETCORE pThis)
1388{
1389 RT_NOREF_PV(pThis);
1390 return false;
1391}
1392
1393
1394/**
1395 * Sets up the first code buffer configuration.
1396 *
1397 * @returns true on success, false if no data buffers configured or failure.
1398 * @param pThis The core state structure.
1399 */
1400static bool CidetCoreSetupFirstCodeBufferConfig(PCIDETCORE pThis)
1401{
1402 Assert(pThis->cCodeBufConfigs > 0);
1403 Assert(CIDETBUF_IS_CODE(pThis->paCodeBufConfigs[0].fFlags));
1404 pThis->CodeBuf.idxCfg = 0;
1405 pThis->CodeBuf.pCfg = &pThis->paCodeBufConfigs[0];
1406 pThis->CodeBuf.off = 0;
1407 pThis->CodeBuf.cb = 0x1000;
1408 pThis->CodeBuf.cbSegLimit = UINT16_MAX;
1409 pThis->CodeBuf.offSegBase = 0;
1410 pThis->CodeBuf.fActive = true;
1411 pThis->CodeBuf.idxOp = 7;
1412 pThis->CodeBuf.fXcptAfterInstruction = false;
1413 pThis->CodeBuf.enmExpectXcpt = kCidetExpectXcpt_None;
1414 return true;
1415}
1416
1417
1418/**
1419 * Gets the (encoded) size of the given operand in the current context.
1420 *
1421 * @returns Size in bytes.
1422 * @param pThis The core state structure (for context).
1423 * @param iOp The operand index.
1424 */
1425uint32_t CidetCoreGetOperandSize(PCIDETCORE pThis, uint8_t iOp)
1426{
1427 Assert(iOp < RT_ELEMENTS(pThis->aOperands));
1428 uint32_t cbOp = g_acbCidetOfSizes[(pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) >> CIDET_OF_Z_SHIFT];
1429 if (cbOp == UINT16_MAX)
1430 {
1431 Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_VAR_WDQ);
1432 if (CIDETMODE_IS_64BIT(pThis->bMode))
1433 {
1434 if (pThis->fRexW)
1435 cbOp = 8;
1436 else if (!pThis->fOpSizePrf)
1437 cbOp = 4;
1438 else
1439 cbOp = 2;
1440 }
1441 else if (CIDETMODE_IS_32BIT(pThis->bMode))
1442 cbOp = !pThis->fOpSizePrf ? 4 : 2;
1443 else
1444 {
1445 Assert(CIDETMODE_IS_16BIT(pThis->bMode));
1446 cbOp = !pThis->fOpSizePrf ? 2 : 4;
1447 }
1448 return cbOp;
1449 }
1450
1451 if (cbOp == UINT16_MAX - 1)
1452 {
1453 Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_SPECIAL);
1454 AssertReleaseFailedReturn(0);
1455 }
1456
1457 if (cbOp)
1458 {
1459#ifdef VBOX_STRICT
1460 switch (cbOp)
1461 {
1462 case 1: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_BYTE); break;
1463 case 2: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_WORD); break;
1464 case 4: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_DWORD); break;
1465 case 8: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_QWORD); break;
1466 case 10: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_TBYTE); break;
1467 case 16: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_OWORD); break;
1468 case 32: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_YWORD); break;
1469 case 64: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_ZWORD); break;
1470 default: AssertFailed();
1471 }
1472#endif
1473 return cbOp;
1474 }
1475 AssertReleaseFailedReturn(0);
1476}
1477
1478
1479static bool CideCoreSetInstruction(PCIDETCORE pThis, PCCIDETINSTR pInstr)
1480{
1481 AssertReleaseMsgReturn(RT_VALID_PTR(pInstr), ("%p\n", pInstr), false);
1482
1483 pThis->pCurInstr = pInstr;
1484
1485 /*
1486 * Extract info from the instruction descriptor.
1487 */
1488 pThis->fUsesModRm = false;
1489 pThis->fUsesVexIndexRegs = false;
1490 pThis->idxMrmRegOp = 7;
1491 pThis->idxMrmRmOp = 7;
1492 pThis->fMrmRegOp = 0;
1493 pThis->fMrmRmOp = 0;
1494 pThis->fInstrFlags = pInstr->fFlags;
1495 pThis->cOperands = pInstr->cOperands;
1496 if (pInstr->fFlags & CIDET_IF_MODRM)
1497 {
1498 pThis->fUsesModRm = true;
1499 for (uint8_t iOp = 0; iOp < pInstr->cOperands; iOp++)
1500 if (pInstr->afOperands[iOp] & CIDET_OF_M_REG)
1501 {
1502 pThis->idxMrmRegOp = iOp;
1503 pThis->fMrmRegOp = pInstr->afOperands[iOp];
1504 }
1505 else if (pInstr->afOperands[iOp] & CIDET_OF_M_RM)
1506 {
1507 pThis->idxMrmRmOp = iOp;
1508 pThis->fMrmRmOp = pInstr->afOperands[iOp];
1509 }
1510 }
1511 else
1512 AssertFailedReturn(false);
1513
1514 uint8_t iOp;
1515 for (iOp = 0; iOp < pInstr->cOperands; iOp++)
1516 {
1517 pThis->aOperands[iOp].fFlags = pInstr->afOperands[iOp];
1518 pThis->aOperands[iOp].iReg = UINT8_MAX;
1519 pThis->aOperands[iOp].cb = (uint8_t)CidetCoreGetOperandSize(pThis, iOp);
1520 pThis->aOperands[iOp].fIsImmediate = (pInstr->afOperands[iOp] & CIDET_OF_K_MASK) == CIDET_OF_K_IMM;
1521 pThis->aOperands[iOp].fIsMem = (pInstr->afOperands[iOp] & CIDET_OF_K_MASK) == CIDET_OF_K_MEM;
1522 pThis->aOperands[iOp].fIsRipRelative = false;
1523 pThis->aOperands[iOp].cbMemDisp = 0;
1524 pThis->aOperands[iOp].iMemBaseReg = UINT8_MAX;
1525 pThis->aOperands[iOp].iMemIndexReg = UINT8_MAX;
1526 pThis->aOperands[iOp].uMemScale = 1;
1527 pThis->aOperands[iOp].iEffSeg = UINT8_MAX;
1528 pThis->aOperands[iOp].offSeg = UINT64_MAX;
1529 pThis->aOperands[iOp].uEffAddr = UINT64_MAX;
1530 pThis->aOperands[iOp].uImmDispValue = UINT64_MAX;
1531 pThis->aOperands[iOp].uMemBaseRegValue = UINT64_MAX;
1532 pThis->aOperands[iOp].uMemIndexRegValue = UINT64_MAX;
1533 pThis->aOperands[iOp].In.pv = NULL;
1534 pThis->aOperands[iOp].Expected.pv = NULL;
1535 pThis->aOperands[iOp].pDataBuf = NULL;
1536 }
1537
1538 for (; iOp < RT_ELEMENTS(pThis->aOperands); iOp++)
1539 {
1540 pThis->aOperands[iOp].fFlags = 0;
1541 pThis->aOperands[iOp].iReg = UINT8_MAX;
1542 pThis->aOperands[iOp].cb = 0;
1543 pThis->aOperands[iOp].fIsImmediate = false;
1544 pThis->aOperands[iOp].fIsMem = false;
1545 pThis->aOperands[iOp].fIsRipRelative = false;
1546 pThis->aOperands[iOp].cbMemDisp = 0;
1547 pThis->aOperands[iOp].iMemBaseReg = UINT8_MAX;
1548 pThis->aOperands[iOp].iMemIndexReg = UINT8_MAX;
1549 pThis->aOperands[iOp].uMemScale = 1;
1550 pThis->aOperands[iOp].iEffSeg = UINT8_MAX;
1551 pThis->aOperands[iOp].offSeg = UINT64_MAX;
1552 pThis->aOperands[iOp].uEffAddr = UINT64_MAX;
1553 pThis->aOperands[iOp].uImmDispValue = UINT64_MAX;
1554 pThis->aOperands[iOp].uMemBaseRegValue = UINT64_MAX;
1555 pThis->aOperands[iOp].uMemIndexRegValue = UINT64_MAX;
1556 pThis->aOperands[iOp].In.pv = NULL;
1557 pThis->aOperands[iOp].Expected.pv = NULL;
1558 pThis->aOperands[iOp].pDataBuf = NULL;
1559 }
1560
1561 /*
1562 * Reset various things.
1563 */
1564 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aiInOut); i++)
1565 pThis->aiInOut[i] = 0;
1566
1567 return true;
1568}
1569
1570
1571static bool CidetCoreSetupInOut(PCIDETCORE pThis)
1572{
1573 /*
1574 * Enumerate the operands.
1575 */
1576 uint8_t *pbBuf = &pThis->abBuf[0];
1577 pbBuf = RT_ALIGN_PT(pbBuf, 16, uint8_t *);
1578
1579 uint8_t idxOp = pThis->cOperands;
1580 while (idxOp-- > 0)
1581 {
1582 if (pThis->aOperands[idxOp].fIsMem)
1583 {
1584 /*
1585 * Memory operand.
1586 */
1587 Assert(pThis->aOperands[idxOp].fIsMem);
1588
1589 /* Set the In & Expected members to point to temporary buffer space. */
1590 pThis->aOperands[idxOp].Expected.pu8 = pbBuf;
1591 pbBuf += pThis->aOperands[idxOp].cb;
1592 pbBuf = RT_ALIGN_PT(pbBuf, 16, uint8_t *);
1593
1594 pThis->aOperands[idxOp].In.pu8 = pbBuf;
1595 pbBuf += pThis->aOperands[idxOp].cb;
1596 pbBuf = RT_ALIGN_PT(pbBuf, 16, uint8_t *);
1597
1598 /* Initialize the buffer we're gonna use. */
1599 pThis->aOperands[idxOp].iEffSeg = pThis->uSegPrf != X86_SREG_COUNT
1600 ? pThis->uSegPrf
1601 : !(pThis->aOperands[idxOp].fFlags & CIDET_OF_ALWAYS_SEG_ES) ? X86_SREG_DS
1602 : X86_SREG_ES;
1603
1604 PCIDETBUF pDataBuf = pThis->aOperands[idxOp].pDataBuf;
1605 AssertReleaseReturn(pDataBuf, false);
1606 Assert(pDataBuf->cb == pThis->aOperands[idxOp].cb);
1607 Assert(pDataBuf->idxOp == idxOp);
1608 if (!pThis->pfnReInitDataBuf(pThis, pDataBuf))
1609 {
1610 pThis->cSkippedReInitDataBuf++;
1611 return false;
1612 }
1613 pDataBuf->fActive = true;
1614
1615 /* Calc buffer related operand members. */
1616 pThis->aOperands[idxOp].uEffAddr = pDataBuf->uEffBufAddr + pDataBuf->off;
1617 uint64_t offSeg = pThis->aOperands[idxOp].uEffAddr - pDataBuf->uSegBase;
1618 pThis->aOperands[idxOp].offSeg = offSeg;
1619 AssertRelease(offSeg <= g_au64ByteSizeToMask[pThis->cbAddrMode]);
1620
1621 /*
1622 * Select register and displacement values for the buffer addressing (works on offSeg).
1623 */
1624 uint8_t const iMemIndexReg = pThis->aOperands[idxOp].iMemIndexReg;
1625 uint8_t const iMemBaseReg = pThis->aOperands[idxOp].iMemBaseReg;
1626 if (pThis->aOperands[idxOp].fIsRipRelative)
1627 {
1628 /* rip relative. */
1629 pThis->aOperands[idxOp].uImmDispValue = offSeg - (pThis->InCtx.rip + pThis->cbInstr);
1630 Assert(pThis->aOperands[idxOp].cbMemDisp == 4);
1631 if ( (int64_t)pThis->aOperands[idxOp].uImmDispValue > INT32_MAX
1632 || (int64_t)pThis->aOperands[idxOp].uImmDispValue < INT32_MIN)
1633 {
1634 pThis->cSkippedDataBufWrtRip++;
1635 return false;
1636 }
1637 }
1638 else if (iMemBaseReg != UINT8_MAX)
1639 {
1640 if ( iMemBaseReg != iMemIndexReg
1641 || pThis->fUsesVexIndexRegs)
1642 {
1643 /* [base] or [base + disp] or [base + index * scale] or [base + index * scale + disp] */
1644 if (pThis->aOperands[idxOp].cbMemDisp > 0)
1645 {
1646 pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
1647 offSeg -= (int64_t)pThis->aOperands[idxOp].uImmDispValue;
1648 }
1649
1650 if (iMemIndexReg != UINT8_MAX)
1651 {
1652 pThis->aOperands[idxOp].uMemIndexRegValue = CidetCoreGetRandU64(pThis, pThis->cbAddrMode);
1653 offSeg -= pThis->aOperands[idxOp].uMemIndexRegValue * pThis->aOperands[idxOp].uMemScale;
1654 }
1655
1656 pThis->aOperands[idxOp].uMemBaseRegValue = offSeg & g_au64ByteSizeToMask[pThis->cbAddrMode];
1657 }
1658 else
1659 {
1660 /* base == index; [base + index * scale] or [base * (scale + 1)]. */
1661 uint8_t const uEffScale = pThis->aOperands[idxOp].uMemScale + 1;
1662 if (pThis->aOperands[idxOp].cbMemDisp > 0)
1663 {
1664 pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
1665 offSeg -= (int64_t)pThis->aOperands[idxOp].uImmDispValue;
1666 offSeg &= g_au64ByteSizeToMask[pThis->cbAddrMode];
1667 uint8_t uRemainder = offSeg % uEffScale;
1668 if (uRemainder != 0)
1669 {
1670 Assert(pThis->aOperands[idxOp].cbMemDisp < 8);
1671 Assert( (int64_t)pThis->aOperands[idxOp].uImmDispValue
1672 <= g_ai64ByteSizeToMax[pThis->aOperands[idxOp].cbMemDisp]);
1673 pThis->aOperands[idxOp].uImmDispValue = (int64_t)pThis->aOperands[idxOp].uImmDispValue
1674 + uRemainder;
1675 offSeg -= uRemainder;
1676 if ( (int64_t)pThis->aOperands[idxOp].uImmDispValue
1677 > g_ai64ByteSizeToMax[pThis->aOperands[idxOp].cbMemDisp])
1678 {
1679 pThis->aOperands[idxOp].uImmDispValue -= uEffScale;
1680 offSeg += uEffScale;
1681 }
1682 Assert(offSeg % uEffScale == 0);
1683 }
1684 }
1685 else
1686 {
1687 offSeg &= g_au64ByteSizeToMask[pThis->cbAddrMode];
1688 if (offSeg % uEffScale != 0)
1689 {
1690 pThis->cSkippedSameBaseIndexRemainder++;
1691 return false;
1692 }
1693 }
1694 offSeg /= uEffScale;
1695 pThis->aOperands[idxOp].uMemBaseRegValue = pThis->aOperands[idxOp].uMemIndexRegValue = offSeg;
1696 }
1697 }
1698 else if (iMemIndexReg != UINT8_MAX)
1699 {
1700 /* [index * scale] or [index * scale + disp] */
1701 if (pThis->aOperands[idxOp].cbMemDisp > 0)
1702 {
1703 pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
1704 offSeg -= (int64_t)pThis->aOperands[idxOp].uImmDispValue;
1705 pThis->aOperands[idxOp].uImmDispValue += offSeg & (RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1);
1706 offSeg &= ~(RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1);
1707 }
1708 else if (offSeg & (RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1))
1709 {
1710 pThis->cSkippedOnlyIndexRemainder++;
1711 return false;
1712 }
1713
1714 pThis->aOperands[idxOp].uMemIndexRegValue = offSeg / pThis->aOperands[idxOp].uMemScale;
1715 Assert((offSeg % pThis->aOperands[idxOp].uMemScale) == 0);
1716 AssertRelease(!pThis->fUsesVexIndexRegs); /** @todo implement VEX indexing */
1717 }
1718 else
1719 {
1720 /* [disp] */
1721 Assert( pThis->aOperands[idxOp].cbMemDisp == 8
1722 || pThis->aOperands[idxOp].cbMemDisp == 4
1723 || pThis->aOperands[idxOp].cbMemDisp == 2
1724 || pThis->aOperands[idxOp].cbMemDisp == 1);
1725 if ( pThis->aOperands[idxOp].cbMemDisp == 4
1726 ? (int64_t)offSeg != (int32_t)offSeg
1727 : pThis->aOperands[idxOp].cbMemDisp == 2
1728 ? (int64_t)offSeg != (int16_t)offSeg
1729 : pThis->aOperands[idxOp].cbMemDisp == 1
1730 ? (int64_t)offSeg != (int8_t)offSeg
1731 : false /* 8 */)
1732 {
1733 pThis->cSkippedDirectAddressingOverflow++;
1734 return false;
1735 }
1736 pThis->aOperands[idxOp].uImmDispValue = offSeg;
1737 }
1738
1739 /*
1740 * Modify the input and expected output contexts with the base and
1741 * index register values. To simplify verification and the work
1742 * here, we update the uMemBaseRegValue and uMemIndexRegValue
1743 * members to reflect the whole register.
1744 */
1745 if (iMemBaseReg != UINT8_MAX)
1746 {
1747 if (pThis->cbAddrMode == 4)
1748 {
1749 pThis->aOperands[idxOp].uMemBaseRegValue &= UINT32_MAX;
1750 pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffff00000000);
1751 }
1752 else if (pThis->cbAddrMode == 2)
1753 {
1754 pThis->aOperands[idxOp].uMemBaseRegValue &= UINT16_MAX;
1755 pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffffffff0000);
1756 }
1757 pThis->InCtx.aGRegs[iMemBaseReg] = pThis->aOperands[idxOp].uMemBaseRegValue;
1758 pThis->ExpectedCtx.aGRegs[iMemBaseReg] = pThis->aOperands[idxOp].uMemBaseRegValue;
1759 }
1760
1761 if (iMemIndexReg != UINT8_MAX)
1762 {
1763 if (pThis->cbAddrMode == 4)
1764 {
1765 pThis->aOperands[idxOp].uMemIndexRegValue &= UINT32_MAX;
1766 pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffff00000000);
1767 }
1768 else if (pThis->cbAddrMode == 2)
1769 {
1770 pThis->aOperands[idxOp].uMemIndexRegValue &= UINT16_MAX;
1771 pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffffffff0000);
1772 }
1773 pThis->InCtx.aGRegs[iMemIndexReg] = pThis->aOperands[idxOp].uMemIndexRegValue;
1774 pThis->ExpectedCtx.aGRegs[iMemIndexReg] = pThis->aOperands[idxOp].uMemIndexRegValue;
1775 }
1776 }
1777 else
1778 {
1779 /*
1780 * Non-memory, so clear the memory related members.
1781 */
1782 Assert(!pThis->aOperands[idxOp].fIsMem);
1783 pThis->aOperands[idxOp].iEffSeg = UINT8_MAX;
1784 pThis->aOperands[idxOp].offSeg = UINT64_MAX;
1785 pThis->aOperands[idxOp].uEffAddr = UINT64_MAX;
1786 pThis->aOperands[idxOp].pDataBuf = NULL;
1787
1788 switch (pThis->aOperands[idxOp].fFlags & CIDET_OF_K_MASK)
1789 {
1790 case CIDET_OF_K_GPR:
1791 if (!pThis->aOperands[idxOp].fIsHighByteRegister)
1792 {
1793 pThis->aOperands[idxOp].In.pv = &pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iReg];
1794 pThis->aOperands[idxOp].Expected.pv = &pThis->ExpectedCtx.aGRegs[pThis->aOperands[idxOp].iReg];
1795 }
1796 else
1797 {
1798 pThis->aOperands[idxOp].In.pv = &pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iReg - 4];
1799 pThis->aOperands[idxOp].In.pu8++;
1800 pThis->aOperands[idxOp].Expected.pv = &pThis->ExpectedCtx.aGRegs[pThis->aOperands[idxOp].iReg - 4];
1801 pThis->aOperands[idxOp].Expected.pu8++;
1802 }
1803 break;
1804
1805 case CIDET_OF_K_IMM:
1806 pThis->aOperands[idxOp].In.pv = NULL;
1807 pThis->aOperands[idxOp].Expected.pv = NULL;
1808 break;
1809
1810 case CIDET_OF_K_SREG:
1811 if (pThis->aOperands[idxOp].iReg < RT_ELEMENTS(pThis->InCtx.aSRegs))
1812 {
1813 pThis->aOperands[idxOp].In.pv = &pThis->InCtx.aSRegs[pThis->aOperands[idxOp].iReg];
1814 pThis->aOperands[idxOp].Expected.pv = &pThis->ExpectedCtx.aSRegs[pThis->aOperands[idxOp].iReg];
1815 }
1816 else
1817 {
1818 pThis->aOperands[idxOp].In.pv = NULL;
1819 pThis->aOperands[idxOp].Expected.pv = NULL;
1820 }
1821 break;
1822
1823 case CIDET_OF_K_CR:
1824 case CIDET_OF_K_SSE:
1825 case CIDET_OF_K_AVX:
1826 case CIDET_OF_K_AVX512:
1827 case CIDET_OF_K_FPU:
1828 case CIDET_OF_K_MMX:
1829 case CIDET_OF_K_AVXFUTURE:
1830 case CIDET_OF_K_SPECIAL:
1831 case CIDET_OF_K_TEST:
1832 /** @todo Implement testing these registers. */
1833 case CIDET_OF_K_NONE:
1834 default:
1835 AssertReleaseFailedReturn(false);
1836 }
1837 }
1838 }
1839 AssertRelease((uintptr_t)pbBuf - (uintptr_t)&pThis->abBuf[0] <= sizeof(pThis->abBuf));
1840
1841 /*
1842 * Call instruction specific setup function (for operand values and flags).
1843 */
1844 int rc = pThis->pCurInstr->pfnSetupInOut(pThis, false /*fInvalid*/);
1845 if (RT_FAILURE(rc))
1846 {
1847 pThis->cSkippedSetupInOut++;
1848 return false;
1849 }
1850
1851 /*
1852 * Do the 2nd set of the memory operand preparations.
1853 */
1854 if (pThis->fHasMemoryOperand)
1855 {
1856 idxOp = pThis->cOperands;
1857 while (idxOp-- > 0)
1858 if (pThis->aOperands[idxOp].fIsMem)
1859 {
1860 Assert(pThis->aOperands[idxOp].pDataBuf);
1861 if (!pThis->pfnSetupDataBuf(pThis, pThis->aOperands[idxOp].pDataBuf, pThis->aOperands[idxOp].In.pv))
1862 {
1863 pThis->cSkippedSetupDataBuf++;
1864 return false;
1865 }
1866
1867 Assert( pThis->aOperands[idxOp].iMemBaseReg == UINT8_MAX
1868 || pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iMemBaseReg] == pThis->aOperands[idxOp].uMemBaseRegValue);
1869 Assert( pThis->aOperands[idxOp].iMemIndexReg == UINT8_MAX
1870 || ( !pThis->fUsesVexIndexRegs
1871 ? pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iMemIndexReg]
1872 == pThis->aOperands[idxOp].uMemIndexRegValue
1873 : false /** @todo VEX indexing */));
1874 }
1875 }
1876
1877 return true;
1878}
1879
1880
1881/**
1882 * Figures the instruction length.
1883 *
1884 * This is a duplicate of CidetCoreAssemble() with the buffer updates removed.
1885 *
1886 * @returns true and pThis->cbInstr on success, false on failure.
1887 * @param pThis The core state structure (for context).
1888 */
1889static bool CidetCoreAssembleLength(PCIDETCORE pThis)
1890{
1891 uint8_t off = 0;
1892
1893 /*
1894 * Prefixes.
1895 */
1896 if (1)
1897 {
1898 if (pThis->fAddrSizePrf)
1899 off++;
1900 if (pThis->fOpSizePrf)
1901 off++;
1902 }
1903 else
1904 {
1905 /** @todo prefix list. */
1906 }
1907
1908 /*
1909 * Prefixes that must come right before the opcode.
1910 */
1911 /** @todo VEX and EVEX. */
1912 if (pThis->fVex)
1913 {
1914 /** @todo VEX and EVEX. */
1915 }
1916 else if (pThis->fEvex)
1917 {
1918 /** @todo VEX and EVEX. */
1919 }
1920 else
1921 {
1922 if (pThis->fRexB || pThis->fRexX || pThis->fRexR || pThis->fRexW || pThis->fRex)
1923 off++;
1924 }
1925
1926 /*
1927 * The opcode.
1928 */
1929 //uint8_t const *pbOpcode = pThis->pCurInstr->abOpcode;
1930 switch (pThis->pCurInstr->cbOpcode)
1931 {
1932 case 3: off++; RT_FALL_THRU();
1933 case 2: off++; RT_FALL_THRU();
1934 case 1: off++;
1935 break;
1936 default:
1937 AssertReleaseFailedReturn(false);
1938 }
1939
1940 /*
1941 * Mod R/M
1942 */
1943 if (pThis->fUsesModRm)
1944 {
1945 off++;
1946 if (pThis->fSib)
1947 off++;
1948 if (pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands))
1949 {
1950 //uint64_t uDispValue = pThis->aOperands[pThis->idxMrmRmOp].uImmDispValue;
1951 switch (pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp)
1952 {
1953 case 0: break;
1954 case 8:
1955 case 7:
1956 case 6:
1957 case 5:
1958 case 4:
1959 case 3:
1960 case 2:
1961 case 1:
1962 break;
1963 default: AssertReleaseFailedReturn(false);
1964 }
1965 off += pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp;
1966 }
1967 }
1968
1969 /*
1970 * Immediates.
1971 */
1972 uint8_t iOp = pThis->cOperands;
1973 while (iOp-- > 0)
1974 if ((pThis->aOperands[iOp].fFlags & CIDET_OF_K_MASK) == CIDET_OF_K_IMM)
1975 {
1976 //uint64_t uImmValue = pThis->aOperands[iOp].uImmDispValue;
1977 switch (pThis->aOperands[iOp].cb)
1978 {
1979 case 8:
1980 case 7:
1981 case 6:
1982 case 5:
1983 case 4:
1984 case 3:
1985 case 2:
1986 case 1:
1987 break;
1988 default: AssertReleaseFailedReturn(false);
1989 }
1990 off += pThis->aOperands[iOp].cb;
1991 }
1992
1993 pThis->cbInstr = off;
1994 return true;
1995}
1996
1997
1998/**
1999 * Assembles the instruction.
2000 *
2001 * This is a duplicate of CidetCoreAssembleLength() with buffer writes.
2002 *
2003 * @returns true and pThis->cbInstr and pThis->abInstr on success, false on
2004 * failure.
2005 * @param pThis The core state structure (for context).
2006 */
2007static bool CidetCoreAssemble(PCIDETCORE pThis)
2008{
2009 uint8_t off = 0;
2010
2011 /*
2012 * Prefixes.
2013 */
2014 if (1)
2015 {
2016 if (pThis->fAddrSizePrf)
2017 pThis->abInstr[off++] = 0x67;
2018 if (pThis->fOpSizePrf)
2019 pThis->abInstr[off++] = 0x66;
2020 }
2021 else
2022 {
2023 /** @todo prefix list. */
2024 }
2025
2026 /*
2027 * Prefixes that must come right before the opcode.
2028 */
2029 /** @todo VEX and EVEX. */
2030 if (pThis->fVex)
2031 {
2032 /** @todo VEX and EVEX. */
2033 }
2034 else if (pThis->fEvex)
2035 {
2036 /** @todo VEX and EVEX. */
2037 }
2038 else
2039 {
2040 if (pThis->fRexB || pThis->fRexX || pThis->fRexR || pThis->fRexW || pThis->fRex)
2041 pThis->abInstr[off++] = 0x40 | (pThis->fRexB * 1) | (pThis->fRexX * 2) | (pThis->fRexR * 4) | (pThis->fRexW * 8);
2042 }
2043
2044 /*
2045 * The opcode.
2046 */
2047 uint8_t const *pbOpcode = pThis->pCurInstr->abOpcode;
2048 switch (pThis->pCurInstr->cbOpcode)
2049 {
2050 case 3: pThis->abInstr[off++] = *pbOpcode++; RT_FALL_THRU();
2051 case 2: pThis->abInstr[off++] = *pbOpcode++; RT_FALL_THRU();
2052 case 1: pThis->abInstr[off++] = *pbOpcode++;
2053 break;
2054 default:
2055 AssertReleaseFailedReturn(false);
2056 }
2057
2058 /*
2059 * Mod R/M
2060 */
2061 if (pThis->fUsesModRm)
2062 {
2063 pThis->abInstr[off++] = pThis->bModRm;
2064 if (pThis->fSib)
2065 pThis->abInstr[off++] = pThis->bSib;
2066 if (pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands))
2067 {
2068 uint64_t uDispValue = pThis->aOperands[pThis->idxMrmRmOp].uImmDispValue;
2069 switch (pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp)
2070 {
2071 case 0: break;
2072 case 8: pThis->abInstr[off + 3] = (uDispValue >> 56) & UINT8_C(0xff); RT_FALL_THRU();
2073 case 7: pThis->abInstr[off + 3] = (uDispValue >> 48) & UINT8_C(0xff); RT_FALL_THRU();
2074 case 6: pThis->abInstr[off + 3] = (uDispValue >> 40) & UINT8_C(0xff); RT_FALL_THRU();
2075 case 5: pThis->abInstr[off + 3] = (uDispValue >> 32) & UINT8_C(0xff); RT_FALL_THRU();
2076 case 4: pThis->abInstr[off + 3] = (uDispValue >> 24) & UINT8_C(0xff); RT_FALL_THRU();
2077 case 3: pThis->abInstr[off + 2] = (uDispValue >> 16) & UINT8_C(0xff); RT_FALL_THRU();
2078 case 2: pThis->abInstr[off + 1] = (uDispValue >> 8) & UINT8_C(0xff); RT_FALL_THRU();
2079 case 1: pThis->abInstr[off] = uDispValue & UINT8_C(0xff);
2080 break;
2081 default: AssertReleaseFailedReturn(false);
2082 }
2083 off += pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp;
2084 }
2085 }
2086
2087 /*
2088 * Immediates.
2089 */
2090 uint8_t iOp = pThis->cOperands;
2091 while (iOp-- > 0)
2092 if ((pThis->aOperands[iOp].fFlags & CIDET_OF_K_MASK) == CIDET_OF_K_IMM)
2093 {
2094 uint64_t uImmValue = pThis->aOperands[iOp].uImmDispValue;
2095 switch (pThis->aOperands[iOp].cb)
2096 {
2097 case 8: pThis->abInstr[off + 3] = (uImmValue >> 56) & UINT8_C(0xff); RT_FALL_THRU();
2098 case 7: pThis->abInstr[off + 3] = (uImmValue >> 48) & UINT8_C(0xff); RT_FALL_THRU();
2099 case 6: pThis->abInstr[off + 3] = (uImmValue >> 40) & UINT8_C(0xff); RT_FALL_THRU();
2100 case 5: pThis->abInstr[off + 3] = (uImmValue >> 32) & UINT8_C(0xff); RT_FALL_THRU();
2101 case 4: pThis->abInstr[off + 3] = (uImmValue >> 24) & UINT8_C(0xff); RT_FALL_THRU();
2102 case 3: pThis->abInstr[off + 2] = (uImmValue >> 16) & UINT8_C(0xff); RT_FALL_THRU();
2103 case 2: pThis->abInstr[off + 1] = (uImmValue >> 8) & UINT8_C(0xff); RT_FALL_THRU();
2104 case 1: pThis->abInstr[off] = uImmValue & UINT8_C(0xff);
2105 break;
2106 default: AssertReleaseFailedReturn(false);
2107 }
2108 off += pThis->aOperands[iOp].cb;
2109 }
2110
2111 pThis->cbInstr = off;
2112 return true;
2113}
2114
2115
2116static bool CidetCoreReInitCodeBuf(PCIDETCORE pThis)
2117{
2118 /*
2119 * Re-initialize the buffer. Requires instruction length and positioning.
2120 */
2121 if (CidetCoreAssembleLength(pThis))
2122 {
2123 pThis->CodeBuf.cb = pThis->cbInstr;
2124 pThis->CodeBuf.off = CIDET_CODE_BUF_SIZE - PAGE_SIZE - pThis->cbInstr;
2125 if (pThis->pfnReInitCodeBuf(pThis, &pThis->CodeBuf))
2126 {
2127 pThis->CodeBuf.fActive = true;
2128
2129 /*
2130 * Update the RIP and CS values in the input and expected contexts.
2131 */
2132 pThis->InCtx.rip = pThis->CodeBuf.uEffBufAddr + pThis->CodeBuf.offActive - pThis->CodeBuf.uSegBase;
2133 pThis->ExpectedCtx.rip = pThis->InCtx.rip + pThis->cbInstr; /** @todo account for expected traps. */
2134 if (pThis->CodeBuf.uSeg != UINT32_MAX)
2135 {
2136 pThis->InCtx.aSRegs[X86_SREG_CS] = pThis->CodeBuf.uSeg;
2137 pThis->ExpectedCtx.aSRegs[X86_SREG_CS] = pThis->CodeBuf.uSeg;
2138 }
2139 return true;
2140 }
2141 else
2142 pThis->cSkippedReInitCodeBuf++;
2143 }
2144 else
2145 pThis->cSkippedAssemble++;
2146 return false;
2147}
2148
2149
2150#ifdef CIDET_DEBUG_DISAS
2151/**
2152 * @callback_method_impl{FNDISREADBYTES}
2153 */
2154static DECLCALLBACK(int) cidetCoreDisReadBytes(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
2155{
2156 PCIDETCORE pThis = (PCIDETCORE)pDis->pvUser;
2157 memcpy(&pDis->abInstr[offInstr], &pThis->abInstr[offInstr], cbMaxRead);
2158 pDis->cbCachedInstr = offInstr + cbMaxRead;
2159 return VINF_SUCCESS;
2160}
2161#endif
2162
2163
2164static bool CidetCoreSetupCodeBuf(PCIDETCORE pThis, unsigned iSubTest)
2165{
2166 if (CidetCoreAssemble(pThis))
2167 {
2168 //CIDET_DPRINTF(("%04u: %.*Rhxs\n", i, pThis->cbInstr, pThis->abInstr));
2169#ifdef CIDET_DEBUG_DISAS
2170 DISCPUSTATE Dis;
2171 char szInstr[80] = {0};
2172 uint32_t cbInstr;
2173 int rcDis = DISInstrToStrEx(pThis->InCtx.rip,
2174 CIDETMODE_IS_64BIT(pThis->bMode) ? DISCPUMODE_64BIT
2175 : CIDETMODE_IS_32BIT(pThis->bMode) ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
2176 cidetCoreDisReadBytes,
2177 pThis,
2178 DISOPTYPE_ALL,
2179 &Dis,
2180 &cbInstr,
2181 szInstr, sizeof(szInstr));
2182 CIDET_DPRINTF(("%04u: %s", iSubTest, szInstr));
2183 Assert(cbInstr == pThis->cbInstr);
2184#else
2185 RT_NOREF_PV(iSubTest);
2186#endif
2187 if (pThis->pfnSetupCodeBuf(pThis, &pThis->CodeBuf, pThis->abInstr))
2188 {
2189 return true;
2190 }
2191 pThis->cSkippedSetupCodeBuf++;
2192 }
2193 else
2194 pThis->cSkippedAssemble++;
2195 return false;
2196}
2197
2198
2199/**
2200 * Compares the output with the output expectations.
2201 *
2202 * @returns true if ok, false if not (calls pfnFailure too).
2203 * @param pThis The core state structure.
2204 */
2205static bool CidetCoreCheckResults(PCIDETCORE pThis)
2206{
2207 if (memcmp(&pThis->ActualCtx, &pThis->ExpectedCtx, CIDETCPUCTX_COMPARE_SIZE) == 0)
2208 return true;
2209
2210 unsigned cDiffs = 0;
2211#define IF_FIELD_DIFFERS_SET_ERROR(a_Field, a_Fmt) \
2212 if (pThis->ActualCtx.a_Field != pThis->ExpectedCtx.a_Field) \
2213 { \
2214 CidetCoreSetError(pThis, #a_Field " differs: got %#llx expected %#llx", \
2215 pThis->ActualCtx.a_Field, pThis->ExpectedCtx.a_Field); \
2216 cDiffs++; \
2217 } else do { } while (0)
2218
2219 IF_FIELD_DIFFERS_SET_ERROR(rip, "%#010llx");
2220 IF_FIELD_DIFFERS_SET_ERROR(rfl, "%#010llx");
2221 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xAX], "%#010llx");
2222 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xBX], "%#010llx");
2223 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xCX], "%#010llx");
2224 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xDX], "%#010llx");
2225 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xSP], "%#010llx");
2226 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xBP], "%#010llx");
2227 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xSI], "%#010llx");
2228 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xDI], "%#010llx");
2229 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x8], "%#010llx");
2230 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x9], "%#010llx");
2231 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x9], "%#010llx");
2232 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x10], "%#010llx");
2233 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x11], "%#010llx");
2234 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x12], "%#010llx");
2235 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x13], "%#010llx");
2236 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x14], "%#010llx");
2237 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x15], "%#010llx");
2238 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_CS], "%#06x");
2239 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_SS], "%#06x");
2240 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_DS], "%#06x");
2241 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_ES], "%#06x");
2242 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_FS], "%#06x");
2243 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_GS], "%#06x");
2244 IF_FIELD_DIFFERS_SET_ERROR(uXcpt, "%#04x");
2245 IF_FIELD_DIFFERS_SET_ERROR(uErr, "%#04llx");
2246 IF_FIELD_DIFFERS_SET_ERROR(cr2, "%#010llx");
2247#ifndef CIDET_REDUCED_CTX
2248 IF_FIELD_DIFFERS_SET_ERROR(tr, "%#06x");
2249 IF_FIELD_DIFFERS_SET_ERROR(ldtr, "%#06x");
2250 IF_FIELD_DIFFERS_SET_ERROR(cr0, "%#010llx");
2251 IF_FIELD_DIFFERS_SET_ERROR(cr3, "%#010llx");
2252 IF_FIELD_DIFFERS_SET_ERROR(cr4, "%#010llx");
2253 IF_FIELD_DIFFERS_SET_ERROR(cr8, "%#010llx");
2254 IF_FIELD_DIFFERS_SET_ERROR(dr0, "%#010llx");
2255 IF_FIELD_DIFFERS_SET_ERROR(dr1, "%#010llx");
2256 IF_FIELD_DIFFERS_SET_ERROR(dr2, "%#010llx");
2257 IF_FIELD_DIFFERS_SET_ERROR(dr3, "%#010llx");
2258 IF_FIELD_DIFFERS_SET_ERROR(dr6, "%#010llx");
2259 IF_FIELD_DIFFERS_SET_ERROR(dr7, "%#010llx");
2260#endif
2261
2262AssertMsgFailed(("cDiffs=%d\n", cDiffs));
2263 Assert(cDiffs > 0);
2264 return cDiffs == 0;
2265}
2266
2267
2268static bool CidetCoreTest_Basic(PCIDETCORE pThis)
2269{
2270 /*
2271 * Iterate all encodings.
2272 */
2273 if (!CidetCoreSetupFirstBaseEncoding(pThis))
2274 return CidetCoreSetError(pThis, "CidetCoreSetupFirstBaseEncoding failed");
2275 unsigned cExecuted = 0;
2276 unsigned cSkipped = 0;
2277 do
2278 {
2279 /*
2280 * Iterate data buffer configurations (one iteration if none).
2281 */
2282 if (CidetCoreSetupFirstMemoryOperandConfig(pThis))
2283 {
2284 do
2285 {
2286 /*
2287 * Iterate code buffer configurations.
2288 */
2289 if (!CidetCoreSetupFirstCodeBufferConfig(pThis))
2290 return CidetCoreSetError(pThis, "CidetCoreSetupFirstMemoryOperandConfig failed");
2291 do
2292 {
2293 /*
2294 * Set up inputs and expected outputs, then emit the test code.
2295 */
2296 pThis->InCtx = pThis->InTemplateCtx;
2297 pThis->InCtx.fTrickyStack = pThis->fHasStackRegInMrmRmBase || pThis->fHasStackRegInMrmReg;
2298 pThis->ExpectedCtx = pThis->InCtx;
2299 if ( CidetCoreReInitCodeBuf(pThis)
2300 && CidetCoreSetupInOut(pThis)
2301 && CidetCoreSetupCodeBuf(pThis, cSkipped + cExecuted)
2302 )
2303 {
2304 if (pThis->pfnExecute(pThis))
2305 {
2306 cExecuted++;
2307
2308 /*
2309 * Check the result against our expectations.
2310 */
2311 CidetCoreCheckResults(pThis);
2312 /** @todo check result. */
2313
2314 }
2315 else
2316 cSkipped++;
2317 }
2318 else
2319 cSkipped++;
2320 } while (CidetCoreSetupNextCodeBufferConfig(pThis));
2321 } while (CidetCoreSetupNextMemoryOperandConfig(pThis));
2322 }
2323 else
2324 cSkipped++;
2325 } while (CidetCoreSetupNextBaseEncoding(pThis));
2326
2327 CIDET_DPRINTF(("CidetCoreTest_Basic: cExecuted=%u cSkipped=%u\n"
2328 " cSkippedSetupInOut =%u\n"
2329 " cSkippedReInitDataBuf =%u\n"
2330 " cSkippedSetupDataBuf =%u\n"
2331 " cSkippedDataBufWrtRip =%u\n"
2332 " cSkippedAssemble =%u\n"
2333 " cSkippedReInitCodeBuf =%u\n"
2334 " cSkippedSetupCodeBuf =%u\n"
2335 " cSkippedSameBaseIndexRemainder =%u\n"
2336 " cSkippedOnlyIndexRemainder =%u\n"
2337 " cSkippedDirectAddressingOverflow =%u\n"
2338 ,
2339 cExecuted, cSkipped,
2340 pThis->cSkippedSetupInOut,
2341 pThis->cSkippedReInitDataBuf,
2342 pThis->cSkippedSetupDataBuf,
2343 pThis->cSkippedDataBufWrtRip,
2344 pThis->cSkippedAssemble,
2345 pThis->cSkippedReInitCodeBuf,
2346 pThis->cSkippedSetupCodeBuf,
2347 pThis->cSkippedSameBaseIndexRemainder,
2348 pThis->cSkippedOnlyIndexRemainder,
2349 pThis->cSkippedDirectAddressingOverflow
2350 ));
2351
2352 return true;
2353}
2354
2355
2356bool CidetCoreTestInstruction(PCIDETCORE pThis, PCCIDETINSTR pInstr)
2357{
2358 AssertReleaseMsgReturn(RT_VALID_PTR(pThis), ("%p\n", pThis), false);
2359 AssertReleaseReturn(pThis->u32Magic == CIDETCORE_MAGIC, false);
2360 AssertReleaseReturn(pThis->cCodeBufConfigs > 0, false);
2361
2362 if (!CideCoreSetInstruction(pThis, pInstr))
2363 return CidetCoreSetError(pThis, "CideCoreSetInstruction failed");
2364
2365 bool fResult = CidetCoreTest_Basic(pThis);
2366
2367 return fResult;
2368}
2369
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