VirtualBox

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

Last change on this file since 107464 was 107417, checked in by vboxsync, 13 days ago

Disassembler/DisasmCore-armv8.cpp: Explicitely cast the result to 64-bit before multiplying (overflow is impossible but silences parfait warning), bugref:3409

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