VirtualBox

source: vbox/trunk/src/VBox/Disassembler/DisasmCore-armv8.cpp@ 106212

Last change on this file since 106212 was 106005, checked in by vboxsync, 4 months ago

Disassembler/ArmV8: Updates and start on floating point and SIMD instructions, bugref:10394 [scm]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.2 KB
Line 
1/* $Id: DisasmCore-armv8.cpp 106005 2024-09-10 12:04:06Z vboxsync $ */
2/** @file
3 * VBox Disassembler - Core Components.
4 */
5
6/*
7 * Copyright (C) 2023-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DIS
33#include <VBox/dis.h>
34#include <VBox/log.h>
35#include <iprt/asm.h> /* Required to get Armv8A64ConvertImmRImmS2Mask64() from armv8.h. */
36#include <iprt/armv8.h>
37#include <iprt/assert.h>
38#include <iprt/errcore.h>
39#include <iprt/param.h>
40#include <iprt/string.h>
41#include <iprt/stdarg.h>
42#include "DisasmInternal-armv8.h"
43
44
45/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48
49/** Parser callback.
50 * @remark no DECLCALLBACK() here because it's considered to be internal and
51 * there is no point in enforcing CDECL. */
52typedef int FNDISPARSEARMV8(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit);
53/** Pointer to a disassembler parser function. */
54typedef FNDISPARSEARMV8 *PFNDISPARSEARMV8;
55
56
57/** Opcode decoder callback.
58 * @remark no DECLCALLBACK() here because it's considered to be internal and
59 * there is no point in enforcing CDECL. */
60typedef uint32_t FNDISDECODEARMV8(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass);
61/** Pointer to a disassembler parser function. */
62typedef FNDISDECODEARMV8 *PFNDISDECODEARMV8;
63
64
65/*********************************************************************************************************************************
66* Defined Constants And Macros *
67*********************************************************************************************************************************/
68
69
70/*********************************************************************************************************************************
71* Internal Functions *
72*********************************************************************************************************************************/
73/** @name Parsers
74 * @{ */
75static FNDISPARSEARMV8 disArmV8ParseIllegal;
76static FNDISPARSEARMV8 disArmV8ParseSize;
77static FNDISPARSEARMV8 disArmV8ParseImm;
78static FNDISPARSEARMV8 disArmV8ParseImmRel;
79static FNDISPARSEARMV8 disArmV8ParseImmAdr;
80static FNDISPARSEARMV8 disArmV8ParseImmZero;
81static FNDISPARSEARMV8 disArmV8ParseReg;
82static FNDISPARSEARMV8 disArmV8ParseRegOff;
83static FNDISPARSEARMV8 disArmV8ParseImmsImmrN;
84static FNDISPARSEARMV8 disArmV8ParseHw;
85static FNDISPARSEARMV8 disArmV8ParseCond;
86static FNDISPARSEARMV8 disArmV8ParsePState;
87static FNDISPARSEARMV8 disArmV8ParseSysReg;
88static FNDISPARSEARMV8 disArmV8ParseSh12;
89static FNDISPARSEARMV8 disArmV8ParseImmTbz;
90static FNDISPARSEARMV8 disArmV8ParseShift;
91static FNDISPARSEARMV8 disArmV8ParseShiftAmount;
92static FNDISPARSEARMV8 disArmV8ParseImmMemOff;
93static FNDISPARSEARMV8 disArmV8ParseSImmMemOff;
94static FNDISPARSEARMV8 disArmV8ParseSImmMemOffUnscaled;
95static FNDISPARSEARMV8 disArmV8ParseOption;
96static FNDISPARSEARMV8 disArmV8ParseS;
97static FNDISPARSEARMV8 disArmV8ParseSetPreIndexed;
98static FNDISPARSEARMV8 disArmV8ParseSetPostIndexed;
99static FNDISPARSEARMV8 disArmV8ParseFpType;
100static FNDISPARSEARMV8 disArmV8ParseFpReg;
101static FNDISPARSEARMV8 disArmV8ParseFpScale;
102static FNDISPARSEARMV8 disArmV8ParseFpFixupFCvt;
103static FNDISPARSEARMV8 disArmV8ParseSimdRegScalar;
104static FNDISPARSEARMV8 disArmV8ParseImmHImmB;
105/** @} */
106
107
108/** @name Decoders
109 * @{ */
110static FNDISDECODEARMV8 disArmV8DecodeIllegal;
111static FNDISDECODEARMV8 disArmV8DecodeLookup;
112static FNDISDECODEARMV8 disArmV8DecodeCollate;
113/** @} */
114
115
116/*********************************************************************************************************************************
117* Global Variables *
118*********************************************************************************************************************************/
119/** Parser opcode table for full disassembly. */
120static PFNDISPARSEARMV8 const g_apfnDisasm[kDisParmParseMax] =
121{
122 disArmV8ParseIllegal,
123 disArmV8ParseSize,
124 disArmV8ParseImm,
125 disArmV8ParseImmRel,
126 disArmV8ParseImmAdr,
127 disArmV8ParseImmZero,
128 disArmV8ParseReg,
129 disArmV8ParseRegOff,
130 disArmV8ParseImmsImmrN,
131 disArmV8ParseHw,
132 disArmV8ParseCond,
133 disArmV8ParsePState,
134 NULL,
135 disArmV8ParseSysReg,
136 disArmV8ParseSh12,
137 disArmV8ParseImmTbz,
138 disArmV8ParseShift,
139 disArmV8ParseShiftAmount,
140 disArmV8ParseImmMemOff,
141 disArmV8ParseSImmMemOff,
142 disArmV8ParseSImmMemOffUnscaled,
143 disArmV8ParseOption,
144 disArmV8ParseS,
145 disArmV8ParseSetPreIndexed,
146 disArmV8ParseSetPostIndexed,
147 disArmV8ParseFpType,
148 disArmV8ParseFpReg,
149 disArmV8ParseFpScale,
150 disArmV8ParseFpFixupFCvt,
151 disArmV8ParseSimdRegScalar,
152 disArmV8ParseImmHImmB
153};
154
155
156/** Opcode decoder table. */
157static PFNDISDECODEARMV8 const g_apfnOpcDecode[kDisArmV8OpcDecodeMax] =
158{
159 disArmV8DecodeIllegal,
160 disArmV8DecodeLookup,
161 disArmV8DecodeCollate
162};
163
164
165DECLINLINE(uint32_t) disArmV8ExtractBitVecFromInsn(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
166{
167 uint32_t fMask = (uint32_t)(RT_BIT_64(idxBitStart + cBits) - 1);
168 return (u32Insn & fMask) >> idxBitStart;
169}
170
171
172DECLINLINE(int32_t) disArmV8ExtractBitVecFromInsnSignExtend(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
173{
174 uint32_t fMask = RT_BIT_32(idxBitStart + cBits) - 1;
175 uint32_t fSign = ~(UINT32_MAX & (RT_BIT_32(cBits - 1) - 1));
176 uint32_t fValue = (u32Insn & fMask) >> idxBitStart;
177 if (fValue & fSign)
178 return (int32_t)(fValue | fSign);
179
180 return (int32_t)fValue;
181}
182
183
184static int disArmV8ParseIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
185{
186 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
187 AssertFailed();
188 return VERR_INTERNAL_ERROR;
189}
190
191
192static int disArmV8ParseSize(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
193{
194 RT_NOREF(pInsnClass, pParam);
195
196 Assert(pInsnParm->cBits == 2);
197 uint32_t u32Size = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
198 switch (u32Size)
199 {
200 case 0: pDis->armv8.cbOperand = sizeof(uint8_t); break;
201 case 1: pDis->armv8.cbOperand = sizeof(uint16_t); break;
202 case 2: pDis->armv8.cbOperand = sizeof(uint32_t); break;
203 case 3: pDis->armv8.cbOperand = sizeof(uint64_t); break;
204 default:
205 AssertReleaseFailed();
206 }
207 *pf64Bit = pDis->armv8.cbOperand == sizeof(uint64_t)
208 || (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_64BIT);
209 return VINF_SUCCESS;
210}
211
212
213static int disArmV8ParseImm(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
214{
215 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
216
217 AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
218
219 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
220 if (pInsnParm->cBits <= 8)
221 {
222 pParam->armv8.cb = sizeof(uint8_t);
223 pParam->fUse |= DISUSE_IMMEDIATE8;
224 }
225 else if (pInsnParm->cBits <= 16)
226 {
227 pParam->armv8.cb = sizeof(uint16_t);
228 pParam->fUse |= DISUSE_IMMEDIATE16;
229 }
230 else if (pInsnParm->cBits <= 32)
231 {
232 pParam->armv8.cb = sizeof(uint32_t);
233 pParam->fUse |= DISUSE_IMMEDIATE32;
234 }
235 else
236 AssertReleaseFailed();
237
238 return VINF_SUCCESS;
239}
240
241
242static int disArmV8ParseImmRel(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
243{
244 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
245
246 AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
247
248 pParam->uValue = (int64_t)disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
249 if (pInsnParm->cBits <= 8)
250 {
251 pParam->armv8.cb = sizeof(int8_t);
252 pParam->fUse |= DISUSE_IMMEDIATE8_REL;
253 }
254 else if (pInsnParm->cBits <= 16)
255 {
256 pParam->armv8.cb = sizeof(int16_t);
257 pParam->fUse |= DISUSE_IMMEDIATE16_REL;
258 }
259 else if (pInsnParm->cBits <= 32)
260 {
261 pParam->armv8.cb = sizeof(int32_t);
262 pParam->fUse |= DISUSE_IMMEDIATE32_REL;
263 }
264 else
265 AssertReleaseFailed();
266
267 return VINF_SUCCESS;
268}
269
270
271static int disArmV8ParseImmAdr(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
272{
273 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit, pInsnParm);
274
275 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, 5, 19);
276 pParam->uValue |= disArmV8ExtractBitVecFromInsn(u32Insn, 29, 2) << 29;
277 pParam->fUse |= DISUSE_IMMEDIATE32;
278 return VINF_SUCCESS;
279}
280
281
282static int disArmV8ParseImmZero(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
283{
284 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pf64Bit, pInsnParm);
285
286 pParam->uValue = 0;
287 pParam->fUse |= DISUSE_IMMEDIATE8;
288 return VINF_SUCCESS;
289}
290
291
292static int disArmV8ParseReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
293{
294 RT_NOREF(pDis, pOp, pInsnClass);
295 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
296 if (*pf64Bit || (pParam->armv8.enmType == kDisArmv8OpParmAddrInGpr))
297 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit;
298 else
299 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_32Bit;
300 return VINF_SUCCESS;
301}
302
303
304static int disArmV8ParseRegOff(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
305{
306 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
307 pParam->armv8.GprIndex.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
308 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit; /* Might get overwritten later on. */
309 pParam->fUse |= DISUSE_INDEX;
310 return VINF_SUCCESS;
311}
312
313
314static int disArmV8ParseImmsImmrN(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
315{
316 RT_NOREF(pDis, pOp);
317 AssertReturn(pInsnParm->cBits == 13, VERR_INTERNAL_ERROR_2);
318
319 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
320 /* N bit must be 0 if 32-bit variant is used. */
321 if ( ( (u32ImmRaw & RT_BIT_32(12))
322 && !*pf64Bit)
323 || ( !(u32ImmRaw & RT_BIT_32(12))
324 && *pf64Bit
325 && (pInsnClass->fClass & DISARMV8INSNCLASS_F_N_FORCED_1_ON_64BIT)))
326 return VERR_DIS_INVALID_OPCODE;
327
328 uint32_t uImm7SizeLen = ((u32ImmRaw & RT_BIT_32(12)) >> 6) | (u32ImmRaw & 0x3f);
329 uint32_t uImm6Rotations = (u32ImmRaw >> 6) & 0x3f;
330 pParam->uValue = *pf64Bit
331 ? Armv8A64ConvertImmRImmS2Mask64(uImm7SizeLen, uImm6Rotations)
332 : Armv8A64ConvertImmRImmS2Mask32(uImm7SizeLen, uImm6Rotations);
333 pParam->armv8.cb = pParam->uValue > UINT32_MAX ? sizeof(uint64_t) : sizeof(uint32_t);
334 pParam->fUse |= pParam->uValue > UINT32_MAX ? DISUSE_IMMEDIATE64 : DISUSE_IMMEDIATE32;
335 return VINF_SUCCESS;
336}
337
338
339static int disArmV8ParseHw(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
340{
341 RT_NOREF(pDis, pOp, pInsnClass, pParam);
342 Assert(pInsnParm->cBits == 2);
343
344 uint32_t u32 = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
345 /* hw<1> must be 0 if this is the 32-bit variant. */
346 if ( !*pf64Bit
347 && (u32 & RT_BIT_32(1)))
348 return VERR_DIS_INVALID_OPCODE;
349
350 Assert(pParam->armv8.enmType == kDisArmv8OpParmImm);
351 Assert(pParam->fUse & (DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32));
352 if (u32)
353 {
354 pParam->armv8.enmExtend = kDisArmv8OpParmExtendLsl;
355 pParam->armv8.u.cExtend = ((uint8_t)u32 & 0x3) << 4;
356 }
357 return VINF_SUCCESS;
358}
359
360
361static int disArmV8ParseCond(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
362{
363 RT_NOREF(pInsnClass, pOp, pParam, pf64Bit);
364 Assert(pInsnParm->cBits <= 4);
365 if (pParam)
366 {
367 /* Conditional as a parameter (CCMP/CCMN). */
368 Assert(pParam->armv8.enmType == kDisArmv8OpParmCond);
369 pParam->armv8.Op.enmCond = (DISARMV8INSTRCOND)disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
370 }
371 else /* Conditional for the base instruction. */
372 pDis->armv8.enmCond = (DISARMV8INSTRCOND)disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
373 return VINF_SUCCESS;
374}
375
376
377static int disArmV8ParsePState(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
378{
379 RT_NOREF(pDis, pOp, pInsnClass, pInsnParm, pf64Bit);
380 uint32_t u32Op1 = disArmV8ExtractBitVecFromInsn(u32Insn, 16, 3);
381 uint32_t u32Op2 = disArmV8ExtractBitVecFromInsn(u32Insn, 5, 3);
382
383 Assert(pDis->aParams[1].armv8.enmType == kDisArmv8OpParmImm);
384 Assert(pDis->aParams[1].armv8.cb == sizeof(uint8_t));
385 Assert(pDis->aParams[1].uValue < 16); /* 4 bit field. */
386
387 uint8_t bCRm = (uint8_t)pDis->aParams[1].uValue;
388
389 /* See C6.2.249 for the defined values. */
390 switch ((u32Op1 << 3) | u32Op2)
391 {
392 case 0x03: /* 000 011 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_UAO; break;
393 case 0x04: /* 000 100 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_PAN; break;
394 case 0x05: /* 000 101 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SPSel; break;
395 case 0x08: /* 001 000 */
396 {
397 pDis->aParams[1].uValue = bCRm & 0x1;
398 switch (bCRm & 0xe)
399 {
400 case 0: /* 000x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_ALLINT; break;
401 case 2: /* 001x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_PM; break;
402 default:
403 return VERR_DIS_INVALID_OPCODE;
404 }
405 break;
406 }
407 case 0x19: /* 011 001 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SSBS; break;
408 case 0x1a: /* 011 010 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_DIT; break;
409 case 0x1b: /* 011 011 */
410 {
411 pDis->aParams[1].uValue = bCRm & 0x1;
412 switch (bCRm & 0xe)
413 {
414 case 2: /* 001x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SVCRSM; break;
415 case 4: /* 010x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SVCRZA; break;
416 case 6: /* 011x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SVCRSMZA; break;
417 default:
418 return VERR_DIS_INVALID_OPCODE;
419 }
420 break;
421 }
422 case 0x1c: /* 011 100 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_TCO; break;
423 case 0x1e: /* 011 110 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_DAIFSet; break;
424 case 0x1f: /* 011 111 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_DAIFClr; break;
425 default:
426 return VERR_DIS_INVALID_OPCODE;
427 }
428
429 return VINF_SUCCESS;
430}
431
432
433static int disArmV8ParseSysReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
434{
435 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
436 AssertReturn(pInsnParm->cBits == 15, VERR_INTERNAL_ERROR_2);
437
438 /* Assumes a op0:op1:CRn:CRm:op2 encoding in the instruction starting at the given bit position. */
439 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
440 pParam->armv8.Op.idSysReg = ARMV8_AARCH64_SYSREG_ID_CREATE(2 + ((u32ImmRaw >> 14) & 0x1),
441 (u32ImmRaw >> 11) & 0x7,
442 (u32ImmRaw >> 7) & 0xf,
443 (u32ImmRaw >> 3) & 0xf,
444 u32ImmRaw & 0x7);
445 pParam->armv8.cb = 0;
446 pParam->fUse |= DISUSE_REG_SYSTEM;
447 return VINF_SUCCESS;
448}
449
450
451static int disArmV8ParseSh12(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
452{
453 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
454 Assert(pInsnParm->cBits == 1);
455 if (u32Insn & RT_BIT_32(pInsnParm->idxBitStart))
456 {
457 /* Shift the immediate pointed to. */
458 pParam->uValue <<= 12;
459
460 /* Re-evaluate the immediate data size. */
461 pParam->fUse &= ~(DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32);
462 if (pParam->uValue <= UINT8_MAX)
463 {
464 pParam->armv8.cb = sizeof(uint8_t);
465 pParam->fUse |= DISUSE_IMMEDIATE8;
466 }
467 else if (pParam->uValue <= UINT16_MAX)
468 {
469 pParam->armv8.cb = sizeof(uint16_t);
470 pParam->fUse |= DISUSE_IMMEDIATE16;
471 }
472 else if (pParam->uValue <= UINT32_MAX)
473 {
474 pParam->armv8.cb = sizeof(uint32_t);
475 pParam->fUse |= DISUSE_IMMEDIATE32;
476 }
477 else
478 AssertReleaseFailed();
479
480 }
481 return VINF_SUCCESS;
482}
483
484
485static int disArmV8ParseImmTbz(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
486{
487 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
488
489 AssertReturn(!pInsnParm->idxBitStart && !pInsnParm->cBits, VERR_INTERNAL_ERROR_2);
490
491 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, 19, 5);
492 pParam->uValue |= (u32Insn & RT_BIT_32(31)) >> 26;
493
494 pParam->armv8.cb = sizeof(uint8_t);
495 pParam->fUse |= DISUSE_IMMEDIATE8;
496 return VINF_SUCCESS;
497}
498
499
500static int disArmV8ParseShift(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
501{
502 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
503
504 AssertReturn(pInsnParm->cBits == 2, VERR_INTERNAL_ERROR_2);
505
506 uint32_t u32Shift = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
507 switch (u32Shift)
508 {
509 case 0: pParam->armv8.enmExtend = kDisArmv8OpParmExtendLsl; break;
510 case 1: pParam->armv8.enmExtend = kDisArmv8OpParmExtendLsr; break;
511 case 2: pParam->armv8.enmExtend = kDisArmv8OpParmExtendAsr; break;
512 case 3: pParam->armv8.enmExtend = kDisArmv8OpParmExtendRor; break;
513 default:
514 AssertReleaseFailed();
515 }
516 return VINF_SUCCESS;
517}
518
519
520static int disArmV8ParseShiftAmount(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
521{
522 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
523
524 uint32_t u32Amount = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
525 /* For a 32-bit operand it is impossible to shift/rotate more than 31 bits. */
526 if ( !*pf64Bit
527 && u32Amount > 31)
528 return VERR_DIS_INVALID_OPCODE;
529
530 Assert(pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone);
531 Assert(u32Amount < 64);
532 pParam->armv8.u.cExtend = (uint8_t)u32Amount;
533 /* Any shift operation with a 0 is essentially no shift being applied. */
534 if (pParam->armv8.u.cExtend == 0)
535 pParam->armv8.enmExtend = kDisArmv8OpParmExtendNone;
536 return VINF_SUCCESS;
537}
538
539
540static int disArmV8ParseImmMemOff(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
541{
542 RT_NOREF(pInsnClass, pOp, pf64Bit);
543
544 AssertReturn(pInsnParm->cBits <= 12, VERR_INTERNAL_ERROR_2);
545 AssertReturn(pDis->armv8.cbOperand != 0, VERR_INTERNAL_ERROR_2);
546
547 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
548 switch (pDis->armv8.cbOperand)
549 {
550 case sizeof(uint8_t): break;
551 case sizeof(uint16_t): pParam->armv8.u.offBase <<= 1; break;
552 case sizeof(uint32_t): pParam->armv8.u.offBase <<= 2; break;
553 case sizeof(uint64_t): pParam->armv8.u.offBase <<= 3; break;
554 default:
555 AssertReleaseFailed();
556 }
557 pParam->armv8.cb = sizeof(int16_t);
558 return VINF_SUCCESS;
559}
560
561
562static int disArmV8ParseSImmMemOff(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
563{
564 RT_NOREF(pDis, pInsnClass, pf64Bit);
565
566 AssertReturn(pInsnParm->cBits <= 7, VERR_INTERNAL_ERROR_2);
567 AssertReturn( (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_32BIT)
568 || (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_64BIT),
569 VERR_INTERNAL_ERROR_2);
570
571 pParam->armv8.cb = sizeof(int16_t);
572 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
573 pParam->armv8.u.offBase <<= (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_32BIT) ? 2 : 3;
574 return VINF_SUCCESS;
575}
576
577
578static int disArmV8ParseSImmMemOffUnscaled(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
579{
580 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
581
582 AssertReturn(pInsnParm->cBits <= 9, VERR_INTERNAL_ERROR_2);
583 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
584 return VINF_SUCCESS;
585}
586
587
588static int disArmV8ParseOption(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
589{
590 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
591
592 AssertReturn(pInsnParm->cBits == 3, VERR_INTERNAL_ERROR_2);
593 uint32_t u32Opt = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
594
595 Assert( pParam->armv8.enmExtend == kDisArmv8OpParmExtendNone
596 && (pParam->fUse & DISUSE_INDEX));
597 switch (u32Opt)
598 {
599 case 0: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtB; break;
600 case 1: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtH; break;
601 case 2: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtW; break;
602 case 3: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtX; break;
603 case 4: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtB; break;
604 case 5: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtH; break;
605 case 6: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtW; break;
606 case 7: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtX; break;
607 default:
608 AssertFailed();
609 }
610
611 /* When option<0> is set to 0, the 32-bit name of the GPR is used, 64-bit when option<0> is set to 1. */
612 pParam->armv8.GprIndex.enmRegType = RT_BOOL(u32Opt & 0x1)
613 ? kDisOpParamArmV8RegType_Gpr_64Bit
614 : kDisOpParamArmV8RegType_Gpr_32Bit;
615 return VINF_SUCCESS;
616}
617
618
619static int disArmV8ParseS(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
620{
621 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
622
623 AssertReturn(pInsnParm->cBits == 1, VERR_INTERNAL_ERROR_2);
624 bool const fS = RT_BOOL(u32Insn & RT_BIT_32(pInsnParm->idxBitStart));
625
626 Assert( pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone
627 && pDis->armv8.cbOperand > 0
628 && pDis->armv8.cbOperand <= 8);
629 if (fS)
630 {
631 switch (pDis->armv8.cbOperand)
632 {
633 case sizeof(uint8_t): pParam->armv8.u.cExtend = 0; break;
634 case sizeof(uint16_t): pParam->armv8.u.cExtend = 1; break;
635 case sizeof(uint32_t): pParam->armv8.u.cExtend = 2; break;
636 case sizeof(uint64_t): pParam->armv8.u.cExtend = 3; break;
637 default:
638 AssertReleaseFailed();
639 }
640 }
641 else if (pParam->armv8.enmExtend == kDisArmv8OpParmExtendUxtX) /* UXTX aka LSL can be ignored if S is not set. */
642 {
643 pParam->armv8.u.cExtend = 0;
644 pParam->armv8.enmExtend = kDisArmv8OpParmExtendNone;
645 }
646
647 return VINF_SUCCESS;
648}
649
650
651static int disArmV8ParseSetPreIndexed(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
652{
653 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pInsnParm, pf64Bit);
654
655 pParam->fUse |= DISUSE_PRE_INDEXED;
656 return VINF_SUCCESS;
657}
658
659
660static int disArmV8ParseSetPostIndexed(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
661{
662 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pInsnParm, pf64Bit);
663
664 pParam->fUse |= DISUSE_POST_INDEXED;
665 return VINF_SUCCESS;
666}
667
668
669static int disArmV8ParseFpType(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
670{
671 RT_NOREF(pOp, pInsnClass, pParam, pf64Bit);
672
673 Assert(pDis->armv8.enmFpType == kDisArmv8InstrFpType_Invalid);
674 uint32_t u32FpType = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
675 switch (u32FpType)
676 {
677 case 0: pDis->armv8.enmFpType = kDisArmv8InstrFpType_Single; break;
678 case 1: pDis->armv8.enmFpType = kDisArmv8InstrFpType_Double; break;
679 case 3: pDis->armv8.enmFpType = kDisArmv8InstrFpType_Half; break;
680 default: return VERR_DIS_INVALID_OPCODE;
681 }
682 return VINF_SUCCESS;
683}
684
685
686static int disArmV8ParseFpReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
687{
688 RT_NOREF(pOp, pInsnClass, pParam, pf64Bit);
689
690 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
691 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
692 switch (pDis->armv8.enmFpType)
693 {
694 case kDisArmv8InstrFpType_Single: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_FpReg_Single; break;
695 case kDisArmv8InstrFpType_Double: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_FpReg_Double; break;
696 case kDisArmv8InstrFpType_Half: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_FpReg_Half; break;
697 default: return VERR_DIS_INVALID_OPCODE;
698 }
699 return VINF_SUCCESS;
700}
701
702
703static int disArmV8ParseFpScale(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
704{
705 RT_NOREF(pDis, pOp, pInsnClass);
706 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
707
708 uint32_t u32Scale = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
709 if ( !*pf64Bit
710 && (u32Scale & RT_BIT_32(5)) == 0)
711 return VERR_DIS_INVALID_OPCODE;
712
713 pParam->uValue = 64 - u32Scale;
714 pParam->armv8.cb = sizeof(uint8_t);
715 pParam->fUse |= DISUSE_IMMEDIATE8;
716 return VINF_SUCCESS;
717}
718
719
720static int disArmV8ParseFpFixupFCvt(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
721{
722 RT_NOREF(pDis, pInsnClass, pParam, pInsnParm, pf64Bit);
723
724 /* Nothing to do if this isn't about fcvt. */
725 if (pOp->Opc.uOpcode != OP_ARMV8_A64_FCVT)
726 return VINF_SUCCESS;
727
728 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
729 Assert( pDis->aParams[0].armv8.enmType == kDisArmv8OpParmReg
730 && pDis->aParams[1].armv8.enmType == kDisArmv8OpParmReg);
731
732 /* Convert source and guest register floating point types to the correct widths. */
733 uint32_t u32Opc = (u32Insn & (RT_BIT_32(15) | RT_BIT_32(16))) >> 15;
734#ifdef VBOX_STRICT
735 uint32_t u32FpType = disArmV8ExtractBitVecFromInsn(u32Insn, 22, 2);
736 Assert( u32Opc != u32FpType
737 && u32Opc != 2);
738#endif
739
740 static const DISOPPARAMARMV8REGTYPE s_aOpc2FpWidth[] =
741 {
742 kDisOpParamArmV8RegType_FpReg_Single,
743 kDisOpParamArmV8RegType_FpReg_Double,
744 (DISOPPARAMARMV8REGTYPE)UINT8_MAX, /* Invalid encoding. */
745 kDisOpParamArmV8RegType_FpReg_Half
746 };
747
748 pDis->aParams[0].armv8.Op.Reg.enmRegType = s_aOpc2FpWidth[u32Opc];
749 return VINF_SUCCESS;
750}
751
752
753static int disArmV8ParseSimdRegScalar(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
754{
755 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
756
757 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
758 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Simd_Scalar_64Bit;
759 return VINF_SUCCESS;
760}
761
762
763static int disArmV8ParseImmHImmB(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
764{
765 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
766
767 Assert(pInsnParm->cBits == 7);
768 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
769 if (!(u32ImmRaw & RT_BIT_32(6))) /* immh == 0xxx is reserved for the scalar variant. */
770 return VERR_DIS_INVALID_OPCODE;
771
772 pParam->uValue = 2 * 64 - u32ImmRaw;
773 pParam->armv8.cb = sizeof(uint8_t);
774 pParam->fUse |= DISUSE_IMMEDIATE8;
775 return VINF_SUCCESS;
776}
777
778
779static uint32_t disArmV8DecodeIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
780{
781 RT_NOREF(pDis, u32Insn, pInsnClass);
782 AssertFailed();
783 return UINT32_MAX;
784}
785
786
787static uint32_t disArmV8DecodeLookup(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
788{
789 RT_NOREF(pDis);
790
791 for (uint32_t i = 0; i < pInsnClass->Hdr.cDecode; i++)
792 {
793 PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[i];
794 if (u32Insn == pOp->fValue)
795 return i;
796 }
797
798 return UINT32_MAX;
799}
800
801
802static uint32_t disArmV8DecodeCollate(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
803{
804 RT_NOREF(pDis);
805
806 /* Need to build a compact representation of the relevant bits from the mask to create an index. */
807 uint32_t fMask = pInsnClass->fMask >> pInsnClass->cShift;
808
809 /** @todo Optimize. */
810 uint32_t idx = 0;
811 uint32_t cShift = 0;
812 while (fMask)
813 {
814 if (fMask & 0x1)
815 {
816 idx |= (u32Insn & 1) << cShift;
817 cShift++;
818 }
819
820 u32Insn >>= 1;
821 fMask >>= 1;
822 }
823
824 if (RT_LIKELY(idx < pInsnClass->Hdr.cDecode))
825 return idx;
826
827 return UINT32_MAX;
828}
829
830
831/**
832 * Looks for possible alias conversions for the given disassembler state.
833 *
834 * @param pDis The disassembler state to process.
835 */
836static void disArmV8A64InsnAliasesProcess(PDISSTATE pDis)
837{
838#define DIS_ARMV8_ALIAS(a_Name) s_DisArmv8Alias ## a_Name
839#define DIS_ARMV8_ALIAS_CREATE(a_Name, a_szOpcode, a_uOpcode, a_fOpType) static const DISOPCODE DIS_ARMV8_ALIAS(a_Name) = OP(a_szOpcode, 0, 0, 0, a_uOpcode, 0, 0, 0, a_fOpType)
840#define DIS_ARMV8_ALIAS_REF(a_Name) &DIS_ARMV8_ALIAS(a_Name)
841 switch (pDis->pCurInstr->uOpcode)
842 {
843 case OP_ARMV8_A64_ORR:
844 {
845 /* Check for possible MOV conversion for the register variant when: shift is None and the first source is the zero register. */
846 Assert(pDis->aParams[1].armv8.enmType == kDisArmv8OpParmReg);
847 Assert( pDis->aParams[1].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_32Bit
848 || pDis->aParams[1].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_64Bit);
849
850 if ( pDis->aParams[2].armv8.enmType == kDisArmv8OpParmReg
851 && pDis->aParams[2].armv8.enmExtend == kDisArmv8OpParmExtendNone
852 && pDis->aParams[1].armv8.Op.Reg.idReg == ARMV8_A64_REG_XZR)
853 {
854 DIS_ARMV8_ALIAS_CREATE(Mov, "mov", OP_ARMV8_A64_MOV, DISOPTYPE_HARMLESS);
855 pDis->pCurInstr = DIS_ARMV8_ALIAS_REF(Mov);
856 pDis->aParams[1] = pDis->aParams[2];
857 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
858 }
859 /** @todo Immediate variant. */
860 break;
861 }
862 case OP_ARMV8_A64_SUBS:
863 {
864 Assert(pDis->aParams[0].armv8.enmType == kDisArmv8OpParmReg);
865 Assert( pDis->aParams[0].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_32Bit
866 || pDis->aParams[0].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_64Bit);
867
868 if (pDis->aParams[0].armv8.Op.Reg.idReg == ARMV8_A64_REG_XZR)
869 {
870 DIS_ARMV8_ALIAS_CREATE(Cmp, "cmp", OP_ARMV8_A64_CMP, DISOPTYPE_HARMLESS);
871 pDis->pCurInstr = DIS_ARMV8_ALIAS_REF(Cmp);
872 pDis->aParams[0] = pDis->aParams[1];
873 pDis->aParams[1] = pDis->aParams[2];
874 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
875 }
876 break;
877 }
878 default:
879 break; /* No conversion */
880 }
881#undef DIS_ARMV8_ALIAS_REF
882#undef DIS_ARMV8_ALIAS_CREATE
883#undef DIS_ARMV8_ALIAS
884}
885
886
887static int disArmV8A64ParseInstruction(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass)
888{
889 AssertPtr(pOp);
890 AssertPtr(pDis);
891 //Assert((u32Insn & pInsnClass->fFixedInsn) == pOp->fValue);
892 if ((u32Insn & pInsnClass->fFixedInsn) != pOp->fValue)
893 return VERR_DIS_INVALID_OPCODE;
894
895 /* Should contain the parameter type on input. */
896 pDis->aParams[0].fUse = 0;
897 pDis->aParams[1].fUse = 0;
898 pDis->aParams[2].fUse = 0;
899 pDis->aParams[3].fUse = 0;
900 pDis->aParams[0].armv8.enmType = pInsnClass->aenmParamTypes[0];
901 pDis->aParams[1].armv8.enmType = pInsnClass->aenmParamTypes[1];
902 pDis->aParams[2].armv8.enmType = pInsnClass->aenmParamTypes[2];
903 pDis->aParams[3].armv8.enmType = pInsnClass->aenmParamTypes[3];
904 pDis->aParams[0].armv8.enmExtend = kDisArmv8OpParmExtendNone;
905 pDis->aParams[1].armv8.enmExtend = kDisArmv8OpParmExtendNone;
906 pDis->aParams[2].armv8.enmExtend = kDisArmv8OpParmExtendNone;
907 pDis->aParams[3].armv8.enmExtend = kDisArmv8OpParmExtendNone;
908 pDis->armv8.enmCond = kDisArmv8InstrCond_Al;
909 pDis->armv8.enmFpType = kDisArmv8InstrFpType_Invalid;
910 pDis->armv8.cbOperand = 0;
911
912 pDis->pCurInstr = &pOp->Opc;
913 Assert(&pOp->Opc != &g_ArmV8A64InvalidOpcode[0]);
914
915 bool f64Bit = false;
916
917 /** @todo Get rid of these and move them to the per opcode
918 * (SF can become a decoder step). */
919 if (pInsnClass->fClass & DISARMV8INSNCLASS_F_SF)
920 f64Bit = RT_BOOL(u32Insn & RT_BIT_32(31));
921 else if (pInsnClass->fClass & DISARMV8INSNCLASS_F_FORCED_64BIT)
922 f64Bit = true;
923
924 if (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_32BIT)
925 f64Bit = false;
926 else if (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_64BIT)
927 f64Bit = true;
928
929 int rc = VINF_SUCCESS;
930 PCDISARMV8INSNPARAM pDecode = &pInsnClass->paParms[0];
931 while ( (pDecode->idxParse != kDisParmParseNop)
932 && RT_SUCCESS(rc))
933 {
934 rc = g_apfnDisasm[pDecode->idxParse](pDis, u32Insn, pOp, pInsnClass,
935 pDecode->idxParam != DIS_ARMV8_INSN_PARAM_UNSET
936 ? &pDis->aParams[pDecode->idxParam]
937 : NULL,
938 pDecode, &f64Bit);
939 pDecode++;
940 }
941
942 /* If parameter parsing returned an invalid opcode error the encoding is invalid. */
943 if (RT_SUCCESS(rc)) /** @todo Introduce flag to switch alias conversion on/off. */
944 disArmV8A64InsnAliasesProcess(pDis);
945 else if (rc == VERR_DIS_INVALID_OPCODE)
946 {
947 pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
948
949 pDis->aParams[0].armv8.enmType = kDisArmv8OpParmNone;
950 pDis->aParams[1].armv8.enmType = kDisArmv8OpParmNone;
951 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
952 pDis->aParams[3].armv8.enmType = kDisArmv8OpParmNone;
953 }
954 pDis->rc = rc;
955 return rc;
956}
957
958
959static int disArmV8A64ParseInvOpcode(PDISSTATE pDis)
960{
961 pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
962 pDis->rc = VERR_DIS_INVALID_OPCODE;
963 return VERR_DIS_INVALID_OPCODE;
964}
965
966
967static int disInstrArmV8DecodeWorker(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8DECODEHDR pHdr)
968{
969 while ( pHdr
970 && pHdr->enmDecodeType != kDisArmV8DecodeType_InsnClass)
971 {
972 if (pHdr->enmDecodeType == kDisArmV8DecodeType_Map)
973 {
974 PCDISARMV8DECODEMAP pMap = (PCDISARMV8DECODEMAP)pHdr;
975
976 uint32_t idxNext = (u32Insn & pMap->fMask) >> pMap->cShift;
977 if (RT_LIKELY(idxNext < pMap->Hdr.cDecode))
978 pHdr = pMap->papNext[idxNext];
979 else
980 {
981 pHdr = NULL;
982 break;
983 }
984 }
985 else
986 {
987 Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_Table);
988 PCDISARMV8DECODETBL pTbl = (PCDISARMV8DECODETBL)pHdr;
989
990 /* Walk all entries in the table and select the best match. */
991 pHdr = NULL;
992 for (uint32_t i = 0; i < pTbl->Hdr.cDecode; i++)
993 {
994 PCDISARMV8DECODETBLENTRY pEntry = &pTbl->paEntries[i];
995 if ((u32Insn & pEntry->fMask) == pEntry->fValue)
996 {
997 pHdr = pEntry->pHdrNext;
998 break;
999 }
1000 }
1001 }
1002 }
1003
1004 if (pHdr)
1005 {
1006 Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_InsnClass);
1007 PCDISARMV8INSNCLASS pInsnClass = (PCDISARMV8INSNCLASS)pHdr;
1008
1009 /* Decode the opcode from the instruction class. */
1010 uint32_t uOpcRaw = 0;
1011 if (pInsnClass->Hdr.cDecode > 1)
1012 {
1013 uOpcRaw = (u32Insn & pInsnClass->fMask) >> pInsnClass->cShift;
1014 if (pInsnClass->enmOpcDecode != kDisArmV8OpcDecodeNop)
1015 uOpcRaw = g_apfnOpcDecode[pInsnClass->enmOpcDecode](pDis, uOpcRaw, pInsnClass);
1016 }
1017
1018 if (uOpcRaw < pInsnClass->Hdr.cDecode)
1019 {
1020 PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[uOpcRaw];
1021 return disArmV8A64ParseInstruction(pDis, u32Insn, pOp, pInsnClass);
1022 }
1023 }
1024
1025 return disArmV8A64ParseInvOpcode(pDis);
1026}
1027
1028
1029/**
1030 * Internal worker for DISInstrEx and DISInstrWithPrefetchedBytes.
1031 *
1032 * @returns VBox status code.
1033 * @param pDis Initialized disassembler state.
1034 * @param paOneByteMap The one byte opcode map to use.
1035 * @param pcbInstr Where to store the instruction size. Can be NULL.
1036 */
1037DECLHIDDEN(int) disInstrWorkerArmV8(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
1038{
1039 RT_NOREF(paOneByteMap);
1040
1041 if (pDis->uCpuMode == DISCPUMODE_ARMV8_A64)
1042 {
1043 *pcbInstr = sizeof(uint32_t);
1044
1045 /* Instructions are always little endian and 4 bytes. */
1046 uint32_t u32Insn = disReadDWord(pDis, 0 /*offInstr*/);
1047 if (RT_FAILURE(pDis->rc))
1048 return pDis->rc;
1049
1050 /** @todo r=bird: This is a waste of time if the host is little endian... */
1051 pDis->Instr.u32 = RT_LE2H_U32(u32Insn);
1052 pDis->cbInstr = sizeof(u32Insn);
1053
1054 return disInstrArmV8DecodeWorker(pDis, u32Insn, &g_aArmV8A64InsnDecodeL0.Hdr);
1055 }
1056
1057 AssertReleaseFailed();
1058 return VERR_NOT_IMPLEMENTED;
1059}
1060
1061
1062/**
1063 * Inlined worker that initializes the disassembler state.
1064 *
1065 * @returns The primary opcode map to use.
1066 * @param pDis The disassembler state.
1067 * @param uInstrAddr The instruction address.
1068 * @param enmCpuMode The CPU mode.
1069 * @param fFilter The instruction filter settings.
1070 * @param pfnReadBytes The byte reader, can be NULL.
1071 * @param pvUser The user data for the reader.
1072 */
1073DECLHIDDEN(PCDISOPCODE) disInitializeStateArmV8(PDISSTATE pDis, DISCPUMODE enmCpuMode, uint32_t fFilter)
1074{
1075 RT_NOREF(pDis, enmCpuMode, fFilter);
1076 return NULL;
1077}
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