VirtualBox

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

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

Disassembler: pcbInstr is optional, bugref:10394

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