From 67926d7c655bd3565ccefe18bf976e86876326a6 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 19 Nov 2013 23:11:53 +0100 Subject: [PATCH] add support of nonpreemptive multitasking and additional comments --- Makefile.example | 2 +- arch/x86/include/asm/processor.h | 36 ++++ arch/x86/include/asm/stddef.h | 93 +---------- arch/x86/include/asm/tasks.h | 68 ++++++++ arch/x86/include/asm/tasks_types.h | 51 ++++++ arch/x86/kernel/Makefile | 2 +- arch/x86/kernel/entry.asm | 23 +++ arch/x86/kernel/tasks.c | 89 ++++++++++ include/eduos/config.h.example | 3 + include/eduos/errno.h | 180 ++++++++++++++++++++ include/eduos/stdarg.h | 14 +- include/eduos/stddef.h | 18 +- include/eduos/stdlib.h | 6 + include/eduos/string.h | 6 + include/eduos/tasks.h | 84 ++++++++++ include/eduos/tasks_types.h | 104 ++++++++++++ kernel/Makefile | 2 +- kernel/main.c | 24 ++- kernel/tasks.c | 254 +++++++++++++++++++++++++++++ mm/memory.c | 43 +++++ 20 files changed, 1003 insertions(+), 99 deletions(-) create mode 100644 arch/x86/include/asm/tasks.h create mode 100644 arch/x86/include/asm/tasks_types.h create mode 100644 arch/x86/kernel/tasks.c create mode 100644 include/eduos/errno.h create mode 100644 include/eduos/tasks.h create mode 100644 include/eduos/tasks_types.h create mode 100644 kernel/tasks.c create mode 100644 mm/memory.c diff --git a/Makefile.example b/Makefile.example index cba2c7f..34029f6 100644 --- a/Makefile.example +++ b/Makefile.example @@ -1,7 +1,7 @@ TOPDIR = $(shell pwd) ARCH = x86 NAME = eduos -KERNDIRS = libkern kernel arch/$(ARCH)/kernel +KERNDIRS = libkern kernel mm arch/$(ARCH)/kernel SUBDIRS = $(KERNDIRS) # Set your own cross compiler tool chain prefix here diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 015142b..64a3a15 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -81,6 +81,42 @@ inline static void rmb(void) { asm volatile("lfence" ::: "memory"); } /// Force strict CPU ordering, serializes store operations. inline static void wmb(void) { asm volatile("sfence" ::: "memory"); } +/** @brief search the first most significant bit + * + * @param i source operand + * @return + * - first bit, which is set in the source operand + * - invalid value, if not bit ist set + */ +static inline size_t msb(size_t i) +{ + size_t ret; + + if (!i) + return (sizeof(size_t)*8); + asm volatile ("bsr %1, %0" : "=r"(ret) : "r"(i) : "cc"); + + return ret; +} + +/** @brief search the least significant bit + * + * @param i source operand + * @return + * - first bit, which is set in the source operand + * - invalid value, if not bit ist set + */ +static inline size_t lsb(size_t i) +{ + size_t ret; + + if (!i) + return (sizeof(size_t)*8); + asm volatile ("bsf %1, %0" : "=r"(ret) : "r"(i) : "cc"); + + return ret; +} + /// A one-instruction-do-nothing #define NOP1 asm volatile ("nop") /// A two-instruction-do-nothing diff --git a/arch/x86/include/asm/stddef.h b/arch/x86/include/asm/stddef.h index 441f89a..5f3b937 100644 --- a/arch/x86/include/asm/stddef.h +++ b/arch/x86/include/asm/stddef.h @@ -40,29 +40,15 @@ extern "C" { #endif -#if __SIZEOF_POINTER__ == 4 #define CONFIG_X86_32 -/// A popular type for addresses +/// This type is used to represent the size of an object. typedef unsigned long size_t; /// Pointer differences typedef long ptrdiff_t; -#ifdef __KERNEL__ +/// It is similar to size_t, but must be a signed type. typedef long ssize_t; +/// The type represents an offset and is similar to size_t, but must be a signed type. typedef long off_t; -#endif -#elif __SIZEOF_POINTER__ == 8 -#define CONFIG_X86_64 -// A popular type for addresses -typedef unsigned long long size_t; -/// Pointer differences -typedef long long ptrdiff_t; -#ifdef __KERNEL__ -typedef long long ssize_t; -typedef long long off_t; -#endif -#else -#error unsupported architecture -#endif /// Unsigned 64 bit integer typedef unsigned long long uint64_t; @@ -83,22 +69,8 @@ typedef char int8_t; /// 16 bit wide char type typedef unsigned short wchar_t; -#ifndef _WINT_T -#define _WINT_T -typedef unsigned int wint_t; -#endif - -/** @brief This defines what the stack looks like after an ISR was called. - * - * All the interrupt handler routines use this type for their only parameter. - * Note: Our kernel doesn't use the GS and FS registers. - */ +/// This defines what the stack looks like after the task context is saved. struct state { -#ifdef CONFIG_X86_32 - // ds register - uint32_t ds; - // es register - uint32_t es; /// EDI register uint32_t edi; /// ESI register @@ -116,61 +88,10 @@ struct state { /// EAX register uint32_t eax; /* pushed by 'pusha' */ - /// Interrupt number - uint32_t int_no; - - // pushed by the processor automatically - uint32_t error; - uint32_t eip; - uint32_t cs; + // state of the controll register uint32_t eflags; - uint32_t useresp; - uint32_t ss; -#elif defined(CONFIG_X86_64) - /// R15 register - uint64_t r15; - /// R14 register - uint64_t r14; - /// R13 register - uint64_t r13; - /// R12 register - uint64_t r12; - /// R11 register - uint64_t r11; - /// R10 register - uint64_t r10; - /// R9 register - uint64_t r9; - /// R8 register - uint64_t r8; - /// RDI register - uint64_t rdi; - /// RSI register - uint64_t rsi; - /// RBP register - uint64_t rbp; - /// (pseudo) RSP register - uint64_t rsp; - /// RBX register - uint64_t rbx; - /// RDX register - uint64_t rdx; - /// RCX register - uint64_t rcx; - /// RAX register - uint64_t rax; - - /// Interrupt number - uint64_t int_no; - - // pushed by the processor automatically - uint64_t error; - uint64_t rip; - uint64_t cs; - uint64_t rflags; - uint64_t userrsp; - uint64_t ss; -#endif + /// state of instruction pointer + uint32_t eip; }; #ifdef __cplusplus diff --git a/arch/x86/include/asm/tasks.h b/arch/x86/include/asm/tasks.h new file mode 100644 index 0000000..5bda21b --- /dev/null +++ b/arch/x86/include/asm/tasks.h @@ -0,0 +1,68 @@ +/* + * 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/tasks.h + * @brief Task related structure definitions + * + * This file contains the task_t structure definition + * and task state define constants + */ + +#ifndef __ASM_TASKS_H__ +#define __ASM_TASKS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Switch to current task + * + * @param stack Pointer to the old stack pointer + */ +void switch_context(size_t** stack); + +/** @brief Setup a default frame for a new task + * + * @param task Pointer to the task structure + * @param ep The entry point for code execution + * @param arg Arguments list pointer for the task's stack + * @return + * - 0 on success + * - -EINVAL (-22) on failure + */ +int create_default_frame(task_t* task, entry_point_t ep, void* arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/arch/x86/include/asm/tasks_types.h b/arch/x86/include/asm/tasks_types.h new file mode 100644 index 0000000..e074a7b --- /dev/null +++ b/arch/x86/include/asm/tasks_types.h @@ -0,0 +1,51 @@ +/* + * 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/tasks_types.h + * @brief Task related structure definitions + * + * This file contains the task_t structure definition + * and task state define constants + */ + +#ifndef __ASM_TASKS_TYPES_H__ +#define __ASM_TASKS_TYPES_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 3a59e1d..54cc71a 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -1,4 +1,4 @@ -C_source := multiboot.c vga.c +C_source := tasks.c multiboot.c vga.c ASM_source := entry.asm string32.asm MODULE := arch_x86_kernel diff --git a/arch/x86/kernel/entry.asm b/arch/x86/kernel/entry.asm index 4d5c343..9b7a01f 100644 --- a/arch/x86/kernel/entry.asm +++ b/arch/x86/kernel/entry.asm @@ -82,11 +82,34 @@ cpu_init: mov cr4, eax ret +extern get_current_stack +extern finish_task_switch + +global switch_context +ALIGN 4 +switch_context: + mov eax, [esp+4] ; on the stack is already the address to store the old esp + pushf ; push controll register + pusha ; push all general purpose registers... + + mov [eax], esp ; store old esp + call get_current_stack ; get new esp + xchg eax, esp + + ; call cleanup code + call finish_task_switch + + ; restore context + popa + popf + ret + ; Here is the definition of our stack. Remember that a stack actually grows ; downwards, so we declare the size of the data before declaring ; the identifier 'default_stack_pointer' SECTION .data resb 8192 ; This reserves 8KBytes of memory here +global default_stack_pointer default_stack_pointer: SECTION .note.GNU-stack noalloc noexec nowrite progbits diff --git a/arch/x86/kernel/tasks.c b/arch/x86/kernel/tasks.c new file mode 100644 index 0000000..e72ca2d --- /dev/null +++ b/arch/x86/kernel/tasks.c @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include + +size_t* get_current_stack(void) +{ + task_t* curr_task = current_task; + + return curr_task->last_stack_pointer; +} + +int create_default_frame(task_t* task, entry_point_t ep, void* arg) +{ + size_t *stack; + struct state *stptr; + size_t state_size; + + if (BUILTIN_EXPECT(!task, 0)) + return -EINVAL; + + if (BUILTIN_EXPECT(!task->stack, 0)) + return -EINVAL; + + memset(task->stack, 0xCD, KERNEL_STACK_SIZE); + + /* The difference between setting up a task for SW-task-switching + * and not for HW-task-switching is setting up a stack and not a TSS. + * This is the stack which will be activated and popped off for iret later. + */ + stack = (size_t*) (task->stack + KERNEL_STACK_SIZE - 16); // => stack is 16byte aligned + + /* Only marker for debugging purposes, ... */ + *stack-- = 0xDEADBEEF; + /* the first-function-to-be-called's arguments, ... */ + *stack-- = (size_t) arg; + + /* and the "caller" we shall return to. + * This procedure cleans the task after exit. */ + *stack = (size_t) leave_kernel_task; + + /* Next bunch on the stack is the initial register state. + * The stack must look like the stack of a task which was + * scheduled away previously. */ + + state_size = sizeof(struct state); + stack = (size_t*) ((size_t) stack - state_size); + + stptr = (struct state *) stack; + memset(stptr, 0x00, state_size); + stptr->esp = (size_t)stack + state_size; + + stptr->eip = (size_t)ep; + stptr->eflags = 0x1202; + + /* Set the task's stack pointer entry to the stack we have crafted right now. */ + task->last_stack_pointer = (size_t*)stack; + + return 0; +} diff --git a/include/eduos/config.h.example b/include/eduos/config.h.example index 5db58b3..df5e5aa 100644 --- a/include/eduos/config.h.example +++ b/include/eduos/config.h.example @@ -33,7 +33,10 @@ extern "C" { #endif #define EDUOS_VERSION "0.1" +#define MAX_TASKS 16 #define VIDEO_MEM_ADDR 0xB8000 // the video memora address +#define CACHE_LINE 64 +#define KERNEL_STACK_SIZE (8*1024) #define BYTE_ORDER LITTLE_ENDIAN diff --git a/include/eduos/errno.h b/include/eduos/errno.h new file mode 100644 index 0000000..a27189c --- /dev/null +++ b/include/eduos/errno.h @@ -0,0 +1,180 @@ +/** + * @author Stefan Lankes + * @file include/eduos/errno.h + * @brief Error number define constants + * + * This file just contains the full list of error numbers which can + * be returned somewhere. In principle, we use the same error codes + * than newlib. + */ + +#ifndef __ERRNO_H__ +#define __ERRNO_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define EPERM 1 /* Not super-user */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No children */ +#define EAGAIN 11 /* No more processes */ +#define ENOMEM 12 /* Not enough core */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define ENOTBLK 15 /* Block device required */ +#endif +#define EBUSY 16 /* Mount device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math arg out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define ENOMSG 35 /* No message of desired type */ +#define EIDRM 36 /* Identifier removed */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define ECHRNG 37 /* Channel number out of range */ +#define EL2NSYNC 38 /* Level 2 not synchronized */ +#define EL3HLT 39 /* Level 3 halted */ +#define EL3RST 40 /* Level 3 reset */ +#define ELNRNG 41 /* Link number out of range */ +#define EUNATCH 42 /* Protocol driver not attached */ +#define ENOCSI 43 /* No CSI structure available */ +#define EL2HLT 44 /* Level 2 halted */ +#endif +#define EDEADLK 45 /* Deadlock condition */ +#define ENOLCK 46 /* No record locks available */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define EBADE 50 /* Invalid exchange */ +#define EBADR 51 /* Invalid request descriptor */ +#define EXFULL 52 /* Exchange full */ +#define ENOANO 53 /* No anode */ +#define EBADRQC 54 /* Invalid request code */ +#define EBADSLT 55 /* Invalid slot */ +#define EDEADLOCK 56 /* File locking deadlock error */ +#define EBFONT 57 /* Bad font file fmt */ +#endif +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data (for no delay io) */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* The object is remote */ +#endif +#define ENOLINK 67 /* The link has been severed */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#endif +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 74 /* Multihop attempted */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define ELBIN 75 /* Inode is remote (not really error) */ +#define EDOTDOT 76 /* Cross mount point (not really error) */ +#endif +#define EBADMSG 77 /* Trying to read unreadable message */ +#define EFTYPE 79 /* Inappropriate file type or format */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define ENOTUNIQ 80 /* Given log. name not unique */ +#define EBADFD 81 /* f.d. invalid for this operation */ +#define EREMCHG 82 /* Remote address changed */ +#define ELIBACC 83 /* Can't access a needed shared lib */ +#define ELIBBAD 84 /* Accessing a corrupted shared lib */ +#define ELIBSCN 85 /* .lib section in a.out corrupted */ +#define ELIBMAX 86 /* Attempting to link in too many libs */ +#define ELIBEXEC 87 /* Attempting to exec a shared library */ +#endif +#define ENOSYS 88 /* Function not implemented */ +#ifdef __CYGWIN__ +#define ENMFILE 89 /* No more files */ +#endif +#define ENOTEMPTY 90 /* Directory not empty */ +#define ENAMETOOLONG 91 /* File or path name too long */ +#define ELOOP 92 /* Too many symbolic links */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ +#define EPROTOTYPE 107 /* Protocol wrong type for socket */ +#define ENOTSOCK 108 /* Socket operation on non-socket */ +#define ENOPROTOOPT 109 /* Protocol not available */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define ESHUTDOWN 110 /* Can't send after socket shutdown */ +#endif +#define ECONNREFUSED 111 /* Connection refused */ +#define EADDRINUSE 112 /* Address already in use */ +#define ECONNABORTED 113 /* Connection aborted */ +#define ENETUNREACH 114 /* Network is unreachable */ +#define ENETDOWN 115 /* Network interface is not configured */ +#define ETIMEDOUT 116 /* Connection timed out */ +#define EHOSTDOWN 117 /* Host is down */ +#define EHOSTUNREACH 118 /* Host is unreachable */ +#define EINPROGRESS 119 /* Connection already in progress */ +#define EALREADY 120 /* Socket already connected */ +#define EDESTADDRREQ 121 /* Destination address required */ +#define EMSGSIZE 122 /* Message too long */ +#define EPROTONOSUPPORT 123 /* Unknown protocol */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define ESOCKTNOSUPPORT 124 /* Socket type not supported */ +#endif +#define EADDRNOTAVAIL 125 /* Address not available */ +#define ENETRESET 126 +#define EISCONN 127 /* Socket is already connected */ +#define ENOTCONN 128 /* Socket is not connected */ +#define ETOOMANYREFS 129 +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define EPROCLIM 130 +#define EUSERS 131 +#endif +#define EDQUOT 132 +#define ESTALE 133 +#define ENOTSUP 134 /* Not supported */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define ENOMEDIUM 135 /* No medium (in tape drive) */ +#endif +#ifdef __CYGWIN__ +#define ENOSHARE 136 /* No such host or network path */ +#define ECASECLASH 137 /* Filename exists with different case */ +#endif +#define EILSEQ 138 +#define EOVERFLOW 139 /* Value too large for defined data type */ +#define ECANCELED 140 /* Operation canceled */ +#define ENOTRECOVERABLE 141 /* State not recoverable */ +#define EOWNERDEAD 142 /* Previous owner died */ +#ifdef __LINUX_ERRNO_EXTENSIONS__ +#define ESTRPIPE 143 /* Streams pipe error */ +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eduos/stdarg.h b/include/eduos/stdarg.h index 9b8d02d..313f7fa 100644 --- a/include/eduos/stdarg.h +++ b/include/eduos/stdarg.h @@ -28,17 +28,27 @@ #ifndef __STDARG_H__ #define __STDARG_H__ +/** + * @author Stefan Lankes + * @file include/eduos/stdarg.h + * @brief Definition of variable argument lists + */ + #ifdef __cplusplus extern "C" { #endif typedef __builtin_va_list va_list; +/// Initialize a variable argument list #define va_start __builtin_va_start +/// Retrieve next argument #define va_arg __builtin_va_arg -#define va_end __builtin_va_end +/// End using variable argument list +#define va_end __builtin_va_end +/// copies the (previously initialized) variable argument list #define va_copy __builtin_va_copy - + #ifdef __cplusplus } #endif diff --git a/include/eduos/stddef.h b/include/eduos/stddef.h index 483f4ad..e488668 100644 --- a/include/eduos/stddef.h +++ b/include/eduos/stddef.h @@ -28,6 +28,12 @@ #ifndef __STDDEF_H__ #define __STDDEF_H__ +/** + * @author Stefan Lankes + * @file include/eduos/stddef.h + * @brief Definition of basic data types + */ + #include #include @@ -37,12 +43,12 @@ extern "C" { #define NULL ((void*) 0) -/* - * macros, which are later used to determine the core id - * and their "private" data - */ -#define per_core(name) name -#define CORE_ID 0 +/// represents a task identifier +typedef unsigned int tid_t; + +struct task; +/// pointer to the current (running) task +extern struct task* current_task; #ifdef __cplusplus } diff --git a/include/eduos/stdlib.h b/include/eduos/stdlib.h index 2a50007..eaed27c 100644 --- a/include/eduos/stdlib.h +++ b/include/eduos/stdlib.h @@ -44,6 +44,12 @@ extern "C" { #endif +/** @brief Create a new stack for a new task + * + * @return start address of the new stack + */ +void* create_stack(tid_t id); + #ifdef __cplusplus } #endif diff --git a/include/eduos/string.h b/include/eduos/string.h index bd4dac3..70284fa 100644 --- a/include/eduos/string.h +++ b/include/eduos/string.h @@ -28,6 +28,12 @@ #ifndef __STRING_H__ #define __STRING_H__ +/** + * @author Stefan Lankes + * @file include/eduos/string.h + * @brief Definition of basic string and memory opeations + */ + #include #include diff --git a/include/eduos/tasks.h b/include/eduos/tasks.h new file mode 100644 index 0000000..05e89e2 --- /dev/null +++ b/include/eduos/tasks.h @@ -0,0 +1,84 @@ +/* + * 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 include/eduos/tasks.h + * @brief Task related + * + * Create and leave tasks or fork them. + */ + +#ifndef __TASKS_H__ +#define __TASKS_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Initialize the multitasking subsystem + * + * This procedure sets the current task to the + * current "task" (there are no tasks, yet) and that was it. + * + * @return + * - 0 on success + * - -ENOMEM (-12) on failure + */ +int multitasking_init(void); + +/** @brief create a kernel task. + * + * @param id The value behind this pointer will be set to the new task's id + * @param ep Pointer to the entry function for the new task + * @param args Arguments the task shall start with + * @param prio Desired priority of the new kernel task + * + * @return + * - 0 on success + * - -EINVAL (-22) on failure + */ +int create_kernel_task(tid_t* id, entry_point_t ep, void* args, uint8_t prio); + +/** @brief Call to rescheduling + * + * This is a purely assembled procedure for rescheduling + */ +void reschedule(void); + +/** @brief This function shall be called by leaving kernel level tasks */ +void NORETURN leave_kernel_task(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eduos/tasks_types.h b/include/eduos/tasks_types.h new file mode 100644 index 0000000..55c5135 --- /dev/null +++ b/include/eduos/tasks_types.h @@ -0,0 +1,104 @@ +/* + * 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 include/eduos/tasks_types.h + * @brief Task related structure definitions + * + * This file contains the task_t structure definition + * and task state define constants + */ + +#ifndef __TASKS_TYPES_H__ +#define __TASKS_TYPES_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define TASK_INVALID 0 +#define TASK_READY 1 +#define TASK_RUNNING 2 +#define TASK_BLOCKED 3 +#define TASK_FINISHED 4 +#define TASK_IDLE 5 + +#define MAX_PRIO 31 +#define REALTIME_PRIO 31 +#define HIGH_PRIO 16 +#define NORMAL_PRIO 8 +#define LOW_PRIO 1 +#define IDLE_PRIO 0 + +typedef int (*entry_point_t)(void*); + +/** @brief Represents a the process control block */ +typedef struct task { + /// Task id = position in the task table + tid_t id; + /// Task status (INVALID, READY, RUNNING, ...) + uint32_t status; + /// copy of the stack pointer before a context switch + size_t* last_stack_pointer; + /// start address of the stack + void* stack; + /// Task priority + uint8_t prio; + /// next task in the queue + struct task* next; + /// previous task in the queue + struct task* prev; +} task_t; + +typedef struct { + task_t* first; + task_t* last; +} task_list_t; + +/** @brief Represents a queue for all runable tasks */ +typedef struct { + /// idle task + task_t* idle __attribute__ ((aligned (CACHE_LINE))); + /// previous task + task_t* old_task; + /// total number of tasks in the queue + uint32_t nr_tasks; + /// indicates the used priority queues + uint32_t prio_bitmap; + /// a queue for each priority + task_list_t queue[MAX_PRIO]; +} runqueue_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kernel/Makefile b/kernel/Makefile index 06612ba..99d1a62 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,4 +1,4 @@ -C_source := main.c +C_source := main.c tasks.c MODULE := kernel include $(TOPDIR)/Makefile.inc diff --git a/kernel/main.c b/kernel/main.c index aec08a6..34fc088 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -28,7 +28,9 @@ #include #include #include +#include #include +#include /* * Note that linker symbols are not variables, they have no memory allocated for @@ -41,24 +43,42 @@ extern const void bss_end; extern char __BUILD_DATE; extern char __BUILD_TIME; +static int foo(void* arg) +{ + int i = 0; + + for(i=0; i<5; i++) { + kprintf("hello from %s\n", (char*) arg); + reschedule(); + } + + return 0; +} + static int eduos_init(void) { // initialize .bss section memset((void*)&bss_start, 0x00, ((size_t) &bss_end - (size_t) &bss_start)); koutput_init(); + multitasking_init(); return 0; } int main(void) { + tid_t id1; + tid_t id2; eduos_init(); kprintf("This is eduOS %s Build %u, %u\n", EDUOS_VERSION, &__BUILD_DATE, &__BUILD_TIME); kprintf("Kernel starts at %p and ends at %p\n", &kernel_start, &kernel_end); - kprintf("\nHello World!\n"); - + + create_kernel_task(&id1, foo, "foo1", NORMAL_PRIO); + create_kernel_task(&id2, foo, "foo2", NORMAL_PRIO); + reschedule(); + while(1) { NOP8; } diff --git a/kernel/tasks.c b/kernel/tasks.c new file mode 100644 index 0000000..372488b --- /dev/null +++ b/kernel/tasks.c @@ -0,0 +1,254 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include + +extern void* default_stack_pointer; + +/** @brief Array of task structures (aka PCB) + * + * A task's id will be its position in this array. + */ +static task_t task_table[MAX_TASKS] = { \ + [0] = {0, TASK_IDLE, NULL, NULL, 0, NULL, NULL}, \ + [1 ... MAX_TASKS-1] = {0, TASK_INVALID, NULL, NULL, 0, NULL, NULL}}; + +static runqueue_t runqueue = { task_table+0, NULL, 0, 0, {[0 ... MAX_PRIO-1] = {NULL, NULL}}}; + +task_t* current_task = task_table+0; + +/** @brief helper function for the assembly code to determine the current task + * @return Pointer to the task_t structure of current task + */ +task_t* get_current_task(void) +{ + return current_task; +} + +/** @brief determines the highest priority of the all runable task + * @return Highest priority + */ +uint32_t get_highest_priority(void) +{ + return msb(runqueue.prio_bitmap); +} + +int multitasking_init(void) +{ + if (BUILTIN_EXPECT(task_table[0].status != TASK_IDLE, 0)) { + kputs("Task 0 is not an idle task\n"); + return -ENOMEM; + } + + task_table[0].prio = IDLE_PRIO; + task_table[0].stack = default_stack_pointer - 8192; + + return 0; +} + +void finish_task_switch(void) +{ + task_t* old; + uint8_t prio; + + if ((old = runqueue.old_task) != NULL) { + if (old->status == TASK_INVALID) { + old->stack = NULL; + old->last_stack_pointer = NULL; + runqueue.old_task = NULL; + } else { + prio = old->prio; + if (!runqueue.queue[prio-1].first) { + old->next = old->prev = NULL; + runqueue.queue[prio-1].first = runqueue.queue[prio-1].last = old; + } else { + old->next = NULL; + old->prev = runqueue.queue[prio-1].last; + runqueue.queue[prio-1].last->next = old; + runqueue.queue[prio-1].last = old; + } + runqueue.old_task = NULL; + runqueue.prio_bitmap |= (1 << prio); + } + } +} + +/** @brief A procedure to be called by + * procedures which are called by exiting tasks. */ +static void NORETURN do_exit(int arg) +{ + task_t* curr_task = current_task; + + kprintf("Terminate task: %u, return value %d\n", curr_task->id, arg); + + curr_task->status = TASK_FINISHED; + reschedule(); + + kprintf("Kernel panic: scheduler found no valid task\n"); + while(1) { + NOP8; + } +} + +/** @brief A procedure to be called by kernel tasks */ +void NORETURN leave_kernel_task(void) { + int result; + + result = 0; //get_return_value(); + do_exit(result); +} + +/** @brief Create a task with a specific entry point + * + * @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) +{ + int ret = -ENOMEM; + uint32_t i; + + if (BUILTIN_EXPECT(!ep, 0)) + return -EINVAL; + if (BUILTIN_EXPECT(prio == IDLE_PRIO, 0)) + return -EINVAL; + if (BUILTIN_EXPECT(prio > MAX_PRIO, 0)) + return -EINVAL; + + for(i=0; inext = task_table+i; + runqueue.queue[prio-1].last = task_table+i; + } + break; + } + } + + return ret; +} + +int create_kernel_task(tid_t* id, entry_point_t ep, void* args, uint8_t prio) +{ + if (prio > MAX_PRIO) + prio = NORMAL_PRIO; + + return create_task(id, ep, args, prio); +} + +size_t** scheduler(void) +{ + task_t* orig_task; + task_t* curr_task; + uint32_t prio; + + orig_task = curr_task = current_task; + + /* signalizes that this task could be reused */ + if (curr_task->status == TASK_FINISHED) { + curr_task->status = TASK_INVALID; + runqueue.old_task = curr_task; + } else runqueue.old_task = NULL; // reset old task + + prio = msb(runqueue.prio_bitmap); // determines highest priority + if (prio >= sizeof(size_t)*8) { + if ((curr_task->status == TASK_RUNNING) || (curr_task->status == TASK_IDLE)) + goto get_task_out; + curr_task = current_task = runqueue.idle; + } else { + // Does the current task have an higher priority? => no task switch + if ((curr_task->prio > prio) && (curr_task->status == TASK_RUNNING)) + goto get_task_out; + + if (curr_task->status == TASK_RUNNING) { + curr_task->status = TASK_READY; + runqueue.old_task = curr_task; + } + + curr_task = current_task = runqueue.queue[prio-1].first; + if (BUILTIN_EXPECT(curr_task->status == TASK_INVALID, 0)) { + kprintf("Upps!!!!!!! Got invalid task %d, orig task %d\n", curr_task->id, orig_task->id); + } + curr_task->status = TASK_RUNNING; + + // remove new task from queue + runqueue.queue[prio-1].first = curr_task->next; + if (!curr_task->next) { + runqueue.queue[prio-1].last = NULL; + runqueue.prio_bitmap &= ~(1 << prio); + } + curr_task->next = curr_task->prev = NULL; + } + +get_task_out: + if (curr_task != orig_task) { + //kprintf("schedule from %u to %u with prio %u\n", orig_task->id, curr_task->id, (uint32_t)curr_task->prio); + + return (size_t**) &(orig_task->last_stack_pointer); + } + + return NULL; +} + +void reschedule(void) +{ + size_t** stack; + if ((stack = scheduler())) + switch_context(stack); +} diff --git a/mm/memory.c b/mm/memory.c new file mode 100644 index 0000000..9b32356 --- /dev/null +++ b/mm/memory.c @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#include +#include + +static char stack[MAX_TASKS-1][KERNEL_STACK_SIZE]; + +void* create_stack(tid_t id) +{ + // idle task uses stack, which is defined in entry.asm + if (BUILTIN_EXPECT(!id, 0)) + return NULL; + // do we have a valid task id? + if (BUILTIN_EXPECT(id >= MAX_TASKS, 0)) + return NULL; + + return (void*) stack[id-1]; +}