From 19fed0bd879c5bedf948cb9f1a18dfad3c56c3eb Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Sat, 11 Jul 2015 00:16:27 +0200 Subject: [PATCH] add the support of user-level tasks --- hermit/arch/x86/include/asm/elf.h | 181 ++++++++++++++++++++++++++++ hermit/arch/x86/include/asm/tasks.h | 3 +- hermit/arch/x86/kernel/tasks.c | 32 +---- hermit/include/hermit/config.h | 2 +- hermit/include/hermit/tasks.h | 20 ++- hermit/kernel/main.c | 7 +- hermit/kernel/syscall.c | 2 +- hermit/kernel/tasks.c | 26 ++-- 8 files changed, 223 insertions(+), 50 deletions(-) create mode 100644 hermit/arch/x86/include/asm/elf.h diff --git a/hermit/arch/x86/include/asm/elf.h b/hermit/arch/x86/include/asm/elf.h new file mode 100644 index 000000000..810ce852d --- /dev/null +++ b/hermit/arch/x86/include/asm/elf.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @author Stefan Lankes + * @file arch/x86/include/asm/elf.h + * @brief Define constants and structures related to ELF + * + * This file keeps define constants for identification and definition of ELF files.\n + * ELF files consist of up to five parts: + * - ELF header + * - program header table + * - section header table + * - ELF sections + * - ELF segment + */ +#ifndef __ELF_H__ +#define __ELF_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ELF_MAGIC 0x464C457F + +#define ELF_ET_NONE 0x0000 // no type +#define ELF_ET_REL 0x0001 // relocatable +#define ELF_ET_EXEC 0x0002 // executeable +#define ELF_ET_DYN 0x0003 // Shared-Object-File +#define ELF_ET_CORE 0x0004 // Corefile +#define ELF_ET_LOPROC 0xFF00 // Processor-specific +#define ELF_ET_HIPROC 0x00FF // Processor-specific + +#define ELF_EM_NONE 0x0000 // no type +#define ELF_EM_M32 0x0001 // AT&T WE 32100 +#define ELF_EM_SPARC 0x0002 // SPARC +#define ELF_EM_386 0x0003 // Intel 80386 +#define ELF_EM_68K 0x0004 // Motorola 68000 +#define ELF_EM_88K 0x0005 // Motorola 88000 +#define ELF_EM_860 0x0007 // Intel 80860 +#define ELF_EM_MIPS 0x0008 // MIPS RS3000 +#define ELF_EM_X86_64 0x003e // Intel X86_64 + +#define ELF_CLASS_NONE 0x0000 +#define ELF_CLASS_32 0x0001 // 32bit file +#define ELF_CLASS_64 0x0002 // 64bit file + +#define ELF_DATA_NONE 0x0000 +#define ELF_DATA_2LSB 0x0001 +#define ELF_DATA_2MSB 0x002 + +/* Legal values for p_type (segment type). */ + +#define ELF_PT_NULL 0 /* Program header table entry unused */ +#define ELF_PT_LOAD 1 /* Loadable program segment */ +#define ELF_PT_DYNAMIC 2 /* Dynamic linking information */ +#define ELF_PT_INTERP 3 /* Program interpreter */ +#define ELF_PT_NOTE 4 /* Auxiliary information */ +#define ELF_PT_SHLIB 5 +#define ELF_PT_PHDR 6 /* Entry for header table itself */ +#define ELF_PT_TLS 7 /* Thread-local storage segment */ +#define ELF_PT_NUM 8 /* Number of defined types */ +#define ELF_PT_LOOS 0x60000000 /* Start of OS-specific */ +#define ELF_PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define ELF_PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define ELF_PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define ELF_PT_LOSUNW 0x6ffffffa +#define ELF_PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define ELF_PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define ELF_PT_HISUNW 0x6fffffff +#define ELF_PT_HIOS 0x6fffffff /* End of OS-specific */ +#define ELF_PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define ELF_PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +/** @brief Identification part of an ELF-file's header + * + * This structure keeps information about the file format + */ +typedef struct { + uint32_t magic; + uint8_t _class; + uint8_t data; + uint8_t version; + uint8_t pad[8]; + uint8_t nident; +} __attribute__ ((packed)) elf_ident_t; + +/** @brief Information about the executable + * + * ELF header\n + * This structure keeps information about the format of the executable itself. + */ +typedef struct { + elf_ident_t ident; + uint16_t type; + uint16_t machine; + uint32_t version; + size_t entry; + size_t ph_offset; + size_t sh_offset; + uint32_t flags; + uint16_t header_size; + uint16_t ph_entry_size; + uint16_t ph_entry_count; + uint16_t sh_entry_size; + uint16_t sh_entry_count; + uint16_t sh_str_table_index; +} __attribute__ ((packed)) elf_header_t; + +/** @brief program header information + * + * program header table\n + * This structure keeps information about the program header. + */ +typedef struct +{ + uint32_t type; + uint32_t flags; + uint64_t offset; + uint64_t virt_addr; + uint64_t phys_addr; + uint64_t file_size; + uint64_t mem_size; + uint64_t alignment; +} __attribute__ ((packed)) elf_program_header_t; + +/** @brief Information about ELF section + * + * ELF section\n + * This structure keeps information about a specific ELF section + */ +typedef struct { + uint32_t name; + uint32_t type; + uint64_t flags; + uint64_t addr; + uint64_t offset; + uint64_t size; + uint32_t link; + uint32_t info; + uint64_t align; + uint64_t enttry_size; +} __attribute__ ((packed)) elf_section_header_t; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/hermit/arch/x86/include/asm/tasks.h b/hermit/arch/x86/include/asm/tasks.h index 621ccc797..5681c3dbd 100644 --- a/hermit/arch/x86/include/asm/tasks.h +++ b/hermit/arch/x86/include/asm/tasks.h @@ -75,8 +75,7 @@ static inline int jump_to_user_code(size_t ep, size_t stack) // x86_64 doesn't longer use segment registers //asm volatile ("mov %0, %%ds; mov %0, %%es" :: "r"(ds)); - asm volatile ("push %0; push %1; pushfq; push %2; push %3" :: "r"(ds), "r"(stack), "r"(cs), "r"(ep)); - asm volatile ("iretq"); + asm volatile ("push %0; push %1; pushfq; push %2; push %3; iretq" :: "r"(ds), "r"(stack), "r"(cs), "r"(ep)); return 0; } diff --git a/hermit/arch/x86/kernel/tasks.c b/hermit/arch/x86/kernel/tasks.c index 864795519..7669af9f1 100644 --- a/hermit/arch/x86/kernel/tasks.c +++ b/hermit/arch/x86/kernel/tasks.c @@ -32,9 +32,9 @@ #include #include #include -//#include +#include #include -//#include +#include #include size_t* get_current_stack(void) @@ -102,8 +102,6 @@ int create_default_frame(task_t* task, entry_point_t ep, void* arg) return 0; } -#if 0 - #define MAX_ARGS (PAGE_SIZE - 2*sizeof(int) - sizeof(vfs_node_t*)) /** @brief Structure which keeps all @@ -139,7 +137,7 @@ static int load_task(load_args_t* largs) file->flags = 0; //TODO: init the hole fildes_t struct! - task_t* curr_task = current_task; + task_t* curr_task = per_core(current_task); int err; if (!largs) @@ -161,25 +159,11 @@ static int load_task(load_args_t* largs) if (BUILTIN_EXPECT(header.type != ELF_ET_EXEC, 0)) goto invalid; -#ifdef CONFIG_X86_32 - if (BUILTIN_EXPECT(header.machine != ELF_EM_386, 0)) - goto invalid; -#elif defined(CONFIG_X86_64) if (BUILTIN_EXPECT(header.machine != ELF_EM_X86_64, 0)) goto invalid; -#else - goto invalid; -#endif -#ifdef CONFIG_X86_32 - if (BUILTIN_EXPECT(header.ident._class != ELF_CLASS_32, 0)) - goto invalid; -#elif defined(CONFIG_X86_64) if (BUILTIN_EXPECT(header.ident._class != ELF_CLASS_64, 0)) goto invalid; -#else - goto invalid; -#endif if (BUILTIN_EXPECT(header.ident.data != ELF_DATA_2LSB, 0)) goto invalid; @@ -208,10 +192,9 @@ static int load_task(load_args_t* largs) addr = get_pages(npages); flags = PG_USER; -#ifdef CONFIG_X86_64 if (has_nx() && !(prog_header.flags & PF_X)) flags |= PG_XD; -#endif + // map page frames in the address space of the current task if (page_map(prog_header.virt_addr, addr, npages, flags|PG_RW)) kprintf("Could not map 0x%x at 0x%x\n", addr, prog_header.virt_addr); @@ -249,10 +232,8 @@ static int load_task(load_args_t* largs) addr = get_pages(npages); stack = header.entry*2; // virtual address of the stack flags = PG_USER|PG_RW; -#ifdef CONFIG_X86_64 if (has_nx() && !(prog_header.flags & PF_X)) flags |= PG_XD; -#endif if (page_map(stack, addr, npages, flags)) { kprintf("Could not map stack at 0x%x\n", stack); @@ -382,7 +363,7 @@ static int user_entry(void* arg) * - 0 on success * - -ENOMEM (-12) or -EINVAL (-22) on failure */ -int create_user_task(tid_t* id, const char* fname, char** argv) +int create_user_task_on_core(tid_t* id, const char* fname, char** argv, uint8_t prio, uint32_t core_id) { vfs_node_t* node; int argc = 0; @@ -421,6 +402,5 @@ int create_user_task(tid_t* id, const char* fname, char** argv) /* create new task */ - return create_task(id, user_entry, load_args, NORMAL_PRIO); + return create_task(id, user_entry, load_args, prio, core_id); } -#endif diff --git a/hermit/include/hermit/config.h b/hermit/include/hermit/config.h index e1e2f82ba..395778256 100644 --- a/hermit/include/hermit/config.h +++ b/hermit/include/hermit/config.h @@ -48,7 +48,7 @@ extern "C" { #define BYTE_ORDER LITTLE_ENDIAN -//#define CONFIG_VGA +#define CONFIG_VGA #define BUILTIN_EXPECT(exp, b) __builtin_expect((exp), (b)) //#define BUILTIN_EXPECT(exp, b) (exp) diff --git a/hermit/include/hermit/tasks.h b/hermit/include/hermit/tasks.h index 48cc6fdfb..c9501051d 100644 --- a/hermit/include/hermit/tasks.h +++ b/hermit/include/hermit/tasks.h @@ -68,6 +68,22 @@ size_t** scheduler(void); */ int multitasking_init(void); +/** @brief Create a task with a specific entry point + * + * @todo Don't acquire table_lock for the whole task creation. + * + * @param id Pointer to a tid_t struct were the id shall be set + * @param ep Pointer to the function the task shall start with + * @param arg Arguments list + * @param prio Desired priority of the new task + * @param core_id Start the new task on the core with this id + * + * @return + * - 0 on success + * - -ENOMEM (-12) or -EINVAL (-22) on failure + */ +int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio, uint32_t core_id); + /** @brief create a kernel-level task on the current core. * * @param id The value behind this pointer will be set to the new task's id @@ -105,7 +121,7 @@ int create_kernel_task_on_core(tid_t* id, entry_point_t ep, void* args, uint8_t * - 0 on success * - -EINVAL (-22) or -ENOMEM (-12)on failure */ -int create_user_task(tid_t* id, const char* fame, char** argv); +int create_user_task(tid_t* id, const char* fame, char** argv, uint8_t prio); /** @brief Create a user level task. * @@ -118,7 +134,7 @@ int create_user_task(tid_t* id, const char* fame, char** argv); * - 0 on success * - -EINVAL (-22) or -ENOMEM (-12)on failure */ -int create_user_task_on_core(tid_t* id, const char* fame, char** argv, uint32_t core_id); +int create_user_task_on_core(tid_t* id, const char* fame, char** argv, uint8_t prio, uint32_t core_id); /** @brief Cleanup function for the task termination * diff --git a/hermit/kernel/main.c b/hermit/kernel/main.c index da95be85c..9e6748c76 100644 --- a/hermit/kernel/main.c +++ b/hermit/kernel/main.c @@ -137,6 +137,8 @@ int smp_main(void) int main(void) { + char* argv1[] = {"/bin/hello", NULL}; + hermit_init(); system_calibration(); // enables also interrupts @@ -154,8 +156,9 @@ int main(void) list_fs(fs_root, 1); #endif - create_kernel_task(NULL, foo, "foo1", NORMAL_PRIO); - create_kernel_task(NULL, foo, "foo2", NORMAL_PRIO); + //create_kernel_task(NULL, foo, "foo1", NORMAL_PRIO); + //create_kernel_task(NULL, foo, "foo2", NORMAL_PRIO); + create_user_task(NULL, "/bin/hello", argv1, NORMAL_PRIO); #if 0 init_netifs(); diff --git a/hermit/kernel/syscall.c b/hermit/kernel/syscall.c index 63db155cf..d204ec546 100644 --- a/hermit/kernel/syscall.c +++ b/hermit/kernel/syscall.c @@ -102,7 +102,7 @@ ssize_t syscall_handler(uint32_t sys_nr, ...) break; } default: - kprintf("invalid system call: %u\n", sys_nr); + kprintf("invalid system call: 0x%lx\n", sys_nr); ret = -ENOSYS; break; }; diff --git a/hermit/kernel/tasks.c b/hermit/kernel/tasks.c index 6e7d1b331..a76114a8c 100644 --- a/hermit/kernel/tasks.c +++ b/hermit/kernel/tasks.c @@ -209,21 +209,7 @@ void NORETURN abort(void) { do_exit(-1); } -/** @brief Create a task with a specific entry point - * - * @todo Don't acquire table_lock for the whole task creation. - * - * @param id Pointer to a tid_t struct were the id shall be set - * @param ep Pointer to the function the task shall start with - * @param arg Arguments list - * @param prio Desired priority of the new task - * @param core_id Start the new task on the core with this id - * - * @return - * - 0 on success - * - -ENOMEM (-12) or -EINVAL (-22) on failure - */ -static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio, uint32_t core_id) +int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio, uint32_t core_id) { int ret = -ENOMEM; uint32_t i; @@ -295,6 +281,14 @@ out: return ret; } +int create_user_task(tid_t* id, const char* fname, char** argv, uint8_t prio) +{ + if (prio > MAX_PRIO) + prio = NORMAL_PRIO; + + return create_user_task_on_core(id, fname, argv, prio, CORE_ID); +} + int create_kernel_task_on_core(tid_t* id, entry_point_t ep, void* args, uint8_t prio, uint32_t core_id) { if (prio > MAX_PRIO) @@ -610,7 +604,7 @@ get_task_out: orig_task->flags &= ~TASK_FPU_USED; } - //kprintf("schedule on core %d from %u to %u with prio %u\n", core_id, orig_task->id, curr_task->id, (uint32_t)curr_task->prio); + kprintf("schedule on core %d from %u to %u with prio %u\n", core_id, orig_task->id, curr_task->id, (uint32_t)curr_task->prio); return (size_t**) &(orig_task->last_stack_pointer); }