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