VirtualBox

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

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

cidet: More code...

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

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