summaryrefslogtreecommitdiff
path: root/gdb/arm-stub.c
diff options
context:
space:
mode:
authorTomasz Malesinski <tomal@rockbox.org>2006-01-25 01:43:07 +0000
committerTomasz Malesinski <tomal@rockbox.org>2006-01-25 01:43:07 +0000
commit2aabc875bfb68142622e699fbb208bd808e2088f (patch)
tree96c9a17ce88e19e21037d6ce56815bc983a53345 /gdb/arm-stub.c
parentd9c0ad1db69dd3a32939725006fbe4ee27dedcff (diff)
downloadrockbox-2aabc875bfb68142622e699fbb208bd808e2088f.tar.gz
rockbox-2aabc875bfb68142622e699fbb208bd808e2088f.zip
GDB stub for ARM
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8447 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'gdb/arm-stub.c')
-rw-r--r--gdb/arm-stub.c574
1 files changed, 574 insertions, 0 deletions
diff --git a/gdb/arm-stub.c b/gdb/arm-stub.c
new file mode 100644
index 0000000000..68b24a7457
--- /dev/null
+++ b/gdb/arm-stub.c
@@ -0,0 +1,574 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Tomasz Malesinski
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <stdbool.h>
21#include <string.h>
22#include "usb_serial.h"
23#include "sscanf.h"
24
25#define BUFMAX 1024
26
27#define VEC_UND 1
28#define VEC_SWI 2
29#define VEC_PABT 3
30#define VEC_DABT 4
31
32static char packet_buf[BUFMAX];
33static char reply_buf[BUFMAX];
34
35static const char hexchars[] = "0123456789abcdef";
36static int gdb_exception_no, gdb_mem_access;
37static unsigned long registers[17];
38
39static inline bool isxdigit(char c)
40{
41 return ((c >= '0') && (c <= '9'))
42 || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
43}
44
45static int hex(char ch) {
46 if ((ch >= 'a') && (ch <= 'f'))
47 return ch - 'a' + 10;
48 if ((ch >= '0') && (ch <= '9'))
49 return ch - '0';
50 if ((ch >= 'A') && (ch <= 'F'))
51 return ch - 'A' + 10;
52 return -1;
53}
54
55static void hex_byte(char *s, int byte) {
56 s[0] = hexchars[(byte >> 4) & 0xf];
57 s[1] = hexchars[byte & 0xf];
58}
59
60static void hex_word(char *s, unsigned long val) {
61 int i;
62 for (i = 0; i < 4; i++)
63 hex_byte(s + i * 2, (val >> (i * 8)) & 0xff);
64}
65
66static void hex_string(char *d, char *s) {
67 while (*s) {
68 hex_byte(d, *s++);
69 d += 2;
70 }
71 *d = 0;
72}
73
74static int get_hex_byte(char *s) {
75 return (hex(s[0]) << 4) + hex(s[1]);
76}
77
78static unsigned long get_hex_word(char *s) {
79 int i;
80 unsigned long r = 0;
81 for (i = 3; i >= 0; i--)
82 r = (r << 8) + get_hex_byte(s + i * 2);
83 return r;
84}
85
86static void reply_error(int n, char *reply) {
87 reply[0] = 'E';
88 hex_byte(reply + 1, n);
89 reply[3] = 0;
90}
91
92static void reply_signal(int n, char *reply) {
93 int signal;
94 reply[0] = 'S';
95 switch (n)
96 {
97 case VEC_UND:
98 signal = 4;
99 break;
100 case VEC_PABT:
101 case VEC_DABT:
102 signal = 7;
103 break;
104 default:
105 signal = 5;
106 break;
107 }
108 hex_byte(reply + 1, signal);
109 reply[3] = 0;
110}
111
112static void reply_ok(char *reply) {
113 strcpy(reply, "OK");
114}
115
116static void serial_write(unsigned char *buf, int len) {
117 int i;
118 for (i = 0; i < len; i++)
119 usb_serial_put_byte(buf[i]);
120}
121
122static void get_packet(char *buf, int len) {
123 int count, checksum;
124 int ch;
125
126 while (1) {
127 do {
128 ch = usb_serial_get_byte();
129 } while (ch != '$');
130
131 checksum = 0;
132 count = 0;
133 while (count < len) {
134 ch = usb_serial_get_byte();
135 if (ch == '$') {
136 checksum = 0;
137 count = 0;
138 } else if (ch == '#')
139 break;
140 else {
141 checksum += ch;
142 buf[count] = ch;
143 count++;
144 }
145 }
146 buf[count] = 0;
147
148 if (ch == '#') {
149 int rchksum;
150
151 ch = usb_serial_get_byte();
152 rchksum = hex(ch) << 4;
153 ch = usb_serial_get_byte();
154 rchksum += hex(ch);
155
156 if ((checksum & 0xff) != rchksum)
157 usb_serial_put_byte('-');
158 else {
159 usb_serial_put_byte('+');
160 return;
161 }
162 }
163 }
164}
165
166static void put_packet(char *buf) {
167 int i, checksum;
168 int ch;
169 char tmp[3];
170
171 do {
172 usb_serial_put_byte('$');
173
174 checksum = 0;
175 for (i = 0; buf[i]; i++)
176 checksum += buf[i];
177
178 serial_write(buf, i);
179
180 tmp[0] = '#';
181 hex_byte(tmp + 1, checksum & 0xff);
182 serial_write(tmp, 3);
183
184 ch = usb_serial_get_byte();
185
186 } while (ch != '+');
187}
188
189static inline unsigned long get_general_reg(int n)
190{
191 return registers[n + 1];
192}
193
194static inline void set_general_reg(int n, unsigned long v)
195{
196 registers[n + 1] = v;
197}
198
199static inline unsigned long get_cpsr(void)
200{
201 return registers[0];
202}
203
204static inline void set_cpsr(unsigned long v)
205{
206 registers[0] = v;
207}
208
209static void g_reply(char *buf) {
210 int i;
211 char *p;
212
213 p = buf;
214 for (i = 0; i < 16; i++) {
215 hex_word(p, get_general_reg(i));
216 p += 8;
217 }
218
219 for (i = 0; i < 8; i++) {
220 memset(p, '0', 16);
221 p += 16;
222 }
223
224 hex_word(p, 0);
225 p += 8;
226 hex_word(p, get_cpsr());
227 p[8] = 0;
228}
229
230static void cmd_get_register(char *args, char *reply) {
231 int r;
232
233 if (sscanf(args, "%x", &r) != 1) {
234 reply_error(0, reply);
235 return;
236 }
237
238 if (r >= 0 && r < 16) {
239 hex_word(reply, get_general_reg(r));
240 reply[8] = 0;
241 } else if (r == 25) {
242 hex_word(reply, get_cpsr());
243 reply[8] = 0;
244 } else {
245 hex_word(reply, 0);
246 reply[8] = 0;
247 }
248}
249
250static void cmd_set_register(char *args, char *reply) {
251 int r, p;
252 unsigned long v;
253
254 p = -1;
255 sscanf(args, "%x=%n", &r, &p);
256 if (p == -1) {
257 reply_error(0, reply);
258 return;
259 }
260
261 v = get_hex_word(args + p);
262 if (r >= 0 && r < 16)
263 set_general_reg(r, v);
264 else if (r == 25)
265 set_cpsr(v);
266 reply_ok(reply);
267}
268
269static void cmd_set_registers(char *args, char *reply) {
270 char *p;
271 int i, len;
272
273 len = strlen(args);
274
275 p = args;
276 for (i = 0; i < 16 && len >= (i + 1) * 8; i++) {
277 set_general_reg(i, get_hex_word(p));
278 p += 8;
279 }
280
281 if (len >= 16 * 8 + 8 * 16 + 2 * 8)
282 {
283 p += 8 * 16 + 8;
284 set_cpsr(get_hex_word(p));
285 }
286
287 reply_ok(reply);
288}
289
290static void cmd_get_memory(char *args, char *reply) {
291 unsigned long addr, len, i;
292
293 if (sscanf(args, "%lx,%lx", &addr, &len) != 2) {
294 reply_error(0, reply);
295 return;
296 }
297
298 if (len > (BUFMAX - 16) / 2) {
299 reply_error(1, reply);
300 return;
301 }
302
303 gdb_mem_access = 1;
304 for (i = 0; i < len; i++)
305 hex_byte(reply + i * 2, *((unsigned char *)(addr + i)));
306 gdb_mem_access = 0;
307
308 reply[len * 2] = 0;
309}
310
311static void cmd_put_memory(char *args, char *reply) {
312 unsigned long addr, len, i;
313 int pos;
314
315 pos = -1;
316 sscanf(args, "%lx,%lx:%n", &addr, &len, &pos);
317 if (pos == -1) {
318 reply_error(0, reply);
319 return;
320 }
321
322 gdb_mem_access = 1;
323 for (i = 0; i < len; i++)
324 *((unsigned char *)(addr + i)) = get_hex_byte(args + pos + i * 2);
325 gdb_mem_access = 0;
326
327 reply_ok(reply);
328}
329
330static void parse_continue_args(char *args) {
331 int sig;
332 unsigned long addr;
333
334 if (sscanf(args, "%x;%lx", &sig, &addr) == 2) {
335 set_general_reg(15, addr);
336 } else if (sscanf(args, "%lx", &addr) == 1) {
337 set_general_reg(15, addr);
338 }
339}
340
341static void cmd_go(char *args) {
342 parse_continue_args(args);
343
344 asm volatile(
345 " mov r1, %0\n"
346 " ldr r12, [r1], #4\n"
347 " mov r0, r12\n"
348 " and r0, r0, #0x1f\n"
349 " cmp r0, #0x10\n"
350 " bne 1f\n"
351 " ldr r14, [r1, #60]\n"
352 " msr spsr_fsxc, r12\n"
353 " ldmia r1, {r0-r14}^\n"
354 " movs r15, r14\n"
355 "1:\n"
356 " msr cpsr_fsxc, r12\n"
357 " ldmia r1, {r0-r15}\n"
358 : : "r" (registers));
359}
360
361static void remote_cmd(char *cmd, char *reply) {
362 (void)cmd;
363 hex_string(reply, "Unrecognized command\n");
364}
365
366static void cmd_query(char *args, char *reply) {
367 if (!strncmp(args, "Rcmd,", 5)) {
368 unsigned i = 0;
369 char *s = args + 5;
370 char cmd[200];
371 while (isxdigit(s[0]) && isxdigit(s[1]) && i < sizeof(cmd) - 1) {
372 cmd[i++] = get_hex_byte(s);
373 s += 2;
374 }
375 cmd[i] = 0;
376 remote_cmd(cmd, reply);
377 } else
378 reply[0] = 0;
379}
380
381void gdb_loop(void) {
382 int no_reply;
383
384 gdb_mem_access = 0;
385
386 while (1) {
387 get_packet(packet_buf, sizeof(packet_buf) - 1);
388
389 no_reply = 0;
390 switch (packet_buf[0]) {
391 case '?':
392 reply_signal(gdb_exception_no, reply_buf);
393 break;
394
395 case 'p':
396 cmd_get_register(packet_buf + 1, reply_buf);
397 break;
398
399 case 'P':
400 cmd_set_register(packet_buf + 1, reply_buf);
401 break;
402
403 case 'g':
404 g_reply(reply_buf);
405 break;
406
407 case 'G':
408 cmd_set_registers(packet_buf + 1, reply_buf);
409 break;
410
411 case 'm':
412 cmd_get_memory(packet_buf + 1, reply_buf);
413 break;
414
415 case 'M':
416 cmd_put_memory(packet_buf + 1, reply_buf);
417 break;
418
419 case 'q':
420 cmd_query(packet_buf + 1, reply_buf);
421 break;
422
423 case 'c':
424 cmd_go(packet_buf + 1);
425 reply_error(1, reply_buf);
426 break;
427
428/* case 's': */
429/* cmd_go(packet_buf + 1); */
430/* break; */
431
432 default:
433 reply_buf[0] = 0;
434 }
435
436 if (!no_reply)
437 put_packet(reply_buf);
438 }
439}
440
441extern void *vectors[];
442
443static void gdb_set_vector(int n, void *p)
444{
445 vectors[n] = p;
446}
447
448void gdb_und_exc(void);
449void gdb_swi_exc(void);
450void gdb_pabt_exc(void);
451void gdb_dabt_exc(void);
452
453static void gdb_set_vectors(void)
454{
455 gdb_set_vector(VEC_UND, gdb_und_exc);
456 gdb_set_vector(VEC_SWI, gdb_swi_exc);
457 gdb_set_vector(VEC_PABT, gdb_pabt_exc);
458 gdb_set_vector(VEC_DABT, gdb_dabt_exc);
459}
460
461void gdb_loop_from_exc(void)
462{
463 if (gdb_mem_access)
464 reply_error(1, reply_buf);
465 else
466 reply_signal(gdb_exception_no, reply_buf);
467 put_packet(reply_buf);
468 gdb_loop();
469}
470
471#define GPIO3_CLR (*(volatile unsigned long *)0x800030d8)
472
473#define IRQ_REG(reg) (*(volatile unsigned long *)(0x80300000 + (reg)))
474
475static inline unsigned long irq_read(int reg)
476{
477 unsigned long v, v2;
478 do
479 {
480 v = IRQ_REG(reg);
481 v2 = IRQ_REG(reg);
482 } while (v != v2);
483 return v;
484}
485
486#define IRQ_WRITE_WAIT(reg, val, cond) \
487 do { unsigned long v, v2; \
488 do { \
489 IRQ_REG(reg) = (val); \
490 v = IRQ_REG(reg); \
491 v2 = IRQ_REG(reg); \
492 } while ((v != v2) || !(cond)); \
493 } while (0);
494
495static void system_init(void)
496{
497 int i;
498
499 /* turn off watchdog */
500 (*(volatile unsigned long *)0x80002804) = 0;
501
502 for (i = 0; i < 0x1c; i++)
503 {
504 IRQ_WRITE_WAIT(0x404 + i * 4, 0x1e000001, (v & 0x3010f) == 1);
505 IRQ_WRITE_WAIT(0x404 + i * 4, 0x4000000, (v & 0x10000) == 0);
506 IRQ_WRITE_WAIT(0x404 + i * 4, 0x10000001, (v & 0xf) == 1);
507 }
508
509 GPIO3_CLR = 1;
510}
511
512void main(void)
513{
514 system_init();
515 usb_serial_init();
516 gdb_exception_no = VEC_SWI;
517 gdb_set_vectors();
518 gdb_loop();
519}
520
521#define str(s) #s
522#define xstr(s) str(s)
523
524asm (".text\n"
525 "gdb_und_exc:\n"
526 " ldr sp, =_stub_stack\n"
527 " sub r14, r14, #4\n"
528 " stmfd sp!, {r0-r3, r12, r14}\n"
529 " mov r0, #" xstr(VEC_UND) "\n"
530 " b gdb_handle_exception\n"
531 "gdb_swi_exc:\n"
532 " ldr sp, =_stub_stack\n"
533 " stmfd sp!, {r0-r3, r12, r14}\n"
534 " mov r0, #" xstr(VEC_SWI) "\n"
535 " b gdb_handle_exception\n"
536 "gdb_pabt_exc:\n"
537 " ldr sp, =_stub_stack\n"
538 " stmfd sp!, {r0-r3, r12, r14}\n"
539 " mov r0, #" xstr(VEC_PABT) "\n"
540 " b gdb_handle_exception\n"
541 "gdb_dabt_exc:\n"
542 " ldr sp, =_stub_stack\n"
543 " sub r14, r14, #4\n"
544 " stmfd sp!, {r0-r3, r12, r14}\n"
545 " ldr r0, =gdb_mem_access\n"
546 " ldr r0, [r0]\n"
547 " tst r0, r0\n"
548 " bne gdb_data_abort\n"
549 " mov r0, #" xstr(VEC_DABT) "\n"
550 " b gdb_handle_exception\n"
551 "gdb_handle_exception:\n"
552 " ldr r1, =gdb_exception_no\n"
553 " str r0, [r1]\n"
554 " ldr r0, =registers\n"
555 " mrs r12, spsr\n"
556 " str r12, [r0], #4\n"
557 " ldmfd sp!, {r2, r3}\n"
558 " stmia r0!, {r2, r3}\n"
559 " ldmfd sp!, {r2, r3, r12, r14}\n"
560 " str r14, [r0, #52]\n"
561 " stmia r0!, {r2-r12}\n"
562 " mrs r1, spsr\n"
563 " and r2, r1, #0x1f\n"
564 " cmp r2, #0x10\n"
565 " bne 1f\n"
566 " stmia r0, {r13, r14}^\n"
567 " b gdb_data_abort\n"
568 "1:\n"
569 " msr cpsr_c, r1\n"
570 " stmia r0, {r13, r14}\n"
571 "gdb_data_abort:\n"
572 " msr cpsr_c, #0xd3\n"
573 " ldr sp, =_stub_stack\n"
574 " b gdb_loop_from_exc\n");