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
|
### Compiler definitions
|
||||||
CC = arm-elf-gcc
|
CC = arm-elf-gcc
|
||||||
LD = arm-elf-gcc
|
LD = arm-elf-ld
|
||||||
AS = arm-elf-as
|
AS = arm-elf-as
|
||||||
AR = arm-elf-ar
|
AR = arm-elf-ar
|
||||||
NM = arm-elf-nm
|
NM = arm-elf-nm
|
||||||
@ -55,7 +55,8 @@ THUMB_FLAGS=-mthumb -mthumb-interwork
|
|||||||
ARM_FLAGS=-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) \
|
-I$(CONTIKI)/platform/$(TARGET) \
|
||||||
${addprefix -I,$(APPDIRS)} \
|
${addprefix -I,$(APPDIRS)} \
|
||||||
-DWITH_UIP -DWITH_ASCII -DMCK=$(MCK) \
|
-DWITH_UIP -DWITH_ASCII -DMCK=$(MCK) \
|
||||||
@ -73,7 +74,7 @@ CONTIKI_TARGET_DIRS_CONCAT = ${addprefix $(CONTIKI)/platform/$(TARGET)/, \
|
|||||||
|
|
||||||
vpath %.c $(PROJECTDIRS) \
|
vpath %.c $(PROJECTDIRS) \
|
||||||
$(CONTIKIDIRS) $(APPDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \
|
$(CONTIKIDIRS) $(APPDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \
|
||||||
$(CONTIKI_CPU)
|
$(CONTIKI_CPU) $(CONTIKI_CPU)/loader $(CONTIKI_CPU)/dbg-io
|
||||||
|
|
||||||
vpath %.S $(CONTIKI_CPU)
|
vpath %.S $(CONTIKI_CPU)
|
||||||
|
|
||||||
@ -96,8 +97,6 @@ interrupt-utils.o: interrupt-utils.c
|
|||||||
$(LD) --relocatable -T $(CONTIKI_CPU)/merge-rodata.ld $< -o $@
|
$(LD) --relocatable -T $(CONTIKI_CPU)/merge-rodata.ld $< -o $@
|
||||||
$(STRIP) -K _init -K _fini --strip-unneeded -g -x $@
|
$(STRIP) -K _init -K _fini --strip-unneeded -g -x $@
|
||||||
|
|
||||||
%.elf: $^ $(STARTUP)
|
|
||||||
$(CC) $(LDFLAGS) $(CFLAGS) $(THUMB_FLAGS) -nostartfiles -o $@ $^
|
|
||||||
|
|
||||||
# Add a namelist to the kernel
|
# Add a namelist to the kernel
|
||||||
%-syms.elf: $^ $(STARTUP)
|
%-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
|
-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
|
$(CC) $(LDFLAGS) $(CFLAGS) $(THUMB_FLAGS) -nostartfiles -o $*-syms.elf $^ $*-nm.c
|
||||||
|
|
||||||
|
%.elf: $^ $(STARTUP)
|
||||||
|
$(CC) $(LDFLAGS) $(CFLAGS) $(THUMB_FLAGS) -nostartfiles -o $@ $^
|
||||||
|
|
||||||
%.ihx: %.elf
|
%.ihx: %.elf
|
||||||
$(OBJCOPY) -O ihex $< $@
|
$(OBJCOPY) -O ihex $< $@
|
||||||
@ -137,3 +138,4 @@ clean:
|
|||||||
-rm *.ihx
|
-rm *.ihx
|
||||||
-rm *.bin
|
-rm *.bin
|
||||||
-rm *-nm.c
|
-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 */
|
/* Adapted from elfloader-avr.c */
|
||||||
|
|
||||||
void
|
int
|
||||||
elfloader_arch_relocate(int input_fd,
|
elfloader_arch_relocate(int input_fd,
|
||||||
struct elfloader_output *output,
|
struct elfloader_output *output,
|
||||||
unsigned int sectionoffset,
|
unsigned int sectionoffset,
|
||||||
@ -25,7 +25,6 @@ elfloader_arch_relocate(int input_fd,
|
|||||||
struct elf32_rela *rela, char *addr)
|
struct elf32_rela *rela, char *addr)
|
||||||
{
|
{
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
unsigned char instr[4];
|
|
||||||
|
|
||||||
type = ELF32_R_TYPE(rela->r_info);
|
type = ELF32_R_TYPE(rela->r_info);
|
||||||
|
|
||||||
@ -46,6 +45,7 @@ elfloader_arch_relocate(int input_fd,
|
|||||||
break;
|
break;
|
||||||
case R_ARM_THM_CALL:
|
case R_ARM_THM_CALL:
|
||||||
{
|
{
|
||||||
|
uint16_t instr[2];
|
||||||
int32_t offset;
|
int32_t offset;
|
||||||
char *base;
|
char *base;
|
||||||
cfs_read(input_fd, (char*)instr, 4);
|
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
|
and I can't think of a case when doing a relative call to
|
||||||
a non-symbol position */
|
a non-symbol position */
|
||||||
base = sectionaddr + (rela->r_offset + 4);
|
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)
|
addr = (char*)((((uint32_t)addr) & 0xfffffffd)
|
||||||
| (((uint32_t)base) & 0x00000002));
|
| (((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",
|
PRINTF("elfloader-arm.c: offset %d too large for relative call\n",
|
||||||
(int)offset);
|
(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); */
|
/* PRINTF("%p: %04x %04x offset: %d addr: %p\n", sectionaddr +rela->r_offset, instr[0], instr[1], (int)offset, addr); */
|
||||||
*(uint16_t*)instr = (*(uint16_t*)instr & 0xf800) | ((offset>>12)&0x07ff);
|
instr[0] = (instr[0] & 0xf800) | ((offset>>12)&0x07ff);
|
||||||
*(uint16_t*)(instr+2) = ((*(uint16_t*)(instr+2) & 0xf800)
|
instr[1] = (instr[1] & 0xf800) | ((offset>>1)&0x07ff);
|
||||||
| ((offset>>1)&0x07ff));
|
|
||||||
elfloader_output_write_segment(output, (char*)instr, 4);
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PRINTF("elfloader-arm.c: unsupported relocation type %d\n", type);
|
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_start__; /* Defined by the linker */
|
||||||
extern char __heap_end__; /* 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;
|
char *prev_heap_end;
|
||||||
|
|
||||||
if (heap_end == 0) {
|
|
||||||
heap_end = &__heap_start__;
|
|
||||||
}
|
|
||||||
prev_heap_end = heap_end;
|
prev_heap_end = heap_end;
|
||||||
if (heap_end + incr > &__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;
|
errno = ENOMEM;
|
||||||
return (caddr_t)-1;
|
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