VirtualBox

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

Last change on this file since 99754 was 98103, checked in by vboxsync, 2 years 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.7 KB
Line 
1/* $Id: cidet-core.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * CPU Instruction Decoding & Execution Tests - Simple Instructions.
4 */
5
6/*
7 * Copyright (C) 2014-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 * 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
141bool CidetInstrHasMrmMemOperand(PCCIDETINSTR pInstr)
142{
143 return CIDET_INSTR_TEST_OP_FLAG(pInstr, CIDET_OF_M_RM_ONLY_M);
144}
145
146
147bool CidetInstrHasMrmRegOperand(PCCIDETINSTR pInstr)
148{
149 return CIDET_INSTR_TEST_OP_FLAG(pInstr, CIDET_OF_M_RM_ONLY_R);
150}
151
152
153bool 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 */
190int 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 */
205bool 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 */
222int64_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 */
245uint64_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
257void 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
329bool CidetCoreIsEncodingCompatibleWithInstruction(PCIDETCORE pThis)
330{
331 RT_NOREF_PV(pThis);
332 return true;
333}
334
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: AssertReleaseFailed();
1208 case 3:
1209 break;
1210 }
1211 }
1212 else
1213 {
1214 if (!pThis->fOpSizePrf)
1215 {
1216 pThis->fOpSizePrf = true;
1217 cidetCoreUpdateOperandSizes(pThis);
1218 return true;
1219 }
1220 }
1221 pThis->fRexW = false;
1222 pThis->fOpSizePrf = false;
1223 cidetCoreUpdateOperandSizes(pThis);
1224 }
1225 return false;
1226}
1227
1228
1229bool CidetCoreSetupNextBaseEncoding(PCIDETCORE pThis)
1230{
1231 if (pThis->fUsesModRm)
1232 {
1233 /*
1234 * The wheels are lined up as follows:
1235 * 1. Address size prefix.
1236 * 2. MODRM.MOD
1237 * 3. MODRM.REG + REX.R
1238 * 4. MODRM.R/M + REX.B
1239 * 5. SIB - MODRM.R/M == 4 && MODRM.MOD != 3:
1240 * 5a) SIB.BASE + REX.B
1241 * 5b) SIB.INDEX + REX.X
1242 * 5c) SIB.SCALE
1243 * 6. Segment prefix overrides if applicable and supported (memory).
1244 * 7. Operand size prefix and REX.W if applicable.
1245 */
1246 if (cidetCoreSetupNextBaseEncoding_OperandSize(pThis))
1247 return true;
1248 if (cidetCoreSetupNextBaseEncoding_SegmentPrefix(pThis))
1249 return true;
1250
1251 /* The ModR/M register value for collision detection. */
1252 uint8_t iReg = ((pThis->bModRm >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) + pThis->fRexR * 8;
1253
1254 if (pThis->fSib)
1255 {
1256 AssertRelease(pThis->fHasMemoryOperand);
1257 if (cidetCoreSetupNextBaseEncoding_SibScale(pThis, iReg))
1258 return true;
1259 if (cidetCoreSetupNextBaseEncoding_SibIndex(pThis, iReg))
1260 return true;
1261 if (cidetCoreSetupNextBaseEncoding_SibBase(pThis, iReg))
1262 return true;
1263 Assert(pThis->bSib == 0);
1264 pThis->fSib = false;
1265 }
1266
1267 if (cidetCoreSetupNextBaseEncoding_MrmRmMod(pThis, iReg))
1268 return true;
1269 if (cidetCoreSetupNextBaseEncoding_MrmReg(pThis, iReg))
1270 return true;
1271 if (cidetCoreSetupNextBaseEncoding_AddressSize(pThis))
1272 return true;
1273 }
1274 else
1275 AssertFailedReturn(false);
1276 return false;
1277}
1278
1279
1280bool CidetCoreSetupFirstBaseEncoding(PCIDETCORE pThis)
1281{
1282 /*
1283 * Reset all the knobs and wheels.
1284 */
1285 pThis->fSib = false;
1286 pThis->uSegPrf = X86_SREG_COUNT;
1287 pThis->fAddrSizePrf = false;
1288 pThis->fOpSizePrf = false;
1289 pThis->fRexW = false;
1290 pThis->fRexR = false;
1291 pThis->fRexX = false;
1292 pThis->fRexB = false;
1293 pThis->fRex = false;
1294 pThis->bModRm = 0;
1295 pThis->bSib = 0;
1296
1297 /* Indicators. */
1298 pThis->cbAddrMode = CIDETMODE_GET_BYTE_COUNT(pThis->bMode);
1299 pThis->fHasMemoryOperand = false;
1300 pThis->fHasRegCollisionMem = false;
1301 pThis->fHasRegCollisionMemBase = false;
1302 pThis->fHasRegCollisionMemIndex = false;
1303 pThis->fHasStackRegInMrmRmBase = false;
1304
1305 /*
1306 * Now, drill down on the instruction encoding.
1307 */
1308 if (pThis->pCurInstr->fFlags & CIDET_IF_MODRM)
1309 {
1310 Assert(pThis->fUsesModRm == true);
1311 cidetCoreSetupFirstBaseEncoding_MrmReg(pThis);
1312 if (pThis->cbAddrMode == 2)
1313 cidetCoreSetupFirstBaseEncoding_MrmRmMod_16bit(pThis, 0);
1314 else if (pThis->cbAddrMode == 4)
1315 cidetCoreSetupFirstBaseEncoding_MrmRmMod_32bit64bit(pThis, 0, false);
1316 else if (pThis->cbAddrMode == 8)
1317 cidetCoreSetupFirstBaseEncoding_MrmRmMod_32bit64bit(pThis, 0, true);
1318 else
1319 AssertReleaseFailedReturn(false);
1320 }
1321 else
1322 AssertFailedReturn(false);
1323 return true;
1324}
1325
1326
1327/**
1328 * The next memory operand configuration.
1329 *
1330 * @returns true if new one to test, false if we've reached end already.
1331 * @param pThis The core state structure.
1332 */
1333bool CidetCoreSetupNextMemoryOperandConfig(PCIDETCORE pThis)
1334{
1335 RT_NOREF_PV(pThis);
1336 return false;
1337}
1338
1339
1340/**
1341 * Sets up the first memory operand configuration and counts memory operands.
1342 *
1343 * @returns true on success, false if no data buffers configured or failure.
1344 * @param pThis The core state structure.
1345 */
1346bool CidetCoreSetupFirstMemoryOperandConfig(PCIDETCORE pThis)
1347{
1348 pThis->cMemoryOperands = 0;
1349 PCIDETBUF pDataBuf = &pThis->DataBuf;
1350 uint8_t idxOp = pThis->cOperands;
1351 while (idxOp-- > 0)
1352 if (!pThis->aOperands[idxOp].fIsMem)
1353 pThis->aOperands[idxOp].pDataBuf = NULL;
1354 else
1355 {
1356 if (RT_UNLIKELY(!pThis->cDataBufConfigs))
1357 return false;
1358
1359 pDataBuf->idxCfg = 0;
1360 pDataBuf->pCfg = &pThis->paDataBufConfigs[0];
1361 pDataBuf->off = 0;
1362 pDataBuf->cb = pThis->aOperands[idxOp].cb;
1363 pDataBuf->cbSegLimit = UINT16_MAX;
1364 pDataBuf->offSegBase = 0;
1365 pDataBuf->fActive = false;
1366 pDataBuf->idxOp = idxOp;
1367 pDataBuf->fXcptAfterInstruction = false;
1368 pDataBuf->enmExpectXcpt = kCidetExpectXcpt_None;
1369 pThis->aOperands[idxOp].pDataBuf = pDataBuf;
1370 pThis->cMemoryOperands++;
1371 pDataBuf++;
1372 }
1373
1374 /** @todo implement more than one memory operand. */
1375 AssertReleaseReturn(pThis->cMemoryOperands <= 1, false);
1376 return true;
1377}
1378
1379
1380/**
1381 * The next code buffer configuration.
1382 *
1383 * @returns true if new one to test, false if we've reached end already.
1384 * @param pThis The core state structure.
1385 */
1386bool CidetCoreSetupNextCodeBufferConfig(PCIDETCORE pThis)
1387{
1388 RT_NOREF_PV(pThis);
1389 return false;
1390}
1391
1392
1393/**
1394 * Sets up the first code buffer configuration.
1395 *
1396 * @returns true on success, false if no data buffers configured or failure.
1397 * @param pThis The core state structure.
1398 */
1399bool CidetCoreSetupFirstCodeBufferConfig(PCIDETCORE pThis)
1400{
1401 Assert(pThis->cCodeBufConfigs > 0);
1402 Assert(CIDETBUF_IS_CODE(pThis->paCodeBufConfigs[0].fFlags));
1403 pThis->CodeBuf.idxCfg = 0;
1404 pThis->CodeBuf.pCfg = &pThis->paCodeBufConfigs[0];
1405 pThis->CodeBuf.off = 0;
1406 pThis->CodeBuf.cb = 0x1000;
1407 pThis->CodeBuf.cbSegLimit = UINT16_MAX;
1408 pThis->CodeBuf.offSegBase = 0;
1409 pThis->CodeBuf.fActive = true;
1410 pThis->CodeBuf.idxOp = 7;
1411 pThis->CodeBuf.fXcptAfterInstruction = false;
1412 pThis->CodeBuf.enmExpectXcpt = kCidetExpectXcpt_None;
1413 return true;
1414}
1415
1416
1417/**
1418 * Gets the (encoded) size of the given operand in the current context.
1419 *
1420 * @returns Size in bytes.
1421 * @param pThis The core state structure (for context).
1422 * @param iOp The operand index.
1423 */
1424uint32_t CidetCoreGetOperandSize(PCIDETCORE pThis, uint8_t iOp)
1425{
1426 Assert(iOp < RT_ELEMENTS(pThis->aOperands));
1427 uint32_t cbOp = g_acbCidetOfSizes[(pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) >> CIDET_OF_Z_SHIFT];
1428 if (cbOp == UINT16_MAX)
1429 {
1430 Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_VAR_WDQ);
1431 if (CIDETMODE_IS_64BIT(pThis->bMode))
1432 {
1433 if (pThis->fRexW)
1434 cbOp = 8;
1435 else if (!pThis->fOpSizePrf)
1436 cbOp = 4;
1437 else
1438 cbOp = 2;
1439 }
1440 else if (CIDETMODE_IS_32BIT(pThis->bMode))
1441 cbOp = !pThis->fOpSizePrf ? 4 : 2;
1442 else
1443 {
1444 Assert(CIDETMODE_IS_16BIT(pThis->bMode));
1445 cbOp = !pThis->fOpSizePrf ? 2 : 4;
1446 }
1447 return cbOp;
1448 }
1449
1450 if (cbOp == UINT16_MAX - 1)
1451 {
1452 Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_SPECIAL);
1453 AssertReleaseFailedReturn(0);
1454 }
1455
1456 if (cbOp)
1457 {
1458#ifdef VBOX_STRICT
1459 switch (cbOp)
1460 {
1461 case 1: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_BYTE); break;
1462 case 2: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_WORD); break;
1463 case 4: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_DWORD); break;
1464 case 8: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_QWORD); break;
1465 case 10: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_TBYTE); break;
1466 case 16: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_OWORD); break;
1467 case 32: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_YWORD); break;
1468 case 64: Assert((pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) == CIDET_OF_Z_ZWORD); break;
1469 default: AssertFailed();
1470 }
1471#endif
1472 return cbOp;
1473 }
1474 AssertReleaseFailedReturn(0);
1475}
1476
1477
1478bool CideCoreSetInstruction(PCIDETCORE pThis, PCCIDETINSTR pInstr)
1479{
1480 AssertReleaseMsgReturn(RT_VALID_PTR(pInstr), ("%p\n", pInstr), false);
1481
1482 pThis->pCurInstr = pInstr;
1483
1484 /*
1485 * Extract info from the instruction descriptor.
1486 */
1487 pThis->fUsesModRm = false;
1488 pThis->fUsesVexIndexRegs = false;
1489 pThis->idxMrmRegOp = 7;
1490 pThis->idxMrmRmOp = 7;
1491 pThis->fMrmRegOp = 0;
1492 pThis->fMrmRmOp = 0;
1493 pThis->fInstrFlags = pInstr->fFlags;
1494 pThis->cOperands = pInstr->cOperands;
1495 if (pInstr->fFlags & CIDET_IF_MODRM)
1496 {
1497 pThis->fUsesModRm = true;
1498 for (uint8_t iOp = 0; iOp < pInstr->cOperands; iOp++)
1499 if (pInstr->afOperands[iOp] & CIDET_OF_M_REG)
1500 {
1501 pThis->idxMrmRegOp = iOp;
1502 pThis->fMrmRegOp = pInstr->afOperands[iOp];
1503 }
1504 else if (pInstr->afOperands[iOp] & CIDET_OF_M_RM)
1505 {
1506 pThis->idxMrmRmOp = iOp;
1507 pThis->fMrmRmOp = pInstr->afOperands[iOp];
1508 }
1509 }
1510 else
1511 AssertFailedReturn(false);
1512
1513 uint8_t iOp;
1514 for (iOp = 0; iOp < pInstr->cOperands; iOp++)
1515 {
1516 pThis->aOperands[iOp].fFlags = pInstr->afOperands[iOp];
1517 pThis->aOperands[iOp].iReg = UINT8_MAX;
1518 pThis->aOperands[iOp].cb = (uint8_t)CidetCoreGetOperandSize(pThis, iOp);
1519 pThis->aOperands[iOp].fIsImmediate = (pInstr->afOperands[iOp] & CIDET_OF_K_MASK) == CIDET_OF_K_IMM;
1520 pThis->aOperands[iOp].fIsMem = (pInstr->afOperands[iOp] & CIDET_OF_K_MASK) == CIDET_OF_K_MEM;
1521 pThis->aOperands[iOp].fIsRipRelative = false;
1522 pThis->aOperands[iOp].cbMemDisp = 0;
1523 pThis->aOperands[iOp].iMemBaseReg = UINT8_MAX;
1524 pThis->aOperands[iOp].iMemIndexReg = UINT8_MAX;
1525 pThis->aOperands[iOp].uMemScale = 1;
1526 pThis->aOperands[iOp].iEffSeg = UINT8_MAX;
1527 pThis->aOperands[iOp].offSeg = UINT64_MAX;
1528 pThis->aOperands[iOp].uEffAddr = UINT64_MAX;
1529 pThis->aOperands[iOp].uImmDispValue = UINT64_MAX;
1530 pThis->aOperands[iOp].uMemBaseRegValue = UINT64_MAX;
1531 pThis->aOperands[iOp].uMemIndexRegValue = UINT64_MAX;
1532 pThis->aOperands[iOp].In.pv = NULL;
1533 pThis->aOperands[iOp].Expected.pv = NULL;
1534 pThis->aOperands[iOp].pDataBuf = NULL;
1535 }
1536
1537 for (; iOp < RT_ELEMENTS(pThis->aOperands); iOp++)
1538 {
1539 pThis->aOperands[iOp].fFlags = 0;
1540 pThis->aOperands[iOp].iReg = UINT8_MAX;
1541 pThis->aOperands[iOp].cb = 0;
1542 pThis->aOperands[iOp].fIsImmediate = false;
1543 pThis->aOperands[iOp].fIsMem = false;
1544 pThis->aOperands[iOp].fIsRipRelative = false;
1545 pThis->aOperands[iOp].cbMemDisp = 0;
1546 pThis->aOperands[iOp].iMemBaseReg = UINT8_MAX;
1547 pThis->aOperands[iOp].iMemIndexReg = UINT8_MAX;
1548 pThis->aOperands[iOp].uMemScale = 1;
1549 pThis->aOperands[iOp].iEffSeg = UINT8_MAX;
1550 pThis->aOperands[iOp].offSeg = UINT64_MAX;
1551 pThis->aOperands[iOp].uEffAddr = UINT64_MAX;
1552 pThis->aOperands[iOp].uImmDispValue = UINT64_MAX;
1553 pThis->aOperands[iOp].uMemBaseRegValue = UINT64_MAX;
1554 pThis->aOperands[iOp].uMemIndexRegValue = UINT64_MAX;
1555 pThis->aOperands[iOp].In.pv = NULL;
1556 pThis->aOperands[iOp].Expected.pv = NULL;
1557 pThis->aOperands[iOp].pDataBuf = NULL;
1558 }
1559
1560 /*
1561 * Reset various things.
1562 */
1563 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aiInOut); i++)
1564 pThis->aiInOut[i] = 0;
1565
1566 return true;
1567}
1568
1569
1570bool CidetCoreSetupInOut(PCIDETCORE pThis)
1571{
1572 /*
1573 * Enumerate the operands.
1574 */
1575 uint8_t *pbBuf = &pThis->abBuf[0];
1576 pbBuf = RT_ALIGN_PT(pbBuf, 16, uint8_t *);
1577
1578 uint8_t idxOp = pThis->cOperands;
1579 while (idxOp-- > 0)
1580 {
1581 if (pThis->aOperands[idxOp].fIsMem)
1582 {
1583 /*
1584 * Memory operand.
1585 */
1586 Assert(pThis->aOperands[idxOp].fIsMem);
1587
1588 /* Set the In & Expected members to point to temporary buffer space. */
1589 pThis->aOperands[idxOp].Expected.pu8 = pbBuf;
1590 pbBuf += pThis->aOperands[idxOp].cb;
1591 pbBuf = RT_ALIGN_PT(pbBuf, 16, uint8_t *);
1592
1593 pThis->aOperands[idxOp].In.pu8 = pbBuf;
1594 pbBuf += pThis->aOperands[idxOp].cb;
1595 pbBuf = RT_ALIGN_PT(pbBuf, 16, uint8_t *);
1596
1597 /* Initialize the buffer we're gonna use. */
1598 pThis->aOperands[idxOp].iEffSeg = pThis->uSegPrf != X86_SREG_COUNT
1599 ? pThis->uSegPrf
1600 : !(pThis->aOperands[idxOp].fFlags & CIDET_OF_ALWAYS_SEG_ES) ? X86_SREG_DS
1601 : X86_SREG_ES;
1602
1603 PCIDETBUF pDataBuf = pThis->aOperands[idxOp].pDataBuf;
1604 AssertReleaseReturn(pDataBuf, false);
1605 Assert(pDataBuf->cb == pThis->aOperands[idxOp].cb);
1606 Assert(pDataBuf->idxOp == idxOp);
1607 if (!pThis->pfnReInitDataBuf(pThis, pDataBuf))
1608 {
1609 pThis->cSkippedReInitDataBuf++;
1610 return false;
1611 }
1612 pDataBuf->fActive = true;
1613
1614 /* Calc buffer related operand members. */
1615 pThis->aOperands[idxOp].uEffAddr = pDataBuf->uEffBufAddr + pDataBuf->off;
1616 uint64_t offSeg = pThis->aOperands[idxOp].uEffAddr - pDataBuf->uSegBase;
1617 pThis->aOperands[idxOp].offSeg = offSeg;
1618 AssertRelease(offSeg <= g_au64ByteSizeToMask[pThis->cbAddrMode]);
1619
1620 /*
1621 * Select register and displacement values for the buffer addressing (works on offSeg).
1622 */
1623 uint8_t const iMemIndexReg = pThis->aOperands[idxOp].iMemIndexReg;
1624 uint8_t const iMemBaseReg = pThis->aOperands[idxOp].iMemBaseReg;
1625 if (pThis->aOperands[idxOp].fIsRipRelative)
1626 {
1627 /* rip relative. */
1628 pThis->aOperands[idxOp].uImmDispValue = offSeg - (pThis->InCtx.rip + pThis->cbInstr);
1629 Assert(pThis->aOperands[idxOp].cbMemDisp == 4);
1630 if ( (int64_t)pThis->aOperands[idxOp].uImmDispValue > INT32_MAX
1631 || (int64_t)pThis->aOperands[idxOp].uImmDispValue < INT32_MIN)
1632 {
1633 pThis->cSkippedDataBufWrtRip++;
1634 return false;
1635 }
1636 }
1637 else if (iMemBaseReg != UINT8_MAX)
1638 {
1639 if ( iMemBaseReg != iMemIndexReg
1640 || pThis->fUsesVexIndexRegs)
1641 {
1642 /* [base] or [base + disp] or [base + index * scale] or [base + index * scale + disp] */
1643 if (pThis->aOperands[idxOp].cbMemDisp > 0)
1644 {
1645 pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
1646 offSeg -= (int64_t)pThis->aOperands[idxOp].uImmDispValue;
1647 }
1648
1649 if (iMemIndexReg != UINT8_MAX)
1650 {
1651 pThis->aOperands[idxOp].uMemIndexRegValue = CidetCoreGetRandU64(pThis, pThis->cbAddrMode);
1652 offSeg -= pThis->aOperands[idxOp].uMemIndexRegValue * pThis->aOperands[idxOp].uMemScale;
1653 }
1654
1655 pThis->aOperands[idxOp].uMemBaseRegValue = offSeg & g_au64ByteSizeToMask[pThis->cbAddrMode];
1656 }
1657 else
1658 {
1659 /* base == index; [base + index * scale] or [base * (scale + 1)]. */
1660 uint8_t const uEffScale = pThis->aOperands[idxOp].uMemScale + 1;
1661 if (pThis->aOperands[idxOp].cbMemDisp > 0)
1662 {
1663 pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
1664 offSeg -= (int64_t)pThis->aOperands[idxOp].uImmDispValue;
1665 offSeg &= g_au64ByteSizeToMask[pThis->cbAddrMode];
1666 uint8_t uRemainder = offSeg % uEffScale;
1667 if (uRemainder != 0)
1668 {
1669 Assert(pThis->aOperands[idxOp].cbMemDisp < 8);
1670 Assert( (int64_t)pThis->aOperands[idxOp].uImmDispValue
1671 <= g_ai64ByteSizeToMax[pThis->aOperands[idxOp].cbMemDisp]);
1672 pThis->aOperands[idxOp].uImmDispValue = (int64_t)pThis->aOperands[idxOp].uImmDispValue
1673 + uRemainder;
1674 offSeg -= uRemainder;
1675 if ( (int64_t)pThis->aOperands[idxOp].uImmDispValue
1676 > g_ai64ByteSizeToMax[pThis->aOperands[idxOp].cbMemDisp])
1677 {
1678 pThis->aOperands[idxOp].uImmDispValue -= uEffScale;
1679 offSeg += uEffScale;
1680 }
1681 Assert(offSeg % uEffScale == 0);
1682 }
1683 }
1684 else
1685 {
1686 offSeg &= g_au64ByteSizeToMask[pThis->cbAddrMode];
1687 if (offSeg % uEffScale != 0)
1688 {
1689 pThis->cSkippedSameBaseIndexRemainder++;
1690 return false;
1691 }
1692 }
1693 offSeg /= uEffScale;
1694 pThis->aOperands[idxOp].uMemBaseRegValue = pThis->aOperands[idxOp].uMemIndexRegValue = offSeg;
1695 }
1696 }
1697 else if (iMemIndexReg != UINT8_MAX)
1698 {
1699 /* [index * scale] or [index * scale + disp] */
1700 if (pThis->aOperands[idxOp].cbMemDisp > 0)
1701 {
1702 pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
1703 offSeg -= (int64_t)pThis->aOperands[idxOp].uImmDispValue;
1704 pThis->aOperands[idxOp].uImmDispValue += offSeg & (RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1);
1705 offSeg &= ~(RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1);
1706 }
1707 else if (offSeg & (RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1))
1708 {
1709 pThis->cSkippedOnlyIndexRemainder++;
1710 return false;
1711 }
1712
1713 pThis->aOperands[idxOp].uMemIndexRegValue = offSeg / pThis->aOperands[idxOp].uMemScale;
1714 Assert((offSeg % pThis->aOperands[idxOp].uMemScale) == 0);
1715 AssertRelease(!pThis->fUsesVexIndexRegs); /** @todo implement VEX indexing */
1716 }
1717 else
1718 {
1719 /* [disp] */
1720 Assert( pThis->aOperands[idxOp].cbMemDisp == 8
1721 || pThis->aOperands[idxOp].cbMemDisp == 4
1722 || pThis->aOperands[idxOp].cbMemDisp == 2
1723 || pThis->aOperands[idxOp].cbMemDisp == 1);
1724 if ( pThis->aOperands[idxOp].cbMemDisp == 4
1725 ? (int64_t)offSeg != (int32_t)offSeg
1726 : pThis->aOperands[idxOp].cbMemDisp == 2
1727 ? (int64_t)offSeg != (int16_t)offSeg
1728 : pThis->aOperands[idxOp].cbMemDisp == 1
1729 ? (int64_t)offSeg != (int8_t)offSeg
1730 : false /* 8 */)
1731 {
1732 pThis->cSkippedDirectAddressingOverflow++;
1733 return false;
1734 }
1735 pThis->aOperands[idxOp].uImmDispValue = offSeg;
1736 }
1737
1738 /*
1739 * Modify the input and expected output contexts with the base and
1740 * index register values. To simplify verification and the work
1741 * here, we update the uMemBaseRegValue and uMemIndexRegValue
1742 * members to reflect the whole register.
1743 */
1744 if (iMemBaseReg != UINT8_MAX)
1745 {
1746 if (pThis->cbAddrMode == 4)
1747 {
1748 pThis->aOperands[idxOp].uMemBaseRegValue &= UINT32_MAX;
1749 pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffff00000000);
1750 }
1751 else if (pThis->cbAddrMode == 2)
1752 {
1753 pThis->aOperands[idxOp].uMemBaseRegValue &= UINT16_MAX;
1754 pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffffffff0000);
1755 }
1756 pThis->InCtx.aGRegs[iMemBaseReg] = pThis->aOperands[idxOp].uMemBaseRegValue;
1757 pThis->ExpectedCtx.aGRegs[iMemBaseReg] = pThis->aOperands[idxOp].uMemBaseRegValue;
1758 }
1759
1760 if (iMemIndexReg != UINT8_MAX)
1761 {
1762 if (pThis->cbAddrMode == 4)
1763 {
1764 pThis->aOperands[idxOp].uMemIndexRegValue &= UINT32_MAX;
1765 pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffff00000000);
1766 }
1767 else if (pThis->cbAddrMode == 2)
1768 {
1769 pThis->aOperands[idxOp].uMemIndexRegValue &= UINT16_MAX;
1770 pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffffffff0000);
1771 }
1772 pThis->InCtx.aGRegs[iMemIndexReg] = pThis->aOperands[idxOp].uMemIndexRegValue;
1773 pThis->ExpectedCtx.aGRegs[iMemIndexReg] = pThis->aOperands[idxOp].uMemIndexRegValue;
1774 }
1775 }
1776 else
1777 {
1778 /*
1779 * Non-memory, so clear the memory related members.
1780 */
1781 Assert(!pThis->aOperands[idxOp].fIsMem);
1782 pThis->aOperands[idxOp].iEffSeg = UINT8_MAX;
1783 pThis->aOperands[idxOp].offSeg = UINT64_MAX;
1784 pThis->aOperands[idxOp].uEffAddr = UINT64_MAX;
1785 pThis->aOperands[idxOp].pDataBuf = NULL;
1786
1787 switch (pThis->aOperands[idxOp].fFlags & CIDET_OF_K_MASK)
1788 {
1789 case CIDET_OF_K_GPR:
1790 if (!pThis->aOperands[idxOp].fIsHighByteRegister)
1791 {
1792 pThis->aOperands[idxOp].In.pv = &pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iReg];
1793 pThis->aOperands[idxOp].Expected.pv = &pThis->ExpectedCtx.aGRegs[pThis->aOperands[idxOp].iReg];
1794 }
1795 else
1796 {
1797 pThis->aOperands[idxOp].In.pv = &pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iReg - 4];
1798 pThis->aOperands[idxOp].In.pu8++;
1799 pThis->aOperands[idxOp].Expected.pv = &pThis->ExpectedCtx.aGRegs[pThis->aOperands[idxOp].iReg - 4];
1800 pThis->aOperands[idxOp].Expected.pu8++;
1801 }
1802 break;
1803
1804 case CIDET_OF_K_IMM:
1805 pThis->aOperands[idxOp].In.pv = NULL;
1806 pThis->aOperands[idxOp].Expected.pv = NULL;
1807 break;
1808
1809 case CIDET_OF_K_SREG:
1810 if (pThis->aOperands[idxOp].iReg < RT_ELEMENTS(pThis->InCtx.aSRegs))
1811 {
1812 pThis->aOperands[idxOp].In.pv = &pThis->InCtx.aSRegs[pThis->aOperands[idxOp].iReg];
1813 pThis->aOperands[idxOp].Expected.pv = &pThis->ExpectedCtx.aSRegs[pThis->aOperands[idxOp].iReg];
1814 }
1815 else
1816 {
1817 pThis->aOperands[idxOp].In.pv = NULL;
1818 pThis->aOperands[idxOp].Expected.pv = NULL;
1819 }
1820 break;
1821
1822 case CIDET_OF_K_CR:
1823 case CIDET_OF_K_SSE:
1824 case CIDET_OF_K_AVX:
1825 case CIDET_OF_K_AVX512:
1826 case CIDET_OF_K_FPU:
1827 case CIDET_OF_K_MMX:
1828 case CIDET_OF_K_AVXFUTURE:
1829 case CIDET_OF_K_SPECIAL:
1830 case CIDET_OF_K_TEST:
1831 /** @todo Implement testing these registers. */
1832 case CIDET_OF_K_NONE:
1833 default:
1834 AssertReleaseFailedReturn(false);
1835 }
1836 }
1837 }
1838 AssertRelease((uintptr_t)pbBuf - (uintptr_t)&pThis->abBuf[0] <= sizeof(pThis->abBuf));
1839
1840 /*
1841 * Call instruction specific setup function (for operand values and flags).
1842 */
1843 int rc = pThis->pCurInstr->pfnSetupInOut(pThis, false /*fInvalid*/);
1844 if (RT_FAILURE(rc))
1845 {
1846 pThis->cSkippedSetupInOut++;
1847 return false;
1848 }
1849
1850 /*
1851 * Do the 2nd set of the memory operand preparations.
1852 */
1853 if (pThis->fHasMemoryOperand)
1854 {
1855 idxOp = pThis->cOperands;
1856 while (idxOp-- > 0)
1857 if (pThis->aOperands[idxOp].fIsMem)
1858 {
1859 Assert(pThis->aOperands[idxOp].pDataBuf);
1860 if (!pThis->pfnSetupDataBuf(pThis, pThis->aOperands[idxOp].pDataBuf, pThis->aOperands[idxOp].In.pv))
1861 {
1862 pThis->cSkippedSetupDataBuf++;
1863 return false;
1864 }
1865
1866 Assert( pThis->aOperands[idxOp].iMemBaseReg == UINT8_MAX
1867 || pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iMemBaseReg] == pThis->aOperands[idxOp].uMemBaseRegValue);
1868 Assert( pThis->aOperands[idxOp].iMemIndexReg == UINT8_MAX
1869 || ( !pThis->fUsesVexIndexRegs
1870 ? pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iMemIndexReg]
1871 == pThis->aOperands[idxOp].uMemIndexRegValue
1872 : false /** @todo VEX indexing */));
1873 }
1874 }
1875
1876 return true;
1877}
1878
1879
1880/**
1881 * Figures the instruction length.
1882 *
1883 * This is a duplicate of CidetCoreAssemble() with the buffer updates removed.
1884 *
1885 * @returns true and pThis->cbInstr on success, false on failure.
1886 * @param pThis The core state structure (for context).
1887 */
1888bool CidetCoreAssembleLength(PCIDETCORE pThis)
1889{
1890 uint8_t off = 0;
1891
1892 /*
1893 * Prefixes.
1894 */
1895 if (1)
1896 {
1897 if (pThis->fAddrSizePrf)
1898 off++;
1899 if (pThis->fOpSizePrf)
1900 off++;
1901 }
1902 else
1903 {
1904 /** @todo prefix list. */
1905 }
1906
1907 /*
1908 * Prefixes that must come right before the opcode.
1909 */
1910 /** @todo VEX and EVEX. */
1911 if (pThis->fVex)
1912 {
1913 /** @todo VEX and EVEX. */
1914 }
1915 else if (pThis->fEvex)
1916 {
1917 /** @todo VEX and EVEX. */
1918 }
1919 else
1920 {
1921 if (pThis->fRexB || pThis->fRexX || pThis->fRexR || pThis->fRexW || pThis->fRex)
1922 off++;
1923 }
1924
1925 /*
1926 * The opcode.
1927 */
1928 //uint8_t const *pbOpcode = pThis->pCurInstr->abOpcode;
1929 switch (pThis->pCurInstr->cbOpcode)
1930 {
1931 case 3: off++; RT_FALL_THRU();
1932 case 2: off++; RT_FALL_THRU();
1933 case 1: off++;
1934 break;
1935 default:
1936 AssertReleaseFailedReturn(false);
1937 }
1938
1939 /*
1940 * Mod R/M
1941 */
1942 if (pThis->fUsesModRm)
1943 {
1944 off++;
1945 if (pThis->fSib)
1946 off++;
1947 if (pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands))
1948 {
1949 //uint64_t uDispValue = pThis->aOperands[pThis->idxMrmRmOp].uImmDispValue;
1950 switch (pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp)
1951 {
1952 case 0: break;
1953 case 8:
1954 case 7:
1955 case 6:
1956 case 5:
1957 case 4:
1958 case 3:
1959 case 2:
1960 case 1:
1961 break;
1962 default: AssertReleaseFailedReturn(false);
1963 }
1964 off += pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp;
1965 }
1966 }
1967
1968 /*
1969 * Immediates.
1970 */
1971 uint8_t iOp = pThis->cOperands;
1972 while (iOp-- > 0)
1973 if ((pThis->aOperands[iOp].fFlags & CIDET_OF_K_MASK) == CIDET_OF_K_IMM)
1974 {
1975 //uint64_t uImmValue = pThis->aOperands[iOp].uImmDispValue;
1976 switch (pThis->aOperands[iOp].cb)
1977 {
1978 case 8:
1979 case 7:
1980 case 6:
1981 case 5:
1982 case 4:
1983 case 3:
1984 case 2:
1985 case 1:
1986 break;
1987 default: AssertReleaseFailedReturn(false);
1988 }
1989 off += pThis->aOperands[iOp].cb;
1990 }
1991
1992 pThis->cbInstr = off;
1993 return true;
1994}
1995
1996
1997/**
1998 * Assembles the instruction.
1999 *
2000 * This is a duplicate of CidetCoreAssembleLength() with buffer writes.
2001 *
2002 * @returns true and pThis->cbInstr and pThis->abInstr on success, false on
2003 * failure.
2004 * @param pThis The core state structure (for context).
2005 */
2006bool CidetCoreAssemble(PCIDETCORE pThis)
2007{
2008 uint8_t off = 0;
2009
2010 /*
2011 * Prefixes.
2012 */
2013 if (1)
2014 {
2015 if (pThis->fAddrSizePrf)
2016 pThis->abInstr[off++] = 0x67;
2017 if (pThis->fOpSizePrf)
2018 pThis->abInstr[off++] = 0x66;
2019 }
2020 else
2021 {
2022 /** @todo prefix list. */
2023 }
2024
2025 /*
2026 * Prefixes that must come right before the opcode.
2027 */
2028 /** @todo VEX and EVEX. */
2029 if (pThis->fVex)
2030 {
2031 /** @todo VEX and EVEX. */
2032 }
2033 else if (pThis->fEvex)
2034 {
2035 /** @todo VEX and EVEX. */
2036 }
2037 else
2038 {
2039 if (pThis->fRexB || pThis->fRexX || pThis->fRexR || pThis->fRexW || pThis->fRex)
2040 pThis->abInstr[off++] = 0x40 | (pThis->fRexB * 1) | (pThis->fRexX * 2) | (pThis->fRexR * 4) | (pThis->fRexW * 8);
2041 }
2042
2043 /*
2044 * The opcode.
2045 */
2046 uint8_t const *pbOpcode = pThis->pCurInstr->abOpcode;
2047 switch (pThis->pCurInstr->cbOpcode)
2048 {
2049 case 3: pThis->abInstr[off++] = *pbOpcode++; RT_FALL_THRU();
2050 case 2: pThis->abInstr[off++] = *pbOpcode++; RT_FALL_THRU();
2051 case 1: pThis->abInstr[off++] = *pbOpcode++;
2052 break;
2053 default:
2054 AssertReleaseFailedReturn(false);
2055 }
2056
2057 /*
2058 * Mod R/M
2059 */
2060 if (pThis->fUsesModRm)
2061 {
2062 pThis->abInstr[off++] = pThis->bModRm;
2063 if (pThis->fSib)
2064 pThis->abInstr[off++] = pThis->bSib;
2065 if (pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands))
2066 {
2067 uint64_t uDispValue = pThis->aOperands[pThis->idxMrmRmOp].uImmDispValue;
2068 switch (pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp)
2069 {
2070 case 0: break;
2071 case 8: pThis->abInstr[off + 3] = (uDispValue >> 56) & UINT8_C(0xff); RT_FALL_THRU();
2072 case 7: pThis->abInstr[off + 3] = (uDispValue >> 48) & UINT8_C(0xff); RT_FALL_THRU();
2073 case 6: pThis->abInstr[off + 3] = (uDispValue >> 40) & UINT8_C(0xff); RT_FALL_THRU();
2074 case 5: pThis->abInstr[off + 3] = (uDispValue >> 32) & UINT8_C(0xff); RT_FALL_THRU();
2075 case 4: pThis->abInstr[off + 3] = (uDispValue >> 24) & UINT8_C(0xff); RT_FALL_THRU();
2076 case 3: pThis->abInstr[off + 2] = (uDispValue >> 16) & UINT8_C(0xff); RT_FALL_THRU();
2077 case 2: pThis->abInstr[off + 1] = (uDispValue >> 8) & UINT8_C(0xff); RT_FALL_THRU();
2078 case 1: pThis->abInstr[off] = uDispValue & UINT8_C(0xff);
2079 break;
2080 default: AssertReleaseFailedReturn(false);
2081 }
2082 off += pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp;
2083 }
2084 }
2085
2086 /*
2087 * Immediates.
2088 */
2089 uint8_t iOp = pThis->cOperands;
2090 while (iOp-- > 0)
2091 if ((pThis->aOperands[iOp].fFlags & CIDET_OF_K_MASK) == CIDET_OF_K_IMM)
2092 {
2093 uint64_t uImmValue = pThis->aOperands[iOp].uImmDispValue;
2094 switch (pThis->aOperands[iOp].cb)
2095 {
2096 case 8: pThis->abInstr[off + 3] = (uImmValue >> 56) & UINT8_C(0xff); RT_FALL_THRU();
2097 case 7: pThis->abInstr[off + 3] = (uImmValue >> 48) & UINT8_C(0xff); RT_FALL_THRU();
2098 case 6: pThis->abInstr[off + 3] = (uImmValue >> 40) & UINT8_C(0xff); RT_FALL_THRU();
2099 case 5: pThis->abInstr[off + 3] = (uImmValue >> 32) & UINT8_C(0xff); RT_FALL_THRU();
2100 case 4: pThis->abInstr[off + 3] = (uImmValue >> 24) & UINT8_C(0xff); RT_FALL_THRU();
2101 case 3: pThis->abInstr[off + 2] = (uImmValue >> 16) & UINT8_C(0xff); RT_FALL_THRU();
2102 case 2: pThis->abInstr[off + 1] = (uImmValue >> 8) & UINT8_C(0xff); RT_FALL_THRU();
2103 case 1: pThis->abInstr[off] = uImmValue & UINT8_C(0xff);
2104 break;
2105 default: AssertReleaseFailedReturn(false);
2106 }
2107 off += pThis->aOperands[iOp].cb;
2108 }
2109
2110 pThis->cbInstr = off;
2111 return true;
2112}
2113
2114
2115bool CidetCoreReInitCodeBuf(PCIDETCORE pThis)
2116{
2117 /*
2118 * Re-initialize the buffer. Requires instruction length and positioning.
2119 */
2120 if (CidetCoreAssembleLength(pThis))
2121 {
2122 pThis->CodeBuf.cb = pThis->cbInstr;
2123 pThis->CodeBuf.off = CIDET_CODE_BUF_SIZE - PAGE_SIZE - pThis->cbInstr;
2124 if (pThis->pfnReInitCodeBuf(pThis, &pThis->CodeBuf))
2125 {
2126 pThis->CodeBuf.fActive = true;
2127
2128 /*
2129 * Update the RIP and CS values in the input and expected contexts.
2130 */
2131 pThis->InCtx.rip = pThis->CodeBuf.uEffBufAddr + pThis->CodeBuf.offActive - pThis->CodeBuf.uSegBase;
2132 pThis->ExpectedCtx.rip = pThis->InCtx.rip + pThis->cbInstr; /** @todo account for expected traps. */
2133 if (pThis->CodeBuf.uSeg != UINT32_MAX)
2134 {
2135 pThis->InCtx.aSRegs[X86_SREG_CS] = pThis->CodeBuf.uSeg;
2136 pThis->ExpectedCtx.aSRegs[X86_SREG_CS] = pThis->CodeBuf.uSeg;
2137 }
2138 return true;
2139 }
2140 else
2141 pThis->cSkippedReInitCodeBuf++;
2142 }
2143 else
2144 pThis->cSkippedAssemble++;
2145 return false;
2146}
2147
2148
2149#ifdef CIDET_DEBUG_DISAS
2150/**
2151 * @callback_method_impl{FNDISREADBYTES}
2152 */
2153static DECLCALLBACK(int) cidetCoreDisReadBytes(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
2154{
2155 PCIDETCORE pThis = (PCIDETCORE)pDis->pvUser;
2156 memcpy(&pDis->abInstr[offInstr], &pThis->abInstr[offInstr], cbMaxRead);
2157 pDis->cbCachedInstr = offInstr + cbMaxRead;
2158 return VINF_SUCCESS;
2159}
2160#endif
2161
2162
2163bool CidetCoreSetupCodeBuf(PCIDETCORE pThis, unsigned iSubTest)
2164{
2165 if (CidetCoreAssemble(pThis))
2166 {
2167 //CIDET_DPRINTF(("%04u: %.*Rhxs\n", i, pThis->cbInstr, pThis->abInstr));
2168#ifdef CIDET_DEBUG_DISAS
2169 DISCPUSTATE Dis;
2170 char szInstr[80] = {0};
2171 uint32_t cbInstr;
2172 int rcDis = DISInstrToStrEx(pThis->InCtx.rip,
2173 CIDETMODE_IS_64BIT(pThis->bMode) ? DISCPUMODE_64BIT
2174 : CIDETMODE_IS_32BIT(pThis->bMode) ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
2175 cidetCoreDisReadBytes,
2176 pThis,
2177 DISOPTYPE_ALL,
2178 &Dis,
2179 &cbInstr,
2180 szInstr, sizeof(szInstr));
2181 CIDET_DPRINTF(("%04u: %s", iSubTest, szInstr));
2182 Assert(cbInstr == pThis->cbInstr);
2183#else
2184 RT_NOREF_PV(iSubTest);
2185#endif
2186 if (pThis->pfnSetupCodeBuf(pThis, &pThis->CodeBuf, pThis->abInstr))
2187 {
2188 return true;
2189 }
2190 pThis->cSkippedSetupCodeBuf++;
2191 }
2192 else
2193 pThis->cSkippedAssemble++;
2194 return false;
2195}
2196
2197
2198/**
2199 * Compares the output with the output expectations.
2200 *
2201 * @returns true if ok, false if not (calls pfnFailure too).
2202 * @param pThis The core state structure.
2203 */
2204bool CidetCoreCheckResults(PCIDETCORE pThis)
2205{
2206 if (memcmp(&pThis->ActualCtx, &pThis->ExpectedCtx, CIDETCPUCTX_COMPARE_SIZE) == 0)
2207 return true;
2208
2209 unsigned cDiffs = 0;
2210#define IF_FIELD_DIFFERS_SET_ERROR(a_Field, a_Fmt) \
2211 if (pThis->ActualCtx.a_Field != pThis->ExpectedCtx.a_Field) \
2212 { \
2213 CidetCoreSetError(pThis, #a_Field " differs: got %#llx expected %#llx", \
2214 pThis->ActualCtx.a_Field, pThis->ExpectedCtx.a_Field); \
2215 cDiffs++; \
2216 } else do { } while (0)
2217
2218 IF_FIELD_DIFFERS_SET_ERROR(rip, "%#010llx");
2219 IF_FIELD_DIFFERS_SET_ERROR(rfl, "%#010llx");
2220 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xAX], "%#010llx");
2221 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xBX], "%#010llx");
2222 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xCX], "%#010llx");
2223 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xDX], "%#010llx");
2224 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xSP], "%#010llx");
2225 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xBP], "%#010llx");
2226 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xSI], "%#010llx");
2227 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xDI], "%#010llx");
2228 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x8], "%#010llx");
2229 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x9], "%#010llx");
2230 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x9], "%#010llx");
2231 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x10], "%#010llx");
2232 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x11], "%#010llx");
2233 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x12], "%#010llx");
2234 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x13], "%#010llx");
2235 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x14], "%#010llx");
2236 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x15], "%#010llx");
2237 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_CS], "%#06x");
2238 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_SS], "%#06x");
2239 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_DS], "%#06x");
2240 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_ES], "%#06x");
2241 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_FS], "%#06x");
2242 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_GS], "%#06x");
2243 IF_FIELD_DIFFERS_SET_ERROR(uXcpt, "%#04x");
2244 IF_FIELD_DIFFERS_SET_ERROR(uErr, "%#04llx");
2245 IF_FIELD_DIFFERS_SET_ERROR(cr2, "%#010llx");
2246#ifndef CIDET_REDUCED_CTX
2247 IF_FIELD_DIFFERS_SET_ERROR(tr, "%#06x");
2248 IF_FIELD_DIFFERS_SET_ERROR(ldtr, "%#06x");
2249 IF_FIELD_DIFFERS_SET_ERROR(cr0, "%#010llx");
2250 IF_FIELD_DIFFERS_SET_ERROR(cr3, "%#010llx");
2251 IF_FIELD_DIFFERS_SET_ERROR(cr4, "%#010llx");
2252 IF_FIELD_DIFFERS_SET_ERROR(cr8, "%#010llx");
2253 IF_FIELD_DIFFERS_SET_ERROR(dr0, "%#010llx");
2254 IF_FIELD_DIFFERS_SET_ERROR(dr1, "%#010llx");
2255 IF_FIELD_DIFFERS_SET_ERROR(dr2, "%#010llx");
2256 IF_FIELD_DIFFERS_SET_ERROR(dr3, "%#010llx");
2257 IF_FIELD_DIFFERS_SET_ERROR(dr6, "%#010llx");
2258 IF_FIELD_DIFFERS_SET_ERROR(dr7, "%#010llx");
2259#endif
2260
2261AssertMsgFailed(("cDiffs=%d\n", cDiffs));
2262 Assert(cDiffs > 0);
2263 return cDiffs == 0;
2264}
2265
2266
2267bool CidetCoreTest_Basic(PCIDETCORE pThis)
2268{
2269 /*
2270 * Iterate all encodings.
2271 */
2272 if (!CidetCoreSetupFirstBaseEncoding(pThis))
2273 return CidetCoreSetError(pThis, "CidetCoreSetupFirstBaseEncoding failed");
2274 unsigned cExecuted = 0;
2275 unsigned cSkipped = 0;
2276 do
2277 {
2278 /*
2279 * Iterate data buffer configurations (one iteration if none).
2280 */
2281 if (CidetCoreSetupFirstMemoryOperandConfig(pThis))
2282 {
2283 do
2284 {
2285 /*
2286 * Iterate code buffer configurations.
2287 */
2288 if (!CidetCoreSetupFirstCodeBufferConfig(pThis))
2289 return CidetCoreSetError(pThis, "CidetCoreSetupFirstMemoryOperandConfig failed");
2290 do
2291 {
2292 /*
2293 * Set up inputs and expected outputs, then emit the test code.
2294 */
2295 pThis->InCtx = pThis->InTemplateCtx;
2296 pThis->InCtx.fTrickyStack = pThis->fHasStackRegInMrmRmBase || pThis->fHasStackRegInMrmReg;
2297 pThis->ExpectedCtx = pThis->InCtx;
2298 if ( CidetCoreReInitCodeBuf(pThis)
2299 && CidetCoreSetupInOut(pThis)
2300 && CidetCoreSetupCodeBuf(pThis, cSkipped + cExecuted)
2301 )
2302 {
2303 if (pThis->pfnExecute(pThis))
2304 {
2305 cExecuted++;
2306
2307 /*
2308 * Check the result against our expectations.
2309 */
2310 CidetCoreCheckResults(pThis);
2311 /** @todo check result. */
2312
2313 }
2314 else
2315 cSkipped++;
2316 }
2317 else
2318 cSkipped++;
2319 } while (CidetCoreSetupNextCodeBufferConfig(pThis));
2320 } while (CidetCoreSetupNextMemoryOperandConfig(pThis));
2321 }
2322 else
2323 cSkipped++;
2324 } while (CidetCoreSetupNextBaseEncoding(pThis));
2325
2326 CIDET_DPRINTF(("CidetCoreTest_Basic: cExecuted=%u cSkipped=%u\n"
2327 " cSkippedSetupInOut =%u\n"
2328 " cSkippedReInitDataBuf =%u\n"
2329 " cSkippedSetupDataBuf =%u\n"
2330 " cSkippedDataBufWrtRip =%u\n"
2331 " cSkippedAssemble =%u\n"
2332 " cSkippedReInitCodeBuf =%u\n"
2333 " cSkippedSetupCodeBuf =%u\n"
2334 " cSkippedSameBaseIndexRemainder =%u\n"
2335 " cSkippedOnlyIndexRemainder =%u\n"
2336 " cSkippedDirectAddressingOverflow =%u\n"
2337 ,
2338 cExecuted, cSkipped,
2339 pThis->cSkippedSetupInOut,
2340 pThis->cSkippedReInitDataBuf,
2341 pThis->cSkippedSetupDataBuf,
2342 pThis->cSkippedDataBufWrtRip,
2343 pThis->cSkippedAssemble,
2344 pThis->cSkippedReInitCodeBuf,
2345 pThis->cSkippedSetupCodeBuf,
2346 pThis->cSkippedSameBaseIndexRemainder,
2347 pThis->cSkippedOnlyIndexRemainder,
2348 pThis->cSkippedDirectAddressingOverflow
2349 ));
2350
2351 return true;
2352}
2353
2354
2355bool CidetCoreTestInstruction(PCIDETCORE pThis, PCCIDETINSTR pInstr)
2356{
2357 AssertReleaseMsgReturn(RT_VALID_PTR(pThis), ("%p\n", pThis), false);
2358 AssertReleaseReturn(pThis->u32Magic == CIDETCORE_MAGIC, false);
2359 AssertReleaseReturn(pThis->cCodeBufConfigs > 0, false);
2360
2361 if (!CideCoreSetInstruction(pThis, pInstr))
2362 return CidetCoreSetError(pThis, "CideCoreSetInstruction failed");
2363
2364 bool fResult = CidetCoreTest_Basic(pThis);
2365
2366 return fResult;
2367}
2368
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