VirtualBox

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

Last change on this file since 53608 was 53608, checked in by vboxsync, 10 years ago

cidet: Reduce context for linux. Enabled the 2nd instruction (add Ev,Gv) and fixed associated bugs.

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

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