VirtualBox

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

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

build fix

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