VirtualBox

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

Last change on this file since 106752 was 106751, checked in by vboxsync, 3 months ago

Disassembler: Decode SIMD ldr/str (register offset) instructions, bugref:10394

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