[elf] Execute simple static ELF binaries.

This commit is contained in:
Kevin Lange 2011-04-08 15:27:12 -05:00
parent 09a8fb68bc
commit e273784242
7 changed files with 179 additions and 19 deletions

90
kernel/core/elf.c Normal file
View File

@ -0,0 +1,90 @@
/*
* ELF Executable Loader
*/
#include <system.h>
#include <fs.h>
#include <elf.h>
static void
a_task(int argc, char ** argv) {
syscall_print("Hello world!\n");
syscall_print("I am: (");
char blarg[2] = { '0' + argc, 0};
syscall_print(blarg);
syscall_print(") ");
syscall_print(argv[0]);
syscall_print("\n");
syscall_exit(2);
}
/**
* Load and execute.
* @param path Path to the executable to attempt to execute.
* @param argc Number of arguments (because I'm not counting for you)
* @param argv Pointer to a string of arguments
*/
int
exec(
char * path,
int argc,
char ** argv
) {
/* Load the requested file */
int child = fork();
if (child == 0) {
/* Read in the binary */
fs_node_t * file = kopen(path,0);
if (!file) {
/* Command not found */
kexit(127);
}
Elf32_Header * header = (Elf32_Header *)malloc(file->length);
size_t bytes_read = read_fs(file, 0, file->length, (uint8_t *)header);
/* Alright, we've read the binary, time to load the loadable sections */
/* Verify the magic */
if ( header->e_ident[0] != ELFMAG0 ||
header->e_ident[1] != ELFMAG1 ||
header->e_ident[2] != ELFMAG2 ||
header->e_ident[3] != ELFMAG3) {
kprintf("Fatal: Not a valid ELF executable.\n");
kexit(127);
}
for (uintptr_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) {
Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)header + (header->e_shoff + x));
if (shdr->sh_addr) {
for (uintptr_t i = 0; i < shdr->sh_size; i += 0x1000) {
/* This doesn't care if we already allocated this page */
alloc_frame(get_page(shdr->sh_addr + i, 1, current_directory), 0, 1);
}
memcpy((void *)(shdr->sh_addr), (void *)((uintptr_t)header + shdr->sh_offset), shdr->sh_size);
}
}
enter_user_jmp((uintptr_t)header->e_entry, argc, argv);
/* We should never reach this mode */
kexit(0x5ADFACE);
} else {
/* You can wait here if you want... */
task_t * volatile child_task = gettask(child);
while (child_task->finished == 0) {
if (child_task->finished != 0) break;
}
return child_task->retval;
}
return -1;
}
/*
* vim:noexpandtab
* vim:tabstop=4
* vim:shiftwidth=4
*/

View File

@ -221,6 +221,12 @@ start_shell() {
} else {
bochs_draw_line(atoi(argv[1]),atoi(argv[2]),atoi(argv[3]),atoi(argv[4]),0xFFFFFF);
}
} else if (!strcmp(cmd, "exec")) {
if (tokenid < 2) {
continue;
}
int ret = exec(argv[1],tokenid - 1, &argv[1]);
kprintf("Returned %d\n", ret);
} else if (!strcmp(cmd, "boredom")) {
int x = 30;
if (tokenid > 1) {

View File

@ -6,15 +6,25 @@
static int print(char * s) {
kprintf(s);
return 2;
return 0;
}
static int exit(int retval) {
/* Deschedule the current task */
kprintf("Task (id=%d) exiting with return value %d.\n", getpid(), retval);
current_task->retval = retval;
current_task->finished = 1;
while (1) { };
return retval;
}
static void syscall_handler(struct regs * r);
static uintptr_t syscalls[] = {
/* System Call Table */
(uintptr_t)&exit,
(uintptr_t)&print
};
uint32_t num_syscalls = 1;
uint32_t num_syscalls = 2;
void
syscalls_install() {
@ -47,9 +57,5 @@ syscall_handler(
r->eax = ret;
}
//DEFN_SYSCALL1(print, 0, const char *)
int syscall_print(const char * p1) {
int a = 0xA5ADFACE;
__asm__ __volatile__("int $0x7F" : "=a" (a) : "0" (0), "b" ((int)p1));
return a;
}
DEFN_SYSCALL1(exit, 0, int)
DEFN_SYSCALL1(print, 1, const char *)

View File

@ -6,7 +6,7 @@
#define KERNEL_STACK_SIZE 0x2000
__volatile__ task_t * current_task = NULL;
__volatile__ task_t * ready_queue;
__volatile__ task_t * ready_queue = NULL;
uint32_t next_pid = 0;
@ -112,6 +112,17 @@ tasking_install() {
__asm__ __volatile__ ("sti");
}
task_t *
gettask(
uint32_t pid
) {
task_t * output = (task_t *)ready_queue;
while (output->id != pid && output != NULL) {
output = output->next;
}
return output;
}
uint32_t
fork() {
__asm__ __volatile__ ("cli");
@ -125,6 +136,7 @@ fork() {
new_task->page_directory = directory;
new_task->next = NULL;
new_task->stack = kvmalloc(KERNEL_STACK_SIZE);
new_task->finished = 0;
task_t * tmp_task = (task_t *)ready_queue;
while (tmp_task->next) {
tmp_task = tmp_task->next;
@ -219,3 +231,37 @@ enter_user_mode() {
"1:\n"
"mov %ax, %ax\n");
}
void
enter_user_jmp(uintptr_t location, int argc, char ** argv) {
set_kernel_stack(current_task->stack + KERNEL_STACK_SIZE);
__asm__ __volatile__(
"cli\n"
//"mov $0x23, %ax\n"
"mov $0x23, %%ax\n"
"mov %%ax, %%ds\n"
"mov %%ax, %%es\n"
"mov %%ax, %%fs\n"
"mov %%ax, %%gs\n"
"mov %%esp, %%eax\n"
"pushl $0x23\n"
"pushl %%eax\n"
"pushf\n"
"popl %%eax\n"
"orl $0x200, %%eax\n"
"pushl %%eax\n"
"pushl $0x1B\n"
"pushl %2\n"
"pushl %1\n"
"call *%0\n"
: : "m"(location), "m"(argc), "m"(argv));
}
void kexit(int retval) {
kprintf("Kernel task (id=%d) exiting with return value %d.\n", getpid(), retval);
current_task->retval = retval;
current_task->finished = 1;
while (1) {
__asm__ __volatile__("hlt");
}
}

View File

@ -168,12 +168,6 @@ extern void serial_send(char out);
extern void serial_string(char * out);
/* Tasks */
extern uintptr_t read_eip();
extern void copy_page_physical(uint32_t, uint32_t);
extern page_directory_t * clone_directory(page_directory_t * src);
extern page_table_t * clone_table(page_table_t * src, uintptr_t * physAddr);
extern void move_stack(void *new_stack_start, size_t size);
typedef struct task {
uint32_t id;
uintptr_t esp;
@ -183,8 +177,20 @@ typedef struct task {
struct task *next;
uintptr_t stack;
uintptr_t user_stack;
int retval;
uint8_t finished;
} task_t;
extern __volatile__ task_t * current_task;
extern __volatile__ task_t * ready_queue;
extern uintptr_t read_eip();
extern void copy_page_physical(uint32_t, uint32_t);
extern page_directory_t * clone_directory(page_directory_t * src);
extern page_table_t * clone_table(page_table_t * src, uintptr_t * physAddr);
extern void move_stack(void *new_stack_start, size_t size);
extern task_t * gettask(uint32_t pid);
extern void kexit(int retval);
typedef struct tss_entry {
uint32_t prev_tss;
@ -221,6 +227,7 @@ extern void switch_task();
extern uint32_t fork();
extern uint32_t getpid();
extern void enter_user_mode();
extern void enter_user_jmp(uintptr_t location, int argc, char ** argv);
uintptr_t initial_esp;
@ -269,6 +276,9 @@ extern uint8_t number_font[][12];
void set_fpu_cw(const uint16_t);
void enable_fpu();
/* ELF */
int exec( char *, int, char **);
/* Sytem Calls */
void syscalls_install();
#define DECL_SYSCALL0(fn) int syscall_##fn()
@ -293,6 +303,7 @@ void syscalls_install();
return a; \
}
DECL_SYSCALL1(exit, int);
DECL_SYSCALL1(print, const char *);
#endif

View File

@ -6,8 +6,9 @@ _start:
push 0 ; argv
extern main
call main
mov eax, 0
int 0x79
mov ebx, eax ; return value from main
mov eax, 0x0
int 0x7F
_wait:
hlt
jmp _wait

View File

@ -1,10 +1,10 @@
int syscall_print(const char * p1) {
int a = 0xA5ADFACE;
__asm__ __volatile__("int $0x7F" : "=a" (a) : "0" (0), "b" ((int)p1));
__asm__ __volatile__("int $0x7F" : "=a" (a) : "0" (1), "b" ((int)p1));
return a;
}
int main(int argc, char ** argv) {
syscall_print("Hello world!");
syscall_print("Hello world!\n");
return 0;
}