VirtualBox

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

Last change on this file since 106999 was 106817, checked in by vboxsync, 3 months ago

Disassembler: Decode SIMD load/store multiple structures (post-indexed) instructions immediate, bugref:10394

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