diff --git a/cpu/at91sam7s/Makefile.at91sam7s b/cpu/at91sam7s/Makefile.at91sam7s index 0a262c315..5a0dce74c 100644 --- a/cpu/at91sam7s/Makefile.at91sam7s +++ b/cpu/at91sam7s/Makefile.at91sam7s @@ -30,7 +30,7 @@ CONTIKIDIRS=$(CONTIKI)/core/sys:$(CONTIKI)/core/dev:$(CONTIKI)/core/cfs:$(CONTIK ### Compiler definitions CC = arm-elf-gcc -LD = arm-elf-gcc +LD = arm-elf-ld AS = arm-elf-as AR = arm-elf-ar NM = arm-elf-nm @@ -55,7 +55,8 @@ THUMB_FLAGS=-mthumb -mthumb-interwork ARM_FLAGS=-mthumb-interwork -CFLAGSNO = -I. -I$(CONTIKI)/core -I$(CONTIKI_CPU) \ +CFLAGSNO = -I. -I$(CONTIKI)/core -I$(CONTIKI_CPU) -I$(CONTIKI_CPU)/loader \ + -I$(CONTIKI_CPU)/dbg-io\ -I$(CONTIKI)/platform/$(TARGET) \ ${addprefix -I,$(APPDIRS)} \ -DWITH_UIP -DWITH_ASCII -DMCK=$(MCK) \ @@ -73,7 +74,7 @@ CONTIKI_TARGET_DIRS_CONCAT = ${addprefix $(CONTIKI)/platform/$(TARGET)/, \ vpath %.c $(PROJECTDIRS) \ $(CONTIKIDIRS) $(APPDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \ - $(CONTIKI_CPU) + $(CONTIKI_CPU) $(CONTIKI_CPU)/loader $(CONTIKI_CPU)/dbg-io vpath %.S $(CONTIKI_CPU) @@ -96,8 +97,6 @@ interrupt-utils.o: interrupt-utils.c $(LD) --relocatable -T $(CONTIKI_CPU)/merge-rodata.ld $< -o $@ $(STRIP) -K _init -K _fini --strip-unneeded -g -x $@ -%.elf: $^ $(STARTUP) - $(CC) $(LDFLAGS) $(CFLAGS) $(THUMB_FLAGS) -nostartfiles -o $@ $^ # Add a namelist to the kernel %-syms.elf: $^ $(STARTUP) @@ -107,6 +106,8 @@ interrupt-utils.o: interrupt-utils.c -test -r $*.exclude && grep -v -f $*.exclude $*-nm.c >$*-tmp.c && mv $*-tmp.c $*-nm.c $(CC) $(LDFLAGS) $(CFLAGS) $(THUMB_FLAGS) -nostartfiles -o $*-syms.elf $^ $*-nm.c +%.elf: $^ $(STARTUP) + $(CC) $(LDFLAGS) $(CFLAGS) $(THUMB_FLAGS) -nostartfiles -o $@ $^ %.ihx: %.elf $(OBJCOPY) -O ihex $< $@ @@ -137,3 +138,4 @@ clean: -rm *.ihx -rm *.bin -rm *-nm.c + -rm *.ko diff --git a/cpu/at91sam7s/dbg-io/dbg-printf.c b/cpu/at91sam7s/dbg-io/dbg-printf.c new file mode 100644 index 000000000..5fee17689 --- /dev/null +++ b/cpu/at91sam7s/dbg-io/dbg-printf.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +StrFormatResult +write_str(void *user_data, const char *data, unsigned int len) +{ + dbg_send_bytes((unsigned char*)data, len); + return STRFORMAT_OK; +} + + +static StrFormatContext ctxt = + { + write_str, + NULL + }; +int +printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + return format_str_v(&ctxt, fmt, ap); + va_end(ap); +} + + diff --git a/cpu/at91sam7s/dbg-io/dbg-putchar.c b/cpu/at91sam7s/dbg-io/dbg-putchar.c new file mode 100644 index 000000000..54f3db53f --- /dev/null +++ b/cpu/at91sam7s/dbg-io/dbg-putchar.c @@ -0,0 +1,26 @@ +#include +#include +#include + +#undef putchar +#undef putc + +int +putchar(int c) +{ + dbg_putchar(c); + return c; +} + +int +putc(int c, FILE *f) +{ + dbg_putchar(c); + return c; +} + +int +__sp(struct _reent *_ptr, int c, FILE *_p) { + dbg_putchar(c); + return c; +} diff --git a/cpu/at91sam7s/dbg-io/dbg-puts.c b/cpu/at91sam7s/dbg-io/dbg-puts.c new file mode 100644 index 000000000..fa90d1022 --- /dev/null +++ b/cpu/at91sam7s/dbg-io/dbg-puts.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int +puts(const char *str) +{ + dbg_send_bytes((unsigned char*)str, strlen(str)); + dbg_putchar('\n'); + return 0; +} diff --git a/cpu/at91sam7s/dbg-io/strformat.c b/cpu/at91sam7s/dbg-io/strformat.c new file mode 100644 index 000000000..460f00a2d --- /dev/null +++ b/cpu/at91sam7s/dbg-io/strformat.c @@ -0,0 +1,615 @@ +#include + +#define HAVE_DOUBLE + +#define HAVE_LONGLONG +#ifndef LARGEST_SIGNED +#ifdef HAVE_LONGLONG +#define LARGEST_SIGNED long long int +#else +#define LARGEST_UNSIGNED long int +#endif +#endif + +#ifndef LARGEST_UNSIGNED +#ifdef HAVE_LONGLONG +#define LARGEST_UNSIGNED unsigned long long int +#else +#define LARGEST_UNSIGNED unsigned long int +#endif +#endif + +#ifndef POINTER_INT +#define POINTER_INT unsigned long +#endif + +typedef unsigned int FormatFlags; + +#define MAKE_MASK(shift,size) (((1 << size) - 1) << (shift)) + +#define JUSTIFY_SHIFT 0 +#define JUSTIFY_SIZE 1 +#define JUSTIFY_RIGHT 0x0000 +#define JUSTIFY_LEFT 0x0001 +#define JUSTIFY_MASK MAKE_MASK(JUSTIFY_SHIFT,JUSTIFY_SIZE) + + +/* How a positive number is prefixed */ +#define POSITIVE_SHIFT (JUSTIFY_SHIFT + JUSTIFY_SIZE) +#define POSITIVE_NONE (0x0000 << POSITIVE_SHIFT) +#define POSITIVE_SPACE (0x0001 << POSITIVE_SHIFT) +#define POSITIVE_PLUS (0x0003 << POSITIVE_SHIFT) +#define POSITIVE_MASK MAKE_MASK(POSITIVE_SHIFT, POSITIVE_SIZE) + +#define POSITIVE_SIZE 2 + +#define ALTERNATE_FORM_SHIFT (POSITIVE_SHIFT + POSITIVE_SIZE) +#define ALTERNATE_FORM_SIZE 1 +#define ALTERNATE_FORM (0x0001 << ALTERNATE_FORM_SHIFT) + + +#define PAD_SHIFT (ALTERNATE_FORM_SHIFT + ALTERNATE_FORM_SIZE) +#define PAD_SIZE 1 +#define PAD_SPACE (0x0000 << PAD_SHIFT) +#define PAD_ZERO (0x0001 << PAD_SHIFT) + +#define SIZE_SHIFT (PAD_SHIFT + PAD_SIZE) +#define SIZE_SIZE 3 +#define SIZE_CHAR (0x0001 << SIZE_SHIFT) +#define SIZE_SHORT (0x0002 << SIZE_SHIFT) +#define SIZE_INT (0x0000 << SIZE_SHIFT) +#define SIZE_LONG (0x0003 << SIZE_SHIFT) +#define SIZE_LONGLONG (0x0004 << SIZE_SHIFT) +#define SIZE_MASK MAKE_MASK(SIZE_SHIFT,SIZE_SIZE) + +#define CONV_SHIFT (SIZE_SHIFT + SIZE_SIZE) +#define CONV_SIZE 3 +#define CONV_INTEGER (0x0001 << CONV_SHIFT) +#define CONV_FLOAT (0x0002 << CONV_SHIFT) +#define CONV_POINTER (0x0003 << CONV_SHIFT) +#define CONV_STRING (0x0004 << CONV_SHIFT) +#define CONV_CHAR (0x0005 << CONV_SHIFT) +#define CONV_PERCENT (0x0006 << CONV_SHIFT) +#define CONV_WRITTEN (0x0007 << CONV_SHIFT) +#define CONV_MASK MAKE_MASK(CONV_SHIFT, CONV_SIZE) + +#define RADIX_SHIFT (CONV_SHIFT + CONV_SIZE) +#define RADIX_SIZE 2 +#define RADIX_DECIMAL (0x0001 << RADIX_SHIFT) +#define RADIX_OCTAL (0x0002 << RADIX_SHIFT) +#define RADIX_HEX (0x0003 << RADIX_SHIFT) +#define RADIX_MASK MAKE_MASK(RADIX_SHIFT,RADIX_SIZE) + +#define SIGNED_SHIFT (RADIX_SHIFT + RADIX_SIZE) +#define SIGNED_SIZE 1 +#define SIGNED_NO (0x0000 << SIGNED_SHIFT) +#define SIGNED_YES (0x0001 << SIGNED_SHIFT) +#define SIGNED_MASK MAKE_MASK(SIGNED_SHIFT,SIGNED_SIZE) + +#define CAPS_SHIFT (SIGNED_SHIFT + SIGNED_SIZE) +#define CAPS_SIZE 1 +#define CAPS_NO (0x0000 << CAPS_SHIFT) +#define CAPS_YES (0x0001 << CAPS_SHIFT) +#define CAPS_MASK MAKE_MASK(CAPS_SHIFT,CAPS_SIZE) + +#define FLOAT_SHIFT (CAPS_SHIFT + CAPS_SIZE) +#define FLOAT_SIZE 2 +#define FLOAT_NORMAL (0x0000 << FLOAT_SHIFT) +#define FLOAT_EXPONENT (0x0001 << FLOAT_SHIFT) +#define FLOAT_DEPENDANT (0x0002 << FLOAT_SHIFT) +#define FLOAT_HEX (0x0003 << FLOAT_SHIFT) +#define FLOAT_MASK MAKE_MASK(FLOAT_SHIFT, FLOAT_SIZE) + +static FormatFlags +parse_flags(const char **posp) +{ + FormatFlags flags = 0; + const char *pos = *posp; + while (1) { + switch(*pos) { + case '-': + flags |= JUSTIFY_LEFT; + break; + case '+': + flags |= POSITIVE_PLUS; + break; + case ' ': + flags |= POSITIVE_SPACE; + break; + case '#': + flags |= ALTERNATE_FORM; + break; + case '0': + flags |= PAD_ZERO; + break; + default: + *posp = pos; + return flags; + } + pos++; + } + +} + +static unsigned int +parse_uint(const char **posp) +{ + unsigned v = 0; + const char *pos = *posp; + char ch; + while((ch = *pos) >= '0' && ch <= '9') { + v = v * 10 + (ch - '0'); + pos++; + } + *posp = pos; + return v; +} + +#define MAXCHARS_HEX ((sizeof(LARGEST_UNSIGNED) * 8) / 4 ) + +/* Largest number of characters needed for converting an unsigned integer. + */ +#define MAXCHARS ((sizeof(LARGEST_UNSIGNED) * 8 + 2) / 3 ) + +static unsigned int +output_uint_decimal(char **posp, LARGEST_UNSIGNED v) +{ + unsigned int len; + char *pos = *posp; + while (v > 0) { + *--pos = (v % 10) + '0'; + v /= 10; + } + len = *posp - pos; + *posp = pos; + return len; +} + +static unsigned int +output_uint_hex(char **posp, LARGEST_UNSIGNED v, unsigned int flags) +{ + unsigned int len; + const char *hex = (flags & CAPS_YES) ?"0123456789ABCDEF":"0123456789abcdef"; + char *pos = *posp; + while (v > 0) { + *--pos = hex[(v % 16)]; + v /= 16; + } + len = *posp - pos; + *posp = pos; + return len; +} + +static unsigned int +output_uint_octal(char **posp, LARGEST_UNSIGNED v) +{ + unsigned int len; + char *pos = *posp; + while (v > 0) { + *--pos = (v % 8) + '0'; + v /= 8; + } + len = *posp - pos; + *posp = pos; + return len; +} + +static StrFormatResult +fill_space(const StrFormatContext *ctxt, unsigned int len) +{ + StrFormatResult res; + static const char buffer[16] = " "; + while(len > 16) { + res = ctxt->write_str(ctxt->user_data, buffer, 16); + if (res != STRFORMAT_OK) return res; + len -= 16; + } + if (len == 0) return STRFORMAT_OK; + return ctxt->write_str(ctxt->user_data, buffer, len); +} + +static StrFormatResult +fill_zero(const StrFormatContext *ctxt, unsigned int len) +{ + StrFormatResult res; + static const char buffer[16] = "0000000000000000"; + while(len > 16) { + res = ctxt->write_str(ctxt->user_data, buffer, 16); + if (res != STRFORMAT_OK) return res; + len -= 16; + } + if (len == 0) return STRFORMAT_OK; + return ctxt->write_str(ctxt->user_data, buffer, len); +} + +#define CHECKCB(res) {if ((res) != STRFORMAT_OK) {va_end(ap); return -1;}} + +int +format_str(const StrFormatContext *ctxt, const char *format, ...) +{ + int ret; + va_list ap; + va_start(ap, format); + ret = format_str_v(ctxt, format, ap); + va_end(ap); + return ret; +} + +int +format_str_v(const StrFormatContext *ctxt, const char *format, va_list ap) +{ + unsigned int written = 0; + const char *pos = format; + while(*pos != '\0') { + FormatFlags flags; + unsigned int minwidth = 0; + int precision = -1; /* Negative means no precision */ + char ch; + const char *start = pos; + while( (ch = *pos) != '\0' && ch != '%') pos++; + if (pos != start) { + CHECKCB(ctxt->write_str(ctxt->user_data, start, pos - start)); + written += pos - start; + } + if (*pos == '\0') { + va_end(ap); + return written; + } + pos++; + if (*pos == '\0') { + va_end(ap); + return written; + } + flags = parse_flags(&pos); + + /* parse width */ + if (*pos >= '1' && *pos <= '9') { + minwidth = parse_uint(&pos); + } else if (*pos == '*') { + int w = va_arg(ap,int); + if (w < 0) { + flags |= JUSTIFY_LEFT; + minwidth = w; + } else { + minwidth = w; + } + pos ++; + } + + /* parse precision */ + if (*pos == '.') { + pos++; + if (*pos >= '0' && *pos <= '9') { + precision = parse_uint(&pos); + } else if (*pos == '*') { + precision = va_arg(ap,int); + } + } + if (*pos == 'l') { + pos++; + if (*pos == 'l') { + flags |= SIZE_LONGLONG; + pos++; + } else { + flags |= SIZE_LONG; + } + } else if (*pos == 'h') { + pos++; + if (*pos == 'h') { + flags |= SIZE_CHAR; + pos++; + } else { + flags |= SIZE_SHORT; + } + } + + /* parse conversion specifier */ + switch(*pos) { + case 'd': + case 'i': + flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_YES; + break; + case 'u': + flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_NO; + break; + case 'o': + flags |= CONV_INTEGER | RADIX_OCTAL | SIGNED_NO; + break; + case 'x': + flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO; + break; + case 'X': + flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO | CAPS_YES; + break; +#ifdef HAVE_DOUBLE + case 'f': + flags |= CONV_FLOAT | FLOAT_NORMAL; + break; + case 'F': + flags |= CONV_FLOAT | FLOAT_NORMAL | CAPS_YES; + break; + case 'e': + flags |= CONV_FLOAT | FLOAT_EXPONENT; + break; + case 'E': + flags |= CONV_FLOAT | FLOAT_EXPONENT | CAPS_YES; + break; + case 'g': + flags |= CONV_FLOAT | FLOAT_DEPENDANT; + break; + case 'G': + flags |= CONV_FLOAT | FLOAT_DEPENDANT | CAPS_YES; + break; + case 'a': + flags |= CONV_FLOAT | FLOAT_HEX; + break; + case 'A': + flags |= CONV_FLOAT | FLOAT_HEX | CAPS_YES; + break; +#endif + case 'c': + flags |= CONV_CHAR; + break; + case 's': + flags |= CONV_STRING; + break; + case 'p': + flags |= CONV_POINTER; + break; + case 'n': + flags |= CONV_WRITTEN; + break; + case '%': + flags |= CONV_PERCENT; + break; + case '\0': + va_end(ap); + return written; + } + pos++; + switch(flags & CONV_MASK) { + case CONV_PERCENT: + CHECKCB(ctxt->write_str(ctxt->user_data, "%", 1)); + written++; + break; + case CONV_INTEGER: + { + /* unsigned integers */ + char *prefix = 0; /* sign, "0x" or "0X" */ + unsigned int prefix_len = 0; + char buffer[MAXCHARS]; + char *conv_pos = buffer + MAXCHARS; + unsigned int conv_len = 0; + unsigned int width = 0; + unsigned int precision_fill; + unsigned int field_fill; + LARGEST_UNSIGNED uvalue = 0; + int negative = 0; + + if (precision < 0) precision = 1; + else flags &= ~PAD_ZERO; + + if (flags & SIGNED_YES) { + /* signed integers */ + LARGEST_SIGNED value = 0; + switch(flags & SIZE_MASK) { + case SIZE_CHAR: + value = (signed char)va_arg(ap, int); + break; + case SIZE_SHORT: + value = (short)va_arg(ap, int); + break; + case SIZE_INT: + value = va_arg(ap, int); + break; +#ifndef HAVE_LONGLONG + case SIZE_LONGLONG: /* Treat long long the same as long */ +#endif + case SIZE_LONG: + value = va_arg(ap, long); + break; +#ifdef HAVE_LONGLONG + case SIZE_LONGLONG: + value = va_arg(ap, long long); + break; +#endif + } + if (value < 0) { + uvalue = -value; + negative = 1; + } else { + uvalue = value; + } + } else { + + switch(flags & SIZE_MASK) { + case SIZE_CHAR: + uvalue = (unsigned char)va_arg(ap,unsigned int); + break; + case SIZE_SHORT: + uvalue = (unsigned short)va_arg(ap,unsigned int); + break; + case SIZE_INT: + uvalue = va_arg(ap,unsigned int); + break; +#ifndef HAVE_LONGLONG + case SIZE_LONGLONG: /* Treat long long the same as long */ +#endif + case SIZE_LONG: + uvalue = va_arg(ap,unsigned long); + break; +#ifdef HAVE_LONGLONG + case SIZE_LONGLONG: + uvalue = va_arg(ap,unsigned long long); + break; +#endif + } + } + + switch(flags & (RADIX_MASK)) { + case RADIX_DECIMAL: + conv_len = output_uint_decimal(&conv_pos,uvalue); + break; + case RADIX_OCTAL: + conv_len = output_uint_octal(&conv_pos,uvalue); + break; + case RADIX_HEX: + conv_len = output_uint_hex(&conv_pos,uvalue, flags); + break; + } + + width += conv_len; + precision_fill = (precision > conv_len) ? precision - conv_len : 0; + if ((flags & (RADIX_MASK | ALTERNATE_FORM)) + == (RADIX_OCTAL | ALTERNATE_FORM)) { + if (precision_fill < 1) precision_fill = 1; + } + + width += precision_fill; + + if ((flags & (RADIX_MASK | ALTERNATE_FORM)) + == (RADIX_HEX | ALTERNATE_FORM) && uvalue != 0) { + prefix_len = 2; + if (flags & CAPS_YES) { + prefix = "0X"; + } else { + prefix = "0x"; + } + } + + if (flags & SIGNED_YES) { + if (negative) { + prefix = "-"; + prefix_len = 1; + } else { + switch(flags & POSITIVE_MASK) { + case POSITIVE_SPACE: + prefix = " "; + prefix_len = 1; + break; + case POSITIVE_PLUS: + prefix = "+"; + prefix_len = 1; + break; + } + } + } + + width += prefix_len; + + field_fill = (minwidth > width) ? minwidth - width : 0; + + if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) { + if (flags & PAD_ZERO) { + precision_fill += field_fill; + } else { + CHECKCB(fill_space(ctxt,field_fill)); + } + } + + if (prefix_len > 0) + CHECKCB(ctxt->write_str(ctxt->user_data, prefix, prefix_len)); + written += prefix_len; + + CHECKCB(fill_zero(ctxt,precision_fill)); + written += prefix_len; + + CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos,conv_len)); + written += conv_len; + + if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) { + CHECKCB(fill_space(ctxt,field_fill)); + } + written += field_fill; + } + break; + case CONV_STRING: + { + unsigned int field_fill; + unsigned int len; + char *str = va_arg(ap,char *); + if (str) { + char *pos = str; + while(*pos != '\0') pos++; + len = pos - str; + } else { + str = "(null)"; + len = 6; + } + if (precision >= 0 && precision < len) len = precision; + field_fill = (minwidth > len) ? minwidth - len : 0; + if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) { + CHECKCB(fill_space(ctxt,field_fill)); + } + CHECKCB(ctxt->write_str(ctxt->user_data, str,len)); + written += len; + if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) { + CHECKCB(fill_space(ctxt,field_fill)); + } + written += field_fill; + } + break; + case CONV_POINTER: + { + LARGEST_UNSIGNED uvalue = + (LARGEST_UNSIGNED)(POINTER_INT)va_arg(ap,void *); + char buffer[MAXCHARS_HEX + 3]; + char *conv_pos = buffer + MAXCHARS_HEX+3; + unsigned int conv_len; + unsigned int field_fill; + + conv_len = output_uint_hex(&conv_pos,uvalue,flags); + if (conv_len == 0) { + *--conv_pos = '0'; + conv_len++; + } + *--conv_pos = 'x'; + *--conv_pos = '0'; + *--conv_pos = '#'; + conv_len += 3; + + field_fill = (minwidth > conv_len) ? minwidth - conv_len : 0; + + if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) { + CHECKCB(fill_space(ctxt,field_fill)); + } + + CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos,conv_len)); + written += conv_len; + + if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) { + CHECKCB(fill_space(ctxt,field_fill)); + } + written += field_fill; + } + break; + case CONV_CHAR: + { + char ch = va_arg(ap,int); + unsigned int field_fill = (minwidth > 1) ? minwidth - 1 : 0; + if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) { + CHECKCB(fill_space(ctxt,field_fill)); + written += field_fill; + } + + CHECKCB(ctxt->write_str(ctxt->user_data, &ch, 1)); + written++; + + if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) { + CHECKCB(fill_space(ctxt,field_fill)); + } + written+= field_fill; + } + break; + case CONV_WRITTEN: + { + int *p = va_arg(ap,int*); + *p = written; + } + break; + + } + } + + return written; +} diff --git a/cpu/at91sam7s/dbg-io/strformat.h b/cpu/at91sam7s/dbg-io/strformat.h new file mode 100644 index 000000000..d953c3e1e --- /dev/null +++ b/cpu/at91sam7s/dbg-io/strformat.h @@ -0,0 +1,25 @@ +#ifndef __STRFORMAT_H__ +#define __STRFORMAT_H__ + +#include + +#define STRFORMAT_OK 0 +#define STRFORMAT_FAILED 1 +typedef unsigned int StrFormatResult; + +/* The data argument may only be considered valid during the function call */ +typedef StrFormatResult (*StrFormatWrite)(void *user_data, const char *data, unsigned int len); + +typedef struct _StrFormatContext +{ + StrFormatWrite write_str; + void *user_data; +} StrFormatContext; + +int format_str(const StrFormatContext *ctxt, const char *format, ...) + __attribute__ ((__format__ (__printf__, 2,3))); + +int +format_str_v(const StrFormatContext *ctxt, const char *format, va_list ap); + +#endif /* __STRFORMAT_H__ */ diff --git a/cpu/at91sam7s/elfloader-arm.c b/cpu/at91sam7s/elfloader-arm.c index 56d9c7fb7..fd33adb9e 100644 --- a/cpu/at91sam7s/elfloader-arm.c +++ b/cpu/at91sam7s/elfloader-arm.c @@ -17,7 +17,7 @@ /* Adapted from elfloader-avr.c */ -void +int elfloader_arch_relocate(int input_fd, struct elfloader_output *output, unsigned int sectionoffset, @@ -25,7 +25,6 @@ elfloader_arch_relocate(int input_fd, struct elf32_rela *rela, char *addr) { unsigned int type; - unsigned char instr[4]; type = ELF32_R_TYPE(rela->r_info); @@ -46,6 +45,7 @@ elfloader_arch_relocate(int input_fd, break; case R_ARM_THM_CALL: { + uint16_t instr[2]; int32_t offset; char *base; cfs_read(input_fd, (char*)instr, 4); @@ -53,7 +53,24 @@ elfloader_arch_relocate(int input_fd, and I can't think of a case when doing a relative call to a non-symbol position */ base = sectionaddr + (rela->r_offset + 4); - if (((*(uint16_t*)(instr+2)) & 0x1800) == 0x0800) { + + if (((instr[1]) & 0xe800) == 0xe800) { + /* BL or BLX */ + if (((uint32_t)addr) & 0x1) { + /* BL */ + instr[1] |= 0x1800; + } else { +#if defined(__ARM_ARCH_4T__) + return ELFLOADER_UNHANDLED_RELOC; +#else + /* BLX */ + instr[1] &= ~0x1800; + instr[1] |= 0x0800; +#endif + } + } + /* Adjust address for BLX */ + if ((instr[1] & 0x1800) == 0x0800) { addr = (char*)((((uint32_t)addr) & 0xfffffffd) | (((uint32_t)base) & 0x00000002)); } @@ -62,17 +79,17 @@ elfloader_arch_relocate(int input_fd, PRINTF("elfloader-arm.c: offset %d too large for relative call\n", (int)offset); } - /* PRINTF("%p: %04x %04x offset: %d addr: %p\n", sectionaddr +rela->r_offset, *(uint16_t*)instr, *(uint16_t*)(instr+2), (int)offset, addr); */ - *(uint16_t*)instr = (*(uint16_t*)instr & 0xf800) | ((offset>>12)&0x07ff); - *(uint16_t*)(instr+2) = ((*(uint16_t*)(instr+2) & 0xf800) - | ((offset>>1)&0x07ff)); + /* PRINTF("%p: %04x %04x offset: %d addr: %p\n", sectionaddr +rela->r_offset, instr[0], instr[1], (int)offset, addr); */ + instr[0] = (instr[0] & 0xf800) | ((offset>>12)&0x07ff); + instr[1] = (instr[1] & 0xf800) | ((offset>>1)&0x07ff); elfloader_output_write_segment(output, (char*)instr, 4); - /* PRINTF("cfs_write: %04x %04x\n",*(uint16_t*)instr, *(uint16_t*)(instr+2)); */ + /* PRINTF("cfs_write: %04x %04x\n",instr[0], instr[1]); */ } break; default: PRINTF("elfloader-arm.c: unsupported relocation type %d\n", type); - break; + return ELFLOADER_UNHANDLED_RELOC; } + return ELFLOADER_OK; } diff --git a/cpu/at91sam7s/loader/codeprop-otf.c b/cpu/at91sam7s/loader/codeprop-otf.c new file mode 100644 index 000000000..38e6b421f --- /dev/null +++ b/cpu/at91sam7s/loader/codeprop-otf.c @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: codeprop-otf.c,v 1.1 2007/03/07 16:07:26 ksb Exp $ + */ + +/** \addtogroup esb + * @{ */ + +/** + * + * \file + * Code propagation and storage. + * \author + * Adam Dunkels + * + * This file implements a simple form of code propagation, which + * allows a binary program to be downloaded and propagated throughout + * a network of devices. + * + * Features: + * + * Commands: load code, start code + * Point-to-point download over TCP + * Point-to-multipoint delivery over UDP broadcasts + * Versioning of code modules + * + * Procedure: + * + * 1. Receive code over TCP + * 2. Send code packets over UDP + * + * When a code packet is deemed to be missed, a NACK is sent. If a + * NACK is received, the sending restarts at the point in the + * binary where the NACK pointed to. (This is *not* very efficient, + * but simple to implement...) + * + * States: + * + * Receiving code header -> receiving code -> sending code + * + */ + +#include + +#include "contiki-net.h" +#include "cfs/cfs.h" +#include "codeprop-otf.h" +#include "loader/elfloader-otf.h" +#include + +static const char *err_msgs[] = + {"OK\r\n", "Bad ELF header\r\n", "No symtab\r\n", "No strtab\r\n", + "No text\r\n", "Symbol not found\r\n", "Segment not found\r\n", + "No startpoint\r\n", "Unhandled relocation\r\n", + "Relocation out of range\r\n", "Relocations not sorted\r\n", + "Input error\r\n" , "Ouput error\r\n" }; + +#define CODEPROP_DATA_PORT 6510 + +/*static int random_rand(void) { return 1; }*/ + +#if 0 +#define PRINTF(x) printf x +#else +#define PRINTF(x) +#endif + +#define START_TIMEOUT 12 * CLOCK_SECOND +#define MISS_NACK_TIMEOUT (CLOCK_SECOND / 8) * (random_rand() % 8) +#define HIT_NACK_TIMEOUT (CLOCK_SECOND / 8) * (8 + random_rand() % 16) +#define NACK_REXMIT_TIMEOUT CLOCK_SECOND * (4 + random_rand() % 4) + +#define WAITING_TIME CLOCK_SECOND * 10 + +#define NUM_SEND_DUPLICATES 2 + +#define UDPHEADERSIZE 8 +#define UDPDATASIZE 32 + +struct codeprop_udphdr { + u16_t id; + u16_t type; +#define TYPE_DATA 0x0001 +#define TYPE_NACK 0x0002 + u16_t addr; + u16_t len; + u8_t data[UDPDATASIZE]; +}; + +struct codeprop_tcphdr { + u16_t len; +}; + +static void uipcall(void *state); + +PROCESS(codeprop_process, "Code propagator"); + +struct codeprop_state { + u8_t state; +#define STATE_NONE 0 +#define STATE_RECEIVING_TCPDATA 1 +#define STATE_RECEIVING_UDPDATA 2 +#define STATE_SENDING_UDPDATA 3 + u16_t count; + u16_t addr; + u16_t len; + u16_t id; + struct etimer sendtimer; + struct timer nacktimer, timer, starttimer; + u8_t received; + u8_t send_counter; + struct pt tcpthread_pt; + struct pt udpthread_pt; + struct pt recv_udpthread_pt; +}; + +static int fd; + +static struct uip_udp_conn *udp_conn; + +static struct codeprop_state s; + +void system_log(char *msg); + +static clock_time_t send_time; + +#define CONNECTION_TIMEOUT (30 * CLOCK_SECOND) + +/*---------------------------------------------------------------------*/ +void +codeprop_set_rate(clock_time_t time) +{ + send_time = time; +} +/*---------------------------------------------------------------------*/ +PROCESS_THREAD(codeprop_process, ev, data) +{ + PROCESS_BEGIN(); + + elfloader_init(); + + s.id = 0/*random_rand()*/; + + send_time = CLOCK_SECOND/4; + + PT_INIT(&s.udpthread_pt); + PT_INIT(&s.recv_udpthread_pt); + + tcp_listen(HTONS(CODEPROP_DATA_PORT)); + + udp_conn = udp_broadcast_new(HTONS(CODEPROP_DATA_PORT), NULL); + + s.state = STATE_NONE; + s.received = 0; + s.addr = 0; + s.len = 0; + + fd = cfs_open("codeprop-image", CFS_READ | CFS_WRITE); + + while(1) { + + PROCESS_YIELD(); + + if(ev == tcpip_event) { + uipcall(data); + } else if(ev == PROCESS_EVENT_TIMER) { + tcpip_poll_udp(udp_conn); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------*/ +static u16_t +send_udpdata(struct codeprop_udphdr *uh) +{ + u16_t len; + + uh->type = HTONS(TYPE_DATA); + uh->addr = htons(s.addr); + uh->id = htons(s.id); + + if(s.len - s.addr > UDPDATASIZE) { + len = UDPDATASIZE; + } else { + len = s.len - s.addr; + } + + cfs_seek(fd, s.addr); + cfs_read(fd, (char*)&uh->data[0], len); + /* eeprom_read(EEPROMFS_ADDR_CODEPROP + s.addr, + &uh->data[0], len);*/ + + uh->len = htons(s.len); + + PRINTF(("codeprop: sending packet from address 0x%04x\n", s.addr)); + uip_udp_send(len + UDPHEADERSIZE); + + return len; +} +/*---------------------------------------------------------------------*/ +static +PT_THREAD(send_udpthread(struct pt *pt)) +{ + int len; + struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata; + + + PT_BEGIN(pt); + + while(1) { + PT_WAIT_UNTIL(pt, s.state == STATE_SENDING_UDPDATA); + + for(s.addr = 0; s.addr < s.len; ) { + len = send_udpdata(uh); + s.addr += len; + + etimer_set(&s.sendtimer, CLOCK_SECOND/4); + do { + PT_WAIT_UNTIL(pt, uip_newdata() || etimer_expired(&s.sendtimer)); + + if(uip_newdata()) { + if(uh->type == HTONS(TYPE_NACK)) { + PRINTF(("send_udpthread: got NACK for address 0x%x (now 0x%x)\n", + htons(uh->addr), s.addr)); + /* Only accept a NACK if it points to a lower byte. */ + if(htons(uh->addr) <= s.addr) { + /* beep();*/ + s.addr = htons(uh->addr); + } + } + PT_YIELD(pt); + } + } while(!etimer_expired(&s.sendtimer)); + } + + s.state = STATE_NONE; + +/* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */ + } + PT_END(pt); +} +/*---------------------------------------------------------------------*/ +static void +send_nack(struct codeprop_udphdr *uh, unsigned short addr) +{ + uh->type = HTONS(TYPE_NACK); + uh->addr = htons(addr); + uip_udp_send(UDPHEADERSIZE); +} +/*---------------------------------------------------------------------*/ +static +PT_THREAD(recv_udpthread(struct pt *pt)) +{ + int len; + struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata; + + /* if(uip_newdata()) { + PRINTF(("recv_udpthread: id %d uh->id %d\n", s.id, htons(uh->id))); + }*/ + + PT_BEGIN(pt); + + while(1) { + + do { + PT_WAIT_UNTIL(pt, uip_newdata() && + uh->type == HTONS(TYPE_DATA) && + htons(uh->id) > s.id); + + if(htons(uh->addr) != 0) { + s.addr = 0; + send_nack(uh, 0); + } + + } while(htons(uh->addr) != 0); + + /* leds_on(LEDS_YELLOW); + beep_down(10000);*/ + + s.addr = 0; + s.id = htons(uh->id); + s.len = htons(uh->len); + + timer_set(&s.timer, CONNECTION_TIMEOUT); +/* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */ + + while(s.addr < s.len) { + + if(htons(uh->addr) == s.addr) { + /* leds_blink();*/ + len = uip_datalen() - UDPHEADERSIZE; + if(len > 0) { + /* eeprom_write(EEPROMFS_ADDR_CODEPROP + s.addr, + &uh->data[0], len);*/ + cfs_seek(fd, s.addr); + cfs_write(fd, (char*)&uh->data[0], len); + + /* beep();*/ + PRINTF(("Saved %d bytes at address %d, %d bytes left\n", + uip_datalen() - UDPHEADERSIZE, s.addr, + s.len - s.addr)); + + s.addr += len; + } + + } else if(htons(uh->addr) > s.addr) { + PRINTF(("sending nack since 0x%x != 0x%x\n", htons(uh->addr), s.addr)); + send_nack(uh, s.addr); + } + + if(s.addr < s.len) { + + /* timer_set(&s.nacktimer, NACK_TIMEOUT);*/ + + do { + timer_set(&s.nacktimer, HIT_NACK_TIMEOUT); + PT_YIELD_UNTIL(pt, timer_expired(&s.nacktimer) || + (uip_newdata() && + uh->type == HTONS(TYPE_DATA) && + htons(uh->id) == s.id)); + if(timer_expired(&s.nacktimer)) { + send_nack(uh, s.addr); + } + } while(timer_expired(&s.nacktimer)); + } + + } + + /* leds_off(LEDS_YELLOW); + beep_quick(2);*/ + /* printf("Received entire bunary over udr\n");*/ + codeprop_start_program(); + PT_EXIT(pt); + } + + PT_END(pt); +} +/*---------------------------------------------------------------------*/ + +#define CODEPROP_TCPHDR_SIZE 2 + +static +PT_THREAD(recv_tcpthread(struct pt *pt)) +{ + struct codeprop_tcphdr *th; + int datalen = uip_datalen(); + PT_BEGIN(pt); + + while(1) { + + PT_WAIT_UNTIL(pt, uip_connected()); + + codeprop_exit_program(); + + s.state = STATE_RECEIVING_TCPDATA; + + s.addr = 0; + s.count = 0; + + /* Read the header. */ + PT_WAIT_UNTIL(pt, uip_newdata() && uip_datalen() > 0); + + if(uip_datalen() < CODEPROP_TCPHDR_SIZE) { + PRINTF(("codeprop: header not found in first tcp segment\n")); + uip_abort(); + } + th = (struct codeprop_tcphdr *)uip_appdata; + s.len = htons(th->len); + s.addr = 0; + uip_appdata += CODEPROP_TCPHDR_SIZE; + datalen -= CODEPROP_TCPHDR_SIZE; + + /* Read the rest of the data. */ + do { + if(datalen > 0) { + /* printf("Got %d bytes\n", datalen); */ + + if (cfs_seek(fd, s.addr) != s.addr) { + PRINTF(("codeprop: seek in buffer file failed\n")); + uip_abort(); + } + + if (cfs_write(fd, uip_appdata, datalen) != datalen) { + PRINTF(("codeprop: write to buffer file failed\n")); + uip_abort(); + } + s.addr += datalen; + } + if(s.addr < s.len) { + PT_YIELD_UNTIL(pt, uip_newdata()); + } + } while(s.addr < s.len); +#if 1 + + { + static int err; + + err = codeprop_start_program(); + + /* Print out the "OK"/error message. */ + do { + if (err >= 0 && err < sizeof(err_msgs)/sizeof(char*)) { + uip_send(err_msgs[err], strlen(err_msgs[err])); + } else { + uip_send("Unknown error\r\n", 15); + } + PT_WAIT_UNTIL(pt, uip_acked() || uip_rexmit() || uip_closed()); + } while(uip_rexmit()); + + /* Close the connection. */ + uip_close(); + } +#endif + ++s.id; + s.state = STATE_SENDING_UDPDATA; + tcpip_poll_udp(udp_conn); + + PT_WAIT_UNTIL(pt, s.state != STATE_SENDING_UDPDATA); + /* printf("recv_tcpthread: unblocked\n");*/ + } + + PT_END(pt); +} +/*---------------------------------------------------------------------*/ +void +codeprop_start_broadcast(unsigned int len) +{ + s.addr = 0; + s.len = len; + ++s.id; + s.state = STATE_SENDING_UDPDATA; + tcpip_poll_udp(udp_conn); +} +/*---------------------------------------------------------------------*/ +void +codeprop_exit_program(void) +{ + if(elfloader_autostart_processes != NULL) { + autostart_exit(elfloader_autostart_processes); + } +} +/*---------------------------------------------------------------------*/ +int +codeprop_start_program(void) +{ + int err; + + codeprop_exit_program(); + + err = elfloader_load(fd, codeprop_output); + if(err == ELFLOADER_OK) { + PRINTF(("codeprop: starting %s\n", + elfloader_autostart_processes[0]->name)); + autostart_start(elfloader_autostart_processes); + } + return err; +} +/*---------------------------------------------------------------------*/ +static void +uipcall(void *state) +{ + if(uip_udpconnection()) { + recv_udpthread(&s.recv_udpthread_pt); + send_udpthread(&s.udpthread_pt); + } else { + if(uip_conn->lport == HTONS(CODEPROP_DATA_PORT)) { + if(uip_connected()) { + + if(state == NULL) { + s.addr = 0; + s.count = 0; + PT_INIT(&s.tcpthread_pt); + process_poll(&codeprop_process); + tcp_markconn(uip_conn, &s); +/* process_post(PROCESS_BROADCAST, codeprop_event_quit, */ +/* (process_data_t)NULL); */ + } else { + PRINTF(("codeprop: uip_connected() and state != NULL\n")); + uip_abort(); + } + } + recv_tcpthread(&s.tcpthread_pt); + + + if(uip_closed() || uip_aborted() || uip_timedout()) { + PRINTF(("codeprop: connection down\n")); + tcp_markconn(uip_conn, NULL); + } + } + } +} +/*---------------------------------------------------------------------*/ +/** @} */ diff --git a/cpu/at91sam7s/loader/codeprop-otf.h b/cpu/at91sam7s/loader/codeprop-otf.h new file mode 100644 index 000000000..1268707f7 --- /dev/null +++ b/cpu/at91sam7s/loader/codeprop-otf.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: codeprop-otf.h,v 1.1 2007/03/07 16:07:26 ksb Exp $ + */ +#ifndef __CODEPROP_H__ +#define __CODEPROP_H__ + +#include "contiki.h" + +#define CODEPROP_DATA_PORT 6510 + +PROCESS_NAME(codeprop_process); + +void codeprop_set_rate(clock_time_t time); +void codeprop_start_broadcast(unsigned int len); +void codeprop_exit_program(void); +int codeprop_start_program(void); + +/* Segment writing object */ +extern struct elfloader_output *codeprop_output; + +extern char *codeprop_filesystem; + +#endif /* __CODEPROP_H__ */ diff --git a/cpu/at91sam7s/loader/elfloader-arch-otf.h b/cpu/at91sam7s/loader/elfloader-arch-otf.h new file mode 100644 index 000000000..808c0b8a5 --- /dev/null +++ b/cpu/at91sam7s/loader/elfloader-arch-otf.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * Copyright (c) 2007, Simon Berg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: elfloader-arch-otf.h,v 1.1 2007/03/07 16:07:26 ksb Exp $ + */ +/** + * \addtogroup elfloader + * @{ + */ + +/** + * \defgroup elfloaderarch Architecture specific functionality for the ELF loader. + * + * The architecture specific functionality for the Contiki ELF loader + * has to be implemented for each processor type Contiki runs on. + * + * Since the ELF format is slightly different for different processor + * types, the Contiki ELF loader is divided into two parts: the + * generic ELF loader module (\ref elfloader) and the architecture + * specific part (this module). The architecture specific part deals + * with memory allocation, code and data relocation, and writing the + * relocated ELF code into program memory. + * + * To port the Contiki ELF loader to a new processor type, this module + * has to be implemented for the new processor type. + * + * @{ + */ + +/** + * \file + * Header file for the architecture specific parts of the Contiki ELF loader. + * + * \author + * Adam Dunkels + * + */ + +#ifndef __ELFLOADER_ARCH_H__ +#define __ELFLOADER_ARCH_H__ + +#include "elfloader-otf.h" + + +/** + * \brief Perform a relocation. + * \param output The output object for the segment. + * \param sectionoffset The file offset at which the relocation can be found. + * \param sectionaddr The section start address (absolute runtime). + * \param rela A pointer to an ELF32 rela structure (struct elf32_rela). + * \param addr The relocated address. + * + * This function is called from the Contiki ELF loader to + * perform a relocation on a piece of code or data. The + * relocated address is calculated by the Contiki ELF + * loader, based on information in the ELF file, and it is + * the responsibility of this function to patch the + * executable code. The Contiki ELF loader passes a + * pointer to an ELF32 rela structure (struct elf32_rela) + * that contains information about how to patch the + * code. This information is different from processor to + * processor. + */ +int elfloader_arch_relocate(int input_fd, + struct elfloader_output *output, + unsigned int sectionoffset, + char *sectionaddr, + struct elf32_rela *rela, char *addr); + +#endif /* __ELFLOADER_ARCH_H__ */ + +/** @} */ +/** @} */ diff --git a/cpu/at91sam7s/loader/elfloader-otf.c b/cpu/at91sam7s/loader/elfloader-otf.c new file mode 100644 index 000000000..c9b7d4470 --- /dev/null +++ b/cpu/at91sam7s/loader/elfloader-otf.c @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * Copyright (c) 2007, Simon Berg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: elfloader-otf.c,v 1.1 2007/03/07 16:07:26 ksb Exp $ + */ + +#include "contiki.h" + +#include "loader/elfloader-otf.h" +#include "loader/elfloader-arch-otf.h" + +#include "cfs/cfs.h" +#include "loader/symtab.h" + +#include +#include +#include + +#if 0 +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) do {} while (0) +#endif + +#define EI_NIDENT 16 + + +struct elf32_ehdr { + unsigned char e_ident[EI_NIDENT]; /* ident bytes */ + elf32_half e_type; /* file type */ + elf32_half e_machine; /* target machine */ + elf32_word e_version; /* file version */ + elf32_addr e_entry; /* start address */ + elf32_off e_phoff; /* phdr file offset */ + elf32_off e_shoff; /* shdr file offset */ + elf32_word e_flags; /* file flags */ + elf32_half e_ehsize; /* sizeof ehdr */ + elf32_half e_phentsize; /* sizeof phdr */ + elf32_half e_phnum; /* number phdrs */ + elf32_half e_shentsize; /* sizeof shdr */ + elf32_half e_shnum; /* number shdrs */ + elf32_half e_shstrndx; /* shdr string index */ +}; + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ + +struct elf32_shdr { + elf32_word sh_name; /* section name */ + elf32_word sh_type; /* SHT_... */ + elf32_word sh_flags; /* SHF_... */ + elf32_addr sh_addr; /* virtual address */ + elf32_off sh_offset; /* file offset */ + elf32_word sh_size; /* section size */ + elf32_word sh_link; /* misc info */ + elf32_word sh_info; /* misc info */ + elf32_word sh_addralign; /* memory alignment */ + elf32_word sh_entsize; /* entry size if table */ +}; + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +struct elf32_rel { + elf32_addr r_offset; /* Location to be relocated. */ + elf32_word r_info; /* Relocation type and symbol index. */ +}; + +struct elf32_sym { + elf32_word st_name; /* String table index of name. */ + elf32_addr st_value; /* Symbol value. */ + elf32_word st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + elf32_half st_shndx; /* Section index of symbol. */ +}; + +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +struct relevant_section { + unsigned char number; + unsigned int offset; + char *address; +}; + +char elfloader_unknown[30]; /* Name that caused link error. */ + +struct process **elfloader_autostart_processes; + +static struct relevant_section bss, data, rodata, text; + +const static unsigned char elf_magic_header[] = + {0x7f, 0x45, 0x4c, 0x46, /* 0x7f, 'E', 'L', 'F' */ + 0x01, /* Only 32-bit objects. */ + 0x01, /* Only LSB data. */ + 0x01, /* Only ELF version 1. */ + }; + +/* Copy data from the elf file to a segment */ +static int +copy_segment_data(int input_fd, unsigned int offset, + struct elfloader_output *output, unsigned int len) +{ + char buffer[16]; + int res; + if (cfs_seek(input_fd, offset) != offset) return ELFLOADER_INPUT_ERROR; + while(len > sizeof(buffer)) { + res = cfs_read(input_fd, buffer, sizeof(buffer)); + if (res != sizeof(buffer)) return ELFLOADER_INPUT_ERROR; + res = elfloader_output_write_segment(output, buffer, sizeof(buffer)); + if (res != sizeof(buffer)) return ELFLOADER_OUTPUT_ERROR; + len -= sizeof(buffer); + } + res = cfs_read(input_fd, buffer, len); + if (res != len) return ELFLOADER_INPUT_ERROR; + res = elfloader_output_write_segment(output, buffer, len); + if (res != len) return ELFLOADER_OUTPUT_ERROR; + return ELFLOADER_OK; +} + +static int +seek_read(int fd, unsigned int offset, char *buf, int len) +{ + if (cfs_seek(fd, offset) != offset) return -1; + return cfs_read(fd, buf, len); +} + +static void * +find_local_symbol(int input_fd, const char *symbol, + unsigned int symtab, unsigned short symtabsize, + unsigned int strtab) +{ + struct elf32_sym s; + unsigned int a; + char name[30]; + struct relevant_section *sect; + int ret; + + for(a = symtab; a < symtab + symtabsize; a += sizeof(s)) { + ret = seek_read(input_fd, a, (char *)&s, sizeof(s)); + if (ret < 0) return NULL; + + if(s.st_name != 0) { + ret = seek_read(input_fd, strtab + s.st_name, name, sizeof(name)); + if (ret < 0) return NULL; + + if(strcmp(name, symbol) == 0) { + if(s.st_shndx == bss.number) { + sect = &bss; + } else if(s.st_shndx == data.number) { + sect = &data; + } else if(s.st_shndx == text.number) { + sect = &text; + } else { + return NULL; + } + return &(sect->address[s.st_value]); + } + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static int +relocate_section(int input_fd, + struct elfloader_output *output, + unsigned int section, unsigned short size, + unsigned int sectionaddr, + char *sectionbase, + unsigned int strs, + unsigned int strtab, + unsigned int symtab, unsigned short symtabsize, + unsigned char using_relas) +{ + /* sectionbase added; runtime start address of current section */ + struct elf32_rela rela; /* Now used both for rel and rela data! */ + int rel_size = 0; + struct elf32_sym s; + unsigned int a; + char name[30]; + char *addr; + struct relevant_section *sect; + int ret; + + /* determine correct relocation entry sizes */ + if(using_relas) { + rel_size = sizeof(struct elf32_rela); + } else { + rel_size = sizeof(struct elf32_rel); + } + + for(a = section; a < section + size; a += rel_size) { + ret = seek_read(input_fd, a, (char *)&rela, rel_size); + if (ret < 0) return ELFLOADER_INPUT_ERROR; + ret = seek_read(input_fd, + (symtab + + sizeof(struct elf32_sym) * ELF32_R_SYM(rela.r_info)), + (char *)&s, sizeof(s)); + if (ret < 0) return ELFLOADER_INPUT_ERROR; + if(s.st_name != 0) { + ret = seek_read(input_fd, strtab + s.st_name, name, sizeof(name)); + if (ret < 0) return ELFLOADER_INPUT_ERROR; + PRINTF("name: %s\n", name); + addr = (char *)symtab_lookup(name); + /* ADDED */ + if(addr == NULL) { + PRINTF("name not found in global: %s\n", name); + addr = find_local_symbol(input_fd, name, symtab, symtabsize, strtab); + PRINTF("found address %p\n", addr); + } + if(addr == NULL) { + if(s.st_shndx == bss.number) { + sect = &bss; + } else if(s.st_shndx == data.number) { + sect = &data; + } else if(s.st_shndx == rodata.number) { + sect = &rodata; + } else if(s.st_shndx == text.number) { + sect = &text; + } else { + PRINTF("elfloader unknown name: '%30s'\n", name); + memcpy(elfloader_unknown, name, sizeof(elfloader_unknown)); + elfloader_unknown[sizeof(elfloader_unknown) - 1] = 0; + return ELFLOADER_SYMBOL_NOT_FOUND; + } + addr = sect->address; + } + } else { + if(s.st_shndx == bss.number) { + sect = &bss; + } else if(s.st_shndx == data.number) { + sect = &data; + } else if(s.st_shndx == rodata.number) { + sect = &rodata; + } else if(s.st_shndx == text.number) { + sect = &text; + } else { + return ELFLOADER_SEGMENT_NOT_FOUND; + } + + addr = sect->address; + } + +#if 0 /* We don't know how big the relocation is or even if we need to read it. + Let the architecture dependant code decide */ + if (!using_relas) { + /* copy addend to rela structure */ + ret = seek_read(fd, sectionaddr + rela.r_offset, &rela.r_addend, 4); + if (ret < 0) return ELFLOADER_INPUT_ERROR; + } +#endif + { + /* Copy data up to the next relocation */ + unsigned int offset = elfloader_output_segment_offset(output); + if (rela.r_offset < offset) { + PRINTF("elfloader relocation out of offset order\n"); + + } + if (rela.r_offset > offset) { + ret = copy_segment_data(input_fd, offset+sectionaddr, output, + rela.r_offset - offset); + if (ret != ELFLOADER_OK) return ret; + } + } + ret = elfloader_arch_relocate(input_fd, output, sectionaddr, sectionbase, + &rela, addr); + if (ret != ELFLOADER_OK) return ret; + } + return ELFLOADER_OK; +} +/*---------------------------------------------------------------------------*/ +static void * +find_program_processes(int input_fd, + unsigned int symtab, unsigned short size, + unsigned int strtab) +{ + struct elf32_sym s; + unsigned int a; + char name[30]; + + for(a = symtab; a < symtab + size; a += sizeof(s)) { + seek_read(input_fd, a, (char *)&s, sizeof(s)); + + if(s.st_name != 0) { + seek_read(input_fd, strtab + s.st_name, name, sizeof(name)); + if(strcmp(name, "autostart_processes") == 0) { + return &data.address[s.st_value]; + } + } + } + return NULL; +/* return find_local_symbol(fd, "autostart_processes", symtab, size, strtab); */ +} +/*---------------------------------------------------------------------------*/ +void +elfloader_init(void) +{ + elfloader_autostart_processes = NULL; +} +/*---------------------------------------------------------------------------*/ +#if 0 +static void +print_chars(unsigned char *ptr, int num) +{ + int i; + for(i = 0; i < num; ++i) { + PRINTF("%d", ptr[i]); + if(i == num - 1) { + PRINTF("\n"); + } else { + PRINTF(", "); + } + } +} +#endif /* 0 */ + +static int +copy_segment(int input_fd, + struct elfloader_output *output, + unsigned int section, unsigned short size, + unsigned int sectionaddr, + char *sectionbase, + unsigned int strs, + unsigned int strtab, + unsigned int symtab, unsigned short symtabsize, + unsigned char using_relas, + unsigned int seg_size, unsigned int seg_type) +{ + unsigned int offset; + int ret; + ret = elfloader_output_start_segment(output, seg_type,sectionbase, seg_size); + if (ret != ELFLOADER_OK) return ret; + ret = relocate_section(input_fd, output, + section, size, + sectionaddr, + sectionbase, + strs, + strtab, + symtab, symtabsize, using_relas); + if (ret != ELFLOADER_OK) return ret; + offset = elfloader_output_segment_offset(output); + ret = copy_segment_data(input_fd, offset+sectionaddr, output,seg_size - offset); + if (ret != ELFLOADER_OK) return ret; + return elfloader_output_end_segment(output); +} + +/*---------------------------------------------------------------------------*/ +int +elfloader_load(int input_fd, struct elfloader_output *output) +{ + struct elf32_ehdr ehdr; + struct elf32_shdr shdr; + struct elf32_shdr strtable; + unsigned int strs; + unsigned int shdrptr; + unsigned int nameptr; + char name[12]; + + int i; + unsigned short shdrnum, shdrsize; + + unsigned char using_relas = -1; + unsigned short textoff = 0, textsize, textrelaoff = 0, textrelasize; + unsigned short dataoff = 0, datasize, datarelaoff = 0, datarelasize; + unsigned short rodataoff = 0, rodatasize, rodatarelaoff = 0, rodatarelasize; + unsigned short symtaboff = 0, symtabsize; + unsigned short strtaboff = 0, strtabsize; + unsigned short bsssize = 0; + + struct process **process; + int ret; + + elfloader_unknown[0] = 0; + + /* The ELF header is located at the start of the buffer. */ + ret = seek_read(input_fd, 0, (char *)&ehdr, sizeof(ehdr)); + if (ret != sizeof(ehdr)) return ELFLOADER_INPUT_ERROR; + + /* print_chars(ehdr.e_ident, sizeof(elf_magic_header)); + print_chars(elf_magic_header, sizeof(elf_magic_header));*/ + /* Make sure that we have a correct and compatible ELF header. */ + if(memcmp(ehdr.e_ident, elf_magic_header, sizeof(elf_magic_header)) != 0) { + PRINTF("ELF header problems\n"); + return ELFLOADER_BAD_ELF_HEADER; + } + + /* Grab the section header. */ + shdrptr = ehdr.e_shoff; + ret = seek_read(input_fd, shdrptr, (char *)&shdr, sizeof(shdr)); + if (ret != sizeof(shdr)) return ELFLOADER_INPUT_ERROR; + + /* Get the size and number of entries of the section header. */ + shdrsize = ehdr.e_shentsize; + shdrnum = ehdr.e_shnum; + + /* The string table section: holds the names of the sections. */ + ret = seek_read(input_fd, ehdr.e_shoff + shdrsize * ehdr.e_shstrndx, + (char *)&strtable, sizeof(strtable)); + if (ret != sizeof(strtable)) return ELFLOADER_INPUT_ERROR; + + /* Get a pointer to the actual table of strings. This table holds + the names of the sections, not the names of other symbols in the + file (these are in the sybtam section). */ + strs = strtable.sh_offset; + + /* Go through all sections and pick out the relevant ones. The + ".text" segment holds the actual code from the ELF file, the + ".data" segment contains initialized data, the ".rodata" segment + contains read-only data, the ".bss" segment holds the size of the + unitialized data segment. The ".rel[a].text" and ".rel[a].data" + segments contains relocation information for the contents of the + ".text" and ".data" segments, respectively. The ".symtab" segment + contains the symbol table for this file. The ".strtab" segment + points to the actual string names used by the symbol table. + + In addition to grabbing pointers to the relevant sections, we + also save the section number for resolving addresses in the + relocator code. + */ + + + /* Initialize the segment sizes to zero so that we can check if + their sections was found in the file or not. */ + textsize = textrelasize = datasize = datarelasize = + rodatasize = rodatarelasize = symtabsize = strtabsize = 0; + + bss.number = data.number = rodata.number = text.number = -1; + + shdrptr = ehdr.e_shoff; + for(i = 0; i < shdrnum; ++i) { + + ret = seek_read(input_fd, shdrptr, (char *)&shdr, sizeof(shdr)); + if (ret != sizeof(shdr)) return ELFLOADER_INPUT_ERROR; + + /* The name of the section is contained in the strings table. */ + nameptr = strs + shdr.sh_name; + ret = seek_read(input_fd, nameptr, name, sizeof(name)); + if (ret != sizeof(name)) return ELFLOADER_INPUT_ERROR; + + /* Match the name of the section with a predefined set of names + (.text, .data, .bss, .rela.text, .rela.data, .symtab, and + .strtab). */ + /* added support for .rodata, .rel.text and .rel.data). */ + + if(strncmp(name, ".text", 5) == 0) { + textoff = shdr.sh_offset; + textsize = shdr.sh_size; + text.number = i; + text.offset = textoff; + } else if(strncmp(name, ".rel.text", 9) == 0) { + using_relas = 0; + textrelaoff = shdr.sh_offset; + textrelasize = shdr.sh_size; + } else if(strncmp(name, ".rela.text", 10) == 0) { + using_relas = 1; + textrelaoff = shdr.sh_offset; + textrelasize = shdr.sh_size; + } else if(strncmp(name, ".data", 5) == 0) { + dataoff = shdr.sh_offset; + datasize = shdr.sh_size; + data.number = i; + data.offset = dataoff; + } else if(strncmp(name, ".rodata", 7) == 0) { + /* read-only data handled the same way as regular text section */ + rodataoff = shdr.sh_offset; + rodatasize = shdr.sh_size; + rodata.number = i; + rodata.offset = rodataoff; + } else if(strncmp(name, ".rel.rodata", 11) == 0) { + /* using elf32_rel instead of rela */ + using_relas = 0; + rodatarelaoff = shdr.sh_offset; + rodatarelasize = shdr.sh_size; + } else if(strncmp(name, ".rela.rodata", 12) == 0) { + using_relas = 1; + rodatarelaoff = shdr.sh_offset; + rodatarelasize = shdr.sh_size; + } else if(strncmp(name, ".rel.data", 9) == 0) { + /* using elf32_rel instead of rela */ + using_relas = 0; + datarelaoff = shdr.sh_offset; + datarelasize = shdr.sh_size; + } else if(strncmp(name, ".rela.data", 10) == 0) { + using_relas = 1; + datarelaoff = shdr.sh_offset; + datarelasize = shdr.sh_size; + } else if(strncmp(name, ".symtab", 7) == 0) { + symtaboff = shdr.sh_offset; + symtabsize = shdr.sh_size; + } else if(strncmp(name, ".strtab", 7) == 0) { + strtaboff = shdr.sh_offset; + strtabsize = shdr.sh_size; + } else if(strncmp(name, ".bss", 4) == 0) { + bsssize = shdr.sh_size; + bss.number = i; + bss.offset = 0; + } + + /* Move on to the next section header. */ + shdrptr += shdrsize; + } + + if(symtabsize == 0) { + return ELFLOADER_NO_SYMTAB; + } + if(strtabsize == 0) { + return ELFLOADER_NO_STRTAB; + } + if(textsize == 0) { + return ELFLOADER_NO_TEXT; + } + + + if (bsssize) { + bss.address = (char *) + elfloader_output_alloc_segment(output, ELFLOADER_SEG_BSS, bsssize); + if (!bss.address) return ELFLOADER_OUTPUT_ERROR; + } + if (datasize) { + data.address = (char *) + elfloader_output_alloc_segment(output,ELFLOADER_SEG_DATA,datasize); + if (!data.address) return ELFLOADER_OUTPUT_ERROR; + } + if (textsize) { + text.address = (char *) + elfloader_output_alloc_segment(output,ELFLOADER_SEG_TEXT,textsize); + if (!text.address) return ELFLOADER_OUTPUT_ERROR; + } + if (rodatasize) { + rodata.address = (char *) + elfloader_output_alloc_segment(output,ELFLOADER_SEG_RODATA,rodatasize); + if (!rodata.address) return ELFLOADER_OUTPUT_ERROR; + } + +/* printf("bss base address: bss.address = 0x%08x\n", bss.address); + printf("data base address: data.address = 0x%08x\n", data.address); + printf("text base address: text.address = 0x%08x\n", text.address); + printf("rodata base address: rodata.address = 0x%08x\n", rodata.address); */ + + + /* If we have text segment relocations, we process them. */ + PRINTF("elfloader: relocate text\n"); + if(textrelasize > 0) { + ret = copy_segment(input_fd, output, + textrelaoff, textrelasize, + textoff, + text.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas, + textsize, ELFLOADER_SEG_TEXT); + if(ret != ELFLOADER_OK) { + return ret; + } + } + + /* If we have any rodata segment relocations, we process them too. */ + PRINTF("elfloader: relocate rodata\n"); + if(rodatarelasize > 0) { + ret = copy_segment(input_fd, output, + rodatarelaoff, rodatarelasize, + rodataoff, + rodata.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas, + rodatasize, ELFLOADER_SEG_RODATA); + if(ret != ELFLOADER_OK) { + PRINTF("elfloader: data failed\n"); + return ret; + } + } + + /* If we have any data segment relocations, we process them too. */ + PRINTF("elfloader: relocate data\n"); + if(datarelasize > 0) { + ret = copy_segment(input_fd, output, + datarelaoff, datarelasize, + dataoff, + data.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas, + datasize, ELFLOADER_SEG_DATA); + if(ret != ELFLOADER_OK) { + PRINTF("elfloader: data failed\n"); + return ret; + } + ret = elfloader_output_end_segment(output); + if (ret != ELFLOADER_OK) return ret; + } + + /* Write text and rodata segment into flash and data segment into RAM. */ +/* elfloader_arch_write_rom(fd, textoff, textsize, text.address); */ +/* elfloader_arch_write_rom(fd, rodataoff, rodatasize, rodata.address); */ + +/* memset(bss.address, 0, bsssize); */ +/* seek_read(fd, dataoff, data.address, datasize); */ + + { + /* Write zeros to bss segment */ + unsigned int len = bsssize; + static const char zeros[16] = {0}; + ret = elfloader_output_start_segment(output, ELFLOADER_SEG_BSS, + bss.address,bsssize); + if (ret != ELFLOADER_OK) return ret; + while(len > sizeof(zeros)) { + ret = elfloader_output_write_segment(output, zeros, sizeof(zeros)); + if (ret != sizeof(zeros)) return ELFLOADER_OUTPUT_ERROR; + len -= sizeof(zeros); + } + ret = elfloader_output_write_segment(output, zeros, len); + if (ret != len) return ELFLOADER_OUTPUT_ERROR; + } + + PRINTF("elfloader: autostart search\n"); + process = find_local_symbol(input_fd, "autostart_processes", symtaboff, symtabsize, strtaboff); + if(process != NULL) { + PRINTF("elfloader: autostart found\n"); + elfloader_autostart_processes = process; + return ELFLOADER_OK; + } else { + PRINTF("elfloader: no autostart\n"); + process = find_program_processes(input_fd, symtaboff, symtabsize, strtaboff); + if(process != NULL) { + PRINTF("elfloader: FOUND PRG\n"); + } + return ELFLOADER_NO_STARTPOINT; + } +} +/*---------------------------------------------------------------------------*/ diff --git a/cpu/at91sam7s/loader/elfloader-otf.h b/cpu/at91sam7s/loader/elfloader-otf.h new file mode 100644 index 000000000..91dc94b9b --- /dev/null +++ b/cpu/at91sam7s/loader/elfloader-otf.h @@ -0,0 +1,314 @@ +/** + * \addtogroup loader + * @{ + */ + +/** + * \defgroup elfloader The Contiki ELF loader + * + * The Contiki ELF loader links, relocates, and loads ELF + * (Executable Linkable Format) object files into a running Contiki + * system. + * + * ELF is a standard format for relocatable object code and executable + * files. ELF is the standard program format for Linux, Solaris, and + * other operating systems. + * + * An ELF file contains either a standalone executable program or a + * program module. The file contains both the program code, the + * program data, as well as information about how to link, relocate, + * and load the program into a running system. + * + * The ELF file is composed of a set of sections. The sections contain + * program code, data, or relocation information, but can also contain + * debugging information. + * + * To link and relocate an ELF file, the Contiki ELF loader first + * parses the ELF file structure to find the appropriate ELF + * sections. It then allocates memory for the program code and data in + * ROM and RAM, respectively. After allocating memory, the Contiki ELF + * loader starts relocating the code found in the ELF file. + * + * @{ + */ + +/** + * \file + * Header file for the Contiki ELF loader. + * \author + * Adam Dunkels + * Simon Berg + * + */ + +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * Copyright (c) 2007, Simon Berg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#ifndef __ELFLOADER_H__ +#define __ELFLOADER_H__ + +#include "cfs/cfs.h" + +/** + * Return value from elfloader_load() indicating that loading worked. + */ +#define ELFLOADER_OK 0 +/** + * Return value from elfloader_load() indicating that the ELF file had + * a bad header. + */ +#define ELFLOADER_BAD_ELF_HEADER 1 +/** + * Return value from elfloader_load() indicating that no symbol table + * could be find in the ELF file. + */ +#define ELFLOADER_NO_SYMTAB 2 +/** + * Return value from elfloader_load() indicating that no string table + * could be find in the ELF file. + */ +#define ELFLOADER_NO_STRTAB 3 +/** + * Return value from elfloader_load() indicating that the size of the + * .text segment was zero. + */ +#define ELFLOADER_NO_TEXT 4 +/** + * Return value from elfloader_load() indicating that a symbol + * specific symbol could not be found. + * + * If this value is returned from elfloader_load(), the symbol has + * been copied into the elfloader_unknown[] array. + */ +#define ELFLOADER_SYMBOL_NOT_FOUND 5 +/** + * Return value from elfloader_load() indicating that one of the + * required segments (.data, .bss, or .text) could not be found. + */ +#define ELFLOADER_SEGMENT_NOT_FOUND 6 +/** + * Return value from elfloader_load() indicating that no starting + * point could be found in the loaded module. + */ +#define ELFLOADER_NO_STARTPOINT 7 + +/** + * Return value from elfloader_load() indicating that the ELF file contained + * a relocation type that the implementation can't handle. + */ +#define ELFLOADER_UNHANDLED_RELOC 8 + +/** + * Return value from elfloader_load() indicating that the offset for + * a relative addressing mode was too big. + */ +#define ELFLOADER_OUTOF_RANGE 9 + +/** + * Return value from elfloader_load() indicating that the relocations + * where not sorted by offset + */ +#define ELFLOADER_RELOC_NOT_SORTED 10 + +/** + * Return value from elfloader_load() indicating that reading from the + * ELF file failed in some way. + */ +#define ELFLOADER_INPUT_ERROR 11 + +/** + * Return value from elfloader_load() indicating that writing to a segment + * failed. + */ +#define ELFLOADER_OUTPUT_ERROR 12 + + +#define ELFLOADER_SEG_TEXT 1 +#define ELFLOADER_SEG_RODATA 2 +#define ELFLOADER_SEG_DATA 3 +#define ELFLOADER_SEG_BSS 4 + +/** + * elfloader output object + * + * This object defines methods (callbacks) for writing the segments to memory. + * It can be extended by the user to include any necessary state. + */ + +struct elfloader_output { + const struct elfloader_output_ops *ops; +}; +/** + * \brief Allocate a new segment + * \param input The output object + * \param type Type of segment + * \param size Size of segment in bytes + * \return A pointer to the start of the segment. + * + * The returned address doesn't need to correspond to any real memory, + * since it's only used for calculating the relocations. + */ + +void *elfloader_allocate_segment(struct elfloader_output *output, + unsigned int type, int size); + +/** + * \brief Start writing to a new segment + * \param input The output object + * \param type Type of segment + * \param addr Address of segment from elfloader_allocate_segment + * \param size Size of segment in bytes + * \return Returns ELFLOADER_OK if successful, otherwise an error code + * + */ + +int elfloader_start_segment(struct elfloader_output *output, + unsigned int type, void *addr, int size); +/** + * \brief Mark end of segment + * \param input The output object + * \return Zero if successful + */ + +int elfloader_end_segment(struct elfloader_output *output); + +/** + * \brief Write data to a segment + * \param input The output object + * \param buf Data to be written + * \param len Length of data + * \return The number of bytes actually written, or negative if failed. + */ + +int elfloader_write_segment(struct elfloader_output *output, const char *buf, + unsigned int len); + +/** + * \brief Get the current offset in the file where the next data will + * be written. + * \param input The output object + * \return The current offset. + */ + +unsigned int elfloader_segment_offset(struct elfloader_output *output); + +#define elfloader_output_alloc_segment(output, type, size) \ +((output)->ops->allocate_segment(output, type, size)) + +#define elfloader_output_start_segment(output, type, addr, size) \ +((output)->ops->start_segment(output, type, addr, size)) + +#define elfloader_output_end_segment(output) \ +((output)->ops->end_segment(output)) + +#define elfloader_output_write_segment(output, buf, len) \ +((output)->ops->write_segment(output, buf, len)) + +#define elfloader_output_segment_offset(output) \ +((output)->ops->segment_offset(output)) + + +struct elfloader_output_ops { + void * (*allocate_segment)(struct elfloader_output *output, + unsigned int type, int size); + int (*start_segment)(struct elfloader_output *output, + unsigned int type, void *addr, int size); + int (*end_segment)(struct elfloader_output *output); + int (*write_segment)(struct elfloader_output *output, const char *buf, + unsigned int len); + unsigned int (*segment_offset)(struct elfloader_output *output); +}; + + +/** + * elfloader initialization function. + * + * This function should be called at boot up to initilize the elfloader. + */ +void elfloader_init(void); + +/** + * \brief Load and relocate an ELF file. + * \param input Input object defining how to read from the ELF file + * \param output Output object defining how to create and write to seegments. + * \return ELFLOADER_OK if loading and relocation worked. + * Otherwise an error value. + * + * If the function is able to load the ELF file, a pointer + * to the process structure in the model is stored in the + * elfloader_loaded_process variable. + * + */ +int elfloader_load(int input_fd, + struct elfloader_output *output); + +/** + * A pointer to the processes loaded with elfloader_load(). + */ +extern struct process **elfloader_autostart_processes; + +/** + * If elfloader_load() could not find a specific symbol, it is copied + * into this array. + */ +extern char elfloader_unknown[30]; + +#ifdef ELFLOADER_CONF_DATAMEMORY_SIZE +#define ELFLOADER_DATAMEMORY_SIZE ELFLOADER_CONF_DATAMEMORY_SIZE +#else +#define ELFLOADER_DATAMEMORY_SIZE 0x100 +#endif + +#ifdef ELFLOADER_CONF_TEXTMEMORY_SIZE +#define ELFLOADER_TEXTMEMORY_SIZE ELFLOADER_CONF_TEXTMEMORY_SIZE +#else +#define ELFLOADER_TEXTMEMORY_SIZE 0x100 +#endif + +typedef unsigned long elf32_word; +typedef signed long elf32_sword; +typedef unsigned short elf32_half; +typedef unsigned long elf32_off; +typedef unsigned long elf32_addr; + +struct elf32_rela { + elf32_addr r_offset; /* Location to be relocated. */ + elf32_word r_info; /* Relocation type and symbol index. */ + elf32_sword r_addend; /* Addend. */ +}; + + +#endif /* __ELFLOADER_H__ */ + +/** @} */ +/** @} */ diff --git a/cpu/at91sam7s/loader/ram-segments.c b/cpu/at91sam7s/loader/ram-segments.c new file mode 100644 index 000000000..05f949d38 --- /dev/null +++ b/cpu/at91sam7s/loader/ram-segments.c @@ -0,0 +1,140 @@ +#ifndef __RAM_SEGMENTS_C__1POIF5E8U4__ +#define __RAM_SEGMENTS_C__1POIF5E8U4__ + +#include +#include +#include +#include +#include +#include + +struct ram_output +{ + struct elfloader_output output; + char *base; + unsigned int offset; + void *text; + void *rodata; + void *data; + void *bss; +}; + +static void * +allocate_segment(struct elfloader_output * const output, + unsigned int type, int size) +{ + struct ram_output * const ram = (struct ram_output *)output; + void *block = malloc(size); + if (!block) return NULL; + switch(type) { + case ELFLOADER_SEG_TEXT: + if (ram->text) free(ram->text); + ram->text = block; + break; + case ELFLOADER_SEG_RODATA: + if (ram->rodata) free(ram->rodata); + ram->rodata = block; + break; + case ELFLOADER_SEG_DATA: + if (ram->data) free(ram->data); + ram->data = block; + break; + case ELFLOADER_SEG_BSS: + if (ram->bss) free(ram->bss); + ram->bss = block; + break; + default: + free(block); + return NULL; + } + return block; +} + +static int +start_segment(struct elfloader_output *output, + unsigned int type, void *addr, int size) +{ + ((struct ram_output*)output)->base = addr; + ((struct ram_output*)output)->offset = 0; + return ELFLOADER_OK; +} + +static int +end_segment(struct elfloader_output *output) +{ + return ELFLOADER_OK; +} + +static int +write_segment(struct elfloader_output *output, const char *buf, + unsigned int len) +{ + struct ram_output * const ram = (struct ram_output *)output; + memcpy(ram->base + ram->offset, buf, len); + ram->offset += len; + return len; +} + +static unsigned int +segment_offset(struct elfloader_output *output) +{ + return ((struct ram_output*)output)->offset; +} + +static const struct elfloader_output_ops elf_output_ops = + { + allocate_segment, + start_segment, + end_segment, + write_segment, + segment_offset + }; + + +static struct ram_output seg_output = { + {&elf_output_ops}, + NULL, + 0, + NULL, + NULL, + NULL, + NULL +}; + +PROCESS(ram_segments_cleanup_process, "RAM segments cleanup process"); + +PROCESS_THREAD(ram_segments_cleanup_process, ev, data) +{ + PROCESS_BEGIN(); + while(1) { + PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_EXITED + || ev == PROCESS_EVENT_EXIT); + if (ev == PROCESS_EVENT_EXIT) break; + if (elfloader_autostart_processes || + elfloader_autostart_processes[0] == data) { + PROCESS_PAUSE(); /* Let the process exit */ + if (seg_output.text) { + free(seg_output.text); + seg_output.text = NULL; + } + if (seg_output.rodata) { + free(seg_output.rodata); + seg_output.rodata = NULL; + } + if (seg_output.data) { + free(seg_output.data); + seg_output.data = NULL; + } + + if (seg_output.bss) { + free(seg_output.bss); + seg_output.bss = NULL; + } + elfloader_autostart_processes = NULL; + } + } + PROCESS_END(); +} +struct elfloader_output *codeprop_output = &seg_output.output; + +#endif /* __RAM_SEGMENTS_C__1POIF5E8U4__ */ diff --git a/cpu/at91sam7s/loader/ram-segments.h b/cpu/at91sam7s/loader/ram-segments.h new file mode 100644 index 000000000..6f3936dfa --- /dev/null +++ b/cpu/at91sam7s/loader/ram-segments.h @@ -0,0 +1,6 @@ +#ifndef __RAM_SEGMENTS_H__8EDB9N09UD__ +#define __RAM_SEGMENTS_H__8EDB9N09UD__ + +PROCESS_NAME(ram_segments_cleanup_process); + +#endif /* __RAM_SEGMENTS_H__8EDB9N09UD__ */ diff --git a/cpu/at91sam7s/newlib-syscalls.c b/cpu/at91sam7s/newlib-syscalls.c index 96d8198ae..b4e098bd2 100644 --- a/cpu/at91sam7s/newlib-syscalls.c +++ b/cpu/at91sam7s/newlib-syscalls.c @@ -68,15 +68,13 @@ _sbrk(int incr) { extern char __heap_start__; /* Defined by the linker */ extern char __heap_end__; /* Defined by the linker */ - static char *heap_end; + static char *heap_end = &__heap_start__; char *prev_heap_end; - if (heap_end == 0) { - heap_end = &__heap_start__; - } prev_heap_end = heap_end; if (heap_end + incr > &__heap_end__) { - _write (2, "Heap full\n", 10); + printf("Heap full (requested %d, available %d)\n", + incr, &__heap_end__ - heap_end); errno = ENOMEM; return (caddr_t)-1; } diff --git a/cpu/at91sam7s/startup-SAM7S.S b/cpu/at91sam7s/startup-SAM7S.S new file mode 100644 index 000000000..15e5218c6 --- /dev/null +++ b/cpu/at91sam7s/startup-SAM7S.S @@ -0,0 +1,498 @@ +/***********************************************************************/ +/* */ +/* startup_SAM7S.S: Startup file for Atmel AT91SAM7S device series */ +/* */ +/***********************************************************************/ +/* ported to arm-elf-gcc / WinARM by Martin Thomas, KL, .de */ +/* */ +/* modifications Copyright Martin Thomas 2005 */ +/* */ +/* Based on a file that has been a part of the uVision/ARM */ +/* development tools, Copyright KEIL ELEKTRONIK GmbH 2002-2004 */ +/***********************************************************************/ + +/* + Modifications by Martin Thomas: + - added handling of execption vectors in RAM ("ramfunc") + - added options to remap the interrupt vectors to RAM + (see makefile for switch-option) + - replaced all ";" and "#" for comments with // or / * * / + - added C++ ctor handling + - .text in RAM for debugging (RAM_RUN) +*/ +/* + Modifications by Simon Berg + - added stack segment + - running program as system by defining RUN_AS_SYSTEM +*/ + +// mt: this file should not be used with the Configuration Wizard +// since a lot of changes have been done for the WinARM/gcc example +/* +// *** <<< Use Configuration Wizard in Context Menu >>> *** +*/ + + + +// *** Startup Code (executed after Reset) *** + + +// Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs + + .equ Mode_USR, 0x10 + .equ Mode_FIQ, 0x11 + .equ Mode_IRQ, 0x12 + .equ Mode_SVC, 0x13 + .equ Mode_ABT, 0x17 + .equ Mode_UND, 0x1B + .equ Mode_SYS, 0x1F + + .equ I_Bit, 0x80 /* when I bit is set, IRQ is disabled */ + .equ F_Bit, 0x40 /* when F bit is set, FIQ is disabled */ + + +// Internal Memory Base Addresses + .equ FLASH_BASE, 0x00100000 + .equ RAM_BASE, 0x00200000 + + +/* +// Stack Configuration +// Top of Stack Address <0x0-0xFFFFFFFF:4> +// Stack Sizes (in Bytes) +// Undefined Mode <0x0-0xFFFFFFFF:4> +// Supervisor Mode <0x0-0xFFFFFFFF:4> +// Abort Mode <0x0-0xFFFFFFFF:4> +// Fast Interrupt Mode <0x0-0xFFFFFFFF:4> +// Interrupt Mode <0x0-0xFFFFFFFF:4> +// User/System Mode <0x0-0xFFFFFFFF:4> +// +// +*/ + .equ Top_Stack, 0x00204000 + .equ UND_Stack_Size, 0x00000004 + .equ SVC_Stack_Size, 0x00000400 + .equ ABT_Stack_Size, 0x00000004 + .equ FIQ_Stack_Size, 0x00000004 + .equ IRQ_Stack_Size, 0x00000400 + .equ USR_Stack_Size, 0x00000400 + + + .bss + .section .stack , "aw", %nobits + +USR_Stack_Start: + .skip USR_Stack_Size +USR_Stack_End: +IRQ_Stack_Start: + .skip IRQ_Stack_Size +IRQ_Stack_End: +FIQ_Stack_Start: + .skip FIQ_Stack_Size +FIQ_Stack_End: +ABT_Stack_Start: + .skip ABT_Stack_Size +ABT_Stack_End: +SVC_Stack_Start: + .skip SVC_Stack_Size +SVC_Stack_End: +UND_Stack_Start: + .skip UND_Stack_Size +UND_Stack_End: + +// Embedded Flash Controller (EFC) definitions + .equ EFC_BASE, 0xFFFFFF00 /* EFC Base Address */ + .equ EFC_FMR, 0x60 /* EFC_FMR Offset */ + +/* +// Embedded Flash Controller (EFC) +// FMCN: Flash Microsecond Cycle Number <0-255> +// Number of Master Clock Cycles in 1us +// FWS: Flash Wait State +// <0=> Read: 1 cycle / Write: 2 cycles +// <1=> Read: 2 cycle / Write: 3 cycles +// <2=> Read: 3 cycle / Write: 4 cycles +// <3=> Read: 4 cycle / Write: 4 cycles +// +*/ + .equ EFC_SETUP, 1 + .equ EFC_FMR_Val, 0x00320100 + + +// Watchdog Timer (WDT) definitions + .equ WDT_BASE, 0xFFFFFD40 /* WDT Base Address */ + .equ WDT_MR, 0x04 /* WDT_MR Offset */ + +/* +// Watchdog Timer (WDT) +// WDV: Watchdog Counter Value <0-4095> +// WDD: Watchdog Delta Value <0-4095> +// WDFIEN: Watchdog Fault Interrupt Enable +// WDRSTEN: Watchdog Reset Enable +// WDRPROC: Watchdog Reset Processor +// WDDBGHLT: Watchdog Debug Halt +// WDIDLEHLT: Watchdog Idle Halt +// WDDIS: Watchdog Disable +// +*/ + .equ WDT_SETUP, 1 + .equ WDT_MR_Val, 0x00008000 // Disable watchdog + + +// Power Mangement Controller (PMC) definitions + .equ PMC_BASE, 0xFFFFFC00 /* PMC Base Address */ + .equ PMC_MOR, 0x20 /* PMC_MOR Offset */ + .equ PMC_MCFR, 0x24 /* PMC_MCFR Offset */ + .equ PMC_PLLR, 0x2C /* PMC_PLLR Offset */ + .equ PMC_MCKR, 0x30 /* PMC_MCKR Offset */ + .equ PMC_SR, 0x68 /* PMC_SR Offset */ + .equ PMC_MOSCEN, (1<<0) /* Main Oscillator Enable */ + .equ PMC_OSCBYPASS, (1<<1) /* Main Oscillator Bypass */ + .equ PMC_OSCOUNT, (0xFF<<8) /* Main OScillator Start-up Time */ + .equ PMC_DIV, (0xFF<<0) /* PLL Divider */ + .equ PMC_PLLCOUNT, (0x3F<<8) /* PLL Lock Counter */ + .equ PMC_OUT, (0x03<<14) /* PLL Clock Frequency Range */ + .equ PMC_MUL, (0x7FF<<16) /* PLL Multiplier */ + .equ PMC_USBDIV, (0x03<<28) /* USB Clock Divider */ + .equ PMC_CSS, (3<<0) /* Clock Source Selection */ + .equ PMC_PRES, (7<<2) /* Prescaler Selection */ + .equ PMC_MOSCS, (1<<0) /* Main Oscillator Stable */ + .equ PMC_LOCK, (1<<2) /* PLL Lock Status */ + +/* +// Power Mangement Controller (PMC) +// Main Oscillator +// MOSCEN: Main Oscillator Enable +// OSCBYPASS: Oscillator Bypass +// OSCCOUNT: Main Oscillator Startup Time <0-255> +// +// Phase Locked Loop (PLL) +// DIV: PLL Divider <0-255> +// MUL: PLL Multiplier <0-2047> +// PLL Output is multiplied by MUL+1 +// OUT: PLL Clock Frequency Range +// <0=> 80..160MHz <1=> Reserved +// <2=> 150..220MHz <3=> Reserved +// PLLCOUNT: PLL Lock Counter <0-63> +// USBDIV: USB Clock Divider +// <0=> None <1=> 2 <2=> 4 <3=> Reserved +// +// CSS: Clock Source Selection +// <0=> Slow Clock +// <1=> Main Clock +// <2=> Reserved +// <3=> PLL Clock +// PRES: Prescaler +// <0=> None +// <1=> Clock / 2 <2=> Clock / 4 +// <3=> Clock / 8 <4=> Clock / 16 +// <5=> Clock / 32 <6=> Clock / 64 +// <7=> Reserved +// +*/ + .equ PMC_SETUP, 1 + .equ PMC_MOR_Val, 0x00000601 /* Enable main oscilator, + 48 cycles startup */ + .equ PMC_PLLR_Val, 0x00191C05 /* 28 cycles startup, + PLL = 5.2* * main clock */ + .equ PMC_MCKR_Val, 0x0000000B /* MCK = PLL/4 */ + +/* Reset controller */ + .equ RSTC_BASE, 0xfffffd00 + .equ RSTC_CR, 0x00 + .equ RSTC_SR, 0x04 + .equ RSTC_MR, 0x08 + + .equ RSTC_SETUP, 1 + .equ RSTC_MR_Val, 0xa5000001 /* Enable user reset */ + + + +#if (defined(VECTORS_IN_RAM) && defined(ROM_RUN)) || defined(USE_SAMBA) + +/* + Exception Vectors to be placed in RAM - added by mt + -> will be used after remapping in ROM_RUN + -> not needed for RAM_RUN + -> moved to address 0 after remapping + Mapped to Address 0 after remapping in ROM_RUN + Absolute addressing mode must be used. + Dummy Handlers are implemented as infinite loops which can be modified. + VECTORS_IN_RAM defined in makefile/by commandline +*/ + .text + .arm + .section .vectram, "ax" + +VectorsRAM: LDR PC,Reset_AddrR + LDR PC,Undef_AddrR + LDR PC,SWI_AddrR + LDR PC,PAbt_AddrR + LDR PC,DAbt_AddrR + NOP /* Reserved Vector */ + LDR PC,[PC,#-0xF20] /* Vector From AIC_IVR */ + LDR PC,[PC,#-0xF20] /* Vector From AIC_FVR */ + +Reset_AddrR: .word Reset_Handler +Undef_AddrR: .word Undef_HandlerR +SWI_AddrR: .word SWI_HandlerR +PAbt_AddrR: .word PAbt_HandlerR +DAbt_AddrR: .word DAbt_HandlerR +// .word 0xdeadbeef /* Test Reserved Address */ + .word 0 /* Reserved Address */ +IRQ_AddrR: .word IRQ_HandlerR +FIQ_AddrR: .word FIQ_HandlerR + +Undef_HandlerR: B Undef_HandlerR +SWI_HandlerR: B SWI_HandlerR +PAbt_HandlerR: B PAbt_HandlerR +DAbt_HandlerR: B DAbt_HandlerR +IRQ_HandlerR: B IRQ_HandlerR +FIQ_HandlerR: B FIQ_HandlerR + +VectorsRAM_end: +#endif /* VECTORS_IN_RAM && ROM_RUN */ + + + +#ifndef USE_SAMBA + +/* + Exception Vectors + - for ROM_RUN: placed in 0x00000000 + - for RAM_RUN: placed at 0x00200000 (on AT91SAM7S64) + - for USE_SAMBA: not used + -> will be used during startup before remapping with target ROM_RUN + -> will be used "always" in code without remapping or with target RAM_RUN + Mapped to Address relative address 0 of .text + Absolute addressing mode must be used. + Dummy Handlers are implemented as infinite loops which can be modified. +*/ + .text + .arm + .section .vectrom, "ax" + +Vectors: LDR PC,Reset_Addr + LDR PC,Undef_Addr + LDR PC,SWI_Addr + LDR PC,PAbt_Addr + LDR PC,DAbt_Addr + NOP /* Reserved Vector */ +// LDR PC,IRQ_Addr + LDR PC,[PC,#-0xF20] /* Vector From AIC_IVR */ +// LDR PC,FIQ_Addr + LDR PC,[PC,#-0xF20] /* Vector From AIC_FVR */ + +Reset_Addr: .word Reset_Handler +Undef_Addr: .word Undef_Handler +SWI_Addr: .word SWI_Handler +PAbt_Addr: .word PAbt_Handler +DAbt_Addr: .word DAbt_Handler + .word 0 /* Reserved Address */ +IRQ_Addr: .word IRQ_Handler +FIQ_Addr: .word FIQ_Handler + +Undef_Handler: B Undef_Handler +SWI_Handler: B SWI_Handler +PAbt_Handler: B PAbt_Handler +DAbt_Handler: B DAbt_Handler +IRQ_Handler: B IRQ_Handler +FIQ_Handler: B FIQ_Handler + +#endif + +// Starupt Code must be linked first at Address at which it expects to run. + + .text + .arm + .section .init, "ax" + + .global _startup + .func _startup +_startup: + + +// Reset Handler + LDR pc, =Reset_Handler +Reset_Handler: + +// Setup EFC +.if EFC_SETUP + LDR R0, =EFC_BASE + LDR R1, =EFC_FMR_Val + STR R1, [R0, #EFC_FMR] +.endif + + +// Setup WDT +.if WDT_SETUP + LDR R0, =WDT_BASE + LDR R1, =WDT_MR_Val + STR R1, [R0, #WDT_MR] +.endif + +// Setup reset controller +.if RSTC_SETUP + LDR R0, =RSTC_BASE + LDR R1, =RSTC_MR_Val + STR R1, [R0, #RSTC_MR] +.endif + +// Setup PMC +.if PMC_SETUP + LDR R0, =PMC_BASE + +// Setup Main Oscillator + LDR R1, =PMC_MOR_Val + STR R1, [R0, #PMC_MOR] + +// Wait until Main Oscillator is stablilized +.if (PMC_MOR_Val & PMC_MOSCEN) +MOSCS_Loop: LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MOSCS + BEQ MOSCS_Loop +.endif + +// Setup the PLL +.if (PMC_PLLR_Val & PMC_MUL) + LDR R1, =PMC_PLLR_Val + STR R1, [R0, #PMC_PLLR] + +// Wait until PLL is stabilized +PLL_Loop: LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_LOCK + BEQ PLL_Loop +.endif + +// Select Clock + LDR R1, =PMC_MCKR_Val + STR R1, [R0, #PMC_MCKR] +.endif + + +// Setup Stack for each mode + + LDR R0, =Top_Stack + +// Enter Undefined Instruction Mode and set its Stack Pointer + MSR CPSR_c, #Mode_UND|I_Bit|F_Bit + LDR SP, =UND_Stack_End + +// Enter Abort Mode and set its Stack Pointer + MSR CPSR_c, #Mode_ABT|I_Bit|F_Bit + LDR SP, =ABT_Stack_End + +// Enter FIQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_FIQ|I_Bit|F_Bit + LDR SP, =FIQ_Stack_End + +// Enter IRQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_IRQ|I_Bit|F_Bit + LDR SP, =IRQ_Stack_End + +// Enter Supervisor Mode and set its Stack Pointer + MSR CPSR_c, #Mode_SVC|I_Bit|F_Bit + LDR SP, =SVC_Stack_End + +// Enter User Mode and set its Stack Pointer +#ifndef RUN_AS_SYSTEM + MSR CPSR_c, #Mode_SYS +#else + MSR CPSR_c, #Mode_USR +#endif + LDR SP, =USR_Stack_End + +// Setup a default Stack Limit (when compiled with "-mapcs-stack-check") + LDR SL, =USR_Stack_End + +#ifdef ROM_RUN +// Relocate .data section (Copy from ROM to RAM) + LDR R1, =_etext + LDR R2, =_data + LDR R3, =_edata +LoopRel: CMP R2, R3 + LDRLO R0, [R1], #4 + STRLO R0, [R2], #4 + BLO LoopRel +#endif + + +// Clear .bss section (Zero init) + MOV R0, #0 + LDR R1, =__bss_start__ + LDR R2, =__bss_end__ +LoopZI: CMP R1, R2 + STRLO R0, [R1], #4 + BLO LoopZI + + +#if defined(VECTORS_IN_RAM) || defined(RAM_RUN) +/* + *** Remap *** + ROM_RUN: exception vectors for RAM have been already copied + to 0x00200000 by the .data copy-loop + RAM_RUN: exception vectors are already placed at 0x0020000 by + linker settings +*/ + .equ MC_BASE,0xFFFFFF00 /* MC Base Address */ + .equ MC_RCR, 0x00 /* MC_RCR Offset */ + + LDR R0, =MC_BASE + MOV R1, #1 + STR R1, [R0, #MC_RCR] // Remap +#endif /* VECTORS_IN_RAM || RAM_RUN */ + +#ifdef USE_SAMBA +// Copy interrupt vectors to RAM, that has previously been mapped to 0 + MOV R1, #0 + LDR R2, = VectorsRAM + LDR R3, = VectorsRAM_end +LoopVectCopy: CMP R2, R3 + LDRLO R0, [R2], #4 + STRLO R0, [R1], #4 + BLO LoopVectCopy +#endif + + +/* + Call C++ constructors (for objects in "global scope") + added by Martin Thomas based on a Anglia Design + example-application for STR7 ARM +*/ + + LDR r0, =__ctors_start__ + LDR r1, =__ctors_end__ +ctor_loop: + CMP r0, r1 + BEQ ctor_end + LDR r2, [r0], #4 /* this ctor's address */ + STMFD sp!, {r0-r1} /* save loop counters */ + MOV lr, pc /* set return address */ +// MOV pc, r2 + BX r2 /* call ctor */ + LDMFD sp!, {r0-r1} /* restore loop counters */ + B ctor_loop +ctor_end: + + +// Enter the C code + mov r0,#0 // no arguments (argc = 0) + mov r1,r0 + mov r2,r0 + mov fp,r0 // null frame pointer + mov r7,r0 // null frame pointer for thumb + ldr r10,=main + adr lr, __main_exit + bx r10 // enter main() + +__main_exit: B __main_exit + + + .size _startup, . - _startup + .endfunc + +.end + + + +