From 2aabc875bfb68142622e699fbb208bd808e2088f Mon Sep 17 00:00:00 2001 From: Tomasz Malesinski Date: Wed, 25 Jan 2006 01:43:07 +0000 Subject: GDB stub for ARM git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8447 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 4 + firmware/crt0.S | 13 +- gdb/Makefile | 65 ++++++- gdb/SOURCES | 3 + gdb/arm-stub.c | 574 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/linker.cfg | 64 ++++++- 6 files changed, 720 insertions(+), 3 deletions(-) create mode 100644 gdb/SOURCES create mode 100644 gdb/arm-stub.c diff --git a/firmware/SOURCES b/firmware/SOURCES index 3a5f551585..dbfa102ceb 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -170,3 +170,7 @@ replaygain.c pcm_record.c #endif sound.c +#if defined(IRIVER_IFP7XX_SERIES) && defined(STUB) +common/sscanf.c +usb_serial.c +#endif diff --git a/firmware/crt0.S b/firmware/crt0.S index ba478f804c..5946276604 100644 --- a/firmware/crt0.S +++ b/firmware/crt0.S @@ -93,6 +93,7 @@ remap_end: strhi r5, [r2], #4 bhi 1b +#ifndef STUB /* Zero out IBSS */ ldr r2, =_iedata ldr r3, =_iend @@ -111,6 +112,7 @@ remap_end: ldrhi r5, [r2], #4 strhi r5, [r3], #4 bhi 1b +#endif /* !STUB */ #endif /* !BOOTLOADER */ /* Initialise bss section to zero */ @@ -283,8 +285,10 @@ vectors: .text +#ifndef STUB .global irq .global UIE +#endif /* All illegal exceptions call into UIE with exception address as first parameter. This is calculated differently depending on which exception @@ -317,11 +321,18 @@ data_abort_handler: b UIE irq_handler: +#ifndef STUB stmfd sp!, {r0-r3, r12, lr} bl irq ldmfd sp!, {r0-r3, r12, lr} +#endif subs pc, lr, #4 - + +#ifdef STUB +UIE: + b UIE +#endif + /* 256 words of IRQ stack */ .space 256*4 irq_stack: diff --git a/gdb/Makefile b/gdb/Makefile index 61f4cb838d..fa94eac9b1 100644 --- a/gdb/Makefile +++ b/gdb/Makefile @@ -7,6 +7,67 @@ # $Id$ # +ifeq ($(ARCHOS),ifp7xx) + +INCLUDES= -I$(FIRMDIR)/include -I$(FIRMDIR)/export -I. -I$(OBJDIR) \ + -I$(BUILDDIR) + +DEPFILE = $(OBJDIR)/dep-stub +LDS := linker.cfg + +SRC := $(shell cat SOURCES | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) -E -P -include "config.h" - ) +DIRS = . + +ifdef APPEXTRA + DIRS += $(subst :, ,$(APPEXTRA)) + INCLUDES += $(patsubst %,-I%,$(subst :, ,$(APPEXTRA))) +endif + +ifndef VERSION +VERSION=$(shell date +%y%m%d-%H%M) +endif + +CFLAGS = $(GCCOPTS) $(INCLUDES) $(TARGET) $(DEFINES) \ + -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} + +OBJS := $(SRC:%.c=$(OBJDIR)/%.o) +SOURCES = $(SRC) +LINKFILE = $(OBJDIR)/linkage.lds + +LIBROCKBOX = $(BUILDDIR)/librockbox.a + +all: $(BUILDDIR)/$(BINARY) $(FLASHFILE) + +dep: $(DEPFILE) + +$(LINKFILE): $(LDS) + @echo "Build LDS file" + @cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) -E -P $(ROMBUILD) - >$@ + +$(OBJDIR)/stub.elf : $(OBJS) $(LINKFILE) $(DEPFILE) $(LIBROCKBOX) + @echo "LD stub.elf" + @$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJS) -L$(BUILDDIR) -L$(BUILDDIR)/firmware -lrockbox -lgcc -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/stub.map + +$(OBJDIR)/stub.bin : $(OBJDIR)/stub.elf + @echo "OBJCOPY $<" + @$(OC) -O binary $< $@ + +$(BUILDDIR)/$(BINARY) : $(OBJDIR)/stub.bin + @echo "Build stub file" + $(MKFIRMWARE) $< $@ + +include $(TOOLSDIR)/make.inc + +clean: + @echo "cleaning stub" + @-rm -f $(OBJS) $(BUILDDIR)/$(BINARY) \ + $(OBJDIR)/stub.bin $(OBJDIR)/stub.elf $(OBJDIR)/*.map \ + $(LINKFILE) $(DEPFILE) + +-include $(DEPFILE) + +else # not ifp7xx + ifdef RECORDER EXTRA = -DRECORDER EXT = ajz @@ -38,6 +99,8 @@ $(TARGET).elf: $(OBJS) clean: rm $(OBJS) $(TARGET).map $(TARGET).elf $(TARGET).out $(TARGET).mod $(TARGET).ajz -start.o: start.S +start.o: start.s sh-stub.o: sh-stub.c setjmp.o: setjmp.S + +endif diff --git a/gdb/SOURCES b/gdb/SOURCES new file mode 100644 index 0000000000..9668d12dc8 --- /dev/null +++ b/gdb/SOURCES @@ -0,0 +1,3 @@ +#ifdef CPU_ARM +arm-stub.c +#endif 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Tomasz Malesinski + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include "usb_serial.h" +#include "sscanf.h" + +#define BUFMAX 1024 + +#define VEC_UND 1 +#define VEC_SWI 2 +#define VEC_PABT 3 +#define VEC_DABT 4 + +static char packet_buf[BUFMAX]; +static char reply_buf[BUFMAX]; + +static const char hexchars[] = "0123456789abcdef"; +static int gdb_exception_no, gdb_mem_access; +static unsigned long registers[17]; + +static inline bool isxdigit(char c) +{ + return ((c >= '0') && (c <= '9')) + || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')); +} + +static int hex(char ch) { + if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + if ((ch >= 'A') && (ch <= 'F')) + return ch - 'A' + 10; + return -1; +} + +static void hex_byte(char *s, int byte) { + s[0] = hexchars[(byte >> 4) & 0xf]; + s[1] = hexchars[byte & 0xf]; +} + +static void hex_word(char *s, unsigned long val) { + int i; + for (i = 0; i < 4; i++) + hex_byte(s + i * 2, (val >> (i * 8)) & 0xff); +} + +static void hex_string(char *d, char *s) { + while (*s) { + hex_byte(d, *s++); + d += 2; + } + *d = 0; +} + +static int get_hex_byte(char *s) { + return (hex(s[0]) << 4) + hex(s[1]); +} + +static unsigned long get_hex_word(char *s) { + int i; + unsigned long r = 0; + for (i = 3; i >= 0; i--) + r = (r << 8) + get_hex_byte(s + i * 2); + return r; +} + +static void reply_error(int n, char *reply) { + reply[0] = 'E'; + hex_byte(reply + 1, n); + reply[3] = 0; +} + +static void reply_signal(int n, char *reply) { + int signal; + reply[0] = 'S'; + switch (n) + { + case VEC_UND: + signal = 4; + break; + case VEC_PABT: + case VEC_DABT: + signal = 7; + break; + default: + signal = 5; + break; + } + hex_byte(reply + 1, signal); + reply[3] = 0; +} + +static void reply_ok(char *reply) { + strcpy(reply, "OK"); +} + +static void serial_write(unsigned char *buf, int len) { + int i; + for (i = 0; i < len; i++) + usb_serial_put_byte(buf[i]); +} + +static void get_packet(char *buf, int len) { + int count, checksum; + int ch; + + while (1) { + do { + ch = usb_serial_get_byte(); + } while (ch != '$'); + + checksum = 0; + count = 0; + while (count < len) { + ch = usb_serial_get_byte(); + if (ch == '$') { + checksum = 0; + count = 0; + } else if (ch == '#') + break; + else { + checksum += ch; + buf[count] = ch; + count++; + } + } + buf[count] = 0; + + if (ch == '#') { + int rchksum; + + ch = usb_serial_get_byte(); + rchksum = hex(ch) << 4; + ch = usb_serial_get_byte(); + rchksum += hex(ch); + + if ((checksum & 0xff) != rchksum) + usb_serial_put_byte('-'); + else { + usb_serial_put_byte('+'); + return; + } + } + } +} + +static void put_packet(char *buf) { + int i, checksum; + int ch; + char tmp[3]; + + do { + usb_serial_put_byte('$'); + + checksum = 0; + for (i = 0; buf[i]; i++) + checksum += buf[i]; + + serial_write(buf, i); + + tmp[0] = '#'; + hex_byte(tmp + 1, checksum & 0xff); + serial_write(tmp, 3); + + ch = usb_serial_get_byte(); + + } while (ch != '+'); +} + +static inline unsigned long get_general_reg(int n) +{ + return registers[n + 1]; +} + +static inline void set_general_reg(int n, unsigned long v) +{ + registers[n + 1] = v; +} + +static inline unsigned long get_cpsr(void) +{ + return registers[0]; +} + +static inline void set_cpsr(unsigned long v) +{ + registers[0] = v; +} + +static void g_reply(char *buf) { + int i; + char *p; + + p = buf; + for (i = 0; i < 16; i++) { + hex_word(p, get_general_reg(i)); + p += 8; + } + + for (i = 0; i < 8; i++) { + memset(p, '0', 16); + p += 16; + } + + hex_word(p, 0); + p += 8; + hex_word(p, get_cpsr()); + p[8] = 0; +} + +static void cmd_get_register(char *args, char *reply) { + int r; + + if (sscanf(args, "%x", &r) != 1) { + reply_error(0, reply); + return; + } + + if (r >= 0 && r < 16) { + hex_word(reply, get_general_reg(r)); + reply[8] = 0; + } else if (r == 25) { + hex_word(reply, get_cpsr()); + reply[8] = 0; + } else { + hex_word(reply, 0); + reply[8] = 0; + } +} + +static void cmd_set_register(char *args, char *reply) { + int r, p; + unsigned long v; + + p = -1; + sscanf(args, "%x=%n", &r, &p); + if (p == -1) { + reply_error(0, reply); + return; + } + + v = get_hex_word(args + p); + if (r >= 0 && r < 16) + set_general_reg(r, v); + else if (r == 25) + set_cpsr(v); + reply_ok(reply); +} + +static void cmd_set_registers(char *args, char *reply) { + char *p; + int i, len; + + len = strlen(args); + + p = args; + for (i = 0; i < 16 && len >= (i + 1) * 8; i++) { + set_general_reg(i, get_hex_word(p)); + p += 8; + } + + if (len >= 16 * 8 + 8 * 16 + 2 * 8) + { + p += 8 * 16 + 8; + set_cpsr(get_hex_word(p)); + } + + reply_ok(reply); +} + +static void cmd_get_memory(char *args, char *reply) { + unsigned long addr, len, i; + + if (sscanf(args, "%lx,%lx", &addr, &len) != 2) { + reply_error(0, reply); + return; + } + + if (len > (BUFMAX - 16) / 2) { + reply_error(1, reply); + return; + } + + gdb_mem_access = 1; + for (i = 0; i < len; i++) + hex_byte(reply + i * 2, *((unsigned char *)(addr + i))); + gdb_mem_access = 0; + + reply[len * 2] = 0; +} + +static void cmd_put_memory(char *args, char *reply) { + unsigned long addr, len, i; + int pos; + + pos = -1; + sscanf(args, "%lx,%lx:%n", &addr, &len, &pos); + if (pos == -1) { + reply_error(0, reply); + return; + } + + gdb_mem_access = 1; + for (i = 0; i < len; i++) + *((unsigned char *)(addr + i)) = get_hex_byte(args + pos + i * 2); + gdb_mem_access = 0; + + reply_ok(reply); +} + +static void parse_continue_args(char *args) { + int sig; + unsigned long addr; + + if (sscanf(args, "%x;%lx", &sig, &addr) == 2) { + set_general_reg(15, addr); + } else if (sscanf(args, "%lx", &addr) == 1) { + set_general_reg(15, addr); + } +} + +static void cmd_go(char *args) { + parse_continue_args(args); + + asm volatile( + " mov r1, %0\n" + " ldr r12, [r1], #4\n" + " mov r0, r12\n" + " and r0, r0, #0x1f\n" + " cmp r0, #0x10\n" + " bne 1f\n" + " ldr r14, [r1, #60]\n" + " msr spsr_fsxc, r12\n" + " ldmia r1, {r0-r14}^\n" + " movs r15, r14\n" + "1:\n" + " msr cpsr_fsxc, r12\n" + " ldmia r1, {r0-r15}\n" + : : "r" (registers)); +} + +static void remote_cmd(char *cmd, char *reply) { + (void)cmd; + hex_string(reply, "Unrecognized command\n"); +} + +static void cmd_query(char *args, char *reply) { + if (!strncmp(args, "Rcmd,", 5)) { + unsigned i = 0; + char *s = args + 5; + char cmd[200]; + while (isxdigit(s[0]) && isxdigit(s[1]) && i < sizeof(cmd) - 1) { + cmd[i++] = get_hex_byte(s); + s += 2; + } + cmd[i] = 0; + remote_cmd(cmd, reply); + } else + reply[0] = 0; +} + +void gdb_loop(void) { + int no_reply; + + gdb_mem_access = 0; + + while (1) { + get_packet(packet_buf, sizeof(packet_buf) - 1); + + no_reply = 0; + switch (packet_buf[0]) { + case '?': + reply_signal(gdb_exception_no, reply_buf); + break; + + case 'p': + cmd_get_register(packet_buf + 1, reply_buf); + break; + + case 'P': + cmd_set_register(packet_buf + 1, reply_buf); + break; + + case 'g': + g_reply(reply_buf); + break; + + case 'G': + cmd_set_registers(packet_buf + 1, reply_buf); + break; + + case 'm': + cmd_get_memory(packet_buf + 1, reply_buf); + break; + + case 'M': + cmd_put_memory(packet_buf + 1, reply_buf); + break; + + case 'q': + cmd_query(packet_buf + 1, reply_buf); + break; + + case 'c': + cmd_go(packet_buf + 1); + reply_error(1, reply_buf); + break; + +/* case 's': */ +/* cmd_go(packet_buf + 1); */ +/* break; */ + + default: + reply_buf[0] = 0; + } + + if (!no_reply) + put_packet(reply_buf); + } +} + +extern void *vectors[]; + +static void gdb_set_vector(int n, void *p) +{ + vectors[n] = p; +} + +void gdb_und_exc(void); +void gdb_swi_exc(void); +void gdb_pabt_exc(void); +void gdb_dabt_exc(void); + +static void gdb_set_vectors(void) +{ + gdb_set_vector(VEC_UND, gdb_und_exc); + gdb_set_vector(VEC_SWI, gdb_swi_exc); + gdb_set_vector(VEC_PABT, gdb_pabt_exc); + gdb_set_vector(VEC_DABT, gdb_dabt_exc); +} + +void gdb_loop_from_exc(void) +{ + if (gdb_mem_access) + reply_error(1, reply_buf); + else + reply_signal(gdb_exception_no, reply_buf); + put_packet(reply_buf); + gdb_loop(); +} + +#define GPIO3_CLR (*(volatile unsigned long *)0x800030d8) + +#define IRQ_REG(reg) (*(volatile unsigned long *)(0x80300000 + (reg))) + +static inline unsigned long irq_read(int reg) +{ + unsigned long v, v2; + do + { + v = IRQ_REG(reg); + v2 = IRQ_REG(reg); + } while (v != v2); + return v; +} + +#define IRQ_WRITE_WAIT(reg, val, cond) \ + do { unsigned long v, v2; \ + do { \ + IRQ_REG(reg) = (val); \ + v = IRQ_REG(reg); \ + v2 = IRQ_REG(reg); \ + } while ((v != v2) || !(cond)); \ + } while (0); + +static void system_init(void) +{ + int i; + + /* turn off watchdog */ + (*(volatile unsigned long *)0x80002804) = 0; + + for (i = 0; i < 0x1c; i++) + { + IRQ_WRITE_WAIT(0x404 + i * 4, 0x1e000001, (v & 0x3010f) == 1); + IRQ_WRITE_WAIT(0x404 + i * 4, 0x4000000, (v & 0x10000) == 0); + IRQ_WRITE_WAIT(0x404 + i * 4, 0x10000001, (v & 0xf) == 1); + } + + GPIO3_CLR = 1; +} + +void main(void) +{ + system_init(); + usb_serial_init(); + gdb_exception_no = VEC_SWI; + gdb_set_vectors(); + gdb_loop(); +} + +#define str(s) #s +#define xstr(s) str(s) + +asm (".text\n" + "gdb_und_exc:\n" + " ldr sp, =_stub_stack\n" + " sub r14, r14, #4\n" + " stmfd sp!, {r0-r3, r12, r14}\n" + " mov r0, #" xstr(VEC_UND) "\n" + " b gdb_handle_exception\n" + "gdb_swi_exc:\n" + " ldr sp, =_stub_stack\n" + " stmfd sp!, {r0-r3, r12, r14}\n" + " mov r0, #" xstr(VEC_SWI) "\n" + " b gdb_handle_exception\n" + "gdb_pabt_exc:\n" + " ldr sp, =_stub_stack\n" + " stmfd sp!, {r0-r3, r12, r14}\n" + " mov r0, #" xstr(VEC_PABT) "\n" + " b gdb_handle_exception\n" + "gdb_dabt_exc:\n" + " ldr sp, =_stub_stack\n" + " sub r14, r14, #4\n" + " stmfd sp!, {r0-r3, r12, r14}\n" + " ldr r0, =gdb_mem_access\n" + " ldr r0, [r0]\n" + " tst r0, r0\n" + " bne gdb_data_abort\n" + " mov r0, #" xstr(VEC_DABT) "\n" + " b gdb_handle_exception\n" + "gdb_handle_exception:\n" + " ldr r1, =gdb_exception_no\n" + " str r0, [r1]\n" + " ldr r0, =registers\n" + " mrs r12, spsr\n" + " str r12, [r0], #4\n" + " ldmfd sp!, {r2, r3}\n" + " stmia r0!, {r2, r3}\n" + " ldmfd sp!, {r2, r3, r12, r14}\n" + " str r14, [r0, #52]\n" + " stmia r0!, {r2-r12}\n" + " mrs r1, spsr\n" + " and r2, r1, #0x1f\n" + " cmp r2, #0x10\n" + " bne 1f\n" + " stmia r0, {r13, r14}^\n" + " b gdb_data_abort\n" + "1:\n" + " msr cpsr_c, r1\n" + " stmia r0, {r13, r14}\n" + "gdb_data_abort:\n" + " msr cpsr_c, #0xd3\n" + " ldr sp, =_stub_stack\n" + " b gdb_loop_from_exc\n"); diff --git a/gdb/linker.cfg b/gdb/linker.cfg index 5d5334b92f..2cc6a0e9b4 100644 --- a/gdb/linker.cfg +++ b/gdb/linker.cfg @@ -1,5 +1,65 @@ +#include "config.h" + +#ifdef CPU_ARM +ENTRY(start) +STARTUP(crt0.o) +OUTPUT_FORMAT(elf32-littlearm) +#else ENTRY(_start) OUTPUT_FORMAT(elf32-sh) +#endif + +#ifdef IRIVER_IFP7XX_SERIES +MEMORY +{ + IRAM : ORIGIN = 0, LENGTH = 0x10000 + DRAM : ORIGIN = 0x24000000, LENGTH = 0x8000 +} + +SECTIONS +{ + .text : + { + *(.init*) + *(.text) + *(.text*) + *(.rodata) + *(.rodata*) + *(.glue_7) + *(.glue_7t) + } >DRAM + + .data : + { + *(.data) + } >DRAM + + .vectors : + { + _vectorsstart = .; + *(.vectors) + _vectorsend = .; + } >IRAM AT>DRAM + _vectorscopy = LOADADDR(.vectors); + + .stack (NOLOAD) : + { + stackbegin = .; + . += 0x400; + _stub_stack = .; + . += 0x200; + stackend = .; + } >DRAM + + .bss (NOLOAD) : + { + _edata = .; + *(.bss) + _end = .; + } >DRAM +} +#else + SECTIONS { .vectors 0x09000000 : @@ -25,4 +85,6 @@ SECTIONS { LONG(0); } - } +} + +#endif -- cgit v1.2.3