aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-02-13 21:52:48 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-02-13 21:52:48 +0100
commit47e6cd42f0744f6c04b8347093f6549339a856c9 (patch)
treec91fc43178d136c2aa0f093087ba8cfb4e90bdae
parentcf0b8a52287ee7c747b1d5a7d77abdef1fb46f94 (diff)
downloadkogata-47e6cd42f0744f6c04b8347093f6549339a856c9.tar.gz
kogata-47e6cd42f0744f6c04b8347093f6549339a856c9.zip
Implement ELF loading ; arrange so that user processes run.
-rwxr-xr-xrun_qemu.sh2
-rw-r--r--src/apps/init/main.c2
-rw-r--r--src/kernel/Makefile2
-rw-r--r--src/kernel/core/gdt.c21
-rw-r--r--src/kernel/core/kmain.c19
-rw-r--r--src/kernel/core/paging.c3
-rw-r--r--src/kernel/include/elf.h59
-rw-r--r--src/kernel/include/process.h6
-rw-r--r--src/kernel/user/elf.c70
-rw-r--r--src/kernel/user/process.c8
-rw-r--r--src/lib/libkogata/start.c7
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(&current_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);
}