Added ELF-loader code, should probably eventually end up in core/loader.
Added some replacements for newlib's stdout. Added missing startup code. Some minor fixes.
This commit is contained in:
parent
d684c14aa6
commit
b105b40e9a
@ -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
|
||||
|
28
cpu/at91sam7s/dbg-io/dbg-printf.c
Normal file
28
cpu/at91sam7s/dbg-io/dbg-printf.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include <stdio.h>
|
||||
#include <debug-uart.h>
|
||||
#include <string.h>
|
||||
#include <strformat.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
26
cpu/at91sam7s/dbg-io/dbg-putchar.c
Normal file
26
cpu/at91sam7s/dbg-io/dbg-putchar.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include <stdio.h>
|
||||
#include <debug-uart.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
11
cpu/at91sam7s/dbg-io/dbg-puts.c
Normal file
11
cpu/at91sam7s/dbg-io/dbg-puts.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <stdio.h>
|
||||
#include <debug-uart.h>
|
||||
#include <string.h>
|
||||
|
||||
int
|
||||
puts(const char *str)
|
||||
{
|
||||
dbg_send_bytes((unsigned char*)str, strlen(str));
|
||||
dbg_putchar('\n');
|
||||
return 0;
|
||||
}
|
615
cpu/at91sam7s/dbg-io/strformat.c
Normal file
615
cpu/at91sam7s/dbg-io/strformat.c
Normal file
@ -0,0 +1,615 @@
|
||||
#include <strformat.h>
|
||||
|
||||
#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;
|
||||
}
|
25
cpu/at91sam7s/dbg-io/strformat.h
Normal file
25
cpu/at91sam7s/dbg-io/strformat.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef __STRFORMAT_H__
|
||||
#define __STRFORMAT_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#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__ */
|
@ -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;
|
||||
}
|
||||
|
522
cpu/at91sam7s/loader/codeprop-otf.c
Normal file
522
cpu/at91sam7s/loader/codeprop-otf.c
Normal file
@ -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 <adam@sics.se>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "contiki-net.h"
|
||||
#include "cfs/cfs.h"
|
||||
#include "codeprop-otf.h"
|
||||
#include "loader/elfloader-otf.h"
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
/** @} */
|
52
cpu/at91sam7s/loader/codeprop-otf.h
Normal file
52
cpu/at91sam7s/loader/codeprop-otf.h
Normal file
@ -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__ */
|
101
cpu/at91sam7s/loader/elfloader-arch-otf.h
Normal file
101
cpu/at91sam7s/loader/elfloader-arch-otf.h
Normal file
@ -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 <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#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__ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
680
cpu/at91sam7s/loader/elfloader-otf.c
Normal file
680
cpu/at91sam7s/loader/elfloader-otf.c
Normal file
@ -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 <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
314
cpu/at91sam7s/loader/elfloader-otf.h
Normal file
314
cpu/at91sam7s/loader/elfloader-otf.h
Normal file
@ -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 <adam@sics.se>
|
||||
* Simon Berg <ksb@users.sourceforge.net>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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__ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
140
cpu/at91sam7s/loader/ram-segments.c
Normal file
140
cpu/at91sam7s/loader/ram-segments.c
Normal file
@ -0,0 +1,140 @@
|
||||
#ifndef __RAM_SEGMENTS_C__1POIF5E8U4__
|
||||
#define __RAM_SEGMENTS_C__1POIF5E8U4__
|
||||
|
||||
#include <loader/elfloader-otf.h>
|
||||
#include <loader/codeprop-otf.h>
|
||||
#include <sys/types.h>
|
||||
#include <lib/malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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__ */
|
6
cpu/at91sam7s/loader/ram-segments.h
Normal file
6
cpu/at91sam7s/loader/ram-segments.h
Normal file
@ -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__ */
|
@ -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;
|
||||
}
|
||||
|
498
cpu/at91sam7s/startup-SAM7S.S
Normal file
498
cpu/at91sam7s/startup-SAM7S.S
Normal file
@ -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 */
|
||||
/* <eversmith@heizung-thomas.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
|
||||
|
||||
|
||||
/*
|
||||
// <h> Stack Configuration
|
||||
// <o> Top of Stack Address <0x0-0xFFFFFFFF:4>
|
||||
// <h> Stack Sizes (in Bytes)
|
||||
// <o1> Undefined Mode <0x0-0xFFFFFFFF:4>
|
||||
// <o2> Supervisor Mode <0x0-0xFFFFFFFF:4>
|
||||
// <o3> Abort Mode <0x0-0xFFFFFFFF:4>
|
||||
// <o4> Fast Interrupt Mode <0x0-0xFFFFFFFF:4>
|
||||
// <o5> Interrupt Mode <0x0-0xFFFFFFFF:4>
|
||||
// <o6> User/System Mode <0x0-0xFFFFFFFF:4>
|
||||
// </h>
|
||||
// </h>
|
||||
*/
|
||||
.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 */
|
||||
|
||||
/*
|
||||
// <e> Embedded Flash Controller (EFC)
|
||||
// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
|
||||
// <i> Number of Master Clock Cycles in 1us
|
||||
// <o1.8..9> 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
|
||||
// </e>
|
||||
*/
|
||||
.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 */
|
||||
|
||||
/*
|
||||
// <e> Watchdog Timer (WDT)
|
||||
// <o1.0..11> WDV: Watchdog Counter Value <0-4095>
|
||||
// <o1.16..27> WDD: Watchdog Delta Value <0-4095>
|
||||
// <o1.12> WDFIEN: Watchdog Fault Interrupt Enable
|
||||
// <o1.13> WDRSTEN: Watchdog Reset Enable
|
||||
// <o1.14> WDRPROC: Watchdog Reset Processor
|
||||
// <o1.28> WDDBGHLT: Watchdog Debug Halt
|
||||
// <o1.29> WDIDLEHLT: Watchdog Idle Halt
|
||||
// <o1.15> WDDIS: Watchdog Disable
|
||||
// </e>
|
||||
*/
|
||||
.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 */
|
||||
|
||||
/*
|
||||
// <e> Power Mangement Controller (PMC)
|
||||
// <h> Main Oscillator
|
||||
// <o1.0> MOSCEN: Main Oscillator Enable
|
||||
// <o1.1> OSCBYPASS: Oscillator Bypass
|
||||
// <o1.8..15> OSCCOUNT: Main Oscillator Startup Time <0-255>
|
||||
// </h>
|
||||
// <h> Phase Locked Loop (PLL)
|
||||
// <o2.0..7> DIV: PLL Divider <0-255>
|
||||
// <o2.16..26> MUL: PLL Multiplier <0-2047>
|
||||
// <i> PLL Output is multiplied by MUL+1
|
||||
// <o2.14..15> OUT: PLL Clock Frequency Range
|
||||
// <0=> 80..160MHz <1=> Reserved
|
||||
// <2=> 150..220MHz <3=> Reserved
|
||||
// <o2.8..13> PLLCOUNT: PLL Lock Counter <0-63>
|
||||
// <o2.28..29> USBDIV: USB Clock Divider
|
||||
// <0=> None <1=> 2 <2=> 4 <3=> Reserved
|
||||
// </h>
|
||||
// <o3.0..1> CSS: Clock Source Selection
|
||||
// <0=> Slow Clock
|
||||
// <1=> Main Clock
|
||||
// <2=> Reserved
|
||||
// <3=> PLL Clock
|
||||
// <o3.2..4> PRES: Prescaler
|
||||
// <0=> None
|
||||
// <1=> Clock / 2 <2=> Clock / 4
|
||||
// <3=> Clock / 8 <4=> Clock / 16
|
||||
// <5=> Clock / 32 <6=> Clock / 64
|
||||
// <7=> Reserved
|
||||
// </e>
|
||||
*/
|
||||
.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
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user