]> git.sur5r.net Git - openocd/blob - src/target/arm_dpm.c
Cortex-A8: implement DPM
[openocd] / 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 }