VirtualBox

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

Last change on this file since 71214 was 69111, checked in by vboxsync, 7 years ago

(C) year

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