VirtualBox

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

Last change on this file since 62484 was 62484, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 89.9 KB
Line 
1/* $Id: cidet-core.cpp 62484 2016-07-22 18:35:33Z vboxsync $ */
2/** @file
3 * CPU Instruction Decoding & Execution Tests - Simple Instructions.
4 */
5
6/*
7 * Copyright (C) 2014-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. 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 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aiInOut); i++)
1549 pThis->aiInOut[i] = 0;
1550
1551 return true;
1552}
1553
1554
1555bool CidetCoreSetupInOut(PCIDETCORE pThis)
1556{
1557 /*
1558 * Enumerate the operands.
1559 */
1560 uint8_t *pbBuf = &pThis->abBuf[0];
1561 pbBuf = RT_ALIGN_PT(pbBuf, 16, uint8_t *);
1562
1563 uint8_t idxOp = pThis->cOperands;
1564 while (idxOp-- > 0)
1565 {
1566 if (pThis->aOperands[idxOp].fIsMem)
1567 {
1568 /*
1569 * Memory operand.
1570 */
1571 Assert(pThis->aOperands[idxOp].fIsMem);
1572
1573 /* Set the In & Expected members to point to temporary buffer space. */
1574 pThis->aOperands[idxOp].Expected.pu8 = pbBuf;
1575 pbBuf += pThis->aOperands[idxOp].cb;
1576 pbBuf = RT_ALIGN_PT(pbBuf, 16, uint8_t *);
1577
1578 pThis->aOperands[idxOp].In.pu8 = pbBuf;
1579 pbBuf += pThis->aOperands[idxOp].cb;
1580 pbBuf = RT_ALIGN_PT(pbBuf, 16, uint8_t *);
1581
1582 /* Initialize the buffer we're gonna use. */
1583 pThis->aOperands[idxOp].iEffSeg = pThis->uSegPrf != X86_SREG_COUNT
1584 ? pThis->uSegPrf
1585 : !(pThis->aOperands[idxOp].fFlags & CIDET_OF_ALWAYS_SEG_ES) ? X86_SREG_DS
1586 : X86_SREG_ES;
1587
1588 PCIDETBUF pDataBuf = pThis->aOperands[idxOp].pDataBuf;
1589 AssertReleaseReturn(pDataBuf, false);
1590 Assert(pDataBuf->cb == pThis->aOperands[idxOp].cb);
1591 Assert(pDataBuf->idxOp == idxOp);
1592 if (!pThis->pfnReInitDataBuf(pThis, pDataBuf))
1593 {
1594 pThis->cSkippedReInitDataBuf++;
1595 return false;
1596 }
1597 pDataBuf->fActive = true;
1598
1599 /* Calc buffer related operand members. */
1600 pThis->aOperands[idxOp].uEffAddr = pDataBuf->uEffBufAddr + pDataBuf->off;
1601 uint64_t offSeg = pThis->aOperands[idxOp].uEffAddr - pDataBuf->uSegBase;
1602 pThis->aOperands[idxOp].offSeg = offSeg;
1603 AssertRelease(offSeg <= g_au64ByteSizeToMask[pThis->cbAddrMode]);
1604
1605 /*
1606 * Select register and displacement values for the buffer addressing (works on offSeg).
1607 */
1608 uint8_t const iMemIndexReg = pThis->aOperands[idxOp].iMemIndexReg;
1609 uint8_t const iMemBaseReg = pThis->aOperands[idxOp].iMemBaseReg;
1610 if (pThis->aOperands[idxOp].fIsRipRelative)
1611 {
1612 /* rip relative. */
1613 pThis->aOperands[idxOp].uImmDispValue = offSeg - (pThis->InCtx.rip + pThis->cbInstr);
1614 Assert(pThis->aOperands[idxOp].cbMemDisp == 4);
1615 if ( (int64_t)pThis->aOperands[idxOp].uImmDispValue > INT32_MAX
1616 || (int64_t)pThis->aOperands[idxOp].uImmDispValue < INT32_MIN)
1617 {
1618 pThis->cSkippedDataBufWrtRip++;
1619 return false;
1620 }
1621 }
1622 else if (iMemBaseReg != UINT8_MAX)
1623 {
1624 if ( iMemBaseReg != iMemIndexReg
1625 || pThis->fUsesVexIndexRegs)
1626 {
1627 /* [base] or [base + disp] or [base + index * scale] or [base + index * scale + disp] */
1628 if (pThis->aOperands[idxOp].cbMemDisp > 0)
1629 {
1630 pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
1631 offSeg -= (int64_t)pThis->aOperands[idxOp].uImmDispValue;
1632 }
1633
1634 if (iMemIndexReg != UINT8_MAX)
1635 {
1636 pThis->aOperands[idxOp].uMemIndexRegValue = CidetCoreGetRandU64(pThis, pThis->cbAddrMode);
1637 offSeg -= pThis->aOperands[idxOp].uMemIndexRegValue * pThis->aOperands[idxOp].uMemScale;
1638 }
1639
1640 pThis->aOperands[idxOp].uMemBaseRegValue = offSeg & g_au64ByteSizeToMask[pThis->cbAddrMode];
1641 }
1642 else
1643 {
1644 /* base == index; [base + index * scale] or [base * (scale + 1)]. */
1645 uint8_t const uEffScale = pThis->aOperands[idxOp].uMemScale + 1;
1646 if (pThis->aOperands[idxOp].cbMemDisp > 0)
1647 {
1648 pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
1649 offSeg -= (int64_t)pThis->aOperands[idxOp].uImmDispValue;
1650 offSeg &= g_au64ByteSizeToMask[pThis->cbAddrMode];
1651 uint8_t uRemainder = offSeg % uEffScale;
1652 if (uRemainder != 0)
1653 {
1654 Assert(pThis->aOperands[idxOp].cbMemDisp < 8);
1655 Assert( (int64_t)pThis->aOperands[idxOp].uImmDispValue
1656 <= g_ai64ByteSizeToMax[pThis->aOperands[idxOp].cbMemDisp]);
1657 pThis->aOperands[idxOp].uImmDispValue = (int64_t)pThis->aOperands[idxOp].uImmDispValue
1658 + uRemainder;
1659 offSeg -= uRemainder;
1660 if ( (int64_t)pThis->aOperands[idxOp].uImmDispValue
1661 > g_ai64ByteSizeToMax[pThis->aOperands[idxOp].cbMemDisp])
1662 {
1663 pThis->aOperands[idxOp].uImmDispValue -= uEffScale;
1664 offSeg += uEffScale;
1665 }
1666 Assert(offSeg % uEffScale == 0);
1667 }
1668 }
1669 else
1670 {
1671 offSeg &= g_au64ByteSizeToMask[pThis->cbAddrMode];
1672 if (offSeg % uEffScale != 0)
1673 {
1674 pThis->cSkippedSameBaseIndexRemainder++;
1675 return false;
1676 }
1677 }
1678 offSeg /= uEffScale;
1679 pThis->aOperands[idxOp].uMemBaseRegValue = pThis->aOperands[idxOp].uMemIndexRegValue = offSeg;
1680 }
1681 }
1682 else if (iMemIndexReg != UINT8_MAX)
1683 {
1684 /* [index * scale] or [index * scale + disp] */
1685 if (pThis->aOperands[idxOp].cbMemDisp > 0)
1686 {
1687 pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
1688 offSeg -= (int64_t)pThis->aOperands[idxOp].uImmDispValue;
1689 pThis->aOperands[idxOp].uImmDispValue += offSeg & (RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1);
1690 offSeg &= ~(RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1);
1691 }
1692 else if (offSeg & (RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1))
1693 {
1694 pThis->cSkippedOnlyIndexRemainder++;
1695 return false;
1696 }
1697
1698 pThis->aOperands[idxOp].uMemIndexRegValue = offSeg / pThis->aOperands[idxOp].uMemScale;
1699 Assert((offSeg % pThis->aOperands[idxOp].uMemScale) == 0);
1700 AssertRelease(!pThis->fUsesVexIndexRegs); /** @todo implement VEX indexing */
1701 }
1702 else
1703 {
1704 /* [disp] */
1705 Assert( pThis->aOperands[idxOp].cbMemDisp == 8
1706 || pThis->aOperands[idxOp].cbMemDisp == 4
1707 || pThis->aOperands[idxOp].cbMemDisp == 2
1708 || pThis->aOperands[idxOp].cbMemDisp == 1);
1709 if ( pThis->aOperands[idxOp].cbMemDisp == 4
1710 ? (int64_t)offSeg != (int32_t)offSeg
1711 : pThis->aOperands[idxOp].cbMemDisp == 2
1712 ? (int64_t)offSeg != (int16_t)offSeg
1713 : pThis->aOperands[idxOp].cbMemDisp == 1
1714 ? (int64_t)offSeg != (int8_t)offSeg
1715 : false /* 8 */)
1716 {
1717 pThis->cSkippedDirectAddressingOverflow++;
1718 return false;
1719 }
1720 pThis->aOperands[idxOp].uImmDispValue = offSeg;
1721 }
1722
1723 /*
1724 * Modify the input and expected output contexts with the base and
1725 * index register values. To simplify verification and the work
1726 * here, we update the uMemBaseRegValue and uMemIndexRegValue
1727 * members to reflect the whole register.
1728 */
1729 if (iMemBaseReg != UINT8_MAX)
1730 {
1731 if (pThis->cbAddrMode == 4)
1732 {
1733 pThis->aOperands[idxOp].uMemBaseRegValue &= UINT32_MAX;
1734 pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffff00000000);
1735 }
1736 else if (pThis->cbAddrMode == 2)
1737 {
1738 pThis->aOperands[idxOp].uMemBaseRegValue &= UINT16_MAX;
1739 pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffffffff0000);
1740 }
1741 pThis->InCtx.aGRegs[iMemBaseReg] = pThis->aOperands[idxOp].uMemBaseRegValue;
1742 pThis->ExpectedCtx.aGRegs[iMemBaseReg] = pThis->aOperands[idxOp].uMemBaseRegValue;
1743 }
1744
1745 if (iMemIndexReg != UINT8_MAX)
1746 {
1747 if (pThis->cbAddrMode == 4)
1748 {
1749 pThis->aOperands[idxOp].uMemIndexRegValue &= UINT32_MAX;
1750 pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffff00000000);
1751 }
1752 else if (pThis->cbAddrMode == 2)
1753 {
1754 pThis->aOperands[idxOp].uMemIndexRegValue &= UINT16_MAX;
1755 pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffffffff0000);
1756 }
1757 pThis->InCtx.aGRegs[iMemIndexReg] = pThis->aOperands[idxOp].uMemIndexRegValue;
1758 pThis->ExpectedCtx.aGRegs[iMemIndexReg] = pThis->aOperands[idxOp].uMemIndexRegValue;
1759 }
1760 }
1761 else
1762 {
1763 /*
1764 * Non-memory, so clear the memory related members.
1765 */
1766 Assert(!pThis->aOperands[idxOp].fIsMem);
1767 pThis->aOperands[idxOp].iEffSeg = UINT8_MAX;
1768 pThis->aOperands[idxOp].offSeg = UINT64_MAX;
1769 pThis->aOperands[idxOp].uEffAddr = UINT64_MAX;
1770 pThis->aOperands[idxOp].pDataBuf = NULL;
1771
1772 switch (pThis->aOperands[idxOp].fFlags & CIDET_OF_K_MASK)
1773 {
1774 case CIDET_OF_K_GPR:
1775 if (!pThis->aOperands[idxOp].fIsHighByteRegister)
1776 {
1777 pThis->aOperands[idxOp].In.pv = &pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iReg];
1778 pThis->aOperands[idxOp].Expected.pv = &pThis->ExpectedCtx.aGRegs[pThis->aOperands[idxOp].iReg];
1779 }
1780 else
1781 {
1782 pThis->aOperands[idxOp].In.pv = &pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iReg - 4];
1783 pThis->aOperands[idxOp].In.pu8++;
1784 pThis->aOperands[idxOp].Expected.pv = &pThis->ExpectedCtx.aGRegs[pThis->aOperands[idxOp].iReg - 4];
1785 pThis->aOperands[idxOp].Expected.pu8++;
1786 }
1787 break;
1788
1789 case CIDET_OF_K_IMM:
1790 pThis->aOperands[idxOp].In.pv = NULL;
1791 pThis->aOperands[idxOp].Expected.pv = NULL;
1792 break;
1793
1794 case CIDET_OF_K_SREG:
1795 if (pThis->aOperands[idxOp].iReg < RT_ELEMENTS(pThis->InCtx.aSRegs))
1796 {
1797 pThis->aOperands[idxOp].In.pv = &pThis->InCtx.aSRegs[pThis->aOperands[idxOp].iReg];
1798 pThis->aOperands[idxOp].Expected.pv = &pThis->ExpectedCtx.aSRegs[pThis->aOperands[idxOp].iReg];
1799 }
1800 else
1801 {
1802 pThis->aOperands[idxOp].In.pv = NULL;
1803 pThis->aOperands[idxOp].Expected.pv = NULL;
1804 }
1805 break;
1806
1807 case CIDET_OF_K_CR:
1808 case CIDET_OF_K_SSE:
1809 case CIDET_OF_K_AVX:
1810 case CIDET_OF_K_AVX512:
1811 case CIDET_OF_K_FPU:
1812 case CIDET_OF_K_MMX:
1813 case CIDET_OF_K_AVXFUTURE:
1814 case CIDET_OF_K_SPECIAL:
1815 case CIDET_OF_K_TEST:
1816 /** @todo Implement testing these registers. */
1817 case CIDET_OF_K_NONE:
1818 default:
1819 AssertReleaseFailedReturn(false);
1820 }
1821 }
1822 }
1823 AssertRelease((uintptr_t)pbBuf - (uintptr_t)&pThis->abBuf[0] <= sizeof(pThis->abBuf));
1824
1825 /*
1826 * Call instruction specific setup function (for operand values and flags).
1827 */
1828 int rc = pThis->pCurInstr->pfnSetupInOut(pThis, false /*fInvalid*/);
1829 if (RT_FAILURE(rc))
1830 {
1831 pThis->cSkippedSetupInOut++;
1832 return false;
1833 }
1834
1835 /*
1836 * Do the 2nd set of the memory operand preparations.
1837 */
1838 if (pThis->fHasMemoryOperand)
1839 {
1840 idxOp = pThis->cOperands;
1841 while (idxOp-- > 0)
1842 if (pThis->aOperands[idxOp].fIsMem)
1843 {
1844 Assert(pThis->aOperands[idxOp].pDataBuf);
1845 if (!pThis->pfnSetupDataBuf(pThis, pThis->aOperands[idxOp].pDataBuf, pThis->aOperands[idxOp].In.pv))
1846 {
1847 pThis->cSkippedSetupDataBuf++;
1848 return false;
1849 }
1850
1851 Assert( pThis->aOperands[idxOp].iMemBaseReg == UINT8_MAX
1852 || pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iMemBaseReg] == pThis->aOperands[idxOp].uMemBaseRegValue);
1853 Assert( pThis->aOperands[idxOp].iMemIndexReg == UINT8_MAX
1854 || ( !pThis->fUsesVexIndexRegs
1855 ? pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iMemIndexReg]
1856 == pThis->aOperands[idxOp].uMemIndexRegValue
1857 : false /** @todo VEX indexing */));
1858 }
1859 }
1860
1861 return true;
1862}
1863
1864
1865/**
1866 * Figures the instruction length.
1867 *
1868 * This is a duplicate of CidetCoreAssemble() with the buffer updates removed.
1869 *
1870 * @returns true and pThis->cbInstr on success, false on failure.
1871 * @param pThis The core state structure (for context).
1872 */
1873bool CidetCoreAssembleLength(PCIDETCORE pThis)
1874{
1875 uint8_t off = 0;
1876
1877 /*
1878 * Prefixes.
1879 */
1880 if (1)
1881 {
1882 if (pThis->fAddrSizePrf)
1883 off++;
1884 if (pThis->fOpSizePrf)
1885 off++;
1886 }
1887 else
1888 {
1889 /** @todo prefix list. */
1890 }
1891
1892 /*
1893 * Prefixes that must come right before the opcode.
1894 */
1895 /** @todo VEX and EVEX. */
1896 if (pThis->fVex)
1897 {
1898 /** @todo VEX and EVEX. */
1899 }
1900 else if (pThis->fEvex)
1901 {
1902 /** @todo VEX and EVEX. */
1903 }
1904 else
1905 {
1906 if (pThis->fRexB || pThis->fRexX || pThis->fRexR || pThis->fRexW || pThis->fRex)
1907 off++;
1908 }
1909
1910 /*
1911 * The opcode.
1912 */
1913 uint8_t const *pbOpcode = pThis->pCurInstr->abOpcode;
1914 switch (pThis->pCurInstr->cbOpcode)
1915 {
1916 case 3: off++;
1917 case 2: off++;
1918 case 1: off++;
1919 break;
1920 default:
1921 AssertReleaseFailedReturn(false);
1922 }
1923
1924 /*
1925 * Mod R/M
1926 */
1927 if (pThis->fUsesModRm)
1928 {
1929 off++;
1930 if (pThis->fSib)
1931 off++;
1932 if (pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands))
1933 {
1934 uint64_t uDispValue = pThis->aOperands[pThis->idxMrmRmOp].uImmDispValue;
1935 switch (pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp)
1936 {
1937 case 0: break;
1938 case 8:
1939 case 7:
1940 case 6:
1941 case 5:
1942 case 4:
1943 case 3:
1944 case 2:
1945 case 1:
1946 break;
1947 default: AssertReleaseFailedReturn(false);
1948 }
1949 off += pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp;
1950 }
1951 }
1952
1953 /*
1954 * Immediates.
1955 */
1956 uint8_t iOp = pThis->cOperands;
1957 while (iOp-- > 0)
1958 if ((pThis->aOperands[iOp].fFlags & CIDET_OF_K_MASK) == CIDET_OF_K_IMM)
1959 {
1960 uint64_t uImmValue = pThis->aOperands[iOp].uImmDispValue;
1961 switch (pThis->aOperands[iOp].cb)
1962 {
1963 case 8:
1964 case 7:
1965 case 6:
1966 case 5:
1967 case 4:
1968 case 3:
1969 case 2:
1970 case 1:
1971 break;
1972 default: AssertReleaseFailedReturn(false);
1973 }
1974 off += pThis->aOperands[iOp].cb;
1975 }
1976
1977 pThis->cbInstr = off;
1978 return true;
1979}
1980
1981
1982/**
1983 * Assembles the instruction.
1984 *
1985 * This is a duplicate of CidetCoreAssembleLength() with buffer writes.
1986 *
1987 * @returns true and pThis->cbInstr and pThis->abInstr on success, false on
1988 * failure.
1989 * @param pThis The core state structure (for context).
1990 */
1991bool CidetCoreAssemble(PCIDETCORE pThis)
1992{
1993 uint8_t off = 0;
1994
1995 /*
1996 * Prefixes.
1997 */
1998 if (1)
1999 {
2000 if (pThis->fAddrSizePrf)
2001 pThis->abInstr[off++] = 0x67;
2002 if (pThis->fOpSizePrf)
2003 pThis->abInstr[off++] = 0x66;
2004 }
2005 else
2006 {
2007 /** @todo prefix list. */
2008 }
2009
2010 /*
2011 * Prefixes that must come right before the opcode.
2012 */
2013 /** @todo VEX and EVEX. */
2014 if (pThis->fVex)
2015 {
2016 /** @todo VEX and EVEX. */
2017 }
2018 else if (pThis->fEvex)
2019 {
2020 /** @todo VEX and EVEX. */
2021 }
2022 else
2023 {
2024 if (pThis->fRexB || pThis->fRexX || pThis->fRexR || pThis->fRexW || pThis->fRex)
2025 pThis->abInstr[off++] = 0x40 | (pThis->fRexB * 1) | (pThis->fRexX * 2) | (pThis->fRexR * 4) | (pThis->fRexW * 8);
2026 }
2027
2028 /*
2029 * The opcode.
2030 */
2031 uint8_t const *pbOpcode = pThis->pCurInstr->abOpcode;
2032 switch (pThis->pCurInstr->cbOpcode)
2033 {
2034 case 3: pThis->abInstr[off++] = *pbOpcode++;
2035 case 2: pThis->abInstr[off++] = *pbOpcode++;
2036 case 1: pThis->abInstr[off++] = *pbOpcode++;
2037 break;
2038 default:
2039 AssertReleaseFailedReturn(false);
2040 }
2041
2042 /*
2043 * Mod R/M
2044 */
2045 if (pThis->fUsesModRm)
2046 {
2047 pThis->abInstr[off++] = pThis->bModRm;
2048 if (pThis->fSib)
2049 pThis->abInstr[off++] = pThis->bSib;
2050 if (pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands))
2051 {
2052 uint64_t uDispValue = pThis->aOperands[pThis->idxMrmRmOp].uImmDispValue;
2053 switch (pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp)
2054 {
2055 case 0: break;
2056 case 8: pThis->abInstr[off + 3] = (uDispValue >> 56) & UINT8_C(0xff);
2057 case 7: pThis->abInstr[off + 3] = (uDispValue >> 48) & UINT8_C(0xff);
2058 case 6: pThis->abInstr[off + 3] = (uDispValue >> 40) & UINT8_C(0xff);
2059 case 5: pThis->abInstr[off + 3] = (uDispValue >> 32) & UINT8_C(0xff);
2060 case 4: pThis->abInstr[off + 3] = (uDispValue >> 24) & UINT8_C(0xff);
2061 case 3: pThis->abInstr[off + 2] = (uDispValue >> 16) & UINT8_C(0xff);
2062 case 2: pThis->abInstr[off + 1] = (uDispValue >> 8) & UINT8_C(0xff);
2063 case 1: pThis->abInstr[off] = uDispValue & UINT8_C(0xff);
2064 break;
2065 default: AssertReleaseFailedReturn(false);
2066 }
2067 off += pThis->aOperands[pThis->idxMrmRmOp].cbMemDisp;
2068 }
2069 }
2070
2071 /*
2072 * Immediates.
2073 */
2074 uint8_t iOp = pThis->cOperands;
2075 while (iOp-- > 0)
2076 if ((pThis->aOperands[iOp].fFlags & CIDET_OF_K_MASK) == CIDET_OF_K_IMM)
2077 {
2078 uint64_t uImmValue = pThis->aOperands[iOp].uImmDispValue;
2079 switch (pThis->aOperands[iOp].cb)
2080 {
2081 case 8: pThis->abInstr[off + 3] = (uImmValue >> 56) & UINT8_C(0xff);
2082 case 7: pThis->abInstr[off + 3] = (uImmValue >> 48) & UINT8_C(0xff);
2083 case 6: pThis->abInstr[off + 3] = (uImmValue >> 40) & UINT8_C(0xff);
2084 case 5: pThis->abInstr[off + 3] = (uImmValue >> 32) & UINT8_C(0xff);
2085 case 4: pThis->abInstr[off + 3] = (uImmValue >> 24) & UINT8_C(0xff);
2086 case 3: pThis->abInstr[off + 2] = (uImmValue >> 16) & UINT8_C(0xff);
2087 case 2: pThis->abInstr[off + 1] = (uImmValue >> 8) & UINT8_C(0xff);
2088 case 1: pThis->abInstr[off] = uImmValue & UINT8_C(0xff);
2089 break;
2090 default: AssertReleaseFailedReturn(false);
2091 }
2092 off += pThis->aOperands[iOp].cb;
2093 }
2094
2095 pThis->cbInstr = off;
2096 return true;
2097}
2098
2099
2100bool CidetCoreReInitCodeBuf(PCIDETCORE pThis)
2101{
2102 /*
2103 * Re-initialize the buffer. Requires instruction length and positioning.
2104 */
2105 if (CidetCoreAssembleLength(pThis))
2106 {
2107 pThis->CodeBuf.cb = pThis->cbInstr;
2108 pThis->CodeBuf.off = CIDET_CODE_BUF_SIZE - PAGE_SIZE - pThis->cbInstr;
2109 if (pThis->pfnReInitCodeBuf(pThis, &pThis->CodeBuf))
2110 {
2111 pThis->CodeBuf.fActive = true;
2112
2113 /*
2114 * Update the RIP and CS values in the input and expected contexts.
2115 */
2116 pThis->InCtx.rip = pThis->CodeBuf.uEffBufAddr + pThis->CodeBuf.offActive - pThis->CodeBuf.uSegBase;
2117 pThis->ExpectedCtx.rip = pThis->InCtx.rip + pThis->cbInstr; /** @todo account for expected traps. */
2118 if (pThis->CodeBuf.uSeg != UINT32_MAX)
2119 {
2120 pThis->InCtx.aSRegs[X86_SREG_CS] = pThis->CodeBuf.uSeg;
2121 pThis->ExpectedCtx.aSRegs[X86_SREG_CS] = pThis->CodeBuf.uSeg;
2122 }
2123 return true;
2124 }
2125 else
2126 pThis->cSkippedReInitCodeBuf++;
2127 }
2128 else
2129 pThis->cSkippedAssemble++;
2130 return false;
2131}
2132
2133
2134#ifdef CIDET_DEBUG_DISAS
2135/**
2136 * @callback_method_impl{FNDISREADBYTES}
2137 */
2138static DECLCALLBACK(int) cidetCoreDisReadBytes(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
2139{
2140 PCIDETCORE pThis = (PCIDETCORE)pDis->pvUser;
2141 memcpy(&pDis->abInstr[offInstr], &pThis->abInstr[offInstr], cbMaxRead);
2142 pDis->cbCachedInstr = offInstr + cbMaxRead;
2143 return VINF_SUCCESS;
2144}
2145#endif
2146
2147
2148bool CidetCoreSetupCodeBuf(PCIDETCORE pThis, unsigned iSubTest)
2149{
2150 if (CidetCoreAssemble(pThis))
2151 {
2152 //CIDET_DPRINTF(("%04u: %.*Rhxs\n", i, pThis->cbInstr, pThis->abInstr));
2153#ifdef CIDET_DEBUG_DISAS
2154 DISCPUSTATE Dis;
2155 char szInstr[80] = {0};
2156 uint32_t cbInstr;
2157 int rcDis = DISInstrToStrEx(pThis->InCtx.rip,
2158 CIDETMODE_IS_64BIT(pThis->bMode) ? DISCPUMODE_64BIT
2159 : CIDETMODE_IS_32BIT(pThis->bMode) ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
2160 cidetCoreDisReadBytes,
2161 pThis,
2162 DISOPTYPE_ALL,
2163 &Dis,
2164 &cbInstr,
2165 szInstr, sizeof(szInstr));
2166 CIDET_DPRINTF(("%04u: %s", iSubTest, szInstr));
2167 Assert(cbInstr == pThis->cbInstr);
2168#endif
2169 if (pThis->pfnSetupCodeBuf(pThis, &pThis->CodeBuf, pThis->abInstr))
2170 {
2171 return true;
2172 }
2173 pThis->cSkippedSetupCodeBuf++;
2174 }
2175 else
2176 pThis->cSkippedAssemble++;
2177 return false;
2178}
2179
2180
2181/**
2182 * Compares the output with the output expectations.
2183 *
2184 * @returns true if ok, false if not (calls pfnFailure too).
2185 * @param pThis The core state structure.
2186 */
2187bool CidetCoreCheckResults(PCIDETCORE pThis)
2188{
2189 if (memcmp(&pThis->ActualCtx, &pThis->ExpectedCtx, CIDETCPUCTX_COMPARE_SIZE) == 0)
2190 return true;
2191
2192 unsigned cDiffs = 0;
2193#define IF_FIELD_DIFFERS_SET_ERROR(a_Field, a_Fmt) \
2194 if (pThis->ActualCtx.a_Field != pThis->ExpectedCtx.a_Field) \
2195 { \
2196 CidetCoreSetError(pThis, #a_Field " differs: got %#llx expected %#llx", \
2197 pThis->ActualCtx.a_Field, pThis->ExpectedCtx.a_Field); \
2198 cDiffs++; \
2199 } else do { } while (0)
2200
2201 IF_FIELD_DIFFERS_SET_ERROR(rip, "%#010llx");
2202 IF_FIELD_DIFFERS_SET_ERROR(rfl, "%#010llx");
2203 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xAX], "%#010llx");
2204 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xBX], "%#010llx");
2205 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xCX], "%#010llx");
2206 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xDX], "%#010llx");
2207 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xSP], "%#010llx");
2208 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xBP], "%#010llx");
2209 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xSI], "%#010llx");
2210 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_xDI], "%#010llx");
2211 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x8], "%#010llx");
2212 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x9], "%#010llx");
2213 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x9], "%#010llx");
2214 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x10], "%#010llx");
2215 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x11], "%#010llx");
2216 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x12], "%#010llx");
2217 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x13], "%#010llx");
2218 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x14], "%#010llx");
2219 IF_FIELD_DIFFERS_SET_ERROR(aGRegs[X86_GREG_x15], "%#010llx");
2220 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_CS], "%#06x");
2221 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_SS], "%#06x");
2222 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_DS], "%#06x");
2223 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_ES], "%#06x");
2224 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_FS], "%#06x");
2225 IF_FIELD_DIFFERS_SET_ERROR(aSRegs[X86_SREG_GS], "%#06x");
2226 IF_FIELD_DIFFERS_SET_ERROR(uXcpt, "%#04x");
2227 IF_FIELD_DIFFERS_SET_ERROR(uErr, "%#04llx");
2228 IF_FIELD_DIFFERS_SET_ERROR(cr2, "%#010llx");
2229#ifndef CIDET_REDUCED_CTX
2230 IF_FIELD_DIFFERS_SET_ERROR(tr, "%#06x");
2231 IF_FIELD_DIFFERS_SET_ERROR(ldtr, "%#06x");
2232 IF_FIELD_DIFFERS_SET_ERROR(cr0, "%#010llx");
2233 IF_FIELD_DIFFERS_SET_ERROR(cr3, "%#010llx");
2234 IF_FIELD_DIFFERS_SET_ERROR(cr4, "%#010llx");
2235 IF_FIELD_DIFFERS_SET_ERROR(cr8, "%#010llx");
2236 IF_FIELD_DIFFERS_SET_ERROR(dr0, "%#010llx");
2237 IF_FIELD_DIFFERS_SET_ERROR(dr1, "%#010llx");
2238 IF_FIELD_DIFFERS_SET_ERROR(dr2, "%#010llx");
2239 IF_FIELD_DIFFERS_SET_ERROR(dr3, "%#010llx");
2240 IF_FIELD_DIFFERS_SET_ERROR(dr6, "%#010llx");
2241 IF_FIELD_DIFFERS_SET_ERROR(dr7, "%#010llx");
2242#endif
2243
2244AssertMsgFailed(("cDiffs=%d\n", cDiffs));
2245 Assert(cDiffs > 0);
2246 return cDiffs == 0;
2247}
2248
2249
2250bool CidetCoreTest_Basic(PCIDETCORE pThis)
2251{
2252 /*
2253 * Iterate all encodings.
2254 */
2255 if (!CidetCoreSetupFirstBaseEncoding(pThis))
2256 return CidetCoreSetError(pThis, "CidetCoreSetupFirstBaseEncoding failed");
2257 unsigned cExecuted = 0;
2258 unsigned cSkipped = 0;
2259 do
2260 {
2261 /*
2262 * Iterate data buffer configurations (one iteration if none).
2263 */
2264 if (CidetCoreSetupFirstMemoryOperandConfig(pThis))
2265 {
2266 do
2267 {
2268 /*
2269 * Iterate code buffer configurations.
2270 */
2271 if (!CidetCoreSetupFirstCodeBufferConfig(pThis))
2272 return CidetCoreSetError(pThis, "CidetCoreSetupFirstMemoryOperandConfig failed");
2273 do
2274 {
2275 /*
2276 * Set up inputs and expected outputs, then emit the test code.
2277 */
2278 pThis->InCtx = pThis->InTemplateCtx;
2279 pThis->InCtx.fTrickyStack = pThis->fHasStackRegInMrmRmBase || pThis->fHasStackRegInMrmReg;
2280 pThis->ExpectedCtx = pThis->InCtx;
2281 if ( CidetCoreReInitCodeBuf(pThis)
2282 && CidetCoreSetupInOut(pThis)
2283 && CidetCoreSetupCodeBuf(pThis, cSkipped + cExecuted)
2284 )
2285 {
2286 if (pThis->pfnExecute(pThis))
2287 {
2288 cExecuted++;
2289
2290 /*
2291 * Check the result against our expectations.
2292 */
2293 CidetCoreCheckResults(pThis);
2294 /** @todo check result. */
2295
2296 }
2297 else
2298 cSkipped++;
2299 }
2300 else
2301 cSkipped++;
2302 } while (CidetCoreSetupNextCodeBufferConfig(pThis));
2303 } while (CidetCoreSetupNextMemoryOperandConfig(pThis));
2304 }
2305 else
2306 cSkipped++;
2307 } while (CidetCoreSetupNextBaseEncoding(pThis));
2308
2309 CIDET_DPRINTF(("CidetCoreTest_Basic: cExecuted=%u cSkipped=%u\n"
2310 " cSkippedSetupInOut =%u\n"
2311 " cSkippedReInitDataBuf =%u\n"
2312 " cSkippedSetupDataBuf =%u\n"
2313 " cSkippedDataBufWrtRip =%u\n"
2314 " cSkippedAssemble =%u\n"
2315 " cSkippedReInitCodeBuf =%u\n"
2316 " cSkippedSetupCodeBuf =%u\n"
2317 " cSkippedSameBaseIndexRemainder =%u\n"
2318 " cSkippedOnlyIndexRemainder =%u\n"
2319 " cSkippedDirectAddressingOverflow =%u\n"
2320 ,
2321 cExecuted, cSkipped,
2322 pThis->cSkippedSetupInOut,
2323 pThis->cSkippedReInitDataBuf,
2324 pThis->cSkippedSetupDataBuf,
2325 pThis->cSkippedDataBufWrtRip,
2326 pThis->cSkippedAssemble,
2327 pThis->cSkippedReInitCodeBuf,
2328 pThis->cSkippedSetupCodeBuf,
2329 pThis->cSkippedSameBaseIndexRemainder,
2330 pThis->cSkippedOnlyIndexRemainder,
2331 pThis->cSkippedDirectAddressingOverflow
2332 ));
2333
2334 return true;
2335}
2336
2337
2338bool CidetCoreTestInstruction(PCIDETCORE pThis, PCCIDETINSTR pInstr)
2339{
2340 AssertReleaseMsgReturn(RT_VALID_PTR(pThis), ("%p\n", pThis), false);
2341 AssertReleaseReturn(pThis->u32Magic == CIDETCORE_MAGIC, false);
2342 AssertReleaseReturn(pThis->cCodeBufConfigs > 0, false);
2343
2344 if (!CideCoreSetInstruction(pThis, pInstr))
2345 return CidetCoreSetError(pThis, "CideCoreSetInstruction failed");
2346
2347 bool fResult = CidetCoreTest_Basic(pThis);
2348
2349 return fResult;
2350}
2351
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