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

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)