[elf] Execute simple static ELF binaries.
This commit is contained in:
parent
09a8fb68bc
commit
e273784242
90
kernel/core/elf.c
Normal file
90
kernel/core/elf.c
Normal 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
|
||||
*/
|
@ -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) {
|
||||
|
@ -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 *)
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user