runtime: support regular function calls from the kernel

This commit is contained in:
Sebastien Bourdeauducq 2014-07-05 19:39:49 +02:00
parent de238503d2
commit a08c6d4410
6 changed files with 169 additions and 79 deletions

View File

@ -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

View File

@ -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;i<ehdr->shnum;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;i<textrelasize;i+=sizeof(struct elf32_rela)) {
struct elf32_rela *rela;
struct elf32_sym *sym;
char *name;
GET_POINTER_SAFE(rela, struct elf32_rela, textrelaoff + i);
GET_POINTER_SAFE(sym, struct elf32_sym, symtaboff + sizeof(struct elf32_sym)*ELF32_R_SYM(rela->info));
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;
}

View File

@ -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 */

View File

@ -1,30 +0,0 @@
#include <generated/csr.h>
#include <irq.h>
#include <uart.h>
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(;;);
}
}

14
soc/runtime/isr.c Normal file
View File

@ -0,0 +1,14 @@
#include <generated/csr.h>
#include <irq.h>
#include <uart.h>
void isr(void);
void isr(void)
{
unsigned int irqs;
irqs = irq_pending() & irq_getmask();
if(irqs & (1 << UART_INTERRUPT))
uart_isr();
}

View File

@ -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);
}
}