diff options
-rw-r--r-- | gdb/arm-stub.c | 194 |
1 files changed, 168 insertions, 26 deletions
diff --git a/gdb/arm-stub.c b/gdb/arm-stub.c index 68b24a7457..0717af49c3 100644 --- a/gdb/arm-stub.c +++ b/gdb/arm-stub.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <string.h> | 21 | #include <string.h> |
22 | #include "usb_serial.h" | 22 | #include "usb_serial.h" |
23 | #include "sscanf.h" | 23 | #include "sscanf.h" |
24 | #include "pnx0101.h" | ||
25 | #include "gdb_api.h" | ||
24 | 26 | ||
25 | #define BUFMAX 1024 | 27 | #define BUFMAX 1024 |
26 | 28 | ||
@@ -34,8 +36,34 @@ static char reply_buf[BUFMAX]; | |||
34 | 36 | ||
35 | static const char hexchars[] = "0123456789abcdef"; | 37 | static const char hexchars[] = "0123456789abcdef"; |
36 | static int gdb_exception_no, gdb_mem_access; | 38 | static int gdb_exception_no, gdb_mem_access; |
39 | static unsigned char watchdog_enabled; | ||
37 | static unsigned long registers[17]; | 40 | static unsigned long registers[17]; |
38 | 41 | ||
42 | void gdb_api_breakpoint(void); | ||
43 | static void gdb_api_log(char *msg); | ||
44 | |||
45 | __attribute__((section(".gdbapi"))) struct gdb_api gdb_api = | ||
46 | { | ||
47 | GDB_API_MAGIC, | ||
48 | {gdb_api_breakpoint, gdb_api_log} | ||
49 | }; | ||
50 | |||
51 | static void watchdog_enable(int on) | ||
52 | { | ||
53 | (*(volatile unsigned long *)0x80002804) = on; | ||
54 | watchdog_enabled = on; | ||
55 | } | ||
56 | |||
57 | static void watchdog_service(void) | ||
58 | { | ||
59 | if (watchdog_enabled) | ||
60 | { | ||
61 | (*(volatile unsigned long *)0x80002804) = 0; | ||
62 | (*(volatile unsigned long *)0x80002808) = 0; | ||
63 | (*(volatile unsigned long *)0x80002804) = 1; | ||
64 | } | ||
65 | } | ||
66 | |||
39 | static inline bool isxdigit(char c) | 67 | static inline bool isxdigit(char c) |
40 | { | 68 | { |
41 | return ((c >= '0') && (c <= '9')) | 69 | return ((c >= '0') && (c <= '9')) |
@@ -113,33 +141,58 @@ static void reply_ok(char *reply) { | |||
113 | strcpy(reply, "OK"); | 141 | strcpy(reply, "OK"); |
114 | } | 142 | } |
115 | 143 | ||
144 | static int get_byte(void) { | ||
145 | int b; | ||
146 | while ((b = usb_serial_try_get_byte()) < 0) | ||
147 | watchdog_service(); | ||
148 | watchdog_service(); | ||
149 | return b; | ||
150 | } | ||
151 | |||
152 | static void put_byte(unsigned char ch) { | ||
153 | while (usb_serial_try_put_byte(ch) < 0) | ||
154 | watchdog_service(); | ||
155 | watchdog_service(); | ||
156 | } | ||
157 | |||
116 | static void serial_write(unsigned char *buf, int len) { | 158 | static void serial_write(unsigned char *buf, int len) { |
117 | int i; | 159 | int i; |
118 | for (i = 0; i < len; i++) | 160 | for (i = 0; i < len; i++) |
119 | usb_serial_put_byte(buf[i]); | 161 | put_byte(buf[i]); |
120 | } | 162 | } |
121 | 163 | ||
122 | static void get_packet(char *buf, int len) { | 164 | static void get_packet(char *buf, int len) { |
123 | int count, checksum; | 165 | int count, checksum, escaped; |
124 | int ch; | 166 | int ch; |
125 | 167 | ||
126 | while (1) { | 168 | while (1) { |
127 | do { | 169 | do { |
128 | ch = usb_serial_get_byte(); | 170 | ch = get_byte(); |
129 | } while (ch != '$'); | 171 | } while (ch != '$'); |
130 | 172 | ||
131 | checksum = 0; | 173 | checksum = 0; |
132 | count = 0; | 174 | count = 0; |
175 | escaped = 0; | ||
133 | while (count < len) { | 176 | while (count < len) { |
134 | ch = usb_serial_get_byte(); | 177 | ch = get_byte(); |
135 | if (ch == '$') { | 178 | if (!escaped) { |
136 | checksum = 0; | 179 | if (ch == '$') { |
137 | count = 0; | 180 | checksum = 0; |
138 | } else if (ch == '#') | 181 | count = 0; |
139 | break; | 182 | } else if (ch == '#') |
140 | else { | 183 | break; |
184 | else if (ch == 0x7d) { | ||
185 | escaped = 1; | ||
186 | checksum += ch; | ||
187 | } else { | ||
188 | checksum += ch; | ||
189 | buf[count] = ch; | ||
190 | count++; | ||
191 | } | ||
192 | } else { | ||
193 | escaped = 0; | ||
141 | checksum += ch; | 194 | checksum += ch; |
142 | buf[count] = ch; | 195 | buf[count] = ch ^ 0x20; |
143 | count++; | 196 | count++; |
144 | } | 197 | } |
145 | } | 198 | } |
@@ -148,15 +201,15 @@ static void get_packet(char *buf, int len) { | |||
148 | if (ch == '#') { | 201 | if (ch == '#') { |
149 | int rchksum; | 202 | int rchksum; |
150 | 203 | ||
151 | ch = usb_serial_get_byte(); | 204 | ch = get_byte(); |
152 | rchksum = hex(ch) << 4; | 205 | rchksum = hex(ch) << 4; |
153 | ch = usb_serial_get_byte(); | 206 | ch = get_byte(); |
154 | rchksum += hex(ch); | 207 | rchksum += hex(ch); |
155 | 208 | ||
156 | if ((checksum & 0xff) != rchksum) | 209 | if ((checksum & 0xff) != rchksum) |
157 | usb_serial_put_byte('-'); | 210 | put_byte('-'); |
158 | else { | 211 | else { |
159 | usb_serial_put_byte('+'); | 212 | put_byte('+'); |
160 | return; | 213 | return; |
161 | } | 214 | } |
162 | } | 215 | } |
@@ -169,7 +222,7 @@ static void put_packet(char *buf) { | |||
169 | char tmp[3]; | 222 | char tmp[3]; |
170 | 223 | ||
171 | do { | 224 | do { |
172 | usb_serial_put_byte('$'); | 225 | put_byte('$'); |
173 | 226 | ||
174 | checksum = 0; | 227 | checksum = 0; |
175 | for (i = 0; buf[i]; i++) | 228 | for (i = 0; buf[i]; i++) |
@@ -181,7 +234,7 @@ static void put_packet(char *buf) { | |||
181 | hex_byte(tmp + 1, checksum & 0xff); | 234 | hex_byte(tmp + 1, checksum & 0xff); |
182 | serial_write(tmp, 3); | 235 | serial_write(tmp, 3); |
183 | 236 | ||
184 | ch = usb_serial_get_byte(); | 237 | ch = get_byte(); |
185 | 238 | ||
186 | } while (ch != '+'); | 239 | } while (ch != '+'); |
187 | } | 240 | } |
@@ -327,6 +380,25 @@ static void cmd_put_memory(char *args, char *reply) { | |||
327 | reply_ok(reply); | 380 | reply_ok(reply); |
328 | } | 381 | } |
329 | 382 | ||
383 | static void cmd_put_memory_binary(char *args, char *reply) { | ||
384 | unsigned long addr, len, i; | ||
385 | int pos; | ||
386 | |||
387 | pos = -1; | ||
388 | sscanf(args, "%lx,%lx:%n", &addr, &len, &pos); | ||
389 | if (pos == -1) { | ||
390 | reply_error(0, reply); | ||
391 | return; | ||
392 | } | ||
393 | |||
394 | gdb_mem_access = 1; | ||
395 | for (i = 0; i < len; i++) | ||
396 | *((unsigned char *)(addr + i)) = args[pos + i]; | ||
397 | gdb_mem_access = 0; | ||
398 | |||
399 | reply_ok(reply); | ||
400 | } | ||
401 | |||
330 | static void parse_continue_args(char *args) { | 402 | static void parse_continue_args(char *args) { |
331 | int sig; | 403 | int sig; |
332 | unsigned long addr; | 404 | unsigned long addr; |
@@ -359,8 +431,40 @@ static void cmd_go(char *args) { | |||
359 | } | 431 | } |
360 | 432 | ||
361 | static void remote_cmd(char *cmd, char *reply) { | 433 | static void remote_cmd(char *cmd, char *reply) { |
362 | (void)cmd; | 434 | int i, err; |
363 | hex_string(reply, "Unrecognized command\n"); | 435 | i = 0; |
436 | err = 0; | ||
437 | while ((cmd[i] >= 'a' && cmd[i] <= 'z') || cmd[i] == '_') | ||
438 | i++; | ||
439 | if (!strncmp(cmd, "reboot", i)) | ||
440 | { | ||
441 | reply_ok(reply); | ||
442 | put_packet(reply); | ||
443 | watchdog_enable(1); | ||
444 | (*(volatile unsigned long *)0x80002804) = 1; | ||
445 | while (1); | ||
446 | } | ||
447 | else if (!strncmp(cmd, "power_off", i)) | ||
448 | { | ||
449 | reply_ok(reply); | ||
450 | put_packet(reply); | ||
451 | GPIO1_CLR = 1 << 16; | ||
452 | GPIO2_SET = 1; | ||
453 | while (1); | ||
454 | } | ||
455 | else if (!strncmp(cmd, "watchdog", i)) | ||
456 | { | ||
457 | int t; | ||
458 | if (sscanf(cmd + i, "%d", &t) == 1) | ||
459 | watchdog_enable(t != 0); | ||
460 | else | ||
461 | err = 1; | ||
462 | reply_ok(reply); | ||
463 | } | ||
464 | else | ||
465 | hex_string(reply, "Unrecognized command\n"); | ||
466 | if (err) | ||
467 | reply_error(err, reply); | ||
364 | } | 468 | } |
365 | 469 | ||
366 | static void cmd_query(char *args, char *reply) { | 470 | static void cmd_query(char *args, char *reply) { |
@@ -416,6 +520,10 @@ void gdb_loop(void) { | |||
416 | cmd_put_memory(packet_buf + 1, reply_buf); | 520 | cmd_put_memory(packet_buf + 1, reply_buf); |
417 | break; | 521 | break; |
418 | 522 | ||
523 | case 'X': | ||
524 | cmd_put_memory_binary(packet_buf + 1, reply_buf); | ||
525 | break; | ||
526 | |||
419 | case 'q': | 527 | case 'q': |
420 | cmd_query(packet_buf + 1, reply_buf); | 528 | cmd_query(packet_buf + 1, reply_buf); |
421 | break; | 529 | break; |
@@ -468,8 +576,6 @@ void gdb_loop_from_exc(void) | |||
468 | gdb_loop(); | 576 | gdb_loop(); |
469 | } | 577 | } |
470 | 578 | ||
471 | #define GPIO3_CLR (*(volatile unsigned long *)0x800030d8) | ||
472 | |||
473 | #define IRQ_REG(reg) (*(volatile unsigned long *)(0x80300000 + (reg))) | 579 | #define IRQ_REG(reg) (*(volatile unsigned long *)(0x80300000 + (reg))) |
474 | 580 | ||
475 | static inline unsigned long irq_read(int reg) | 581 | static inline unsigned long irq_read(int reg) |
@@ -492,12 +598,15 @@ static inline unsigned long irq_read(int reg) | |||
492 | } while ((v != v2) || !(cond)); \ | 598 | } while ((v != v2) || !(cond)); \ |
493 | } while (0); | 599 | } while (0); |
494 | 600 | ||
601 | void fiq(void) | ||
602 | { | ||
603 | } | ||
604 | |||
495 | static void system_init(void) | 605 | static void system_init(void) |
496 | { | 606 | { |
497 | int i; | 607 | int i; |
498 | 608 | ||
499 | /* turn off watchdog */ | 609 | watchdog_enable(0); |
500 | (*(volatile unsigned long *)0x80002804) = 0; | ||
501 | 610 | ||
502 | for (i = 0; i < 0x1c; i++) | 611 | for (i = 0; i < 0x1c; i++) |
503 | { | 612 | { |
@@ -509,13 +618,29 @@ static void system_init(void) | |||
509 | GPIO3_CLR = 1; | 618 | GPIO3_CLR = 1; |
510 | } | 619 | } |
511 | 620 | ||
621 | static void gdb_api_log(char *msg) | ||
622 | { | ||
623 | int i; | ||
624 | |||
625 | reply_buf[0] = 'O'; | ||
626 | i = 1; | ||
627 | while (*msg && i + 2 <= BUFMAX - 1) | ||
628 | { | ||
629 | hex_byte(reply_buf + i, *msg++); | ||
630 | i += 2; | ||
631 | } | ||
632 | reply_buf[i] = 0; | ||
633 | put_packet(reply_buf); | ||
634 | } | ||
635 | |||
512 | void main(void) | 636 | void main(void) |
513 | { | 637 | { |
514 | system_init(); | 638 | system_init(); |
515 | usb_serial_init(); | 639 | usb_serial_init(); |
516 | gdb_exception_no = VEC_SWI; | 640 | gdb_mem_access = 0; |
517 | gdb_set_vectors(); | 641 | gdb_set_vectors(); |
518 | gdb_loop(); | 642 | gdb_api_breakpoint(); |
643 | while (1); | ||
519 | } | 644 | } |
520 | 645 | ||
521 | #define str(s) #s | 646 | #define str(s) #s |
@@ -571,4 +696,21 @@ asm (".text\n" | |||
571 | "gdb_data_abort:\n" | 696 | "gdb_data_abort:\n" |
572 | " msr cpsr_c, #0xd3\n" | 697 | " msr cpsr_c, #0xd3\n" |
573 | " ldr sp, =_stub_stack\n" | 698 | " ldr sp, =_stub_stack\n" |
699 | " b gdb_loop_from_exc\n" | ||
700 | "gdb_api_breakpoint:\n" | ||
701 | " stmfd sp!, {r0-r1}\n" | ||
702 | " ldr r0, =registers\n" | ||
703 | " mrs r1, cpsr\n" | ||
704 | " str r1, [r0], #4\n" | ||
705 | " ldmfd sp!, {r1}\n" | ||
706 | " str r1, [r0], #4\n" | ||
707 | " ldmfd sp!, {r1}\n" | ||
708 | " str r1, [r0], #4\n" | ||
709 | " stmia r0!, {r2-r14}\n" | ||
710 | " str r14, [r0]\n" | ||
711 | " msr cpsr_c, #0xd3\n" | ||
712 | " ldr sp, =_stub_stack\n" | ||
713 | " ldr r0, =gdb_exception_no\n" | ||
714 | " mov r1, #5\n" | ||
715 | " str r1, [r0]\n" | ||
574 | " b gdb_loop_from_exc\n"); | 716 | " b gdb_loop_from_exc\n"); |