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
|
||||
SERIAL=/dev/ttyUSB1
|
||||
|
||||
OBJECTS=esr.o elf_loader.o main.o
|
||||
OBJECTS=isr.o elf_loader.o main.o
|
||||
|
||||
all: runtime.bin
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue