499d592d1e2c95b6973cfa21465ac51a399c4975
[openocd.git] / src / target / armv7a.c
1 /***************************************************************************
2 * Copyright (C) 2009 by David Brownell *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "replacements.h"
24
25 #include "armv7a.h"
26 #include "arm_disassembler.h"
27
28 #include "target.h"
29 #include "register.h"
30 #include "log.h"
31 #include "binarybuffer.h"
32 #include "command.h"
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 bitfield_desc_t armv7a_psr_bitfield_desc[] =
39 {
40 {"M[4:0]", 5},
41 {"T", 1},
42 {"F", 1},
43 {"I", 1},
44 {"A", 1},
45 {"E", 1},
46 {"IT[7:2]", 6},
47 {"GE[3:0]", 4},
48 {"reserved(DNM)", 4},
49 {"J", 1},
50 {"IT[0:1]", 2},
51 {"Q", 1},
52 {"V", 1},
53 {"C", 1},
54 {"Z", 1},
55 {"N", 1},
56 };
57
58 char* armv7a_core_reg_list[] =
59 {
60 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
61 "r8", "r9", "r10", "r11", "r12", "r13_usr", "lr_usr", "pc",
62 "r8_fiq", "r9_fiq", "r10_fiq", "r11_fiq", "r12_fiq", "r13_fiq", "lr_fiq",
63 "r13_irq", "lr_irq",
64 "r13_svc", "lr_svc",
65 "r13_abt", "lr_abt",
66 "r13_und", "lr_und",
67 "cpsr", "spsr_fiq", "spsr_irq", "spsr_svc", "spsr_abt", "spsr_und",
68 "r13_mon", "lr_mon", "spsr_mon"
69 };
70
71 char * armv7a_mode_strings_list[] =
72 {
73 "Illegal mode value", "User", "FIQ", "IRQ",
74 "Supervisor", "Abort", "Undefined", "System", "Monitor"
75 };
76
77 /* Hack! Yuk! allow -1 index, which simplifies codepaths elsewhere in the code */
78 char** armv7a_mode_strings = armv7a_mode_strings_list+1;
79
80 char* armv7a_state_strings[] =
81 {
82 "ARM", "Thumb", "Jazelle", "ThumbEE"
83 };
84
85 armv7a_core_reg_t armv7a_core_reg_list_arch_info[] =
86 {
87 {0, ARMV4_5_MODE_ANY, NULL, NULL},
88 {1, ARMV4_5_MODE_ANY, NULL, NULL},
89 {2, ARMV4_5_MODE_ANY, NULL, NULL},
90 {3, ARMV4_5_MODE_ANY, NULL, NULL},
91 {4, ARMV4_5_MODE_ANY, NULL, NULL},
92 {5, ARMV4_5_MODE_ANY, NULL, NULL},
93 {6, ARMV4_5_MODE_ANY, NULL, NULL},
94 {7, ARMV4_5_MODE_ANY, NULL, NULL},
95 {8, ARMV4_5_MODE_ANY, NULL, NULL},
96 {9, ARMV4_5_MODE_ANY, NULL, NULL},
97 {10, ARMV4_5_MODE_ANY, NULL, NULL},
98 {11, ARMV4_5_MODE_ANY, NULL, NULL},
99 {12, ARMV4_5_MODE_ANY, NULL, NULL},
100 {13, ARMV4_5_MODE_USR, NULL, NULL},
101 {14, ARMV4_5_MODE_USR, NULL, NULL},
102 {15, ARMV4_5_MODE_ANY, NULL, NULL},
103
104 {8, ARMV4_5_MODE_FIQ, NULL, NULL},
105 {9, ARMV4_5_MODE_FIQ, NULL, NULL},
106 {10, ARMV4_5_MODE_FIQ, NULL, NULL},
107 {11, ARMV4_5_MODE_FIQ, NULL, NULL},
108 {12, ARMV4_5_MODE_FIQ, NULL, NULL},
109 {13, ARMV4_5_MODE_FIQ, NULL, NULL},
110 {14, ARMV4_5_MODE_FIQ, NULL, NULL},
111
112 {13, ARMV4_5_MODE_IRQ, NULL, NULL},
113 {14, ARMV4_5_MODE_IRQ, NULL, NULL},
114
115 {13, ARMV4_5_MODE_SVC, NULL, NULL},
116 {14, ARMV4_5_MODE_SVC, NULL, NULL},
117
118 {13, ARMV4_5_MODE_ABT, NULL, NULL},
119 {14, ARMV4_5_MODE_ABT, NULL, NULL},
120
121 {13, ARMV4_5_MODE_UND, NULL, NULL},
122 {14, ARMV4_5_MODE_UND, NULL, NULL},
123
124 {16, ARMV4_5_MODE_ANY, NULL, NULL},
125 {16, ARMV4_5_MODE_FIQ, NULL, NULL},
126 {16, ARMV4_5_MODE_IRQ, NULL, NULL},
127 {16, ARMV4_5_MODE_SVC, NULL, NULL},
128 {16, ARMV4_5_MODE_ABT, NULL, NULL},
129 {16, ARMV4_5_MODE_UND, NULL, NULL},
130
131 {13, ARMV7A_MODE_MON, NULL, NULL},
132 {14, ARMV7A_MODE_MON, NULL, NULL},
133 {16, ARMV7A_MODE_MON, NULL, NULL}
134 };
135
136 /* map core mode (USR, FIQ, ...) and register number to indizes into the register cache */
137 int armv7a_core_reg_map[8][17] =
138 {
139 { /* USR */
140 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31
141 },
142 { /* FIQ */
143 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 15, 32
144 },
145 { /* IRQ */
146 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 23, 24, 15, 33
147 },
148 { /* SVC */
149 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 26, 15, 34
150 },
151 { /* ABT */
152 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 27, 28, 15, 35
153 },
154 { /* UND */
155 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 29, 30, 15, 36
156 },
157 { /* SYS */
158 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31
159 },
160 { /* MON */
161 /* TODO Fix the register mapping for mon, we need r13_mon,
162 * r14_mon and spsr_mon
163 */
164 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31
165 }
166 };
167
168 uint8_t armv7a_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
169
170 reg_t armv7a_gdb_dummy_fp_reg =
171 {
172 "GDB dummy floating-point register", armv7a_gdb_dummy_fp_value,
173 0, 1, 96, NULL, 0, NULL, 0
174 };
175
176 void armv7a_show_fault_registers(target_t *target)
177 {
178 uint32_t dfsr, ifsr, dfar, ifar;
179
180 /* get pointers to arch-specific information */
181 armv4_5_common_t *armv4_5 = target->arch_info;
182 armv7a_common_t *armv7a = armv4_5->arch_info;
183
184 armv7a->read_cp15(target, 0, 0, 5, 0, &dfsr);
185 armv7a->read_cp15(target, 0, 1, 5, 0, &ifsr);
186 armv7a->read_cp15(target, 0, 0, 6, 0, &dfar);
187 armv7a->read_cp15(target, 0, 2, 6, 0, &ifar);
188
189 LOG_USER("Data fault registers DFSR: %8.8" PRIx32
190 ", DFAR: %8.8" PRIx32, dfsr, dfar);
191 LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32
192 ", IFAR: %8.8" PRIx32, ifsr, ifar);
193
194 }
195
196 int armv7a_arch_state(struct target_s *target)
197 {
198 static const char *state[] =
199 {
200 "disabled", "enabled"
201 };
202
203 armv4_5_common_t *armv4_5 = target->arch_info;
204 armv7a_common_t *armv7a = armv4_5->arch_info;
205
206 if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
207 {
208 LOG_ERROR("BUG: called for a non-ARMv4/5 target");
209 exit(-1);
210 }
211
212 LOG_USER("target halted in %s state due to %s, current mode: %s\n"
213 "%s: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "\n"
214 "MMU: %s, D-Cache: %s, I-Cache: %s",
215 armv7a_state_strings[armv7a->core_state],
216 Jim_Nvp_value2name_simple(nvp_target_debug_reason,
217 target->debug_reason)->name,
218 armv7a_mode_strings[
219 armv7a_mode_to_number(armv4_5->core_mode)],
220 armv7a_core_reg_list[armv7a_core_reg_map[
221 armv7a_mode_to_number(armv4_5->core_mode)][16]],
222 buf_get_u32(ARMV7A_CORE_REG_MODE(armv4_5->core_cache,
223 armv4_5->core_mode, 16).value, 0, 32),
224 buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
225 state[armv7a->armv4_5_mmu.mmu_enabled],
226 state[armv7a->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled],
227 state[armv7a->armv4_5_mmu.armv4_5_cache.i_cache_enabled]);
228
229 if (armv4_5->core_mode == ARMV7A_MODE_ABT)
230 armv7a_show_fault_registers(target);
231
232 return ERROR_OK;
233 }
234
235
236 static int handle_dap_baseaddr_command(struct command_context_s *cmd_ctx,
237 char *cmd, char **args, int argc)
238 {
239 target_t *target = get_current_target(cmd_ctx);
240 armv4_5_common_t *armv4_5 = target->arch_info;
241 armv7a_common_t *armv7a = armv4_5->arch_info;
242 swjdp_common_t *swjdp = &armv7a->swjdp_info;
243
244 return dap_baseaddr_command(cmd_ctx, swjdp, args, argc);
245 }
246
247 static int handle_dap_memaccess_command(struct command_context_s *cmd_ctx,
248 char *cmd, char **args, int argc)
249 {
250 target_t *target = get_current_target(cmd_ctx);
251 armv4_5_common_t *armv4_5 = target->arch_info;
252 armv7a_common_t *armv7a = armv4_5->arch_info;
253 swjdp_common_t *swjdp = &armv7a->swjdp_info;
254
255 return dap_memaccess_command(cmd_ctx, swjdp, args, argc);
256 }
257
258 static int handle_dap_apsel_command(struct command_context_s *cmd_ctx,
259 char *cmd, char **args, int argc)
260 {
261 target_t *target = get_current_target(cmd_ctx);
262 armv4_5_common_t *armv4_5 = target->arch_info;
263 armv7a_common_t *armv7a = armv4_5->arch_info;
264 swjdp_common_t *swjdp = &armv7a->swjdp_info;
265
266 return dap_apsel_command(cmd_ctx, swjdp, args, argc);
267 }
268
269 static int handle_dap_apid_command(struct command_context_s *cmd_ctx,
270 char *cmd, char **args, int argc)
271 {
272 target_t *target = get_current_target(cmd_ctx);
273 armv4_5_common_t *armv4_5 = target->arch_info;
274 armv7a_common_t *armv7a = armv4_5->arch_info;
275 swjdp_common_t *swjdp = &armv7a->swjdp_info;
276
277 return dap_apid_command(cmd_ctx, swjdp, args, argc);
278 }
279
280 static int handle_dap_info_command(struct command_context_s *cmd_ctx,
281 char *cmd, char **args, int argc)
282 {
283 target_t *target = get_current_target(cmd_ctx);
284 armv4_5_common_t *armv4_5 = target->arch_info;
285 armv7a_common_t *armv7a = armv4_5->arch_info;
286 swjdp_common_t *swjdp = &armv7a->swjdp_info;
287 uint32_t apsel;
288
289 apsel = swjdp->apsel;
290 if (argc > 0)
291 apsel = strtoul(args[0], NULL, 0);
292
293 return dap_info_command(cmd_ctx, swjdp, apsel);
294 }
295
296 static int
297 handle_armv7a_disassemble_command(struct command_context_s *cmd_ctx,
298 char *cmd, char **args, int argc)
299 {
300 target_t *target = get_current_target(cmd_ctx);
301 armv4_5_common_t *armv4_5 = target->arch_info;
302 int thumb = 0;
303 int count = 1;
304 uint32_t address;
305 int i;
306
307 if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) {
308 command_print(cmd_ctx, "current target isn't an ARM target");
309 return ERROR_OK;
310 }
311
312 /* REVISIT: eventually support ThumbEE disassembly too;
313 * some opcodes work differently.
314 */
315
316 switch (argc) {
317 case 3:
318 if (strcmp(args[2], "thumb") != 0)
319 goto usage;
320 thumb = 1;
321 /* FALL THROUGH */
322 case 2:
323 count = strtoul(args[1], NULL, 0);
324 /* FALL THROUGH */
325 case 1:
326 address = strtoul(args[0], NULL, 0);
327 if (address & 0x01) {
328 if (!thumb) {
329 command_print(cmd_ctx, "Disassemble as Thumb");
330 thumb = 1;
331 }
332 address &= ~1;
333 }
334 break;
335 default:
336 usage:
337 command_print(cmd_ctx,
338 "usage: armv4_5 disassemble <address> [<count> ['thumb']]");
339 return ERROR_OK;
340 }
341
342 for (i = 0; i < count; i++) {
343 arm_instruction_t cur_instruction;
344 int retval;
345
346 if (thumb) {
347 retval = thumb2_opcode(target, address, &cur_instruction);
348 if (retval != ERROR_OK)
349 return retval;
350
351 address += cur_instruction.instruction_size;
352 } else {
353 uint32_t opcode;
354
355 retval = target_read_u32(target, address, &opcode);
356 if (retval != ERROR_OK)
357 return retval;
358
359 retval = arm_evaluate_opcode(opcode, address,
360 &cur_instruction);
361 if (retval != ERROR_OK)
362 return retval;
363
364 address += 4;
365 }
366 command_print(cmd_ctx, "%s", cur_instruction.text);
367 }
368
369 return ERROR_OK;
370 }
371
372 int armv7a_register_commands(struct command_context_s *cmd_ctx)
373 {
374 command_t *arm_adi_v5_dap_cmd;
375 command_t *armv7a_cmd;
376
377 arm_adi_v5_dap_cmd = register_command(cmd_ctx, NULL, "dap",
378 NULL, COMMAND_ANY,
379 "cortex dap specific commands");
380
381 register_command(cmd_ctx, arm_adi_v5_dap_cmd, "info",
382 handle_dap_info_command, COMMAND_EXEC,
383 "dap info for ap [num], "
384 "default currently selected AP");
385 register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apsel",
386 handle_dap_apsel_command, COMMAND_EXEC,
387 "select a different AP [num] (default 0)");
388 register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apid",
389 handle_dap_apid_command, COMMAND_EXEC,
390 "return id reg from AP [num], "
391 "default currently selected AP");
392 register_command(cmd_ctx, arm_adi_v5_dap_cmd, "baseaddr",
393 handle_dap_baseaddr_command, COMMAND_EXEC,
394 "return debug base address from AP [num], "
395 "default currently selected AP");
396 register_command(cmd_ctx, arm_adi_v5_dap_cmd, "memaccess",
397 handle_dap_memaccess_command, COMMAND_EXEC,
398 "set/get number of extra tck for mem-ap memory "
399 "bus access [0-255]");
400
401 armv7a_cmd = register_command(cmd_ctx, NULL, "armv7a",
402 NULL, COMMAND_ANY,
403 "ARMv7-A specific commands");
404
405 register_command(cmd_ctx, armv7a_cmd, "disassemble",
406 handle_armv7a_disassemble_command, COMMAND_EXEC,
407 "disassemble instructions <address> [<count> ['thumb']]");
408
409 return ERROR_OK;
410 }