]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/ArmDisassemblerLib/ThumbDisassembler.c
More updated
[mirror_edk2.git] / ArmPkg / Library / ArmDisassemblerLib / ThumbDisassembler.c
CommitLineData
6f72e28d 1/** @file\r
b32fecd2 2 Thumb Dissassembler. Still a work in progress.\r
3\r
4 Wrong output is a bug, so please fix it. \r
5 Hex output means there is not yet an entry or a decode bug.\r
6 gOpThumb[] are Thumb 16-bit, and gOpThumb2[] work on the 32-bit \r
7 16-bit stream of Thumb2 instruction. Then there are big case \r
8 statements to print everything out. If you are adding instructions\r
9 try to reuse existing case entries if possible.\r
6f72e28d 10\r
11 Copyright (c) 2008-2010, Apple Inc. All rights reserved.\r
12 \r
13 All rights reserved. This program and the accompanying materials\r
14 are licensed and made available under the terms and conditions of the BSD License\r
15 which accompanies this distribution. The full text of the license may be found at\r
16 http://opensource.org/licenses/bsd-license.php\r
17\r
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
20\r
21**/\r
22\r
23#include <Base.h>\r
24#include <Library/BaseLib.h>\r
eeb78924 25#include <Library/DebugLib.h>\r
6f72e28d 26#include <Library/PrintLib.h>\r
27\r
7c34497d 28extern CHAR8 *gCondition[];\r
29\r
6f72e28d 30extern CHAR8 *gReg[];\r
31\r
b32fecd2 32// Thumb address modes\r
6f72e28d 33#define LOAD_STORE_FORMAT1 1\r
eeb78924 34#define LOAD_STORE_FORMAT1_H 101\r
35#define LOAD_STORE_FORMAT1_B 111 \r
6f72e28d 36#define LOAD_STORE_FORMAT2 2\r
37#define LOAD_STORE_FORMAT3 3\r
38#define LOAD_STORE_FORMAT4 4\r
39#define LOAD_STORE_MULTIPLE_FORMAT1 5 \r
7c34497d 40#define PUSH_FORMAT 6 \r
41#define POP_FORMAT 106 \r
6f72e28d 42#define IMMED_8 7\r
43#define CONDITIONAL_BRANCH 8\r
44#define UNCONDITIONAL_BRANCH 9\r
45#define UNCONDITIONAL_BRANCH_SHORT 109\r
46#define BRANCH_EXCHANGE 10\r
47#define DATA_FORMAT1 11\r
48#define DATA_FORMAT2 12\r
49#define DATA_FORMAT3 13\r
50#define DATA_FORMAT4 14\r
51#define DATA_FORMAT5 15\r
52#define DATA_FORMAT6_SP 16\r
53#define DATA_FORMAT6_PC 116\r
54#define DATA_FORMAT7 17\r
55#define DATA_FORMAT8 19\r
56#define CPS_FORMAT 20\r
57#define ENDIAN_FORMAT 21\r
b32fecd2 58#define DATA_CBZ 22\r
59#define ADR_FORMAT 23\r
60\r
61// Thumb2 address modes\r
7c34497d 62#define B_T3 200\r
63#define B_T4 201\r
64#define BL_T2 202\r
b32fecd2 65#define POP_T2 203\r
66#define POP_T3 204\r
67#define STM_FORMAT 205\r
68#define LDM_REG_IMM12_SIGNED 206\r
69#define LDM_REG_IMM12_LSL 207\r
70#define LDM_REG_IMM8 208\r
71#define LDM_REG_IMM12 209\r
72#define LDM_REG_INDIRECT_LSL 210\r
73#define LDM_REG_IMM8_SIGNED 211\r
74#define LDRD_REG_IMM8 212\r
75#define LDREXB 213\r
76#define LDREXD 214\r
77#define SRS_FORMAT 215\r
78#define RFE_FORMAT 216\r
79#define LDRD_REG_IMM8_SIGNED 217\r
eeb78924 80#define ADD_IMM12 218\r
81#define ADD_IMM5 219\r
82#define ADR_THUMB2 220\r
83#define CMN_THUMB2 221\r
c5c902da 84#define ASR_IMM5 222\r
85#define ASR_3REG 223\r
86#define BFC_THUMB2 224\r
87#define CDP_THUMB2 225\r
88#define THUMB2_NO_ARGS 226\r
89#define THUMB2_2REGS 227\r
90#define ADD_IMM5_2REG 228\r
91#define CPD_THUMB2 229\r
92#define THUMB2_4REGS 230\r
93\r
6f72e28d 94\r
95typedef struct {\r
96 CHAR8 *Start;\r
97 UINT32 OpCode;\r
98 UINT32 Mask;\r
99 UINT32 AddressMode;\r
100} THUMB_INSTRUCTIONS;\r
101\r
097bd461 102THUMB_INSTRUCTIONS gOpThumb[] = {\r
6f72e28d 103// Thumb 16-bit instrucitons\r
b32fecd2 104// Op Mask Format\r
6f72e28d 105 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5 },\r
b32fecd2 106 { "ADR", 0xa000, 0xf800, ADR_FORMAT }, // ADR <Rd>, <label>\r
6f72e28d 107 { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2 },\r
108 { "ADD" , 0x3000, 0xf800, DATA_FORMAT3 },\r
109 { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1 },\r
110 { "ADD" , 0x4400, 0xff00, DATA_FORMAT8 }, // A8.6.9\r
111 { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC },\r
7c34497d 112 { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP }, \r
113 { "ADD" , 0xb000, 0xff80, DATA_FORMAT7 },\r
6f72e28d 114\r
115 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5 },\r
116\r
117 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4 },\r
118 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5 },\r
119\r
120 { "B" , 0xd000, 0xf000, CONDITIONAL_BRANCH },\r
7c34497d 121 { "B" , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT },\r
6f72e28d 122 { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE },\r
7c34497d 123 { "BX" , 0x4700, 0xff87, BRANCH_EXCHANGE },\r
6f72e28d 124\r
125 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5 },\r
126 { "BKPT", 0xdf00, 0xff00, IMMED_8 },\r
b32fecd2 127 { "CBZ", 0xb100, 0xfd00, DATA_CBZ },\r
128 { "CBNZ", 0xb900, 0xfd00, DATA_CBZ },\r
6f72e28d 129 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5 },\r
130\r
7c34497d 131 { "CMP" , 0x2800, 0xf800, DATA_FORMAT3 },\r
6f72e28d 132 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5 },\r
133 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8 },\r
134\r
135 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT },\r
7c34497d 136 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },\r
6f72e28d 137 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5 },\r
138\r
139 { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },\r
140 { "LDR" , 0x6800, 0xf800, LOAD_STORE_FORMAT1 },\r
141 { "LDR" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },\r
142 { "LDR" , 0x4800, 0xf800, LOAD_STORE_FORMAT3 },\r
143 { "LDR" , 0x9800, 0xf800, LOAD_STORE_FORMAT4 },\r
eeb78924 144 { "LDRB" , 0x7800, 0xf800, LOAD_STORE_FORMAT1_B },\r
6f72e28d 145 { "LDRB" , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2 },\r
eeb78924 146 { "LDRH" , 0x8800, 0xf800, LOAD_STORE_FORMAT1_H },\r
6f72e28d 147 { "LDRH" , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2 },\r
148 { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2 },\r
149 { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2 },\r
150 \r
7c34497d 151 { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5 }, // LSL with imm5 == 0 is a MOVS, so this must go before LSL\r
6f72e28d 152 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4 },\r
153 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5 },\r
154 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4 },\r
155 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5 },\r
c5c902da 156 { "LSRS", 0x0800, 0xf800, DATA_FORMAT4 }, // LSRS <Rd>, <Rm>, #<imm5>\r
6f72e28d 157\r
7c34497d 158 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3 },\r
6f72e28d 159 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3 },\r
160 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },\r
161\r
162 { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5 },\r
163 { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5 },\r
164 { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5 },\r
165 { "ORR" , 0x4180, 0xffc0, DATA_FORMAT5 },\r
7c34497d 166 { "POP" , 0xbc00, 0xfe00, POP_FORMAT },\r
167 { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT },\r
168\r
6f72e28d 169 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5 },\r
170 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5 },\r
171 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5 },\r
172\r
7c34497d 173 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5 },\r
174 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5 },\r
175 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT },\r
6f72e28d 176\r
177 { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },\r
178 { "STR" , 0x6000, 0xf800, LOAD_STORE_FORMAT1 },\r
179 { "STR" , 0x5000, 0xfe00, LOAD_STORE_FORMAT2 },\r
180 { "STR" , 0x4000, 0xf800, LOAD_STORE_FORMAT3 },\r
181 { "STR" , 0x9000, 0xf800, LOAD_STORE_FORMAT4 },\r
eeb78924 182 { "STRB" , 0x7000, 0xf800, LOAD_STORE_FORMAT1_B },\r
6f72e28d 183 { "STRB" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },\r
eeb78924 184 { "STRH" , 0x8000, 0xf800, LOAD_STORE_FORMAT1_H },\r
6f72e28d 185 { "STRH" , 0x5200, 0xfe00, LOAD_STORE_FORMAT2 },\r
186\r
187 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2 },\r
188 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3 },\r
189 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1 },\r
190 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7 },\r
191\r
192 { "SWI" , 0xdf00, 0xff00, IMMED_8 },\r
193 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5 },\r
194 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5 },\r
195 { "TST" , 0x4200, 0xffc0, DATA_FORMAT5 },\r
196 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5 },\r
197 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5 }\r
b32fecd2 198\r
097bd461 199};\r
200\r
097bd461 201THUMB_INSTRUCTIONS gOpThumb2[] = {\r
b32fecd2 202//Instruct OpCode OpCode Mask Addressig Mode\r
eeb78924 203 \r
c5c902da 204 { "ADR", 0xf2af0000, 0xfbff8000, ADR_THUMB2 }, // ADDR <Rd>, <label> ;Needs to go before ADDW \r
205 { "CMN", 0xf1100f00, 0xfff08f00, CMN_THUMB2 }, // CMN <Rn>, #<const> ;Needs to go before ADD\r
206 { "CMN", 0xeb100f00, 0xfff08f00, ADD_IMM5_2REG }, // CMN <Rn>, <Rm> {,<shift> #<const>}\r
207 { "CMP", 0xf1a00f00, 0xfff08f00, CMN_THUMB2 }, // CMP <Rn>, #<const>\r
208 { "TEQ", 0xf0900f00, 0xfff08f00, CMN_THUMB2 }, // CMP <Rn>, #<const>\r
209 { "TEQ", 0xea900f00, 0xfff08f00, ADD_IMM5_2REG }, // CMN <Rn>, <Rm> {,<shift> #<const>}\r
210 { "TST", 0xf0100f00, 0xfff08f00, CMN_THUMB2 }, // CMP <Rn>, #<const>\r
211 { "TST", 0xea100f00, 0xfff08f00, ADD_IMM5_2REG }, // TST <Rn>, <Rm> {,<shift> #<const>}\r
eeb78924 212\r
213 { "ADC", 0xf1400000, 0xfbe08000, ADD_IMM12 }, // ADC{S} <Rd>, <Rn>, #<const>\r
214 { "ADC", 0xeb400000, 0xffe08000, ADD_IMM5 }, // ADC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
215 { "ADD", 0xf1000000, 0xfbe08000, ADD_IMM12 }, // ADD{S} <Rd>, <Rn>, #<const>\r
216 { "ADD", 0xeb000000, 0xffe08000, ADD_IMM5 }, // ADD{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
217 { "ADDW", 0xf2000000, 0xfbe08000, ADD_IMM12 }, // ADDW{S} <Rd>, <Rn>, #<const>\r
218 { "AND", 0xf0000000, 0xfbe08000, ADD_IMM12 }, // AND{S} <Rd>, <Rn>, #<const>\r
219 { "AND", 0xea000000, 0xffe08000, ADD_IMM5 }, // AND{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
220 { "BIC", 0xf0200000, 0xfbe08000, ADD_IMM12 }, // BIC{S} <Rd>, <Rn>, #<const>\r
221 { "BIC", 0xea200000, 0xffe08000, ADD_IMM5 }, // BIC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
222 { "EOR", 0xf0800000, 0xfbe08000, ADD_IMM12 }, // EOR{S} <Rd>, <Rn>, #<const>\r
223 { "EOR", 0xea800000, 0xffe08000, ADD_IMM5 }, // EOR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
224 { "ORN", 0xf0600000, 0xfbe08000, ADD_IMM12 }, // ORN{S} <Rd>, <Rn>, #<const>\r
225 { "ORN", 0xea600000, 0xffe08000, ADD_IMM5 }, // ORN{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
226 { "ORR", 0xf0400000, 0xfbe08000, ADD_IMM12 }, // ORR{S} <Rd>, <Rn>, #<const>\r
227 { "ORR", 0xea400000, 0xffe08000, ADD_IMM5 }, // ORR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
228 { "RSB", 0xf1c00000, 0xfbe08000, ADD_IMM12 }, // RSB{S} <Rd>, <Rn>, #<const>\r
229 { "RSB", 0xebc00000, 0xffe08000, ADD_IMM5 }, // RSB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
230 { "SBC", 0xf1600000, 0xfbe08000, ADD_IMM12 }, // SBC{S} <Rd>, <Rn>, #<const>\r
231 { "SBC", 0xeb600000, 0xffe08000, ADD_IMM5 }, // SBC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
232 { "SUB", 0xf1a00000, 0xfbe08000, ADD_IMM12 }, // SUB{S} <Rd>, <Rn>, #<const>\r
233 { "SUB", 0xeba00000, 0xffe08000, ADD_IMM5 }, // SUB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}\r
234\r
c5c902da 235 { "ASR", 0xea4f0020, 0xffef8030, ASR_IMM5 }, // ARS <Rd>, <Rm> #<const>} imm3:imm2\r
236 { "ASR", 0xfa40f000, 0xffe0f0f0, ASR_3REG }, // ARS <Rd>, <Rn>, <Rm> \r
237 { "LSR", 0xea4f0010, 0xffef8030, ASR_IMM5 }, // LSR <Rd>, <Rm> #<const>} imm3:imm2\r
238 { "LSR", 0xfa20f000, 0xffe0f0f0, ASR_3REG }, // LSR <Rd>, <Rn>, <Rm> \r
239 { "ROR", 0xea4f0030, 0xffef8030, ASR_IMM5 }, // ROR <Rd>, <Rm> #<const>} imm3:imm2\r
240 { "ROR", 0xfa60f000, 0xffe0f0f0, ASR_3REG }, // ROR <Rd>, <Rn>, <Rm> \r
241\r
242 { "BFC", 0xf36f0000, 0xffff8010, BFC_THUMB2 }, // BFC <Rd>, #<lsb>, #<width>\r
243 { "BIC", 0xf3600000, 0xfff08010, BFC_THUMB2 }, // BIC <Rn>, <Rd>, #<lsb>, #<width>\r
244 { "SBFX", 0xf3400000, 0xfff08010, BFC_THUMB2 }, // SBFX <Rn>, <Rd>, #<lsb>, #<width>\r
245 { "UBFX", 0xf3c00000, 0xfff08010, BFC_THUMB2 }, // UBFX <Rn>, <Rd>, #<lsb>, #<width>\r
246\r
247 { "CPD", 0xee000000, 0xff000010, CPD_THUMB2 }, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>\r
248 { "CPD2", 0xfe000000, 0xff000010, CPD_THUMB2 }, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>\r
249\r
250 { "CLREX", 0xf3bf8f2f, 0xfffffff, THUMB2_NO_ARGS }, // CLREX\r
251\r
252 { "CLZ", 0xfab0f080, 0xfff0f0f0, THUMB2_2REGS }, // CLZ <Rd>,<Rm>\r
253 { "MOV", 0xec4f0000, 0xfff0f0f0, THUMB2_2REGS }, // MOV <Rd>,<Rm>\r
254 { "MOVS", 0xec5f0000, 0xfff0f0f0, THUMB2_2REGS }, // MOVS <Rd>,<Rm>\r
255 { "RBIT", 0xfb90f0a0, 0xfff0f0f0, THUMB2_2REGS }, // RBIT <Rd>,<Rm>\r
256 { "REV", 0xfb90f080, 0xfff0f0f0, THUMB2_2REGS }, // REV <Rd>,<Rm>\r
257 { "REV16", 0xfa90f090, 0xfff0f0f0, THUMB2_2REGS }, // REV16 <Rd>,<Rm>\r
258 { "REVSH", 0xfa90f0b0, 0xfff0f0f0, THUMB2_2REGS }, // REVSH <Rd>,<Rm>\r
259 { "RRX", 0xea4f0030, 0xfffff0f0, THUMB2_2REGS }, // RRX <Rd>,<Rm>\r
260 { "RRXS", 0xea5f0030, 0xfffff0f0, THUMB2_2REGS }, // RRXS <Rd>,<Rm>\r
261\r
262 { "MLA", 0xfb000000, 0xfff000f0, THUMB2_4REGS }, // MLA <Rd>, <Rn>, <Rm>, <Ra>\r
263 { "MLS", 0xfb000010, 0xfff000f0, THUMB2_4REGS }, // MLA <Rd>, <Rn>, <Rm>, <Ra>\r
264\r
265\r
266 { "SMLABB", 0xfb100000, 0xfff000f0, THUMB2_4REGS }, // SMLABB <Rd>, <Rn>, <Rm>, <Ra>\r
267 { "SMLABT", 0xfb100010, 0xfff000f0, THUMB2_4REGS }, // SMLABT <Rd>, <Rn>, <Rm>, <Ra>\r
268 { "SMLABB", 0xfb100020, 0xfff000f0, THUMB2_4REGS }, // SMLATB <Rd>, <Rn>, <Rm>, <Ra>\r
269 { "SMLATT", 0xfb100030, 0xfff000f0, THUMB2_4REGS }, // SMLATT <Rd>, <Rn>, <Rm>, <Ra>\r
270 { "SMLAWB", 0xfb300000, 0xfff000f0, THUMB2_4REGS },// SMLAWB <Rd>, <Rn>, <Rm>, <Ra>\r
271 { "SMLAWT", 0xfb300010, 0xfff000f0, THUMB2_4REGS },// SMLAWT <Rd>, <Rn>, <Rm>, <Ra>\r
272 { "SMLSD", 0xfb400000, 0xfff000f0, THUMB2_4REGS },// SMLSD <Rd>, <Rn>, <Rm>, <Ra>\r
273 { "SMLSDX", 0xfb400010, 0xfff000f0, THUMB2_4REGS },// SMLSDX <Rd>, <Rn>, <Rm>, <Ra>\r
274 { "SMMLA", 0xfb500000, 0xfff000f0, THUMB2_4REGS },// SMMLA <Rd>, <Rn>, <Rm>, <Ra>\r
275 { "SMMLAR", 0xfb500010, 0xfff000f0, THUMB2_4REGS },// SMMLAR <Rd>, <Rn>, <Rm>, <Ra>\r
276 { "SMMLS", 0xfb600000, 0xfff000f0, THUMB2_4REGS },// SMMLS <Rd>, <Rn>, <Rm>, <Ra>\r
277 { "SMMLSR", 0xfb600010, 0xfff000f0, THUMB2_4REGS },// SMMLSR <Rd>, <Rn>, <Rm>, <Ra>\r
278 { "USADA8", 0xfb700000, 0xfff000f0, THUMB2_4REGS },// USADA8 <Rd>, <Rn>, <Rm>, <Ra>\r
279 { "SMLAD", 0xfb200000, 0xfff000f0, THUMB2_4REGS },// SMLAD <Rd>, <Rn>, <Rm>, <Ra>\r
280 { "SMLADX", 0xfb200010, 0xfff000f0, THUMB2_4REGS },// SMLADX <Rd>, <Rn>, <Rm>, <Ra>\r
281\r
282\r
b32fecd2 283 { "B", 0xf0008000, 0xf800d000, B_T3 }, // B<c> <label>\r
284 { "B", 0xf0009000, 0xf800d000, B_T4 }, // B<c> <label>\r
285 { "BL", 0xf000d000, 0xf800d000, B_T4 }, // BL<c> <label>\r
286 { "BLX", 0xf000c000, 0xf800d000, BL_T2 }, // BLX<c> <label>\r
287\r
288 { "POP", 0xe8bd0000, 0xffff2000, POP_T2 }, // POP <registers>\r
289 { "POP", 0xf85d0b04, 0xffff0fff, POP_T3 }, // POP <register>\r
290 { "PUSH", 0xe8ad0000, 0xffffa000, POP_T2 }, // PUSH <registers>\r
291 { "PUSH", 0xf84d0d04, 0xffff0fff, POP_T3 }, // PUSH <register>\r
292 { "STM" , 0xe8800000, 0xffd0a000, STM_FORMAT }, // STM <Rn>{!},<registers>\r
293 { "STMDB", 0xe9800000, 0xffd0a000, STM_FORMAT }, // STMDB <Rn>{!},<registers>\r
294 { "LDM" , 0xe8900000, 0xffd02000, STM_FORMAT }, // LDM <Rn>{!},<registers>\r
295 { "LDMDB", 0xe9100000, 0xffd02000, STM_FORMAT }, // LDMDB <Rn>{!},<registers>\r
6f72e28d 296 \r
b32fecd2 297 { "LDR", 0xf8d00000, 0xfff00000, LDM_REG_IMM12 }, // LDR <rt>, [<rn>, {, #<imm12>]}\r
298 { "LDRB", 0xf8900000, 0xfff00000, LDM_REG_IMM12 }, // LDRB <rt>, [<rn>, {, #<imm12>]}\r
299 { "LDRH", 0xf8b00000, 0xfff00000, LDM_REG_IMM12 }, // LDRH <rt>, [<rn>, {, #<imm12>]}\r
300 { "LDRSB", 0xf9900000, 0xfff00000, LDM_REG_IMM12 }, // LDRSB <rt>, [<rn>, {, #<imm12>]}\r
301 { "LDRSH", 0xf9b00000, 0xfff00000, LDM_REG_IMM12 }, // LDRSH <rt>, [<rn>, {, #<imm12>]}\r
302\r
303 { "LDR", 0xf85f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDR <Rt>, <label> \r
304 { "LDRB", 0xf81f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRB <Rt>, <label> \r
305 { "LDRH", 0xf83f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRH <Rt>, <label> \r
306 { "LDRSB", 0xf91f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRSB <Rt>, <label> \r
307 { "LDRSH", 0xf93f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRSB <Rt>, <label> \r
6f72e28d 308 \r
b32fecd2 309 { "LDR", 0xf8500000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDR <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
310 { "LDRB", 0xf8100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
311 { "LDRH", 0xf8300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
312 { "LDRSB", 0xf9100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
313 { "LDRSH", 0xf9300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
314\r
315 { "LDR", 0xf8500800, 0xfff00800, LDM_REG_IMM8 }, // LDR <rt>, [<rn>, {, #<imm8>]}\r
316 { "LDRBT", 0xf8100e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRBT <rt>, [<rn>, {, #<imm8>]}\r
317 { "LDRHT", 0xf8300e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRHT <rt>, [<rn>, {, #<imm8>]}\r
318 { "LDRSB", 0xf9900800, 0xfff00800, LDM_REG_IMM8 }, // LDRHT <rt>, [<rn>, {, #<imm8>]} {!} form? \r
319 { "LDRSBT",0xf9100e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRHBT <rt>, [<rn>, {, #<imm8>]} {!} form? \r
320 { "LDRSH" ,0xf9300800, 0xfff00800, LDM_REG_IMM8 }, // LDRSH <rt>, [<rn>, {, #<imm8>]} \r
321 { "LDRSHT",0xf9300e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRSHT <rt>, [<rn>, {, #<imm8>]} \r
322 { "LDRT", 0xf8500e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRT <rt>, [<rn>, {, #<imm8>]} \r
323\r
324 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}\r
325 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8 }, // LDRD <rt>, <rt2>, <label>\r
326 \r
327 { "LDREX", 0xe8500f00, 0xfff00f00, LDM_REG_IMM8 }, // LDREX <Rt>, [Rn, {#imm8}]] \r
328 { "LDREXB", 0xe8d00f4f, 0xfff00fff, LDREXB }, // LDREXB <Rt>, [<Rn>] \r
329 { "LDREXH", 0xe8d00f5f, 0xfff00fff, LDREXB }, // LDREXH <Rt>, [<Rn>] \r
330 \r
331 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // LDREXD <Rt>, <Rt2>, [<Rn>] \r
6f72e28d 332\r
b32fecd2 333 { "STR", 0xf8c00000, 0xfff00000, LDM_REG_IMM12 }, // STR <rt>, [<rn>, {, #<imm12>]} \r
334 { "STRB", 0xf8800000, 0xfff00000, LDM_REG_IMM12 }, // STRB <rt>, [<rn>, {, #<imm12>]}\r
335 { "STRH", 0xf8a00000, 0xfff00000, LDM_REG_IMM12 }, // STRH <rt>, [<rn>, {, #<imm12>]}\r
336 \r
337 { "STR", 0xf8400000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STR <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
338 { "STRB", 0xf8000000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
339 { "STRH", 0xf8200000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
6f72e28d 340\r
b32fecd2 341 { "STR", 0xf8400800, 0xfff00800, LDM_REG_IMM8 }, // STR <rt>, [<rn>, {, #<imm8>]}\r
342 { "STRH", 0xf8200800, 0xfff00800, LDM_REG_IMM8 }, // STRH <rt>, [<rn>, {, #<imm8>]}\r
343 { "STRBT", 0xf8000e00, 0xfff00f00, LDM_REG_IMM8 }, // STRBT <rt>, [<rn>, {, #<imm8>]}\r
344 { "STRHT", 0xf8200e00, 0xfff00f00, LDM_REG_IMM8 }, // STRHT <rt>, [<rn>, {, #<imm8>]}\r
345 { "STRT", 0xf8400e00, 0xfff00f00, LDM_REG_IMM8 }, // STRT <rt>, [<rn>, {, #<imm8>]} \r
6f72e28d 346\r
b32fecd2 347 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}\r
6f72e28d 348\r
b32fecd2 349 { "STREX", 0xe8400f00, 0xfff00f00, LDM_REG_IMM8 }, // STREX <Rt>, [Rn, {#imm8}]] \r
350 { "STREXB", 0xe8c00f4f, 0xfff00fff, LDREXB }, // STREXB <Rd>, <Rt>, [<Rn>] \r
351 { "STREXH", 0xe8c00f5f, 0xfff00fff, LDREXB }, // STREXH <Rd>, <Rt>, [<Rn>] \r
352 \r
353 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>] \r
6f72e28d 354\r
b32fecd2 355 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT }, // SRSDB<c> SP{!},#<mode>\r
356 { "SRS" , 0xe98dc000, 0xffdffff0, SRS_FORMAT }, // SRS{IA}<c> SP{!},#<mode>\r
357 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT }, // RFEDB<c> <Rn>{!}\r
358 { "RFE" , 0xe990c000, 0xffd0ffff, RFE_FORMAT } // RFE{IA}<c> <Rn>{!}\r
7c34497d 359};\r
6f72e28d 360\r
eeb78924 361CHAR8 *gShiftType[] = {\r
362 "LSL",\r
363 "LSR",\r
364 "ASR",\r
365 "ROR"\r
366};\r
367\r
6f72e28d 368CHAR8 mThumbMregListStr[4*15 + 1];\r
369\r
370CHAR8 *\r
371ThumbMRegList (\r
7c34497d 372 UINT32 RegBitMask\r
6f72e28d 373 )\r
374{\r
375 UINTN Index, Start, End;\r
376 CHAR8 *Str;\r
377 BOOLEAN First;\r
378 \r
379 Str = mThumbMregListStr;\r
380 *Str = '\0';\r
381 AsciiStrCat (Str, "{");\r
eeb78924 382 \r
7c34497d 383 for (Index = 0, First = TRUE; Index <= 15; Index++) {\r
384 if ((RegBitMask & (1 << Index)) != 0) {\r
6f72e28d 385 Start = End = Index;\r
7c34497d 386 for (Index++; ((RegBitMask & (1 << Index)) != 0) && (Index <= 9); Index++) {\r
6f72e28d 387 End = Index;\r
388 }\r
389 \r
390 if (!First) {\r
391 AsciiStrCat (Str, ",");\r
392 } else {\r
393 First = FALSE;\r
394 }\r
395 \r
396 if (Start == End) {\r
7c34497d 397 AsciiStrCat (Str, gReg[Start]);\r
6f72e28d 398 } else {\r
399 AsciiStrCat (Str, gReg[Start]);\r
400 AsciiStrCat (Str, "-");\r
7c34497d 401 AsciiStrCat (Str, gReg[End]);\r
6f72e28d 402 }\r
403 }\r
404 }\r
405 if (First) {\r
406 AsciiStrCat (Str, "ERROR");\r
407 }\r
408 AsciiStrCat (Str, "}");\r
409 \r
410 // BugBug: Make caller pass in buffer it is cleaner\r
411 return mThumbMregListStr;\r
412}\r
413\r
414UINT32\r
7c34497d 415SignExtend32 (\r
416 IN UINT32 Data,\r
417 IN UINT32 TopBit\r
6f72e28d 418 )\r
419{\r
7c34497d 420 if (((Data & TopBit) == 0) || (TopBit == BIT31)) {\r
421 return Data;\r
422 }\r
423 \r
424 do {\r
425 TopBit <<= 1;\r
426 Data |= TopBit; \r
427 } while ((TopBit & BIT31) != BIT31);\r
428\r
429 return Data;\r
6f72e28d 430}\r
431\r
eeb78924 432//\r
433// Some instructions specify the PC is always considered aligned \r
434// The PC is after the instruction that is excuting. So you pass\r
435// in the instruction address and you get back the aligned answer\r
436//\r
c639c2de 437UINT32\r
eeb78924 438PCAlign4 (\r
439 IN UINT32 Data\r
440 )\r
441{\r
442 return (Data + 4) & 0xfffffffc;\r
443}\r
444\r
6f72e28d 445/**\r
097bd461 446 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to \r
447 point to next instructin. \r
448 \r
449 We cheat and only decode instructions that access \r
6f72e28d 450 memory. If the instruction is not found we dump the instruction in hex.\r
451 \r
097bd461 452 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble. \r
453 @param Buf Buffer to sprintf disassembly into.\r
454 @param Size Size of Buf in bytes. \r
f9f937d2 455 @param Extended TRUE dump hex for instruction too.\r
6f72e28d 456 \r
457**/\r
458VOID\r
459DisassembleThumbInstruction (\r
097bd461 460 IN UINT16 **OpCodePtrPtr,\r
6f72e28d 461 OUT CHAR8 *Buf,\r
f9f937d2 462 OUT UINTN Size,\r
463 IN BOOLEAN Extended\r
6f72e28d 464 )\r
465{\r
097bd461 466 UINT16 *OpCodePtr;\r
467 UINT16 OpCode;\r
7c34497d 468 UINT32 OpCode32;\r
6f72e28d 469 UINT32 Index;\r
470 UINT32 Offset;\r
b32fecd2 471 UINT16 Rd, Rn, Rm, Rt, Rt2;\r
6f72e28d 472 BOOLEAN H1, H2, imod;\r
c5c902da 473 UINT32 PC, Target, msbit, lsbit;\r
7c34497d 474 CHAR8 *Cond;\r
b32fecd2 475 BOOLEAN S, J1, J2, P, U, W;\r
c5c902da 476 UINT32 coproc, opc1, opc2, CRd, CRn, CRm; \r
6f72e28d 477\r
097bd461 478 OpCodePtr = *OpCodePtrPtr;\r
479 OpCode = **OpCodePtrPtr;\r
480 \r
481 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.\r
7c34497d 482 OpCode32 = (((UINT32)OpCode) << 16) | *(OpCodePtr + 1);\r
097bd461 483\r
6f72e28d 484 // These register names match branch form, but not others\r
485 Rd = OpCode & 0x7;\r
486 Rn = (OpCode >> 3) & 0x7;\r
487 Rm = (OpCode >> 6) & 0x7;\r
488 H1 = (OpCode & BIT7) != 0;\r
489 H2 = (OpCode & BIT6) != 0;\r
490 imod = (OpCode & BIT4) != 0;\r
7c34497d 491 PC = (UINT32)(UINTN)OpCodePtr;\r
6f72e28d 492\r
097bd461 493 // Increment by the minimum instruction size, Thumb2 could be bigger\r
494 *OpCodePtrPtr += 1;\r
495 \r
496 for (Index = 0; Index < sizeof (gOpThumb)/sizeof (THUMB_INSTRUCTIONS); Index++) {\r
497 if ((OpCode & gOpThumb[Index].Mask) == gOpThumb[Index].OpCode) {\r
f9f937d2 498 if (Extended) {\r
7c34497d 499 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode, gOpThumb[Index].Start); \r
f9f937d2 500 } else {\r
7c34497d 501 Offset = AsciiSPrint (Buf, Size, "%-6a", gOpThumb[Index].Start); \r
f9f937d2 502 }\r
097bd461 503 switch (gOpThumb[Index].AddressMode) {\r
6f72e28d 504 case LOAD_STORE_FORMAT1:\r
505 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]\r
7c34497d 506 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 4) & 0x7c); \r
507 return;\r
eeb78924 508 case LOAD_STORE_FORMAT1_H:\r
509 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]\r
c5c902da 510 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 5) & 0x3e); \r
eeb78924 511 return;\r
512 case LOAD_STORE_FORMAT1_B:\r
513 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]\r
514 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 6) & 0x1f); \r
515 return;\r
516\r
6f72e28d 517 case LOAD_STORE_FORMAT2:\r
518 // A6.5.1 <Rd>, [<Rn>, <Rm>]\r
7c34497d 519 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d, r%d]", Rd, Rn, Rm); \r
520 return;\r
6f72e28d 521 case LOAD_STORE_FORMAT3:\r
522 // A6.5.1 <Rd>, [PC, #<8_bit_offset>]\r
7c34497d 523 Target = (OpCode & 0xff) << 2;\r
eeb78924 524 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [pc, #0x%x] ;0x%08x", (OpCode >> 8) & 7, Target, PCAlign4 (PC) + Target); \r
7c34497d 525 return;\r
6f72e28d 526 case LOAD_STORE_FORMAT4:\r
7c34497d 527 // Rt, [SP, #imm8]\r
528 Target = (OpCode & 0xff) << 2;\r
eeb78924 529 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [sp, #0x%x]", (OpCode >> 8) & 7, Target); \r
7c34497d 530 return;\r
6f72e28d 531 \r
532 case LOAD_STORE_MULTIPLE_FORMAT1:\r
7c34497d 533 // <Rn>!, {r0-r7}\r
534 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (OpCode & 0xff)); \r
535 return;\r
536 \r
537 case POP_FORMAT:\r
538 // POP {r0-r7,pc}\r
539 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT15 : 0))); \r
540 return;\r
541\r
542 case PUSH_FORMAT:\r
543 // PUSH {r0-r7,lr}\r
544 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT14 : 0))); \r
545 return;\r
546\r
6f72e28d 547 \r
548 case IMMED_8:\r
549 // A6.7 <immed_8>\r
550 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%x", OpCode & 0xff); \r
7c34497d 551 return;\r
6f72e28d 552\r
553 case CONDITIONAL_BRANCH:\r
554 // A6.3.1 B<cond> <target_address>\r
7c34497d 555 // Patch in the condition code. A little hack but based on "%-6a"\r
556 Cond = gCondition[(OpCode >> 8) & 0xf];\r
557 Buf[Offset-5] = *Cond++;\r
558 Buf[Offset-4] = *Cond;\r
559 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0xff) << 1, BIT8)); \r
560 return;\r
6f72e28d 561 case UNCONDITIONAL_BRANCH_SHORT:\r
562 // A6.3.2 B <target_address>\r
7c34497d 563 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0x3ff) << 1, BIT11)); \r
564 return;\r
565 \r
6f72e28d 566 case BRANCH_EXCHANGE:\r
567 // A6.3.3 BX|BLX <Rm>\r
7c34497d 568 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[Rn | (H2 ? 8:0)]); \r
569 return;\r
6f72e28d 570\r
571 case DATA_FORMAT1:\r
572 // A6.4.3 <Rd>, <Rn>, <Rm>\r
573 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, r%d", Rd, Rn, Rm); \r
7c34497d 574 return;\r
6f72e28d 575 case DATA_FORMAT2:\r
576 // A6.4.3 <Rd>, <Rn>, #3_bit_immed\r
577 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rd, Rn, Rm); \r
7c34497d 578 return;\r
6f72e28d 579 case DATA_FORMAT3:\r
7c34497d 580 // A6.4.3 <Rd>|<Rn>, #imm8\r
581 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, #0x%x", (OpCode >> 8) & 7, OpCode & 0xff); \r
582 return;\r
6f72e28d 583 case DATA_FORMAT4:\r
584 // A6.4.3 <Rd>|<Rm>, #immed_5\r
585 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rn, Rd, (OpCode >> 6) & 0x1f); \r
7c34497d 586 return;\r
6f72e28d 587 case DATA_FORMAT5:\r
588 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>\r
589 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d", Rd, Rn); \r
7c34497d 590 return;\r
6f72e28d 591 case DATA_FORMAT6_SP:\r
592 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>\r
7c34497d 593 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, sp, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2); \r
594 return;\r
6f72e28d 595 case DATA_FORMAT6_PC:\r
596 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>\r
7c34497d 597 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, pc, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2); \r
598 return;\r
6f72e28d 599 case DATA_FORMAT7:\r
600 // A6.4.3 SP, SP, #<7_Bit_immed>\r
7c34497d 601 AsciiSPrint (&Buf[Offset], Size - Offset, " sp, sp, 0x%x", (OpCode & 0x7f)*4); \r
602 return;\r
6f72e28d 603 case DATA_FORMAT8:\r
604 // A6.4.3 <Rd>|<Rn>, <Rm>\r
605 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd | (H1 ? 8:0)], gReg[Rn | (H2 ? 8:0)]); \r
7c34497d 606 return;\r
6f72e28d 607 \r
608 case CPS_FORMAT:\r
609 // A7.1.24\r
610 AsciiSPrint (&Buf[Offset], Size - Offset, "%a %a%a%a", imod ? "ID":"IE", ((OpCode & BIT2) == 0) ? "":"a", ((OpCode & BIT1) == 0) ? "":"i", ((OpCode & BIT0) == 0) ? "":"f"); \r
7c34497d 611 return;\r
6f72e28d 612\r
613 case ENDIAN_FORMAT:\r
614 // A7.1.24\r
615 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", (OpCode & BIT3) == 0 ? "LE":"BE"); \r
7c34497d 616 return;\r
b32fecd2 617\r
618 case DATA_CBZ:\r
619 // CB{N}Z <Rn>, <Lable>\r
620 Target = ((OpCode >> 2) & 0x3e) | (((OpCode & BIT9) == BIT9) ? BIT6 : 0);\r
621 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[Rd], PC + 4 + Target); \r
622 return;\r
623\r
624 case ADR_FORMAT:\r
625 // ADR <Rd>, <Label>\r
626 Target = (OpCode & 0xff) << 2;\r
eeb78924 627 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[(OpCode >> 8) & 7], PCAlign4 (PC) + Target); \r
b32fecd2 628 return;\r
6f72e28d 629 }\r
630 }\r
631 }\r
7c34497d 632\r
633 \r
097bd461 634 // Thumb2 are 32-bit instructions\r
635 *OpCodePtrPtr += 1;\r
b32fecd2 636 Rt = (OpCode32 >> 12) & 0xf;\r
637 Rt2 = (OpCode32 >> 8) & 0xf;\r
eeb78924 638 Rd = (OpCode32 >> 8) & 0xf;\r
b32fecd2 639 Rm = (OpCode32 & 0xf);\r
640 Rn = (OpCode32 >> 16) & 0xf;\r
097bd461 641 for (Index = 0; Index < sizeof (gOpThumb2)/sizeof (THUMB_INSTRUCTIONS); Index++) {\r
642 if ((OpCode32 & gOpThumb2[Index].Mask) == gOpThumb2[Index].OpCode) {\r
f9f937d2 643 if (Extended) {\r
c7ed09e3 644 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode32, gOpThumb2[Index].Start); \r
f9f937d2 645 } else {\r
c7ed09e3 646 Offset = AsciiSPrint (Buf, Size, " %-6a", gOpThumb2[Index].Start); \r
f9f937d2 647 }\r
648 switch (gOpThumb2[Index].AddressMode) {\r
7c34497d 649 case B_T3:\r
650 Cond = gCondition[(OpCode32 >> 22) & 0xf];\r
651 Buf[Offset-5] = *Cond++;\r
652 Buf[Offset-4] = *Cond;\r
653 // S:J2:J1:imm6:imm11:0\r
654 Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3f000);\r
c7ed09e3 655 Target |= ((OpCode32 & BIT11) == BIT11)? BIT19 : 0; // J2\r
656 Target |= ((OpCode32 & BIT13) == BIT13)? BIT18 : 0; // J1\r
657 Target |= ((OpCode32 & BIT26) == BIT26)? BIT20 : 0; // S\r
658 Target = SignExtend32 (Target, BIT20);\r
659 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target); \r
7c34497d 660 return;\r
661 case B_T4:\r
662 // S:I1:I2:imm10:imm11:0\r
663 Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3ff000);\r
c7ed09e3 664 S = (OpCode32 & BIT26) == BIT26;\r
665 J1 = (OpCode32 & BIT13) == BIT13;\r
666 J2 = (OpCode32 & BIT11) == BIT11;\r
667 Target |= (!(J2 ^ S) ? BIT22 : 0); // I2\r
668 Target |= (!(J1 ^ S) ? BIT23 : 0); // I1\r
669 Target |= (S ? BIT24 : 0); // S\r
670 Target = SignExtend32 (Target, BIT24);\r
671 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target); \r
7c34497d 672 return;\r
673\r
674 case BL_T2:\r
eeb78924 675 // BLX S:I1:I2:imm10:imm11:0\r
676 Target = ((OpCode32 << 1) & 0xffc) + ((OpCode32 >> 4) & 0x3ff000);\r
c7ed09e3 677 S = (OpCode32 & BIT26) == BIT26;\r
678 J1 = (OpCode32 & BIT13) == BIT13;\r
679 J2 = (OpCode32 & BIT11) == BIT11;\r
680 Target |= (!(J2 ^ S) ? BIT23 : 0); // I2\r
681 Target |= (!(J1 ^ S) ? BIT24 : 0); // I1\r
682 Target |= (S ? BIT25 : 0); // S\r
683 Target = SignExtend32 (Target, BIT25);\r
eeb78924 684 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PCAlign4 (PC) + Target); \r
7c34497d 685 return;\r
b32fecd2 686\r
687 case POP_T2:\r
688 // <reglist> some must be zero, handled in table\r
689 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList (OpCode32 & 0xffff));\r
690 return;\r
691\r
692 case POP_T3:\r
693 // <register> \r
694 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[(OpCode32 >> 12) & 0xf]);\r
695 return;\r
696\r
697 case STM_FORMAT:\r
698 // <Rn>{!}, <registers>\r
699 W = (OpCode32 & BIT21) == BIT21;\r
eeb78924 700 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, %a", gReg[(OpCode32 >> 16) & 0xf], W ? "!":"", ThumbMRegList (OpCode32 & 0xffff));\r
b32fecd2 701 return;\r
702\r
703 case LDM_REG_IMM12_SIGNED:\r
704 // <rt>, <label>\r
705 Target = OpCode32 & 0xfff; \r
706 if ((OpCode32 & BIT23) == 0) {\r
707 // U == 0 means subtrack, U == 1 means add\r
708 Target = -Target;\r
709 }\r
eeb78924 710 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[(OpCode32 >> 12) & 0xf], PCAlign4 (PC) + Target);\r
b32fecd2 711 return;\r
712\r
713 case LDM_REG_INDIRECT_LSL:\r
714 // <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
715 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a, %a", gReg[Rt], gReg[Rn], gReg[Rm]);\r
716 if (((OpCode32 >> 4) && 3) == 0) {\r
717 AsciiSPrint (&Buf[Offset], Size - Offset, "]");\r
718 } else {\r
719 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL #%d]", (OpCode32 >> 4) && 3);\r
720 }\r
721 return;\r
722 \r
723 case LDM_REG_IMM12:\r
724 // <rt>, [<rn>, {, #<imm12>]}\r
725 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);\r
726 if ((OpCode32 && 0xfff) == 0) {\r
727 AsciiSPrint (&Buf[Offset], Size - Offset, "]");\r
728 } else {\r
729 AsciiSPrint (&Buf[Offset], Size - Offset, ", #0x%x]", OpCode32 & 0xfff);\r
730 }\r
731 return;\r
732\r
733 case LDM_REG_IMM8:\r
eeb78924 734 ASSERT (FALSE);\r
b32fecd2 735 // <rt>, [<rn>, {, #<imm8>}]{!}\r
736 W = (OpCode32 & BIT8) == BIT8;\r
737 U = (OpCode32 & BIT9) == BIT9;\r
738 P = (OpCode32 & BIT10) == BIT10;\r
739 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);\r
740 if (P) {\r
741 if ((OpCode32 && 0xff) == 0) {\r
742 AsciiSPrint (&Buf[Offset], Size - Offset, "]%a", W?"!":"");\r
743 } else {\r
eeb78924 744 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", OpCode32 & 0xff, U?"":"-" , W?"!":"");\r
b32fecd2 745 }\r
746 } else {\r
eeb78924 747 AsciiSPrint (&Buf[Offset], Size - Offset, "], #%a0x%x]", OpCode32 & 0xff, U?"":"-");\r
b32fecd2 748 }\r
749 return;\r
750\r
751 case LDRD_REG_IMM8_SIGNED:\r
752 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}\r
753 P = (OpCode32 & BIT24) == BIT24; // index = P\r
754 U = (OpCode32 & BIT23) == BIT23; \r
755 W = (OpCode32 & BIT21) == BIT21;\r
756 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, [%a", gReg[Rt], gReg[Rt2], gReg[Rn]);\r
757 if (P) {\r
758 if ((OpCode32 && 0xff) == 0) {\r
759 AsciiSPrint (&Buf[Offset], Size - Offset, "]");\r
760 } else {\r
761 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-", (OpCode32 & 0xff) << 2, W?"!":"");\r
762 }\r
763 } else {\r
764 if ((OpCode32 && 0xff) != 0) {\r
765 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x", U?"":"-", (OpCode32 & 0xff) << 2);\r
766 }\r
767 }\r
768 return;\r
769\r
770 case LDRD_REG_IMM8: \r
771 // LDRD <rt>, <rt2>, <label> \r
772 Target = (OpCode32 & 0xff) << 2; \r
773 if ((OpCode32 & BIT23) == 0) {\r
774 // U == 0 means subtrack, U == 1 means add\r
775 Target = -Target;\r
776 }\r
777 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rt], gReg[Rt2], PC + 4 + Target);\r
778 return;\r
779\r
780 case LDREXB:\r
781 // LDREXB <Rt>, [Rn]\r
782 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a]", gReg[Rt], gReg[Rn]);\r
783 return;\r
784\r
785 case LDREXD:\r
786 // LDREXD <Rt>, <Rt2>, [<Rn>]\r
787 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, [%a]", gReg[Rt], gReg[Rt2], gReg[Rn]);\r
788 return;\r
789 \r
790 case SRS_FORMAT:\r
791 // SP{!}, #<mode>\r
792 W = (OpCode32 & BIT21) == BIT21;\r
793 AsciiSPrint (&Buf[Offset], Size - Offset, " SP%a, #0x%x", W?"!":"", OpCode32 & 0x1f);\r
794 return;\r
795\r
796 case RFE_FORMAT:\r
797 // <Rn>{!}\r
c639c2de 798 W = (OpCode32 & BIT21) == BIT21;\r
b32fecd2 799 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, #0x%x", gReg[Rn], W?"!":"");\r
800 return;\r
eeb78924 801 \r
802 case ADD_IMM12:\r
803 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8\r
804 if ((OpCode32 & BIT20) == BIT20) {\r
805 Buf[Offset - 3] = 'S'; // assume %-6a\r
806 }\r
807 Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);\r
c5c902da 808 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #0x%x", gReg[Rd], gReg[Rn], Target); \r
eeb78924 809 return;\r
810\r
811 case ADD_IMM5:\r
c5c902da 812 // ADC{S} <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2\r
eeb78924 813 if ((OpCode32 & BIT20) == BIT20) {\r
814 Buf[Offset - 3] = 'S'; // assume %-6a\r
815 }\r
816 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);\r
c5c902da 817 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm]); \r
eeb78924 818 if (Target != 0) {\r
819 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target); \r
820 }\r
821 return;\r
822\r
c5c902da 823 case ADD_IMM5_2REG:\r
824 // CMP <Rn>, <Rm> {,LSL #<const>} imm3:imm2\r
825 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);\r
826 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rn], gReg[Rm]); \r
827 if (Target != 0) {\r
828 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target); \r
829 }\r
830\r
831\r
832 case ASR_IMM5:\r
833 // ARS <Rd>, <Rm> #<const>} imm3:imm2\r
834 if ((OpCode32 & BIT20) == BIT20) {\r
835 Buf[Offset - 3] = 'S'; // assume %-6a\r
836 }\r
837 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);\r
838 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a #%d", gReg[Rd], gReg[Rm], Target); \r
839 return;\r
840\r
841 case ASR_3REG:\r
842 // ARS <Rd>, <Rn>, <Rm>\r
843 if ((OpCode32 & BIT20) == BIT20) {\r
844 Buf[Offset - 3] = 'S'; // assume %-6a\r
845 }\r
846 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a %a", gReg[Rd], gReg[Rn], gReg[Rm]); \r
847 return;\r
848\r
eeb78924 849 case ADR_THUMB2:\r
850 // ADDR <Rd>, <label>\r
851 Target = (OpCode32 & 0xff) | ((OpCode32 >> 8) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);\r
852 if ((OpCode & (BIT23 | BIT21)) == (BIT23 | BIT21)) {\r
853 Target = PCAlign4 (PC) - Target;\r
854 } else {\r
855 Target = PCAlign4 (PC) + Target;\r
856 }\r
857 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, 0x%08x", gReg[Rd], Target); \r
858 return;\r
b32fecd2 859\r
eeb78924 860 case CMN_THUMB2:\r
c5c902da 861 // CMN <Rn>, #<const>}\r
862 Target = (OpCode32 & 0xff) | ((OpCode >> 4) && 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);\r
863 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rn], Target); \r
864 return;\r
865\r
866 case BFC_THUMB2:\r
867 // BFI <Rd>, <Rn>, #<lsb>, #<width>\r
868 msbit = OpCode32 & 0x1f;\r
869 lsbit = ((OpCode32 >> 6) & 3) | ((OpCode >> 10) & 0x1c);\r
870 if ((Rn == 0xf) & (AsciiStrCmp (gOpThumb2[Index].Start, "BFC") == 0)){\r
871 // BFC <Rd>, #<lsb>, #<width>\r
872 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #%d, #%d", gReg[Rd], lsbit, msbit - lsbit + 1); \r
873 } else if (AsciiStrCmp (gOpThumb2[Index].Start, "BFI") == 0) {\r
874 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], lsbit, msbit - lsbit + 1); \r
875 } else {\r
876 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], lsbit, msbit + 1); \r
eeb78924 877 }\r
c5c902da 878 return;\r
879\r
880 case CPD_THUMB2:\r
881 // <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>\r
882 coproc = (OpCode32 >> 8) & 0xf;\r
883 opc1 = (OpCode32 >> 20) & 0xf;\r
884 opc2 = (OpCode32 >> 5) & 0x7;\r
885 CRd = (OpCode32 >> 12) & 0xf;\r
886 CRn = (OpCode32 >> 16) & 0xf;\r
887 CRm = OpCode32 & 0xf;\r
888 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,c%d,c%d,c%d", coproc, opc1, CRd, CRn, CRm);\r
889 if (opc2 != 0) {\r
890 AsciiSPrint (&Buf[Offset], Size - Offset, ",#%d,", opc2);\r
eeb78924 891 }\r
892 return;\r
c5c902da 893\r
894 case THUMB2_2REGS:\r
895 // <Rd>, <Rm>\r
896 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd], gReg[Rm]);\r
897 return;\r
898\r
899 case THUMB2_4REGS:\r
900 // <Rd>, <Rn>, <Rm>, <Ra>\r
901 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm], gReg[Rt]);\r
902 return;\r
903\r
904 case THUMB2_NO_ARGS:\r
905 default:\r
906 break;\r
f9f937d2 907 }\r
097bd461 908 }\r
909 }\r
7c34497d 910\r
911 AsciiSPrint (Buf, Size, "0x%08x", OpCode32);\r
6f72e28d 912}\r
913\r
097bd461 914\r
915\r
916VOID\r
917DisassembleArmInstruction (\r
918 IN UINT32 **OpCodePtr,\r
919 OUT CHAR8 *Buf,\r
f9f937d2 920 OUT UINTN Size,\r
921 IN BOOLEAN Extended\r
097bd461 922 );\r
923\r
924\r
925/**\r
926 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to \r
927 point to next instructin. \r
928 \r
929 We cheat and only decode instructions that access \r
930 memory. If the instruction is not found we dump the instruction in hex.\r
931 \r
932 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble. \r
933 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream\r
f9f937d2 934 @param Extended TRUE dump hex for instruction too.\r
097bd461 935 @param Buf Buffer to sprintf disassembly into.\r
936 @param Size Size of Buf in bytes. \r
937 \r
938**/\r
939VOID\r
940DisassembleInstruction (\r
941 IN UINT8 **OpCodePtr,\r
942 IN BOOLEAN Thumb,\r
f9f937d2 943 IN BOOLEAN Extended,\r
097bd461 944 OUT CHAR8 *Buf,\r
945 OUT UINTN Size\r
946 )\r
947{\r
948 if (Thumb) {\r
f9f937d2 949 DisassembleThumbInstruction ((UINT16 **)OpCodePtr, Buf, Size, Extended);\r
097bd461 950 } else {\r
f9f937d2 951 DisassembleArmInstruction ((UINT32 **)OpCodePtr, Buf, Size, Extended);\r
097bd461 952 }\r
953}\r
6f72e28d 954 \r