diff --git a/soc/runtime/Makefile b/soc/runtime/Makefile index d7653cdce..43238912f 100644 --- a/soc/runtime/Makefile +++ b/soc/runtime/Makefile @@ -3,7 +3,7 @@ include $(MSCDIR)/software/common.mak BOARD=papilio_pro SERIAL=/dev/ttyUSB1 -OBJECTS=esr.o elf_loader.o main.o +OBJECTS=isr.o elf_loader.o main.o all: runtime.bin diff --git a/soc/runtime/elf_loader.c b/soc/runtime/elf_loader.c index f2ade1987..f2518de83 100644 --- a/soc/runtime/elf_loader.c +++ b/soc/runtime/elf_loader.c @@ -38,88 +38,179 @@ static const unsigned char elf_magic_header[] = { #define EM_OR1K 0x005c struct elf32_shdr { - unsigned int name; /* section name */ - unsigned int type; /* SHT_... */ - unsigned int flags; /* SHF_... */ - unsigned int addr; /* virtual address */ - unsigned int offset; /* file offset */ - unsigned int size; /* section size */ - unsigned int link; /* misc info */ - unsigned int info; /* misc info */ - unsigned int addralign; /* memory alignment */ - unsigned int entsize; /* entry size if table */ + unsigned int name; /* section name */ + unsigned int type; /* SHT_... */ + unsigned int flags; /* SHF_... */ + unsigned int addr; /* virtual address */ + unsigned int offset; /* file offset */ + unsigned int size; /* section size */ + unsigned int link; /* misc info */ + unsigned int info; /* misc info */ + unsigned int addralign; /* memory alignment */ + unsigned int entsize; /* entry size if table */ } __attribute__((packed)); -#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_name { char name[12]; } __attribute__((packed)); +struct elf32_rela { + unsigned int offset; /* Location to be relocated. */ + unsigned int info; /* Relocation type and symbol index. */ + int addend; /* Addend. */ +} __attribute__((packed)); + +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +#define R_OR1K_INSN_REL_26 6 + +struct elf32_sym { + unsigned int name; /* String table index of name. */ + unsigned int value; /* Symbol value. */ + unsigned int size; /* Size of associated object. */ + unsigned char info; /* Type and binding information. */ + unsigned char other; /* Reserved (not used). */ + unsigned short shndx; /* Section index of symbol. */ +} __attribute__((packed)); + + #define SANITIZE_OFFSET_SIZE(offset, size) \ - if(offset > 0x10000000) \ + if(offset > 0x10000000) { \ + printf("Incorrect offset in ELF data"); \ return 0; \ - if((offset + size) > elf_length) \ - return 0 + } \ + if((offset + size) > elf_length) { \ + printf("Attempted to access past the end of ELF data"); \ + return 0; \ + } #define GET_POINTER_SAFE(target, target_type, offset) \ SANITIZE_OFFSET_SIZE(offset, sizeof(target_type)); \ target = (target_type *)((char *)elf_data + offset) -int load_elf(void *elf_data, int elf_length, void *dest, int dest_length) +static void *find_symbol(const struct symbol *symbols, const char *name) +{ + int i; + + i = 0; + while((symbols[i].name != NULL) && (strcmp(symbols[i].name, name) != 0)) + i++; + return symbols[i].target; +} + +static int fixup(void *dest, int dest_length, struct elf32_rela *rela, void *target) +{ + int type, offset; + unsigned int *_dest = dest; + unsigned int *_target = target; + + type = ELF32_R_TYPE(rela->info); + offset = rela->offset/4; + if(type == R_OR1K_INSN_REL_26) { + int val; + + val = _target - (_dest + offset); + _dest[offset] = (_dest[offset] & 0xfc000000) | (val & 0x03ffffff); + } else + printf("Unsupported relocation type: %d\n", type); + return 1; +} + +int load_elf(const struct symbol *symbols, void *elf_data, int elf_length, void *dest, int dest_length) { struct elf32_ehdr *ehdr; struct elf32_shdr *strtable; - struct elf32_shdr *shdr; - struct elf32_name *name; unsigned int shdrptr; int i; - unsigned int textoff; - unsigned int textsize; + unsigned int textoff, textsize; + unsigned int textrelaoff, textrelasize; + unsigned int symtaboff, symtabsize; + unsigned int strtaboff, strtabsize; + /* validate ELF */ GET_POINTER_SAFE(ehdr, struct elf32_ehdr, 0); - if(memcmp(ehdr->ident, elf_magic_header, sizeof(elf_magic_header)) != 0) + if(memcmp(ehdr->ident, elf_magic_header, sizeof(elf_magic_header)) != 0) { + printf("Incorrect ELF header\n"); return 0; - if(ehdr->type != ET_REL) return 0; - if(ehdr->machine != EM_OR1K) return 0; + } + if(ehdr->type != ET_REL) { + printf("ELF is not relocatable\n"); + return 0; + } + if(ehdr->machine != EM_OR1K) { + printf("ELF is for a different machine\n"); + return 0; + } + /* extract section info */ GET_POINTER_SAFE(strtable, struct elf32_shdr, ehdr->shoff + ehdr->shentsize*ehdr->shstrndx); - textoff = textsize = 0; + textrelaoff = textrelasize = 0; + symtaboff = symtabsize = 0; + strtaboff = strtabsize = 0; shdrptr = ehdr->shoff; for(i=0;ishnum;i++) { + struct elf32_shdr *shdr; + struct elf32_name *name; + GET_POINTER_SAFE(shdr, struct elf32_shdr, shdrptr); GET_POINTER_SAFE(name, struct elf32_name, strtable->offset + shdr->name); if(strncmp(name->name, ".text", 5) == 0) { textoff = shdr->offset; textsize = shdr->size; + } else if(strncmp(name->name, ".rela.text", 10) == 0) { + textrelaoff = shdr->offset; + textrelasize = shdr->size; + } else if(strncmp(name->name, ".symtab", 7) == 0) { + symtaboff = shdr->offset; + symtabsize = shdr->size; + } else if(strncmp(name->name, ".strtab", 7) == 0) { + strtaboff = shdr->offset; + strtabsize = shdr->size; } shdrptr += ehdr->shentsize; } - SANITIZE_OFFSET_SIZE(textoff, textsize); - if(textsize > dest_length) + SANITIZE_OFFSET_SIZE(textrelaoff, textrelasize); + SANITIZE_OFFSET_SIZE(symtaboff, symtabsize); + SANITIZE_OFFSET_SIZE(strtaboff, strtabsize); + + /* load .text section */ + if(textsize > dest_length) { + printf(".text section is too large\n"); return 0; + } memcpy(dest, (char *)elf_data + textoff, textsize); + /* process .text relocations */ + for(i=0;iinfo)); + if(sym->name != 0) { + void *target; + + name = (char *)elf_data + strtaboff + sym->name; + target = find_symbol(symbols, name); + if(target == NULL) { + printf("Undefined symbol: %s\n", name); + return 0; + } + if(!fixup(dest, dest_length, rela, target)) + return 0; + } else { + printf("Unsupported relocation\n"); + return 0; + } + } + return 1; } diff --git a/soc/runtime/elf_loader.h b/soc/runtime/elf_loader.h index 1672f8199..7c8fae33d 100644 --- a/soc/runtime/elf_loader.h +++ b/soc/runtime/elf_loader.h @@ -1,6 +1,11 @@ #ifndef __ELF_LOADER_H #define __ELF_LOADER_H -int load_elf(void *elf_data, int elf_length, void *dest, int dest_length); +struct symbol { + char *name; + void *target; +}; + +int load_elf(const struct symbol *symbols, void *elf_data, int elf_length, void *dest, int dest_length); #endif /* __ELF_LOADER_H */ diff --git a/soc/runtime/esr.c b/soc/runtime/esr.c deleted file mode 100644 index f9bf1756c..000000000 --- a/soc/runtime/esr.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -static void isr(void) -{ - unsigned int irqs; - - irqs = irq_pending() & irq_getmask(); - - if(irqs & (1 << UART_INTERRUPT)) - uart_isr(); -} - -#define EXTERNAL_IRQ 0x800 -#define SYSTEM_CALL 0xc00 - -void exception_handler(unsigned long vect, unsigned long *sp); -void exception_handler(unsigned long vect, unsigned long *sp) -{ - vect &= 0xf00; - if(vect == SYSTEM_CALL) { - puts("scall"); - } else if(vect == EXTERNAL_IRQ) { - isr(); - } else { - /* Unhandled exception */ - for(;;); - } -} diff --git a/soc/runtime/isr.c b/soc/runtime/isr.c new file mode 100644 index 000000000..c49d31d8d --- /dev/null +++ b/soc/runtime/isr.c @@ -0,0 +1,14 @@ +#include +#include +#include + +void isr(void); +void isr(void) +{ + unsigned int irqs; + + irqs = irq_pending() & irq_getmask(); + + if(irqs & (1 << UART_INTERRUPT)) + uart_isr(); +} diff --git a/soc/runtime/main.c b/soc/runtime/main.c index 8d7554b12..40bd61a1e 100644 --- a/soc/runtime/main.c +++ b/soc/runtime/main.c @@ -29,12 +29,13 @@ static void receive_sync(void) static int receive_length(void) { - int r, i; + unsigned int r; + int i; r = 0; for(i=0;i<4;i++) { r <<= 8; - r |= readchar(); + r |= (unsigned char)readchar(); } return r; } @@ -54,6 +55,16 @@ static int download_kernel(void *buffer, int maxlength) return length; } +static void printint(int x) +{ + printf("%d\n", x); +} + +static const struct symbol syscalls[] = { + {"__syscall_printint", printint}, + {NULL, NULL} +}; + typedef void (*kernel_function)(int); int main(void) @@ -73,11 +84,10 @@ int main(void) while(1) { length = download_kernel(kbuf, sizeof(kbuf)); if(length > 0) { - load_elf(kbuf, length, kcode, sizeof(kcode)); + load_elf(syscalls, kbuf, length, kcode, sizeof(kcode)); flush_cpu_icache(); - for(i=0;i<20;i++) { - printf("=== %2d ===\n", i); - readchar(); + for(i=0;i<40;i++) { + printf("%2d: ", i); k(i); } }