VirtualBox

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

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

Disassembler: Decode Advanced SIMD load/store multiple structures instructions, bugref:10394

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.5 KB
Line 
1/* $Id: DisasmCore-armv8.cpp 106791 2024-10-30 13:59:23Z 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 disArmV8ParseGprZr;
82static FNDISPARSEARMV8 disArmV8ParseGprZr32;
83static FNDISPARSEARMV8 disArmV8ParseGprZr64;
84static FNDISPARSEARMV8 disArmV8ParseGprSp;
85static FNDISPARSEARMV8 disArmV8ParseGprOff;
86static FNDISPARSEARMV8 disArmV8ParseVecReg;
87static FNDISPARSEARMV8 disArmV8ParseAddrGprSp;
88static FNDISPARSEARMV8 disArmV8ParseRegFixed31;
89static FNDISPARSEARMV8 disArmV8ParseImmsImmrN;
90static FNDISPARSEARMV8 disArmV8ParseHw;
91static FNDISPARSEARMV8 disArmV8ParseCond;
92static FNDISPARSEARMV8 disArmV8ParsePState;
93static FNDISPARSEARMV8 disArmV8ParseSysReg;
94static FNDISPARSEARMV8 disArmV8ParseSh12;
95static FNDISPARSEARMV8 disArmV8ParseImmTbz;
96static FNDISPARSEARMV8 disArmV8ParseShift;
97static FNDISPARSEARMV8 disArmV8ParseShiftAmount;
98static FNDISPARSEARMV8 disArmV8ParseImmMemOff;
99static FNDISPARSEARMV8 disArmV8ParseSImmMemOff;
100static FNDISPARSEARMV8 disArmV8ParseSImmMemOffUnscaled;
101static FNDISPARSEARMV8 disArmV8ParseOption;
102static FNDISPARSEARMV8 disArmV8ParseS;
103static FNDISPARSEARMV8 disArmV8ParseSetPreIndexed;
104static FNDISPARSEARMV8 disArmV8ParseSetPostIndexed;
105static FNDISPARSEARMV8 disArmV8ParseFpType;
106static FNDISPARSEARMV8 disArmV8ParseFpReg;
107static FNDISPARSEARMV8 disArmV8ParseFpScale;
108static FNDISPARSEARMV8 disArmV8ParseFpFixupFCvt;
109static FNDISPARSEARMV8 disArmV8ParseSimdRegSize;
110static FNDISPARSEARMV8 disArmV8ParseSimdRegSize32;
111static FNDISPARSEARMV8 disArmV8ParseSimdRegSize64;
112static FNDISPARSEARMV8 disArmV8ParseSimdRegSize128;
113static FNDISPARSEARMV8 disArmV8ParseSimdRegScalar;
114static FNDISPARSEARMV8 disArmV8ParseImmHImmB;
115static FNDISPARSEARMV8 disArmV8ParseSf;
116static FNDISPARSEARMV8 disArmV8ParseImmX16;
117static FNDISPARSEARMV8 disArmV8ParseSImmTags;
118static FNDISPARSEARMV8 disArmV8ParseLdrPacImm;
119static FNDISPARSEARMV8 disArmV8ParseLdrPacW;
120static FNDISPARSEARMV8 disArmV8ParseVecRegElemSize;
121static FNDISPARSEARMV8 disArmV8ParseVecRegQ;
122static FNDISPARSEARMV8 disArmV8ParseVecGrp;
123/** @} */
124
125
126/** @name Decoders
127 * @{ */
128static FNDISDECODEARMV8 disArmV8DecodeIllegal;
129static FNDISDECODEARMV8 disArmV8DecodeLookup;
130static FNDISDECODEARMV8 disArmV8DecodeCollate;
131/** @} */
132
133
134/*********************************************************************************************************************************
135* Global Variables *
136*********************************************************************************************************************************/
137/** Parser opcode table for full disassembly. */
138static PFNDISPARSEARMV8 const g_apfnDisasm[kDisParmParseMax] =
139{
140 disArmV8ParseIllegal,
141 disArmV8ParseSize,
142 disArmV8ParseImm,
143 disArmV8ParseImmRel,
144 disArmV8ParseImmAdr,
145 disArmV8ParseImmZero,
146 disArmV8ParseGprZr,
147 disArmV8ParseGprZr32,
148 disArmV8ParseGprZr64,
149 disArmV8ParseGprSp,
150 disArmV8ParseGprOff,
151 disArmV8ParseVecReg,
152 disArmV8ParseAddrGprSp,
153 disArmV8ParseRegFixed31,
154 disArmV8ParseImmsImmrN,
155 disArmV8ParseHw,
156 disArmV8ParseCond,
157 disArmV8ParsePState,
158 NULL,
159 disArmV8ParseSysReg,
160 disArmV8ParseSh12,
161 disArmV8ParseImmTbz,
162 disArmV8ParseShift,
163 disArmV8ParseShiftAmount,
164 disArmV8ParseImmMemOff,
165 disArmV8ParseSImmMemOff,
166 disArmV8ParseSImmMemOffUnscaled,
167 disArmV8ParseOption,
168 disArmV8ParseS,
169 disArmV8ParseSetPreIndexed,
170 disArmV8ParseSetPostIndexed,
171 disArmV8ParseFpType,
172 disArmV8ParseFpReg,
173 disArmV8ParseFpScale,
174 disArmV8ParseFpFixupFCvt,
175 disArmV8ParseSimdRegSize,
176 disArmV8ParseSimdRegSize32,
177 disArmV8ParseSimdRegSize64,
178 disArmV8ParseSimdRegSize128,
179 disArmV8ParseSimdRegScalar,
180 disArmV8ParseImmHImmB,
181 disArmV8ParseSf,
182 disArmV8ParseImmX16,
183 disArmV8ParseSImmTags,
184 disArmV8ParseLdrPacImm,
185 disArmV8ParseLdrPacW,
186 disArmV8ParseVecRegElemSize,
187 disArmV8ParseVecRegQ,
188 disArmV8ParseVecGrp
189};
190
191
192/** Opcode decoder table. */
193static PFNDISDECODEARMV8 const g_apfnOpcDecode[kDisArmV8OpcDecodeMax] =
194{
195 disArmV8DecodeIllegal,
196 disArmV8DecodeLookup,
197 disArmV8DecodeCollate
198};
199
200
201DECLINLINE(uint32_t) disArmV8ExtractBitVecFromInsn(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
202{
203 uint32_t fMask = (uint32_t)(RT_BIT_64(idxBitStart + cBits) - 1);
204 return (u32Insn & fMask) >> idxBitStart;
205}
206
207
208DECLINLINE(int32_t) disArmV8ExtractBitVecFromInsnSignExtend(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
209{
210 uint32_t const fMask = RT_BIT_32(cBits) - 1;
211 uint32_t const fSignBit = RT_BIT_32(cBits - 1);
212 uint32_t const u32 = (u32Insn >> idxBitStart) & fMask;
213 return (int32_t)((u32 ^ fSignBit) - fSignBit);
214}
215
216
217static int disArmV8ParseIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
218{
219 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
220 AssertFailed();
221 return VERR_INTERNAL_ERROR;
222}
223
224
225static int disArmV8ParseSize(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
226{
227 RT_NOREF(pInsnClass, pParam);
228
229 Assert(pInsnParm->cBits == 2);
230 uint32_t u32Size = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
231 switch (u32Size)
232 {
233 case 0: pDis->armv8.cbOperand = sizeof(uint8_t); break;
234 case 1: pDis->armv8.cbOperand = sizeof(uint16_t); break;
235 case 2: pDis->armv8.cbOperand = sizeof(uint32_t); break;
236 case 3: pDis->armv8.cbOperand = sizeof(uint64_t); break;
237 default:
238 AssertReleaseFailed();
239 }
240 *pf64Bit = pDis->armv8.cbOperand == sizeof(uint64_t)
241 || (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_64BIT);
242 return VINF_SUCCESS;
243}
244
245
246static int disArmV8ParseImm(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
247{
248 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
249
250 AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
251 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
252
253 pParam->armv8.enmType = kDisArmv8OpParmImm;
254 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
255 if (pInsnParm->cBits <= 8)
256 {
257 pParam->armv8.cb = sizeof(uint8_t);
258 pParam->fUse |= DISUSE_IMMEDIATE8;
259 }
260 else if (pInsnParm->cBits <= 16)
261 {
262 pParam->armv8.cb = sizeof(uint16_t);
263 pParam->fUse |= DISUSE_IMMEDIATE16;
264 }
265 else if (pInsnParm->cBits <= 32)
266 {
267 pParam->armv8.cb = sizeof(uint32_t);
268 pParam->fUse |= DISUSE_IMMEDIATE32;
269 }
270 else
271 AssertReleaseFailed();
272
273 return VINF_SUCCESS;
274}
275
276
277static int disArmV8ParseImmRel(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
278{
279 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
280
281 AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
282 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
283
284 pParam->armv8.enmType = kDisArmv8OpParmImmRel;
285 pParam->uValue = (int64_t)disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits) * sizeof(uint32_t);
286 if (pInsnParm->cBits <= 8)
287 {
288 pParam->armv8.cb = sizeof(int8_t);
289 pParam->fUse |= DISUSE_IMMEDIATE8_REL;
290 }
291 else if (pInsnParm->cBits <= 16)
292 {
293 pParam->armv8.cb = sizeof(int16_t);
294 pParam->fUse |= DISUSE_IMMEDIATE16_REL;
295 }
296 else if (pInsnParm->cBits <= 32)
297 {
298 pParam->armv8.cb = sizeof(int32_t);
299 pParam->fUse |= DISUSE_IMMEDIATE32_REL;
300 }
301 else
302 AssertReleaseFailed();
303
304 return VINF_SUCCESS;
305}
306
307
308static int disArmV8ParseImmAdr(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
309{
310 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit, pInsnParm);
311
312 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
313
314 pParam->armv8.enmType = kDisArmv8OpParmImmRel;
315 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, 5, 19);
316 pParam->uValue |= disArmV8ExtractBitVecFromInsn(u32Insn, 29, 2) << 29;
317 pParam->fUse |= DISUSE_IMMEDIATE32;
318 return VINF_SUCCESS;
319}
320
321
322static int disArmV8ParseImmZero(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
323{
324 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pf64Bit, pInsnParm);
325
326 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
327
328 pParam->armv8.enmType = kDisArmv8OpParmImm;
329 pParam->uValue = 0;
330 pParam->fUse |= DISUSE_IMMEDIATE8;
331 return VINF_SUCCESS;
332}
333
334
335static int disArmV8ParseGprZr(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
336{
337 RT_NOREF(pDis, pOp, pInsnClass);
338
339 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
340
341 pParam->armv8.enmType = kDisArmv8OpParmReg;
342
343 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
344 if (*pf64Bit || (pParam->armv8.enmType == kDisArmv8OpParmAddrInGpr))
345 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit;
346 else
347 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_32Bit;
348 return VINF_SUCCESS;
349}
350
351
352static int disArmV8ParseGprZr32(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
353{
354 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
355 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
356
357 pParam->armv8.enmType = kDisArmv8OpParmReg;
358 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
359 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_32Bit;
360 return VINF_SUCCESS;
361}
362
363
364static int disArmV8ParseGprZr64(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
365{
366 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
367 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
368
369 pParam->armv8.enmType = kDisArmv8OpParmReg;
370 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
371 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit;
372 return VINF_SUCCESS;
373}
374
375
376static int disArmV8ParseGprSp(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
377{
378 RT_NOREF(pDis, pOp, pInsnClass);
379 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
380
381 pParam->armv8.enmType = kDisArmv8OpParmReg;
382 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
383 if (pParam->armv8.Op.Reg.idReg == 31)
384 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Sp;
385 else if (*pf64Bit)
386 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit;
387 else
388 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_32Bit;
389 return VINF_SUCCESS;
390}
391
392
393static int disArmV8ParseGprOff(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
394{
395 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
396 Assert(pParam->armv8.enmType != kDisArmv8OpParmNone);
397
398 pParam->armv8.GprIndex.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
399 pParam->armv8.GprIndex.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit; /* Might get overwritten later on. */
400 pParam->fUse |= DISUSE_INDEX;
401 return VINF_SUCCESS;
402}
403
404
405static int disArmV8ParseVecReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
406{
407 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
408 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
409
410 pParam->armv8.enmType = kDisArmv8OpParmReg;
411 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
412 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Simd_Vector;
413 pParam->armv8.Op.Reg.enmVecType = pDis->armv8.enmVecRegType;
414 return VINF_SUCCESS;
415}
416
417
418static int disArmV8ParseAddrGprSp(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
419{
420 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
421 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
422
423 pParam->armv8.enmType = kDisArmv8OpParmAddrInGpr;
424 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
425 if (pParam->armv8.Op.Reg.idReg == 31)
426 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Sp;
427 else
428 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit;
429 return VINF_SUCCESS;
430}
431
432
433static int disArmV8ParseRegFixed31(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
434{
435 RT_NOREF(pDis, pOp, pInsnClass, pParam, pf64Bit);
436 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
437
438 if (disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits) != 31)
439 return VERR_DIS_INVALID_OPCODE;
440 return VINF_SUCCESS;
441}
442
443
444static int disArmV8ParseImmsImmrN(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
445{
446 RT_NOREF(pDis, pOp, pInsnClass);
447 AssertReturn(pInsnParm->cBits == 13, VERR_INTERNAL_ERROR_2);
448
449 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
450 pParam->armv8.enmType = kDisArmv8OpParmImm;
451
452 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
453 /* N bit must be 0 if 32-bit variant is used. */
454 if ( ( (u32ImmRaw & RT_BIT_32(12))
455 && !*pf64Bit)
456 || ( !(u32ImmRaw & RT_BIT_32(12))
457 && *pf64Bit))
458 return VERR_DIS_INVALID_OPCODE;
459
460 uint32_t uImm7SizeLen = ((u32ImmRaw & RT_BIT_32(12)) >> 6) | (u32ImmRaw & 0x3f);
461 uint32_t uImm6Rotations = (u32ImmRaw >> 6) & 0x3f;
462 pParam->uValue = *pf64Bit
463 ? Armv8A64ConvertImmRImmS2Mask64(uImm7SizeLen, uImm6Rotations)
464 : Armv8A64ConvertImmRImmS2Mask32(uImm7SizeLen, uImm6Rotations);
465 pParam->armv8.cb = pParam->uValue > UINT32_MAX ? sizeof(uint64_t) : sizeof(uint32_t);
466 pParam->fUse |= pParam->uValue > UINT32_MAX ? DISUSE_IMMEDIATE64 : DISUSE_IMMEDIATE32;
467 return VINF_SUCCESS;
468}
469
470
471static int disArmV8ParseHw(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
472{
473 RT_NOREF(pDis, pOp, pInsnClass, pParam);
474 Assert(pInsnParm->cBits == 2);
475
476 uint32_t u32 = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
477 /* hw<1> must be 0 if this is the 32-bit variant. */
478 if ( !*pf64Bit
479 && (u32 & RT_BIT_32(1)))
480 return VERR_DIS_INVALID_OPCODE;
481
482 Assert(pParam->armv8.enmType == kDisArmv8OpParmImm);
483 Assert(pParam->fUse & (DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32));
484 if (u32)
485 {
486 pParam->armv8.enmExtend = kDisArmv8OpParmExtendLsl;
487 pParam->armv8.u.cExtend = ((uint8_t)u32 & 0x3) << 4;
488 }
489 return VINF_SUCCESS;
490}
491
492
493static int disArmV8ParseCond(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
494{
495 RT_NOREF(pInsnClass, pOp, pParam, pf64Bit);
496 Assert(pInsnParm->cBits <= 4);
497 if (pParam)
498 {
499 /* Conditional as a parameter (CCMP/CCMN). */
500 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
501 pParam->armv8.enmType = kDisArmv8OpParmCond;
502 pParam->armv8.Op.enmCond = (DISARMV8INSTRCOND)disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
503 }
504 else /* Conditional for the base instruction. */
505 pDis->armv8.enmCond = (DISARMV8INSTRCOND)disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
506 return VINF_SUCCESS;
507}
508
509
510static int disArmV8ParsePState(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
511{
512 RT_NOREF(pDis, pOp, pInsnClass, pInsnParm, pf64Bit);
513 uint32_t u32Op1 = disArmV8ExtractBitVecFromInsn(u32Insn, 16, 3);
514 uint32_t u32Op2 = disArmV8ExtractBitVecFromInsn(u32Insn, 5, 3);
515
516 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
517 Assert(pDis->aParams[1].armv8.enmType == kDisArmv8OpParmImm);
518 Assert(pDis->aParams[1].armv8.cb == sizeof(uint8_t));
519 Assert(pDis->aParams[1].uValue < 16); /* 4 bit field. */
520
521 pParam->armv8.enmType = kDisArmv8OpParmPState;
522 uint8_t bCRm = (uint8_t)pDis->aParams[1].uValue;
523
524 /* See C6.2.249 for the defined values. */
525 switch ((u32Op1 << 3) | u32Op2)
526 {
527 case 0x03: /* 000 011 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_UAO; break;
528 case 0x04: /* 000 100 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_PAN; break;
529 case 0x05: /* 000 101 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SPSel; break;
530 case 0x08: /* 001 000 */
531 {
532 pDis->aParams[1].uValue = bCRm & 0x1;
533 switch (bCRm & 0xe)
534 {
535 case 0: /* 000x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_ALLINT; break;
536 case 2: /* 001x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_PM; break;
537 default:
538 return VERR_DIS_INVALID_OPCODE;
539 }
540 break;
541 }
542 case 0x19: /* 011 001 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SSBS; break;
543 case 0x1a: /* 011 010 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_DIT; break;
544 case 0x1b: /* 011 011 */
545 {
546 pDis->aParams[1].uValue = bCRm & 0x1;
547 switch (bCRm & 0xe)
548 {
549 case 2: /* 001x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SVCRSM; break;
550 case 4: /* 010x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SVCRZA; break;
551 case 6: /* 011x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SVCRSMZA; break;
552 default:
553 return VERR_DIS_INVALID_OPCODE;
554 }
555 break;
556 }
557 case 0x1c: /* 011 100 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_TCO; break;
558 case 0x1e: /* 011 110 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_DAIFSet; break;
559 case 0x1f: /* 011 111 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_DAIFClr; break;
560 default:
561 return VERR_DIS_INVALID_OPCODE;
562 }
563
564 return VINF_SUCCESS;
565}
566
567
568static int disArmV8ParseSysReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
569{
570 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
571 AssertReturn(pInsnParm->cBits == 15, VERR_INTERNAL_ERROR_2);
572
573 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
574 pParam->armv8.enmType = kDisArmv8OpParmSysReg;
575
576 /* Assumes a op0:op1:CRn:CRm:op2 encoding in the instruction starting at the given bit position. */
577 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
578 pParam->armv8.Op.idSysReg = ARMV8_AARCH64_SYSREG_ID_CREATE(2 + ((u32ImmRaw >> 14) & 0x1),
579 (u32ImmRaw >> 11) & 0x7,
580 (u32ImmRaw >> 7) & 0xf,
581 (u32ImmRaw >> 3) & 0xf,
582 u32ImmRaw & 0x7);
583 pParam->armv8.cb = 0;
584 pParam->fUse |= DISUSE_REG_SYSTEM;
585 return VINF_SUCCESS;
586}
587
588
589static int disArmV8ParseSh12(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
590{
591 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
592 Assert(pInsnParm->cBits == 1);
593 Assert(pParam->armv8.enmType == kDisArmv8OpParmImm);
594
595 if (u32Insn & RT_BIT_32(pInsnParm->idxBitStart))
596 {
597 /* Shift the immediate pointed to. */
598 pParam->uValue <<= 12;
599
600 /* Re-evaluate the immediate data size. */
601 pParam->fUse &= ~(DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32);
602 if (pParam->uValue <= UINT8_MAX)
603 {
604 pParam->armv8.cb = sizeof(uint8_t);
605 pParam->fUse |= DISUSE_IMMEDIATE8;
606 }
607 else if (pParam->uValue <= UINT16_MAX)
608 {
609 pParam->armv8.cb = sizeof(uint16_t);
610 pParam->fUse |= DISUSE_IMMEDIATE16;
611 }
612 else if (pParam->uValue <= UINT32_MAX)
613 {
614 pParam->armv8.cb = sizeof(uint32_t);
615 pParam->fUse |= DISUSE_IMMEDIATE32;
616 }
617 else
618 AssertReleaseFailed();
619
620 }
621 return VINF_SUCCESS;
622}
623
624
625static int disArmV8ParseImmTbz(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
626{
627 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
628
629 AssertReturn(!pInsnParm->idxBitStart && !pInsnParm->cBits, VERR_INTERNAL_ERROR_2);
630 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
631 pParam->armv8.enmType = kDisArmv8OpParmImm;
632
633 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, 19, 5);
634 pParam->uValue |= (u32Insn & RT_BIT_32(31)) >> 26;
635
636 pParam->armv8.cb = sizeof(uint8_t);
637 pParam->fUse |= DISUSE_IMMEDIATE8;
638 return VINF_SUCCESS;
639}
640
641
642static int disArmV8ParseShift(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
643{
644 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
645
646 AssertReturn(pInsnParm->cBits == 2, VERR_INTERNAL_ERROR_2);
647
648 uint32_t u32Shift = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
649 switch (u32Shift)
650 {
651 case 0: pParam->armv8.enmExtend = kDisArmv8OpParmExtendLsl; break;
652 case 1: pParam->armv8.enmExtend = kDisArmv8OpParmExtendLsr; break;
653 case 2: pParam->armv8.enmExtend = kDisArmv8OpParmExtendAsr; break;
654 case 3: pParam->armv8.enmExtend = kDisArmv8OpParmExtendRor; break;
655 default:
656 AssertReleaseFailed();
657 }
658 return VINF_SUCCESS;
659}
660
661
662static int disArmV8ParseShiftAmount(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
663{
664 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
665
666 uint32_t u32Amount = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
667 /* For a 32-bit operand it is impossible to shift/rotate more than 31 bits. */
668 if ( !*pf64Bit
669 && u32Amount > 31)
670 return VERR_DIS_INVALID_OPCODE;
671
672 Assert(pParam->armv8.enmType != kDisArmv8OpParmNone);
673 Assert(pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone);
674 Assert(u32Amount < 64);
675 pParam->armv8.u.cExtend = (uint8_t)u32Amount;
676 /* Any shift operation with a 0 is essentially no shift being applied. */
677 if (pParam->armv8.u.cExtend == 0)
678 pParam->armv8.enmExtend = kDisArmv8OpParmExtendNone;
679 return VINF_SUCCESS;
680}
681
682
683static int disArmV8ParseImmMemOff(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
684{
685 RT_NOREF(pInsnClass, pOp, pf64Bit);
686
687 AssertReturn(pInsnParm->cBits <= 12, VERR_INTERNAL_ERROR_2);
688 AssertReturn(pDis->armv8.cbOperand != 0, VERR_INTERNAL_ERROR_2);
689 Assert(pParam->armv8.enmType != kDisArmv8OpParmNone);
690
691 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
692 switch (pDis->armv8.cbOperand)
693 {
694 case sizeof(uint8_t): break;
695 case sizeof(uint16_t): pParam->armv8.u.offBase <<= 1; break;
696 case sizeof(uint32_t): pParam->armv8.u.offBase <<= 2; break;
697 case sizeof(uint64_t): pParam->armv8.u.offBase <<= 3; break;
698 case 16: pParam->armv8.u.offBase <<= 4; break;
699 default:
700 AssertReleaseFailed();
701 }
702 pParam->armv8.cb = sizeof(int16_t);
703 return VINF_SUCCESS;
704}
705
706
707static int disArmV8ParseSImmMemOff(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
708{
709 RT_NOREF(pInsnClass, pf64Bit);
710
711 AssertReturn(pInsnParm->cBits <= 7, VERR_INTERNAL_ERROR_2);
712 AssertReturn( (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_32BIT)
713 || (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_64BIT)
714 || pDis->armv8.cbOperand != 0,
715 VERR_INTERNAL_ERROR_2);
716 Assert(pParam->armv8.enmType != kDisArmv8OpParmNone);
717
718 pParam->armv8.cb = sizeof(int16_t);
719 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
720
721 /** @todo Merge DISARMV8INSNCLASS_F_FORCED_32BIT | DISARMV8INSNCLASS_F_FORCED_64BIT into cbOperand. */
722 if (pDis->armv8.cbOperand)
723 {
724 switch (pDis->armv8.cbOperand)
725 {
726 case sizeof(uint8_t): break;
727 case sizeof(uint16_t): pParam->armv8.u.offBase <<= 1; break;
728 case sizeof(uint32_t): pParam->armv8.u.offBase <<= 2; break;
729 case sizeof(uint64_t): pParam->armv8.u.offBase <<= 3; break;
730 case 16: pParam->armv8.u.offBase <<= 4; break;
731 default:
732 AssertReleaseFailed();
733 }
734 }
735 else
736 pParam->armv8.u.offBase <<= (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_32BIT) ? 2 : 3;
737 return VINF_SUCCESS;
738}
739
740
741static int disArmV8ParseSImmMemOffUnscaled(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
742{
743 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
744
745 AssertReturn(pInsnParm->cBits <= 9, VERR_INTERNAL_ERROR_2);
746 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
747 return VINF_SUCCESS;
748}
749
750
751static int disArmV8ParseOption(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
752{
753 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
754
755 AssertReturn(pInsnParm->cBits == 3, VERR_INTERNAL_ERROR_2);
756 Assert(pParam->armv8.enmType != kDisArmv8OpParmNone);
757
758 uint32_t u32Opt = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
759
760 Assert( pParam->armv8.enmExtend == kDisArmv8OpParmExtendNone
761 /*&& (pParam->fUse & DISUSE_INDEX)*/); /* For add/sub extended register. */
762 switch (u32Opt)
763 {
764 case 0: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtB; break;
765 case 1: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtH; break;
766 case 2: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtW; break;
767 case 3: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtX; break;
768 case 4: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtB; break;
769 case 5: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtH; break;
770 case 6: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtW; break;
771 case 7: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtX; break;
772 default:
773 AssertFailed();
774 }
775
776 /* When option<1:0> is b11, the 64-bit name of the GPR is used, 32-bit otherwise. */
777 if (pParam->fUse & DISUSE_INDEX)
778 pParam->armv8.GprIndex.enmRegType = (u32Opt & 0x3) == 0x3
779 ? kDisOpParamArmV8RegType_Gpr_64Bit
780 : kDisOpParamArmV8RegType_Gpr_32Bit;
781 else
782 {
783 Assert(pParam->armv8.enmType == kDisArmv8OpParmReg);
784 pParam->armv8.Op.Reg.enmRegType = ((u32Opt & 0x3) == 0x3 && *pf64Bit)
785 ? kDisOpParamArmV8RegType_Gpr_64Bit
786 : kDisOpParamArmV8RegType_Gpr_32Bit;
787 }
788 return VINF_SUCCESS;
789}
790
791
792static int disArmV8ParseS(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
793{
794 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
795
796 AssertReturn(pInsnParm->cBits == 1, VERR_INTERNAL_ERROR_2);
797 Assert(pParam->armv8.enmType != kDisArmv8OpParmNone);
798
799 bool const fS = RT_BOOL(u32Insn & RT_BIT_32(pInsnParm->idxBitStart));
800
801 Assert( pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone
802 && pDis->armv8.cbOperand > 0
803 && pDis->armv8.cbOperand <= 16);
804 if (fS)
805 {
806 switch (pDis->armv8.cbOperand)
807 {
808 case sizeof(uint8_t): pParam->armv8.u.cExtend = 0; break;
809 case sizeof(uint16_t): pParam->armv8.u.cExtend = 1; break;
810 case sizeof(uint32_t): pParam->armv8.u.cExtend = 2; break;
811 case sizeof(uint64_t): pParam->armv8.u.cExtend = 3; break;
812 case 16: pParam->armv8.u.cExtend = 4; break;
813 default:
814 AssertReleaseFailed();
815 }
816 }
817 else if (pParam->armv8.enmExtend == kDisArmv8OpParmExtendUxtX) /* UXTX aka LSL can be ignored if S is not set. */
818 {
819 pParam->armv8.u.cExtend = 0;
820 pParam->armv8.enmExtend = kDisArmv8OpParmExtendNone;
821 }
822
823 return VINF_SUCCESS;
824}
825
826
827static int disArmV8ParseSetPreIndexed(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
828{
829 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pInsnParm, pf64Bit);
830
831 pParam->fUse |= DISUSE_PRE_INDEXED;
832 return VINF_SUCCESS;
833}
834
835
836static int disArmV8ParseSetPostIndexed(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
837{
838 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pInsnParm, pf64Bit);
839
840 pParam->fUse |= DISUSE_POST_INDEXED;
841 return VINF_SUCCESS;
842}
843
844
845static int disArmV8ParseFpType(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
846{
847 RT_NOREF(pOp, pInsnClass, pParam, pf64Bit);
848
849 Assert(pDis->armv8.enmFpType == kDisArmv8InstrFpType_Invalid);
850
851 uint32_t u32FpType = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
852 switch (u32FpType)
853 {
854 case 0: pDis->armv8.enmFpType = kDisArmv8InstrFpType_Single; break;
855 case 1: pDis->armv8.enmFpType = kDisArmv8InstrFpType_Double; break;
856 case 3: pDis->armv8.enmFpType = kDisArmv8InstrFpType_Half; break;
857 default: return VERR_DIS_INVALID_OPCODE;
858 }
859 return VINF_SUCCESS;
860}
861
862
863static int disArmV8ParseFpReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
864{
865 RT_NOREF(pOp, pInsnClass, pParam, pf64Bit);
866
867 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
868 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
869
870 pParam->armv8.enmType = kDisArmv8OpParmReg;
871 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
872 switch (pDis->armv8.enmFpType)
873 {
874 case kDisArmv8InstrFpType_Single: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_FpReg_Single; break;
875 case kDisArmv8InstrFpType_Double: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_FpReg_Double; break;
876 case kDisArmv8InstrFpType_Half: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_FpReg_Half; break;
877 default: return VERR_DIS_INVALID_OPCODE;
878 }
879 return VINF_SUCCESS;
880}
881
882
883static int disArmV8ParseFpScale(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
884{
885 RT_NOREF(pDis, pOp, pInsnClass);
886 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
887 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
888
889 pParam->armv8.enmType = kDisArmv8OpParmImm;
890 uint32_t u32Scale = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
891 if ( !*pf64Bit
892 && (u32Scale & RT_BIT_32(5)) == 0)
893 return VERR_DIS_INVALID_OPCODE;
894
895 pParam->uValue = 64 - u32Scale;
896 pParam->armv8.cb = sizeof(uint8_t);
897 pParam->fUse |= DISUSE_IMMEDIATE8;
898 return VINF_SUCCESS;
899}
900
901
902static int disArmV8ParseFpFixupFCvt(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
903{
904 RT_NOREF(pDis, pInsnClass, pParam, pInsnParm, pf64Bit);
905
906 /* Nothing to do if this isn't about fcvt. */
907 if (pOp->Opc.uOpcode != OP_ARMV8_A64_FCVT)
908 return VINF_SUCCESS;
909
910 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
911 Assert( pDis->aParams[0].armv8.enmType == kDisArmv8OpParmReg
912 && pDis->aParams[1].armv8.enmType == kDisArmv8OpParmReg);
913
914 /* Convert source and guest register floating point types to the correct widths. */
915 uint32_t u32Opc = (u32Insn & (RT_BIT_32(15) | RT_BIT_32(16))) >> 15;
916#ifdef VBOX_STRICT
917 uint32_t u32FpType = disArmV8ExtractBitVecFromInsn(u32Insn, 22, 2);
918 Assert( u32Opc != u32FpType
919 && u32Opc != 2);
920#endif
921
922 static const DISOPPARAMARMV8REGTYPE s_aOpc2FpWidth[] =
923 {
924 kDisOpParamArmV8RegType_FpReg_Single,
925 kDisOpParamArmV8RegType_FpReg_Double,
926 (DISOPPARAMARMV8REGTYPE)UINT8_MAX, /* Invalid encoding. */
927 kDisOpParamArmV8RegType_FpReg_Half
928 };
929
930 pDis->aParams[0].armv8.Op.Reg.enmRegType = s_aOpc2FpWidth[u32Opc];
931 return VINF_SUCCESS;
932}
933
934
935static int disArmV8ParseSimdRegSize(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
936{
937 RT_NOREF(pOp, pInsnClass, pParam, pf64Bit);
938
939 Assert(pInsnParm->cBits == 2);
940 uint32_t u32Size = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
941 switch (u32Size)
942 {
943 case 0: pDis->armv8.cbOperand = sizeof(uint8_t); break;
944 case 1: pDis->armv8.cbOperand = sizeof(uint16_t); break;
945 case 2: pDis->armv8.cbOperand = sizeof(uint32_t); break;
946 case 3: pDis->armv8.cbOperand = sizeof(uint64_t); break;
947 default:
948 AssertReleaseFailed();
949 }
950
951 return VINF_SUCCESS;
952}
953
954
955static int disArmV8ParseSimdRegSize32(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
956{
957 RT_NOREF(u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
958
959 pDis->armv8.cbOperand = sizeof(uint32_t);
960 return VINF_SUCCESS;
961}
962
963
964static int disArmV8ParseSimdRegSize64(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
965{
966 RT_NOREF(u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
967
968 pDis->armv8.cbOperand = sizeof(uint64_t);
969 return VINF_SUCCESS;
970}
971
972
973static int disArmV8ParseSimdRegSize128(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
974{
975 RT_NOREF(u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
976
977 pDis->armv8.cbOperand = 16;
978 return VINF_SUCCESS;
979}
980
981
982static int disArmV8ParseSimdRegScalar(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
983{
984 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
985
986 Assert(pDis->armv8.cbOperand != 0);
987 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
988
989 pParam->armv8.enmType = kDisArmv8OpParmReg;
990 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
991 switch (pDis->armv8.cbOperand)
992 {
993 case sizeof(uint8_t): pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Simd_Scalar_8Bit; break;
994 case sizeof(uint16_t): pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Simd_Scalar_16Bit; break;
995 case sizeof(uint32_t): pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Simd_Scalar_32Bit; break;
996 case sizeof(uint64_t): pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Simd_Scalar_64Bit; break;
997 case 16: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Simd_Scalar_128Bit; break;
998 }
999 return VINF_SUCCESS;
1000}
1001
1002
1003static int disArmV8ParseImmHImmB(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
1004{
1005 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
1006
1007 Assert(pInsnParm->cBits == 7);
1008 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
1009
1010 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
1011 if (!(u32ImmRaw & RT_BIT_32(6))) /* immh == 0xxx is reserved for the scalar variant. */
1012 return VERR_DIS_INVALID_OPCODE;
1013
1014 pParam->armv8.enmType = kDisArmv8OpParmImm;
1015 pParam->uValue = 2 * 64 - u32ImmRaw;
1016 pParam->armv8.cb = sizeof(uint8_t);
1017 pParam->fUse |= DISUSE_IMMEDIATE8;
1018 return VINF_SUCCESS;
1019}
1020
1021
1022static int disArmV8ParseSf(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
1023{
1024 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm);
1025
1026 Assert(pInsnParm->cBits == 1);
1027 Assert(pInsnParm->idxBitStart == 31 || pInsnParm->idxBitStart == 30);
1028 *pf64Bit = RT_BOOL(u32Insn & RT_BIT_32(pInsnParm->idxBitStart));
1029 return VINF_SUCCESS;
1030}
1031
1032
1033static int disArmV8ParseImmX16(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
1034{
1035 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
1036
1037 AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
1038 Assert(pParam->armv8.enmType == kDisArmv8OpParmNone);
1039
1040 pParam->armv8.enmType = kDisArmv8OpParmImm;
1041 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits) * 16;
1042 if (pParam->uValue <= UINT8_MAX)
1043 {
1044 pParam->armv8.cb = sizeof(uint8_t);
1045 pParam->fUse |= DISUSE_IMMEDIATE8;
1046 }
1047 else if (pParam->uValue <= UINT16_MAX)
1048 {
1049 pParam->armv8.cb = sizeof(uint16_t);
1050 pParam->fUse |= DISUSE_IMMEDIATE16;
1051 }
1052 else if (pParam->uValue <= UINT32_MAX)
1053 {
1054 pParam->armv8.cb = sizeof(uint32_t);
1055 pParam->fUse |= DISUSE_IMMEDIATE32;
1056 }
1057 else
1058 AssertReleaseFailed();
1059
1060 return VINF_SUCCESS;
1061}
1062
1063
1064static int disArmV8ParseSImmTags(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
1065{
1066 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
1067
1068 AssertReturn(pInsnParm->cBits <= 9, VERR_INTERNAL_ERROR_2);
1069 Assert(pParam->armv8.enmType != kDisArmv8OpParmNone);
1070
1071 pParam->armv8.cb = sizeof(int16_t);
1072 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits) << 4;
1073 return VINF_SUCCESS;
1074}
1075
1076
1077static int disArmV8ParseLdrPacImm(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
1078{
1079 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
1080
1081 Assert(pInsnParm->cBits == 0);
1082 Assert(pInsnParm->idxBitStart == 0);
1083 Assert(pParam->armv8.enmType != kDisArmv8OpParmNone);
1084
1085 uint32_t u32 = disArmV8ExtractBitVecFromInsn(u32Insn, 12, 9) | ((u32Insn & RT_BIT_32(22)) >> 13);
1086 pParam->armv8.cb = sizeof(int16_t);
1087 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsnSignExtend(u32, 0, 10) << 3;
1088 return VINF_SUCCESS;
1089}
1090
1091
1092static int disArmV8ParseLdrPacW(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
1093{
1094 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
1095
1096 Assert(pInsnParm->cBits == 1);
1097 Assert(pInsnParm->idxBitStart == 11);
1098 if (u32Insn & RT_BIT_32(11))
1099 pParam->fUse |= DISUSE_PRE_INDEXED;
1100 return VINF_SUCCESS;
1101}
1102
1103
1104static int disArmV8ParseVecRegElemSize(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
1105{
1106 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
1107
1108 Assert(pInsnParm->cBits == 2);
1109 Assert(pInsnParm->idxBitStart == 10);
1110 Assert(pDis->armv8.enmVecRegType == kDisOpParamArmV8VecRegType_None);
1111
1112 uint32_t u32 = disArmV8ExtractBitVecFromInsn(u32Insn, 10, 2);
1113 switch (u32)
1114 {
1115 case 0: pDis->armv8.enmVecRegType = kDisOpParamArmV8VecRegType_8B; break;
1116 case 1: pDis->armv8.enmVecRegType = kDisOpParamArmV8VecRegType_4H; break;
1117 case 2: pDis->armv8.enmVecRegType = kDisOpParamArmV8VecRegType_2S; break;
1118 case 3: pDis->armv8.enmVecRegType = kDisOpParamArmV8VecRegType_1D; break;
1119 default: AssertFailed(); break;
1120 }
1121
1122 return VINF_SUCCESS;
1123}
1124
1125
1126static int disArmV8ParseVecRegQ(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
1127{
1128 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
1129
1130 Assert(pInsnParm->cBits == 1);
1131 Assert(pInsnParm->idxBitStart == 30);
1132 Assert( pDis->armv8.enmVecRegType != kDisOpParamArmV8VecRegType_None
1133 && pDis->armv8.enmVecRegType < kDisOpParamArmV8VecRegType_2D);
1134 /* This ASSUMES that the vector register type for the 64-bit and 128-bit vector register lengths are adjacent. */
1135 if (u32Insn & RT_BIT_32(30))
1136 pDis->armv8.enmVecRegType = (DISOPPARAMARMV8VECREGTYPE)((uint8_t)pDis->armv8.enmVecRegType + 1);
1137 return VINF_SUCCESS;
1138}
1139
1140
1141static int disArmV8ParseVecGrp(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
1142{
1143 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
1144
1145 /* This is special as it doesn't really parse the instruction but sets the given parameter from vector to group vector and sets the register count based on the number if bits. */
1146 Assert(pInsnParm->cBits <= 4);
1147 Assert(pInsnParm->idxBitStart == 0);
1148 Assert(pParam->armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Simd_Vector);
1149 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Simd_Vector_Group;
1150 pParam->armv8.Op.Reg.cRegs = pInsnParm->cBits;
1151 return VINF_SUCCESS;
1152}
1153
1154
1155static uint32_t disArmV8DecodeIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
1156{
1157 RT_NOREF(pDis, u32Insn, pInsnClass);
1158 AssertFailed();
1159 return UINT32_MAX;
1160}
1161
1162
1163static uint32_t disArmV8DecodeLookup(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
1164{
1165 RT_NOREF(pDis);
1166
1167 for (uint32_t i = 0; i < pInsnClass->Hdr.cDecode; i++)
1168 {
1169 PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[i];
1170 if (u32Insn == pOp->fValue)
1171 return i;
1172 }
1173
1174 return UINT32_MAX;
1175}
1176
1177
1178static uint32_t disArmV8DecodeCollate(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
1179{
1180 RT_NOREF(pDis);
1181
1182 /* Need to build a compact representation of the relevant bits from the mask to create an index. */
1183 uint32_t fMask = pInsnClass->fMask >> pInsnClass->cShift;
1184
1185 /** @todo Optimize. */
1186 uint32_t idx = 0;
1187 uint32_t cShift = 0;
1188 while (fMask)
1189 {
1190 if (fMask & 0x1)
1191 {
1192 idx |= (u32Insn & 1) << cShift;
1193 cShift++;
1194 }
1195
1196 u32Insn >>= 1;
1197 fMask >>= 1;
1198 }
1199
1200 if (RT_LIKELY(idx < pInsnClass->Hdr.cDecode))
1201 return idx;
1202
1203 return UINT32_MAX;
1204}
1205
1206
1207/**
1208 * Looks for possible alias conversions for the given disassembler state.
1209 *
1210 * @param pDis The disassembler state to process.
1211 */
1212static void disArmV8A64InsnAliasesProcess(PDISSTATE pDis)
1213{
1214#define DIS_ARMV8_ALIAS(a_Name) s_DisArmv8Alias ## a_Name
1215#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)
1216#define DIS_ARMV8_ALIAS_REF(a_Name) &DIS_ARMV8_ALIAS(a_Name)
1217 switch (pDis->pCurInstr->uOpcode)
1218 {
1219 case OP_ARMV8_A64_ORR:
1220 {
1221 /* Check for possible MOV conversion for the register variant when: shift is None and the first source is the zero register. */
1222 Assert(pDis->aParams[1].armv8.enmType == kDisArmv8OpParmReg);
1223 Assert( pDis->aParams[1].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_32Bit
1224 || pDis->aParams[1].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_64Bit);
1225
1226 if ( pDis->aParams[2].armv8.enmType == kDisArmv8OpParmReg
1227 && pDis->aParams[2].armv8.enmExtend == kDisArmv8OpParmExtendNone
1228 && pDis->aParams[1].armv8.Op.Reg.idReg == ARMV8_A64_REG_XZR)
1229 {
1230 DIS_ARMV8_ALIAS_CREATE(Mov, "mov", OP_ARMV8_A64_MOV, DISOPTYPE_HARMLESS);
1231 pDis->pCurInstr = DIS_ARMV8_ALIAS_REF(Mov);
1232 pDis->aParams[1] = pDis->aParams[2];
1233 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
1234 }
1235 /** @todo Immediate variant. */
1236 break;
1237 }
1238 case OP_ARMV8_A64_SUBS:
1239 {
1240 Assert(pDis->aParams[0].armv8.enmType == kDisArmv8OpParmReg);
1241 Assert( pDis->aParams[0].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_32Bit
1242 || pDis->aParams[0].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_64Bit);
1243
1244 if (pDis->aParams[0].armv8.Op.Reg.idReg == ARMV8_A64_REG_XZR)
1245 {
1246 DIS_ARMV8_ALIAS_CREATE(Cmp, "cmp", OP_ARMV8_A64_CMP, DISOPTYPE_HARMLESS);
1247 pDis->pCurInstr = DIS_ARMV8_ALIAS_REF(Cmp);
1248 pDis->aParams[0] = pDis->aParams[1];
1249 pDis->aParams[1] = pDis->aParams[2];
1250 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
1251 }
1252 break;
1253 }
1254 default:
1255 break; /* No conversion */
1256 }
1257#undef DIS_ARMV8_ALIAS_REF
1258#undef DIS_ARMV8_ALIAS_CREATE
1259#undef DIS_ARMV8_ALIAS
1260}
1261
1262
1263static int disArmV8A64ParseInstruction(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass)
1264{
1265 AssertPtr(pOp);
1266 AssertPtr(pDis);
1267 //Assert((u32Insn & pInsnClass->fFixedInsn) == pOp->fValue);
1268 if ((u32Insn & pInsnClass->fFixedInsn) != pOp->fValue)
1269 return VERR_DIS_INVALID_OPCODE;
1270
1271 /* Should contain the parameter type on input. */
1272 pDis->aParams[0].fUse = 0;
1273 pDis->aParams[1].fUse = 0;
1274 pDis->aParams[2].fUse = 0;
1275 pDis->aParams[3].fUse = 0;
1276 pDis->aParams[0].armv8.enmType = kDisArmv8OpParmNone;
1277 pDis->aParams[1].armv8.enmType = kDisArmv8OpParmNone;
1278 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
1279 pDis->aParams[3].armv8.enmType = kDisArmv8OpParmNone;
1280 pDis->aParams[0].armv8.enmExtend = kDisArmv8OpParmExtendNone;
1281 pDis->aParams[1].armv8.enmExtend = kDisArmv8OpParmExtendNone;
1282 pDis->aParams[2].armv8.enmExtend = kDisArmv8OpParmExtendNone;
1283 pDis->aParams[3].armv8.enmExtend = kDisArmv8OpParmExtendNone;
1284 pDis->armv8.enmCond = kDisArmv8InstrCond_Al;
1285 pDis->armv8.enmFpType = kDisArmv8InstrFpType_Invalid;
1286 pDis->armv8.enmVecRegType = kDisOpParamArmV8VecRegType_None;
1287 pDis->armv8.cbOperand = 0;
1288
1289 pDis->pCurInstr = &pOp->Opc;
1290 Assert(&pOp->Opc != &g_ArmV8A64InvalidOpcode[0]);
1291
1292 bool f64Bit = true;
1293
1294 if (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_32BIT)
1295 f64Bit = false;
1296 else if (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_64BIT)
1297 f64Bit = true;
1298
1299 int rc = VINF_SUCCESS;
1300 PCDISARMV8INSNPARAM pDecode = &pInsnClass->paParms[0];
1301 if (pOp->paDecode)
1302 pDecode = &pOp->paDecode[0];
1303 while ( (pDecode->idxParse != kDisParmParseNop)
1304 && RT_SUCCESS(rc))
1305 {
1306 rc = g_apfnDisasm[pDecode->idxParse](pDis, u32Insn, pOp, pInsnClass,
1307 pDecode->idxParam != DIS_ARMV8_INSN_PARAM_UNSET
1308 ? &pDis->aParams[pDecode->idxParam]
1309 : NULL,
1310 pDecode, &f64Bit);
1311 pDecode++;
1312 }
1313
1314 /* If parameter parsing returned an invalid opcode error the encoding is invalid. */
1315 if (RT_SUCCESS(rc)) /** @todo Introduce flag to switch alias conversion on/off. */
1316 disArmV8A64InsnAliasesProcess(pDis);
1317 else if (rc == VERR_DIS_INVALID_OPCODE)
1318 {
1319 pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
1320
1321 pDis->aParams[0].armv8.enmType = kDisArmv8OpParmNone;
1322 pDis->aParams[1].armv8.enmType = kDisArmv8OpParmNone;
1323 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
1324 pDis->aParams[3].armv8.enmType = kDisArmv8OpParmNone;
1325 }
1326 pDis->rc = rc;
1327 return rc;
1328}
1329
1330
1331static int disArmV8A64ParseInvOpcode(PDISSTATE pDis)
1332{
1333 pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
1334 pDis->rc = VERR_DIS_INVALID_OPCODE;
1335 return VERR_DIS_INVALID_OPCODE;
1336}
1337
1338
1339static int disInstrArmV8DecodeWorker(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8DECODEHDR pHdr)
1340{
1341 while ( pHdr
1342 && pHdr->enmDecodeType != kDisArmV8DecodeType_InsnClass)
1343 {
1344 if (pHdr->enmDecodeType == kDisArmV8DecodeType_Map)
1345 {
1346 PCDISARMV8DECODEMAP pMap = (PCDISARMV8DECODEMAP)pHdr;
1347
1348 uint32_t idxNext = (u32Insn & pMap->fMask) >> pMap->cShift;
1349 if (RT_LIKELY(idxNext < pMap->Hdr.cDecode))
1350 pHdr = pMap->papNext[idxNext];
1351 else
1352 {
1353 pHdr = NULL;
1354 break;
1355 }
1356 }
1357 else
1358 {
1359 Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_Table);
1360 PCDISARMV8DECODETBL pTbl = (PCDISARMV8DECODETBL)pHdr;
1361
1362 /* Walk all entries in the table and select the best match. */
1363 pHdr = NULL;
1364 for (uint32_t i = 0; i < pTbl->Hdr.cDecode; i++)
1365 {
1366 PCDISARMV8DECODETBLENTRY pEntry = &pTbl->paEntries[i];
1367 if ((u32Insn & pEntry->fMask) == pEntry->fValue)
1368 {
1369 pHdr = pEntry->pHdrNext;
1370 break;
1371 }
1372 }
1373 }
1374 }
1375
1376 if (pHdr)
1377 {
1378 Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_InsnClass);
1379 PCDISARMV8INSNCLASS pInsnClass = (PCDISARMV8INSNCLASS)pHdr;
1380
1381 /* Decode the opcode from the instruction class. */
1382 uint32_t uOpcRaw = 0;
1383 if (pInsnClass->Hdr.cDecode > 1)
1384 {
1385 uOpcRaw = (u32Insn & pInsnClass->fMask) >> pInsnClass->cShift;
1386 if (pInsnClass->enmOpcDecode != kDisArmV8OpcDecodeNop)
1387 uOpcRaw = g_apfnOpcDecode[pInsnClass->enmOpcDecode](pDis, uOpcRaw, pInsnClass);
1388 }
1389
1390 if (uOpcRaw < pInsnClass->Hdr.cDecode)
1391 {
1392 PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[uOpcRaw];
1393 return disArmV8A64ParseInstruction(pDis, u32Insn, pOp, pInsnClass);
1394 }
1395 }
1396
1397 return disArmV8A64ParseInvOpcode(pDis);
1398}
1399
1400
1401/**
1402 * Internal worker for DISInstrEx and DISInstrWithPrefetchedBytes.
1403 *
1404 * @returns VBox status code.
1405 * @param pDis Initialized disassembler state.
1406 * @param paOneByteMap The one byte opcode map to use.
1407 * @param pcbInstr Where to store the instruction size. Can be NULL.
1408 */
1409DECLHIDDEN(int) disInstrWorkerArmV8(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
1410{
1411 RT_NOREF(paOneByteMap);
1412
1413 if (pDis->uCpuMode == DISCPUMODE_ARMV8_A64)
1414 {
1415 if (pcbInstr)
1416 *pcbInstr = sizeof(uint32_t);
1417
1418 /* Instructions are always little endian and 4 bytes. */
1419 uint32_t u32Insn = disReadDWord(pDis, 0 /*offInstr*/);
1420 if (RT_FAILURE(pDis->rc))
1421 return pDis->rc;
1422
1423 /** @todo r=bird: This is a waste of time if the host is little endian... */
1424 pDis->Instr.u32 = RT_LE2H_U32(u32Insn);
1425 pDis->cbInstr = sizeof(u32Insn);
1426
1427 return disInstrArmV8DecodeWorker(pDis, u32Insn, &g_aArmV8A64InsnDecodeL0.Hdr);
1428 }
1429
1430 AssertReleaseFailed();
1431 return VERR_NOT_IMPLEMENTED;
1432}
1433
1434
1435/**
1436 * Inlined worker that initializes the disassembler state.
1437 *
1438 * @returns The primary opcode map to use.
1439 * @param pDis The disassembler state.
1440 * @param uInstrAddr The instruction address.
1441 * @param enmCpuMode The CPU mode.
1442 * @param fFilter The instruction filter settings.
1443 * @param pfnReadBytes The byte reader, can be NULL.
1444 * @param pvUser The user data for the reader.
1445 */
1446DECLHIDDEN(PCDISOPCODE) disInitializeStateArmV8(PDISSTATE pDis, DISCPUMODE enmCpuMode, uint32_t fFilter)
1447{
1448 RT_NOREF(pDis, enmCpuMode, fFilter);
1449 return NULL;
1450}
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