forked from M-Labs/artiq
runtime: support regular function calls from the kernel
This commit is contained in:
parent
de238503d2
commit
a08c6d4410
|
@ -3,7 +3,7 @@ include $(MSCDIR)/software/common.mak
|
||||||
BOARD=papilio_pro
|
BOARD=papilio_pro
|
||||||
SERIAL=/dev/ttyUSB1
|
SERIAL=/dev/ttyUSB1
|
||||||
|
|
||||||
OBJECTS=esr.o elf_loader.o main.o
|
OBJECTS=isr.o elf_loader.o main.o
|
||||||
|
|
||||||
all: runtime.bin
|
all: runtime.bin
|
||||||
|
|
||||||
|
|
|
@ -38,88 +38,179 @@ static const unsigned char elf_magic_header[] = {
|
||||||
#define EM_OR1K 0x005c
|
#define EM_OR1K 0x005c
|
||||||
|
|
||||||
struct elf32_shdr {
|
struct elf32_shdr {
|
||||||
unsigned int name; /* section name */
|
unsigned int name; /* section name */
|
||||||
unsigned int type; /* SHT_... */
|
unsigned int type; /* SHT_... */
|
||||||
unsigned int flags; /* SHF_... */
|
unsigned int flags; /* SHF_... */
|
||||||
unsigned int addr; /* virtual address */
|
unsigned int addr; /* virtual address */
|
||||||
unsigned int offset; /* file offset */
|
unsigned int offset; /* file offset */
|
||||||
unsigned int size; /* section size */
|
unsigned int size; /* section size */
|
||||||
unsigned int link; /* misc info */
|
unsigned int link; /* misc info */
|
||||||
unsigned int info; /* misc info */
|
unsigned int info; /* misc info */
|
||||||
unsigned int addralign; /* memory alignment */
|
unsigned int addralign; /* memory alignment */
|
||||||
unsigned int entsize; /* entry size if table */
|
unsigned int entsize; /* entry size if table */
|
||||||
} __attribute__((packed));
|
} __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 {
|
struct elf32_name {
|
||||||
char name[12];
|
char name[12];
|
||||||
} __attribute__((packed));
|
} __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) \
|
#define SANITIZE_OFFSET_SIZE(offset, size) \
|
||||||
if(offset > 0x10000000) \
|
if(offset > 0x10000000) { \
|
||||||
|
printf("Incorrect offset in ELF data"); \
|
||||||
return 0; \
|
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) \
|
#define GET_POINTER_SAFE(target, target_type, offset) \
|
||||||
SANITIZE_OFFSET_SIZE(offset, sizeof(target_type)); \
|
SANITIZE_OFFSET_SIZE(offset, sizeof(target_type)); \
|
||||||
target = (target_type *)((char *)elf_data + offset)
|
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_ehdr *ehdr;
|
||||||
struct elf32_shdr *strtable;
|
struct elf32_shdr *strtable;
|
||||||
struct elf32_shdr *shdr;
|
|
||||||
struct elf32_name *name;
|
|
||||||
unsigned int shdrptr;
|
unsigned int shdrptr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
unsigned int textoff;
|
unsigned int textoff, textsize;
|
||||||
unsigned int textsize;
|
unsigned int textrelaoff, textrelasize;
|
||||||
|
unsigned int symtaboff, symtabsize;
|
||||||
|
unsigned int strtaboff, strtabsize;
|
||||||
|
|
||||||
|
|
||||||
|
/* validate ELF */
|
||||||
GET_POINTER_SAFE(ehdr, struct elf32_ehdr, 0);
|
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;
|
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);
|
GET_POINTER_SAFE(strtable, struct elf32_shdr, ehdr->shoff + ehdr->shentsize*ehdr->shstrndx);
|
||||||
|
|
||||||
textoff = textsize = 0;
|
textoff = textsize = 0;
|
||||||
|
textrelaoff = textrelasize = 0;
|
||||||
|
symtaboff = symtabsize = 0;
|
||||||
|
strtaboff = strtabsize = 0;
|
||||||
shdrptr = ehdr->shoff;
|
shdrptr = ehdr->shoff;
|
||||||
for(i=0;i<ehdr->shnum;i++) {
|
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(shdr, struct elf32_shdr, shdrptr);
|
||||||
GET_POINTER_SAFE(name, struct elf32_name, strtable->offset + shdr->name);
|
GET_POINTER_SAFE(name, struct elf32_name, strtable->offset + shdr->name);
|
||||||
|
|
||||||
if(strncmp(name->name, ".text", 5) == 0) {
|
if(strncmp(name->name, ".text", 5) == 0) {
|
||||||
textoff = shdr->offset;
|
textoff = shdr->offset;
|
||||||
textsize = shdr->size;
|
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;
|
shdrptr += ehdr->shentsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
SANITIZE_OFFSET_SIZE(textoff, textsize);
|
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;
|
return 0;
|
||||||
|
}
|
||||||
memcpy(dest, (char *)elf_data + textoff, textsize);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#ifndef __ELF_LOADER_H
|
#ifndef __ELF_LOADER_H
|
||||||
#define __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 */
|
#endif /* __ELF_LOADER_H */
|
||||||
|
|
|
@ -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(;;);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -29,12 +29,13 @@ static void receive_sync(void)
|
||||||
|
|
||||||
static int receive_length(void)
|
static int receive_length(void)
|
||||||
{
|
{
|
||||||
int r, i;
|
unsigned int r;
|
||||||
|
int i;
|
||||||
|
|
||||||
r = 0;
|
r = 0;
|
||||||
for(i=0;i<4;i++) {
|
for(i=0;i<4;i++) {
|
||||||
r <<= 8;
|
r <<= 8;
|
||||||
r |= readchar();
|
r |= (unsigned char)readchar();
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +55,16 @@ static int download_kernel(void *buffer, int maxlength)
|
||||||
return length;
|
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);
|
typedef void (*kernel_function)(int);
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
@ -73,11 +84,10 @@ int main(void)
|
||||||
while(1) {
|
while(1) {
|
||||||
length = download_kernel(kbuf, sizeof(kbuf));
|
length = download_kernel(kbuf, sizeof(kbuf));
|
||||||
if(length > 0) {
|
if(length > 0) {
|
||||||
load_elf(kbuf, length, kcode, sizeof(kcode));
|
load_elf(syscalls, kbuf, length, kcode, sizeof(kcode));
|
||||||
flush_cpu_icache();
|
flush_cpu_icache();
|
||||||
for(i=0;i<20;i++) {
|
for(i=0;i<40;i++) {
|
||||||
printf("=== %2d ===\n", i);
|
printf("%2d: ", i);
|
||||||
readchar();
|
|
||||||
k(i);
|
k(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue