VirtualBox

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

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

cidet: Fixed sil,dil,spl,bpl issue and implemented context conversion for linux signal handlers.

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