VirtualBox

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

Last change on this file since 106626 was 106626, checked in by vboxsync, 7 months ago

Disassembler: Re-arrange the ARMv8 tables to allow for multiple decoders for a single instruction class in case instructions in the same class require different decoding, implement decoding of 2-source instructions, bugref:10394

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette