diff options
author | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-13 21:52:48 +0100 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-13 21:52:48 +0100 |
commit | 47e6cd42f0744f6c04b8347093f6549339a856c9 (patch) | |
tree | c91fc43178d136c2aa0f093087ba8cfb4e90bdae | |
parent | cf0b8a52287ee7c747b1d5a7d77abdef1fb46f94 (diff) | |
download | kogata-47e6cd42f0744f6c04b8347093f6549339a856c9.tar.gz kogata-47e6cd42f0744f6c04b8347093f6549339a856c9.zip |
Implement ELF loading ; arrange so that user processes run.
-rwxr-xr-x | run_qemu.sh | 2 | ||||
-rw-r--r-- | src/apps/init/main.c | 2 | ||||
-rw-r--r-- | src/kernel/Makefile | 2 | ||||
-rw-r--r-- | src/kernel/core/gdt.c | 21 | ||||
-rw-r--r-- | src/kernel/core/kmain.c | 19 | ||||
-rw-r--r-- | src/kernel/core/paging.c | 3 | ||||
-rw-r--r-- | src/kernel/include/elf.h | 59 | ||||
-rw-r--r-- | src/kernel/include/process.h | 6 | ||||
-rw-r--r-- | src/kernel/user/elf.c | 70 | ||||
-rw-r--r-- | src/kernel/user/process.c | 8 | ||||
-rw-r--r-- | src/lib/libkogata/start.c | 7 |
11 files changed, 179 insertions, 20 deletions
diff --git a/run_qemu.sh b/run_qemu.sh index 7f7d264..4dce76a 100755 --- a/run_qemu.sh +++ b/run_qemu.sh @@ -3,4 +3,4 @@ cd `dirname $0` make || exit 1 -qemu-system-i386 -kernel src/kernel/kernel.bin -serial stdio -m 16 +qemu-system-i386 -kernel src/kernel/kernel.bin -serial stdio -m 16 -initrd src/apps/init/init.bin diff --git a/src/apps/init/main.c b/src/apps/init/main.c index ef51834..47d7bba 100644 --- a/src/apps/init/main.c +++ b/src/apps/init/main.c @@ -3,7 +3,7 @@ #include <debug.h> int main(int argc, char **argv) { - asm volatile("int $0x80"); + asm volatile("int $0x40"); while(true); } diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 6cfa414..cfaadc3 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -2,7 +2,7 @@ OBJ = core/loader.o core/kmain.o core/dbglog.o core/sys.o \ core/gdt.o core/idt.o core/interrupt.o core/context_switch.o core/thread.o \ core/frame.o core/paging.o core/region.o core/kmalloc.o \ - user/vfs.o user/nullfs.o user/process.o + user/vfs.o user/nullfs.o user/process.o user/elf.o LIB = ../common/libc/libc.lib ../common/libkogata/libkogata.lib ../common/libalgo/libalgo.lib diff --git a/src/kernel/core/gdt.c b/src/kernel/core/gdt.c index 97e6661..ed7abe0 100644 --- a/src/kernel/core/gdt.c +++ b/src/kernel/core/gdt.c @@ -4,27 +4,25 @@ #define GDT_ENTRIES 6 // The contents of each entry is defined in gdt_init. /* One entry of the table */ -struct gdt_entry { +typedef struct { uint16_t limit_low; uint16_t base_low; uint8_t base_middle; uint8_t access; uint8_t granularity; uint8_t base_high; -} __attribute__((packed)); -typedef struct gdt_entry gdt_entry_t; +} __attribute__((packed)) gdt_entry_t; /* Structure defining the whole table : address and size (in bytes). */ -struct gdt_ptr { +typedef struct { uint16_t limit; uint32_t base; -} __attribute__((packed)); -typedef struct gdt_ptr gdt_ptr_t; +} __attribute__((packed)) gdt_ptr_t; /* The TSS is used for hardware multitasking. We don't use that, but we still need a TSS so that user mode process exceptions can be handled correctly by the kernel. */ -struct tss_entry { +typedef struct { uint32_t prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list. uint32_t esp0; // The stack pointer to load when we change to kernel mode. uint32_t ss0; // The stack segment to load when we change to kernel mode. @@ -52,8 +50,7 @@ struct tss_entry { uint32_t ldt; // Unused... uint16_t trap; uint16_t iomap_base; -} __attribute__((packed)); -typedef struct tss_entry tss_entry_t; +} __attribute__((packed)) tss_entry_t; // ========================= // // Actual definitions @@ -86,13 +83,11 @@ void gdt_init() { gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment 0x20 // Write TSS - memset(&tss_entry, 0, sizeof(tss_entry)); + memset(&tss_entry, 0, sizeof(tss_entry_t)); tss_entry.ss0 = 0x10; tss_entry.esp0 = 0; - - tss_entry.cs = 0x0b; - tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13; + tss_entry.iomap_base = sizeof(tss_entry_t); uint32_t tss_base = (uint32_t)&tss_entry; uint32_t tss_limit = tss_base + sizeof(tss_entry_t); diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c index 34438aa..5572ac4 100644 --- a/src/kernel/core/kmain.c +++ b/src/kernel/core/kmain.c @@ -15,6 +15,8 @@ #include <vfs.h> #include <nullfs.h> +#include <process.h> +#include <elf.h> #include <slab_alloc.h> #include <hashtbl.h> @@ -333,6 +335,23 @@ void kernel_init_stage2(void* data) { test_cmdline(mbd, devfs); + fs_handle_t *init_bin = fs_open(devfs, "/mod/init.bin", FM_READ | FM_MMAP); + if (init_bin == 0) PANIC("No init.bin module provided!"); + if (!is_elf(init_bin)) PANIC("init.bin is not valid ELF32 binary"); + + process_t *init_p = new_process(0); + ASSERT(init_p != 0); + + bool add_devfs_ok = proc_add_fs(init_p, devfs, "dev"); + ASSERT(add_devfs_ok); + + proc_entry_t *e = elf_load(init_bin, init_p); + if (e == 0) PANIC("Could not load ELF file init.bin"); + + unref_file(init_bin); + + start_process(init_p, e); + //TODO : // - (OK) populate devfs with information regarding kernel command line & modules // - create user process with init module provided on command line diff --git a/src/kernel/core/paging.c b/src/kernel/core/paging.c index 74331c0..5a58c8c 100644 --- a/src/kernel/core/paging.c +++ b/src/kernel/core/paging.c @@ -221,7 +221,8 @@ bool pd_map_page(void* vaddr, uint32_t frame_id, bool rw) { } current_pd->page[pt] = pd->page[pt] = - (new_pt_frame << PTE_FRAME_SHIFT) | PTE_PRESENT | PTE_RW; + (new_pt_frame << PTE_FRAME_SHIFT) | PTE_PRESENT | PTE_RW + | ((size_t)vaddr < K_HIGHHALF_ADDR ? PTE_USER : 0); invlpg(¤t_pt[pt]); } current_pt[pt].page[page] = diff --git a/src/kernel/include/elf.h b/src/kernel/include/elf.h new file mode 100644 index 0000000..6e0c7cb --- /dev/null +++ b/src/kernel/include/elf.h @@ -0,0 +1,59 @@ +#pragma once + +#include <stddef.h> +#include <stdint.h> + +#include <vfs.h> +#include <process.h> + +/* elf_phdr_t :: p_type : program header entries types */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* elf_phdr_t :: p_flags : program header entries flags */ +#define PF_X (1 << 0) +#define PF_W (1 << 1) +#define PF_R (1 << 2) + +typedef struct { + uint8_t e_ident[16]; /* ELF identification */ + uint16_t e_type; /* 2 (exec file) */ + uint16_t e_machine; /* 3 (intel architecture) */ + uint32_t e_version; /* 1 */ + uint32_t e_entry; /* starting point */ + uint32_t e_phoff; /* program header table offset */ + uint32_t e_shoff; /* section header table offset */ + uint32_t e_flags; /* various flags */ + uint16_t e_ehsize; /* ELF header (this) size */ + + uint16_t e_phentsize; /* program header table entry size */ + uint16_t e_phnum; /* number of entries */ + + uint16_t e_shentsize; /* section header table entry size */ + uint16_t e_shnum; /* number of entries */ + + uint16_t e_shstrndx; /* index of the section name string table */ +} elf_ehdr_t; + +typedef struct { + uint32_t p_type; /* type of segment */ + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; +} elf_phdr_t; + +bool is_elf(fs_handle_t *f); +proc_entry_t elf_load(fs_handle_t *f, process_t *process); //Load an ELF to a process, return entry point + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/include/process.h b/src/kernel/include/process.h index d67ede6..661aaa6 100644 --- a/src/kernel/include/process.h +++ b/src/kernel/include/process.h @@ -27,12 +27,16 @@ struct process; typedef struct process process_t; +typedef void* proc_entry_t; + process_t *current_process(); process_t *new_process(process_t *parent); // void delete_process(process_t *p); // TODO define semantics for freeing stuff -bool start_process(process_t *p, void* entry); // maps a region for user stack +pagedir_t *proc_pagedir(process_t *p); + +bool start_process(process_t *p, proc_entry_t entry); // maps a region for user stack bool proc_add_fs(process_t *p, fs_t *fs, const char* name); fs_t *proc_find_fs(process_t *p, const char* name); diff --git a/src/kernel/user/elf.c b/src/kernel/user/elf.c new file mode 100644 index 0000000..905577d --- /dev/null +++ b/src/kernel/user/elf.c @@ -0,0 +1,70 @@ +#include <string.h> + +#include <elf.h> + + +bool is_elf(fs_handle_t *f) { + elf_ehdr_t h; + if (file_read(f, 0, sizeof(elf_ehdr_t), (char*)&h) != sizeof(elf_ehdr_t)) return false; + + return (h.e_ident[0] == 0x7F && h.e_ident[1] == 'E' + && h.e_ident[2] == 'L' && h.e_ident[3] == 'F'); +} + +proc_entry_t elf_load(fs_handle_t *f, process_t* process) { + if (!is_elf(f)) return 0; + + elf_ehdr_t ehdr; + if (file_read(f, 0, sizeof(elf_ehdr_t), (char*)&ehdr) != sizeof(elf_ehdr_t)) return 0; + + elf_phdr_t phdr; + int i; + + pagedir_t *r = get_current_pagedir(); + switch_pagedir(proc_pagedir(process)); + + // TODO : when we fail, free ressources ? + + for (i = 0; i < ehdr.e_phnum; i++) { + size_t read_phdr_r = + file_read(f, + ehdr.e_phoff + i * sizeof(elf_phdr_t), + sizeof(elf_phdr_t), + (char*)&phdr); + if (read_phdr_r != sizeof(elf_phdr_t)) goto error; + + if (phdr.p_type == PT_LOAD) { + if (phdr.p_flags & PF_W) { + mmap(process, (void*)phdr.p_vaddr, phdr.p_memsz, + ((phdr.p_flags & PF_R) ? MM_READ : 0) | MM_WRITE); + + size_t read_r = file_read(f, phdr.p_offset, phdr.p_filesz, (char*)phdr.p_vaddr); + if (read_r != phdr.p_filesz) goto error; + + if (phdr.p_memsz > phdr.p_filesz) { + memset((char*)phdr.p_vaddr + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz); + } + } else { + if (phdr.p_filesz != phdr.p_memsz) { + dbg_printf("Strange ELF file...\n"); + goto error; + } + + mmap_file(process, + f, phdr.p_offset, + (void*)phdr.p_vaddr, phdr.p_memsz, + ((phdr.p_flags & PF_R) ? MM_READ : 0) | ((phdr.p_flags & PF_X) ? MM_EXEC : 0)); + } + } + } + + switch_pagedir(r); + + return (proc_entry_t)ehdr.e_entry; + +error: + switch_pagedir(r); + return 0; +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index b8b0c23..0f4892d 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -114,6 +114,10 @@ bool start_process(process_t *p, void* entry) { return true; } +pagedir_t *proc_pagedir(process_t *p) { + return p->pd; +} + // ================================== // // MANAGING FILESYSTEMS FOR PROCESSES // // ================================== // @@ -224,6 +228,10 @@ bool munmap(process_t *proc, void* addr) { } } + // TODO : write modified pages back to file! + + if (r->file != 0) unref_file(r->file); + free(r); return true; diff --git a/src/lib/libkogata/start.c b/src/lib/libkogata/start.c index 88a4eb3..030423c 100644 --- a/src/lib/libkogata/start.c +++ b/src/lib/libkogata/start.c @@ -2,8 +2,11 @@ #include <stdint.h> #include <stdbool.h> +extern int main(int, char**); + void __libkogata_start() { - // TODO - while(true); + // TODO : setup + + main(0, 0); } |