split jim_jtag_command into multiple handlers
[openocd.git] / src / target / arm_dpm.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
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "armv4_5.h" /* REVISIT to become arm.h */
25 #include "arm_dpm.h"
26 #include "jtag.h"
27 #include "register.h"
28
29
30 /**
31 * @file
32 * Implements various ARM DPM operations using architectural debug registers.
33 * These routines layer over core-specific communication methods to cope with
34 * implementation differences between cores like ARM1136 and Cortex-A8.
35 */
36
37 /* Toggles between recorded core mode (USR, SVC, etc) and a temporary one.
38 * Routines *must* restore the original mode before returning!!
39 */
40 static int dpm_modeswitch(struct arm_dpm *dpm, enum armv4_5_mode mode)
41 {
42 int retval;
43 uint32_t cpsr;
44
45 /* restore previous mode */
46 if (mode == ARMV4_5_MODE_ANY)
47 cpsr = buf_get_u32(dpm->arm->cpsr->value, 0, 32);
48
49 /* else force to the specified mode */
50 else
51 cpsr = mode;
52
53 retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MSR_GP(0, 0xf, 0), cpsr);
54
55 if (dpm->instr_cpsr_sync)
56 retval = dpm->instr_cpsr_sync(dpm);
57
58 return retval;
59 }
60
61 /* just read the register -- rely on the core mode being right */
62 static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
63 {
64 uint32_t value;
65 int retval;
66
67 switch (regnum) {
68 case 0 ... 14:
69 /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */
70 retval = dpm->instr_read_data_dcc(dpm,
71 ARMV4_5_MCR(14, 0, regnum, 0, 5, 0),
72 &value);
73 break;
74 case 15: /* PC */
75 /* "MOV r0, pc"; then return via DCC */
76 retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value);
77
78 /* NOTE: this seems like a slightly awkward place to update
79 * this value ... but if the PC gets written (the only way
80 * to change what we compute), the arch spec says subsequent
81 * reads return values which are "unpredictable". So this
82 * is always right except in those broken-by-intent cases.
83 */
84 switch (dpm->arm->core_state) {
85 case ARMV4_5_STATE_ARM:
86 value -= 8;
87 break;
88 case ARMV4_5_STATE_THUMB:
89 case ARM_STATE_THUMB_EE:
90 value -= 4;
91 break;
92 case ARMV4_5_STATE_JAZELLE:
93 /* core-specific ... ? */
94 LOG_WARNING("Jazelle PC adjustment unknown");
95 break;
96 }
97 break;
98 default:
99 /* 16: "MRS r0, CPSR"; then return via DCC
100 * 17: "MRS r0, SPSR"; then return via DCC
101 */
102 retval = dpm->instr_read_data_r0(dpm,
103 ARMV4_5_MRS(0, regnum & 1),
104 &value);
105 break;
106 }
107
108 if (retval == ERROR_OK) {
109 buf_set_u32(r->value, 0, 32, value);
110 r->valid = true;
111 r->dirty = false;
112 LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned) value);
113 }
114
115 return retval;
116 }
117
118 /* just write the register -- rely on the core mode being right */
119 static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
120 {
121 int retval;
122 uint32_t value = buf_get_u32(r->value, 0, 32);
123
124 switch (regnum) {
125 case 0 ... 14:
126 /* load register from DCC: "MCR p14, 0, Rnum, c0, c5, 0" */
127 retval = dpm->instr_write_data_dcc(dpm,
128 ARMV4_5_MRC(14, 0, regnum, 0, 5, 0),
129 value);
130 break;
131 case 15: /* PC */
132 /* read r0 from DCC; then "MOV pc, r0" */
133 retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value);
134 break;
135 default:
136 /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf"
137 * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf"
138 */
139 retval = dpm->instr_write_data_r0(dpm,
140 ARMV4_5_MSR_GP(0, 0xf, regnum & 1),
141 value);
142
143 if (regnum == 16 && dpm->instr_cpsr_sync)
144 retval = dpm->instr_cpsr_sync(dpm);
145
146 break;
147 }
148
149 if (retval == ERROR_OK) {
150 r->dirty = false;
151 LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned) value);
152 }
153
154 return retval;
155 }
156
157 /**
158 * Read basic registers of the the current context: R0 to R15, and CPSR;
159 * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
160 * In normal operation this is called on entry to halting debug state,
161 * possibly after some other operations supporting restore of debug state
162 * or making sure the CPU is fully idle (drain write buffer, etc).
163 */
164 int arm_dpm_read_current_registers(struct arm_dpm *dpm)
165 {
166 struct arm *arm = dpm->arm;
167 uint32_t cpsr;
168 int retval;
169 struct reg *r;
170
171 retval = dpm->prepare(dpm);
172 if (retval != ERROR_OK)
173 return retval;
174
175 /* read R0 first (it's used for scratch), then CPSR */
176 r = arm->core_cache->reg_list + 0;
177 if (!r->valid) {
178 retval = dpm_read_reg(dpm, r, 0);
179 if (retval != ERROR_OK)
180 goto fail;
181 }
182 r->dirty = true;
183
184 retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
185 if (retval != ERROR_OK)
186 goto fail;
187
188 /* update core mode and state, plus shadow mapping for R8..R14 */
189 arm_set_cpsr(arm, cpsr);
190
191 /* REVISIT we can probably avoid reading R1..R14, saving time... */
192 for (unsigned i = 1; i < 16; i++) {
193 r = arm_reg_current(arm, i);
194 if (r->valid)
195 continue;
196
197 retval = dpm_read_reg(dpm, r, i);
198 if (retval != ERROR_OK)
199 goto fail;
200 }
201
202 /* NOTE: SPSR ignored (if it's even relevant). */
203
204 fail:
205 /* (void) */ dpm->finish(dpm);
206 return retval;
207 }
208
209 /**
210 * Writes all modified core registers for all processor modes. In normal
211 * operation this is called on exit from halting debug state.
212 */
213 int arm_dpm_write_dirty_registers(struct arm_dpm *dpm)
214 {
215 struct arm *arm = dpm->arm;
216 struct reg_cache *cache = arm->core_cache;
217 int retval;
218 bool did_write;
219
220 retval = dpm->prepare(dpm);
221 if (retval != ERROR_OK)
222 goto done;
223
224 /* Scan the registers until we find one that's both dirty and
225 * eligible for flushing. Flush that and everything else that
226 * shares the same core mode setting. Typically this won't
227 * actually find anything to do...
228 */
229 do {
230 enum armv4_5_mode mode = ARMV4_5_MODE_ANY;
231
232 did_write = false;
233
234 /* check everything except our scratch register R0 */
235 for (unsigned i = 1; i < cache->num_regs; i++) {
236 struct arm_reg *r;
237 unsigned regnum;
238
239 /* also skip PC, CPSR, and non-dirty */
240 if (i == 15)
241 continue;
242 if (arm->cpsr == cache->reg_list + i)
243 continue;
244 if (!cache->reg_list[i].dirty)
245 continue;
246
247 r = cache->reg_list[i].arch_info;
248 regnum = r->num;
249
250 /* may need to pick and set a mode */
251 if (!did_write) {
252 enum armv4_5_mode tmode;
253
254 did_write = true;
255 mode = tmode = r->mode;
256
257 /* cope with special cases */
258 switch (regnum) {
259 case 8 ... 12:
260 /* r8..r12 "anything but FIQ" case;
261 * we "know" core mode is accurate
262 * since we haven't changed it yet
263 */
264 if (arm->core_mode == ARMV4_5_MODE_FIQ
265 && ARMV4_5_MODE_ANY
266 != mode)
267 tmode = ARMV4_5_MODE_USR;
268 break;
269 case 16:
270 /* SPSR */
271 regnum++;
272 break;
273 }
274
275 /* REVISIT error checks */
276 if (tmode != ARMV4_5_MODE_ANY)
277 retval = dpm_modeswitch(dpm, tmode);
278 }
279 if (r->mode != mode)
280 continue;
281
282 retval = dpm_write_reg(dpm,
283 &cache->reg_list[i],
284 regnum);
285
286 }
287
288 } while (did_write);
289
290 /* Restore original CPSR ... assuming either that we changed it,
291 * or it's dirty. Must write PC to ensure the return address is
292 * defined, and must not write it before CPSR.
293 */
294 retval = dpm_modeswitch(dpm, ARMV4_5_MODE_ANY);
295 arm->cpsr->dirty = false;
296
297 retval = dpm_write_reg(dpm, &cache->reg_list[15], 15);
298 cache->reg_list[15].dirty = false;
299
300 /* flush R0 -- it's *very* dirty by now */
301 retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
302 cache->reg_list[0].dirty = false;
303
304 /* (void) */ dpm->finish(dpm);
305 done:
306 return retval;
307 }
308
309 /* Returns ARMV4_5_MODE_ANY or temporary mode to use while reading the
310 * specified register ... works around flakiness from ARM core calls.
311 * Caller already filtered out SPSR access; mode is never MODE_SYS
312 * or MODE_ANY.
313 */
314 static enum armv4_5_mode dpm_mapmode(struct arm *arm,
315 unsigned num, enum armv4_5_mode mode)
316 {
317 enum armv4_5_mode amode = arm->core_mode;
318
319 /* don't switch if the mode is already correct */
320 if (amode == ARMV4_5_MODE_SYS)
321 amode = ARMV4_5_MODE_USR;
322 if (mode == amode)
323 return ARMV4_5_MODE_ANY;
324
325 switch (num) {
326 /* don't switch for non-shadowed registers (r0..r7, r15/pc, cpsr) */
327 case 0 ... 7:
328 case 15:
329 case 16:
330 break;
331 /* r8..r12 aren't shadowed for anything except FIQ */
332 case 8 ... 12:
333 if (mode == ARMV4_5_MODE_FIQ)
334 return mode;
335 break;
336 /* r13/sp, and r14/lr are always shadowed */
337 case 13:
338 case 14:
339 return mode;
340 default:
341 LOG_WARNING("invalid register #%u", num);
342 break;
343 }
344 return ARMV4_5_MODE_ANY;
345 }
346
347 static int arm_dpm_read_core_reg(struct target *target, struct reg *r,
348 int regnum, enum armv4_5_mode mode)
349 {
350 struct arm_dpm *dpm = target_to_arm(target)->dpm;
351 int retval;
352
353 if (regnum < 0 || regnum > 16)
354 return ERROR_INVALID_ARGUMENTS;
355
356 if (regnum == 16) {
357 if (mode != ARMV4_5_MODE_ANY)
358 regnum = 17;
359 } else
360 mode = dpm_mapmode(dpm->arm, regnum, mode);
361
362 /* REVISIT what happens if we try to read SPSR in a core mode
363 * which has no such register?
364 */
365
366 retval = dpm->prepare(dpm);
367 if (retval != ERROR_OK)
368 return retval;
369
370 if (mode != ARMV4_5_MODE_ANY) {
371 retval = dpm_modeswitch(dpm, mode);
372 if (retval != ERROR_OK)
373 goto fail;
374 }
375
376 retval = dpm_read_reg(dpm, r, regnum);
377 /* always clean up, regardless of error */
378
379 if (mode != ARMV4_5_MODE_ANY)
380 /* (void) */ dpm_modeswitch(dpm, ARMV4_5_MODE_ANY);
381
382 fail:
383 /* (void) */ dpm->finish(dpm);
384 return retval;
385 }
386
387 static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
388 int regnum, enum armv4_5_mode mode, uint32_t value)
389 {
390 struct arm_dpm *dpm = target_to_arm(target)->dpm;
391 int retval;
392
393
394 if (regnum < 0 || regnum > 16)
395 return ERROR_INVALID_ARGUMENTS;
396
397 if (regnum == 16) {
398 if (mode != ARMV4_5_MODE_ANY)
399 regnum = 17;
400 } else
401 mode = dpm_mapmode(dpm->arm, regnum, mode);
402
403 /* REVISIT what happens if we try to write SPSR in a core mode
404 * which has no such register?
405 */
406
407 retval = dpm->prepare(dpm);
408 if (retval != ERROR_OK)
409 return retval;
410
411 if (mode != ARMV4_5_MODE_ANY) {
412 retval = dpm_modeswitch(dpm, mode);
413 if (retval != ERROR_OK)
414 goto fail;
415 }
416
417 retval = dpm_write_reg(dpm, r, regnum);
418 /* always clean up, regardless of error */
419
420 if (mode != ARMV4_5_MODE_ANY)
421 /* (void) */ dpm_modeswitch(dpm, ARMV4_5_MODE_ANY);
422
423 fail:
424 /* (void) */ dpm->finish(dpm);
425 return retval;
426 }
427
428 static int arm_dpm_full_context(struct target *target)
429 {
430 struct arm *arm = target_to_arm(target);
431 struct arm_dpm *dpm = arm->dpm;
432 struct reg_cache *cache = arm->core_cache;
433 int retval;
434 bool did_read;
435
436 retval = dpm->prepare(dpm);
437 if (retval != ERROR_OK)
438 goto done;
439
440 do {
441 enum armv4_5_mode mode = ARMV4_5_MODE_ANY;
442
443 did_read = false;
444
445 /* We "know" arm_dpm_read_current_registers() was called so
446 * the unmapped registers (R0..R7, PC, AND CPSR) and some
447 * view of R8..R14 are current. We also "know" oddities of
448 * register mapping: special cases for R8..R12 and SPSR.
449 *
450 * Pick some mode with unread registers and read them all.
451 * Repeat until done.
452 */
453 for (unsigned i = 0; i < cache->num_regs; i++) {
454 struct arm_reg *r;
455
456 if (cache->reg_list[i].valid)
457 continue;
458 r = cache->reg_list[i].arch_info;
459
460 /* may need to pick a mode and set CPSR */
461 if (!did_read) {
462 did_read = true;
463 mode = r->mode;
464
465 /* For R8..R12 when we've entered debug
466 * state in FIQ mode... patch mode.
467 */
468 if (mode == ARMV4_5_MODE_ANY)
469 mode = ARMV4_5_MODE_USR;
470
471 /* REVISIT error checks */
472 retval = dpm_modeswitch(dpm, mode);
473 }
474 if (r->mode != mode)
475 continue;
476
477 /* CPSR was read, so "R16" must mean SPSR */
478 retval = dpm_read_reg(dpm,
479 &cache->reg_list[i],
480 (r->num == 16) ? 17 : r->num);
481
482 }
483
484 } while (did_read);
485
486 retval = dpm_modeswitch(dpm, ARMV4_5_MODE_ANY);
487 /* (void) */ dpm->finish(dpm);
488 done:
489 return retval;
490 }
491
492 /**
493 * Hooks up this DPM to its associated target; call only once.
494 * Initially this only covers the register cache.
495 */
496 int arm_dpm_setup(struct arm_dpm *dpm)
497 {
498 struct arm *arm = dpm->arm;
499 struct target *target = arm->target;
500 struct reg_cache *cache;
501
502 arm->dpm = dpm;
503
504 arm->full_context = arm_dpm_full_context;
505 arm->read_core_reg = arm_dpm_read_core_reg;
506 arm->write_core_reg = arm_dpm_write_core_reg;
507
508 cache = armv4_5_build_reg_cache(target, arm);
509 if (!cache)
510 return ERROR_FAIL;
511
512 *register_get_last_cache_p(&target->reg_cache) = cache;
513 return ERROR_OK;
514 }
515
516 /**
517 * Reinitializes DPM state at the beginning of a new debug session
518 * or after a reset which may have affected the debug module.
519 */
520 int arm_dpm_initialize(struct arm_dpm *dpm)
521 {
522 /* FIXME -- nothing yet */
523 return ERROR_OK;
524 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)