From b83bc1d261dddbad30a054228c153c07e3dc3f5b Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Fri, 6 Dec 2013 09:19:42 +0100 Subject: [PATCH] add first steps to support user-level tasks --- arch/x86/include/asm/irqflags.h | 2 +- arch/x86/include/asm/syscall.h | 99 +++++++++++++++++++++++++++++++++ arch/x86/include/asm/tasks.h | 16 +++++- arch/x86/kernel/entry.asm | 41 ++++++++++++++ arch/x86/kernel/gdt.c | 4 +- arch/x86/kernel/idt.c | 4 ++ arch/x86/kernel/tasks.c | 40 +++++++++---- arch/x86/kernel/timer.c | 4 +- include/eduos/config.h.example | 1 + include/eduos/syscall.h | 84 ++++++++++++++++++++++++++++ include/eduos/tasks.h | 23 +++++++- kernel/Makefile | 2 +- kernel/main.c | 19 +++++-- kernel/syscall.c | 67 ++++++++++++++++++++++ kernel/tasks.c | 37 ++++++++++-- 15 files changed, 415 insertions(+), 28 deletions(-) create mode 100644 arch/x86/include/asm/syscall.h create mode 100644 include/eduos/syscall.h create mode 100644 kernel/syscall.c diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index 8bef7fc..48cfbd0 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -58,7 +58,7 @@ inline static void irq_disable(void) { * * @return The set of flags which have been set until now */ -inline static uint32_t irq_nested_disable(void) { +inline static uint8_t irq_nested_disable(void) { size_t flags; asm volatile("pushf; cli; pop %0": "=r"(flags) : : "memory"); if (flags & (1 << 9)) diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h new file mode 100644 index 0000000..eedb37c --- /dev/null +++ b/arch/x86/include/asm/syscall.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011, 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/syscall.h + * @brief Systemcall related code + * + * This file defines the syscall function and convenience + * based macro definitions for calling it. + */ + +#ifndef __ARCH_SYSCALL_H__ +#define __ARCH_SYSCALL_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define _STR(token) #token +#define _SYSCALLSTR(x) "int $" _STR(x) " " + +/** @brief the syscall function which issues an interrupt to the kernel + * + * It's supposed to be used by the macros defined in this file as the could would read + * cleaner then. + * + * @param nr System call number + * @param arg0 Argument 0 + * @param arg1 Argument 1 + * @param arg2 Argument 2 + * @param arg3 Argument 3 + * @param arg4 Argument 4 + * @return The return value of the system call + */ +inline static long +syscall(int nr, unsigned long arg0, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4) +{ + long res; + + asm volatile (_SYSCALLSTR(INT_SYSCALL) + : "=a" (res) + : "0" (nr), "b" (arg0), "c" (arg1), "d" (arg2), "S" (arg3), "D" (arg4) + : "memory", "cc"); + + return res; +} + + +/// System call macro with one single argument; the syscall number +#define SYSCALL0(NR) \ + syscall(NR, 0, 0, 0, 0, 0) +/// System call macro with system call number and one argument +#define SYSCALL1(NR, ARG1) \ + syscall(NR, (unsigned long)ARG1, 0, 0, 0, 0) +/// System call macro with system call number and 2 arguments +#define SYSCALL2(NR, ARG1, ARG2) \ + syscall(NR, (unsigned long)ARG1, (unsigned long)ARG2, 0, 0, 0) +/// System call macro with system call number and 3 arguments +#define SYSCALL3(NR, ARG1, ARG2, ARG3) \ + syscall(NR, (unsigned long)ARG1, (unsigned long)ARG2, (unsigned long)ARG3, 0, 0) +/// System call macro with system call number and 4 arguments +#define SYSCALL4(NR, ARG1, ARG2, ARG3, ARG4) \ + syscall(NR, (unsigned long)ARG1, (unsigned long)ARG2, (unsigned long)ARG3, (unsigned long) ARG4, 0) +/// System call macro with system call number and 5 arguments +#define SYSCALL5(NR, ARG1, ARG2, ARG3, ARG4) \ + syscall(NR, (unsigned long)ARG1, (unsigned long)ARG2, (unsigned long)ARG3, (unsigned long) ARG4, (unsigned long) ARG5) +#ifdef __cplusplus +} +#endif + +#endif diff --git a/arch/x86/include/asm/tasks.h b/arch/x86/include/asm/tasks.h index 5bda21b..f5b22bc 100644 --- a/arch/x86/include/asm/tasks.h +++ b/arch/x86/include/asm/tasks.h @@ -59,7 +59,21 @@ void switch_context(size_t** stack); * - 0 on success * - -EINVAL (-22) on failure */ -int create_default_frame(task_t* task, entry_point_t ep, void* arg); +int create_default_frame(task_t* task, entry_point_t ep, void* arg, uint8_t user); + +/** @brief Register a task's TSS at GDT + * + * @return + * - 0 on success + */ +static inline int register_task(void) +{ + uint16_t sel = 5 << 3; + + asm volatile ("ltr %%ax" : : "a"(sel)); + + return 0; +} #ifdef __cplusplus } diff --git a/arch/x86/kernel/entry.asm b/arch/x86/kernel/entry.asm index 1b1c36a..08a4c26 100644 --- a/arch/x86/kernel/entry.asm +++ b/arch/x86/kernel/entry.asm @@ -196,6 +196,47 @@ isrstub_pseudo_error 9 %assign i i+1 %endrep +extern syscall_handler +global isrsyscall + +; used to realize system calls +; by entering the handler, the interrupt flag is not cleared +isrsyscall: + cli + push es + push ds + push ebp + push edi + push esi + push edx + push ecx + push ebx + push eax + + ; set kernel data segmenets + mov ax, 0x10 + mov ds, ax + mov es, ax + mov eax, [esp] + sti + + call syscall_handler + + cli + add esp, 4 ; eax contains the return value + ; => we did not restore eax + + pop ebx + pop ecx + pop edx + pop esi + pop edi + pop ebp + pop ds + pop es + sti + iret + extern irq_handler extern get_current_stack extern finish_task_switch diff --git a/arch/x86/kernel/gdt.c b/arch/x86/kernel/gdt.c index 2d28f86..05e1056 100644 --- a/arch/x86/kernel/gdt.c +++ b/arch/x86/kernel/gdt.c @@ -36,9 +36,9 @@ #include gdt_ptr_t gp; -static tss_t task_state_segment __attribute__ ((aligned (PAGE_SIZE))); +static tss_t task_state_segment __attribute__ ((aligned (PAGE_SIZE))); // currently, our kernel has full access to the ioports -static gdt_entry_t gdt[GDT_ENTRIES] = {[0 ... GDT_ENTRIES-1] = {0, 0, 0, 0, 0, 0}}; +static gdt_entry_t gdt[GDT_ENTRIES] = {[0 ... GDT_ENTRIES-1] = {0, 0, 0, 0, 0, 0}}; /* * This is defined in entry.asm. We use this to properly reload diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c index 11a44eb..c8a1463 100644 --- a/arch/x86/kernel/idt.c +++ b/arch/x86/kernel/idt.c @@ -74,6 +74,8 @@ void idt_set_gate(unsigned char num, size_t base, unsigned short sel, configure_idt_entry(&idt[num], base, sel, flags); } +extern void isrsyscall(void); + /* Installs the IDT */ void idt_install(void) { @@ -87,6 +89,8 @@ void idt_install(void) idtp.base = (size_t)&idt; /* Add any new ISRs to the IDT here using idt_set_gate */ + idt_set_gate(INT_SYSCALL, (size_t)isrsyscall, KERNEL_CODE_SELECTOR, + IDT_FLAG_PRESENT|IDT_FLAG_RING3|IDT_FLAG_32BIT|IDT_FLAG_TRAPGATE); } /* Points the processor's internal register to the new IDT */ diff --git a/arch/x86/kernel/tasks.c b/arch/x86/kernel/tasks.c index 7419e2f..2b4ff38 100644 --- a/arch/x86/kernel/tasks.c +++ b/arch/x86/kernel/tasks.c @@ -32,6 +32,8 @@ #include #include +static unsigned char ustacks[MAX_TASKS][KERNEL_STACK_SIZE] __attribute__ ((aligned (PAGE_SIZE))); + size_t* get_current_stack(void) { task_t* curr_task = current_task; @@ -39,9 +41,11 @@ size_t* get_current_stack(void) return curr_task->last_stack_pointer; } -int create_default_frame(task_t* task, entry_point_t ep, void* arg) +int create_default_frame(task_t* task, entry_point_t ep, void* arg, uint8_t user) { - size_t *stack; + uint16_t cs = user ? 0x1B : 0x08; + uint16_t ds = user ? 0x23 : 0x10; + size_t *stack, *ustack; struct state *stptr; size_t state_size; @@ -52,12 +56,16 @@ int create_default_frame(task_t* task, entry_point_t ep, void* arg) return -EINVAL; memset(task->stack, 0xCD, KERNEL_STACK_SIZE); + memset(ustacks[task->id] , 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 + if (user) + stack = (size_t*) (ustacks[task->id] + KERNEL_STACK_SIZE - 16); // => stack is 16byte aligned + else + stack = (size_t*) (task->stack + KERNEL_STACK_SIZE - 16); // => stack is 16byte aligned /* Only marker for debugging purposes, ... */ *stack-- = 0xDEADBEEF; @@ -66,14 +74,21 @@ int create_default_frame(task_t* task, entry_point_t ep, void* arg) /* and the "caller" we shall return to. * This procedure cleans the task after exit. */ - *stack = (size_t) leave_kernel_task; + if (user) + *stack = (size_t) leave_user_task; + else + *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. */ - /* In legacy modes, this push is conditional and based on a change in current privilege level (CPL).*/ - state_size = sizeof(struct state) - 2*sizeof(size_t); + if (user) { + ustack = stack; + stack = (size_t*) (task->stack + KERNEL_STACK_SIZE - 16); + state_size = sizeof(struct state); + } else state_size = sizeof(struct state) - 2*sizeof(size_t); + stack = (size_t*) ((size_t) stack - state_size); stptr = (struct state *) stack; @@ -86,11 +101,16 @@ int create_default_frame(task_t* task, entry_point_t ep, void* arg) /* The instruction pointer shall be set on the first function to be called after IRETing */ stptr->eip = (size_t)ep; - stptr->cs = 0x08; - stptr->ds = stptr->es = 0x10; + stptr->cs = cs; + stptr->ds = stptr->es = ds; stptr->eflags = 0x1202; - // the creation of a kernel tasks didn't change the IOPL level - // => useresp & ss is not required + + if (user) { + // the creation of a user-level tasks change the IOPL level + // => useresp & ss is required + stptr->ss = ds; + stptr->useresp = (size_t)ustack; + } /* Set the task's stack pointer entry to the stack we have crafted right now. */ task->last_stack_pointer = (size_t*)stack; diff --git a/arch/x86/kernel/timer.c b/arch/x86/kernel/timer.c index b3a6357..5d1309e 100644 --- a/arch/x86/kernel/timer.c +++ b/arch/x86/kernel/timer.c @@ -60,9 +60,9 @@ static void timer_handler(struct state *s) * Every TIMER_FREQ clocks (approximately 1 second), we will * display a message on the screen */ - /*if (timer_ticks % TIMER_FREQ == 0) { + if (timer_ticks % TIMER_FREQ == 0) { vga_puts("One second has passed\n"); - }*/ + } } #define LATCH(f) ((CLOCK_TICK_RATE + f/2) / f) diff --git a/include/eduos/config.h.example b/include/eduos/config.h.example index ca32416..7bf80e7 100644 --- a/include/eduos/config.h.example +++ b/include/eduos/config.h.example @@ -40,6 +40,7 @@ extern "C" { #define CACHE_LINE 64 #define KERNEL_STACK_SIZE (8*1024) #define PAGE_SHIFT 12 +#define INT_SYSCALL 0x80 #define BYTE_ORDER LITTLE_ENDIAN diff --git a/include/eduos/syscall.h b/include/eduos/syscall.h new file mode 100644 index 0000000..5df7961 --- /dev/null +++ b/include/eduos/syscall.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, 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/syscall.h + * @brief System call number definitions + * + * This file contains define constants for every syscall's number. + */ + +#ifndef __SYSCALL_H__ +#define __SYSCALL_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NR_exit 0 +#define __NR_write 1 +#define __NR_open 2 +#define __NR_close 3 +#define __NR_read 4 +#define __NR_lseek 6 +#define __NR_unlink 7 +#define __NR_getpid 8 +#define __NR_kill 9 +#define __NR_fstat 10 +#define __NR_sbrk 11 +#define __NR_fork 12 +#define __NR_wait 13 +#define __NR_execve 14 +#define __NR_times 15 +#define __NR_accept 16 +#define __NR_bind 17 +#define __NR_closesocket 18 +#define __NR_connect 19 +#define __NR_listen 20 +#define __NR_recv 21 +#define __NR_send 22 +#define __NR_socket 23 +#define __NR_getsockopt 24 +#define __NR_setsockopt 25 +#define __NR_gethostbyname 26 +#define __NR_sendto 27 +#define __NR_recvfrom 28 +#define __NR_select 29 +#define __NR_stat 30 +#define __NR_dup 31 +#define __NR_dup2 32 +#define __NR_clone 33 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eduos/tasks.h b/include/eduos/tasks.h index 92c0ae0..f204583 100644 --- a/include/eduos/tasks.h +++ b/include/eduos/tasks.h @@ -44,6 +44,9 @@ extern "C" { #endif +/** @brief System call to terminate a user level process */ +void NORETURN sys_exit(int); + /** @brief Task switcher * * Timer-interrupted use of this function for task switching @@ -65,7 +68,7 @@ size_t** scheduler(void); */ int multitasking_init(void); -/** @brief create a kernel task. +/** @brief create a kernel-level 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 @@ -78,6 +81,19 @@ int multitasking_init(void); */ int create_kernel_task(tid_t* id, entry_point_t ep, void* args, uint8_t prio); +/** @brief create a user-level 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_user_task(tid_t* id, entry_point_t ep, void* args, uint8_t prio); + /** @brief determine the highest priority of all tasks, which are ready * * @return @@ -115,9 +131,12 @@ int block_current_task(void); /** @brief Abort current task */ void NORETURN abort(void); -/** @brief This function shall be called by leaving kernel level tasks */ +/** @brief This function shall be called by leaving kernel-level tasks */ void NORETURN leave_kernel_task(void); +/** @brief This function shall be called by leaving user-level tasks */ +void NORETURN leave_user_task(void); + #ifdef __cplusplus } #endif diff --git a/kernel/Makefile b/kernel/Makefile index 99d1a62..f998553 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,4 +1,4 @@ -C_source := main.c tasks.c +C_source := main.c tasks.c syscall.c MODULE := kernel include $(TOPDIR)/Makefile.inc diff --git a/kernel/main.c b/kernel/main.c index 6c66bf6..9c99383 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include @@ -47,7 +47,14 @@ extern const void bss_end; extern char __BUILD_DATE; extern char __BUILD_TIME; -static sem_t sem; +/*static*/ int userfoo(void* arg) +{ + //SYSCALL1(__NR_write, "hello from userfoo\n"); + //kprintf("hello from %s\n", (char*) arg); + while(1) { } + + return 0; +} static int foo(void* arg) { @@ -57,6 +64,11 @@ static int foo(void* arg) kprintf("hello from %s\n", (char*) arg); } + // demo of an exception + /*i = 0; + i = 32 / i; + kprintf("i = %d\n", i);*/ + return 0; } @@ -88,9 +100,8 @@ int main(void) kprintf("Processor frequency: %u MHz\n", get_cpu_frequency()); - sem_init(&sem, 1); create_kernel_task(&id1, foo, "foo1", NORMAL_PRIO); - create_kernel_task(&id2, foo, "foo2", NORMAL_PRIO); + create_user_task(&id2, userfoo, "userfoo", NORMAL_PRIO); while(1) { HALT; diff --git a/kernel/syscall.c b/kernel/syscall.c new file mode 100644 index 0000000..b98cdd3 --- /dev/null +++ b/kernel/syscall.c @@ -0,0 +1,67 @@ +/* + * 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 + +static int sys_write(const char* buff) +{ + kputs("bbba\n"); + kputs(buff); + + return 0; +} + +int syscall_handler(uint32_t sys_nr, ...) +{ + int ret = -EINVAL; + va_list vl; + + va_start(vl, sys_nr); + + switch(sys_nr) + { + case __NR_exit: + sys_exit(va_arg(vl, uint32_t)); + ret = 0; + break; + case __NR_write: + ret = sys_write(va_arg(vl, const char*)); + break; + default: + kputs("invalid system call\n"); + ret = -ENOSYS; + break; + }; + + va_end(vl); + + return ret; +} diff --git a/kernel/tasks.c b/kernel/tasks.c index 1418503..70f075f 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -28,10 +28,12 @@ #include #include #include +#include #include #include #include #include +#include /** @brief Array of task structures (aka PCB) * @@ -71,6 +73,9 @@ int multitasking_init(void) task_table[0].prio = IDLE_PRIO; task_table[0].stack = (void*) &boot_stack; + // register idle task + register_task(); + return 0; } @@ -127,6 +132,15 @@ static void NORETURN do_exit(int arg) } } +/** @brief A procedure to be called by user-level tasks */ +void NORETURN leave_user_task(void) +{ + SYSCALL1(__NR_exit, 0); + + // we should never reach this point + while(1) { HALT; } +} + /** @brief A procedure to be called by kernel tasks */ void NORETURN leave_kernel_task(void) { int result; @@ -135,6 +149,11 @@ void NORETURN leave_kernel_task(void) { do_exit(result); } +/** @brief To be called by the systemcall to exit tasks */ +void NORETURN sys_exit(int arg) { + do_exit(arg); +} + /** @brief Aborting a task is like exiting it with result -1 */ void NORETURN abort(void) { do_exit(-1); @@ -152,7 +171,7 @@ void NORETURN abort(void) { * - 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) +static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio, uint8_t user) { int ret = -ENOMEM; uint32_t i; @@ -177,7 +196,7 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio) if (id) *id = i; - ret = create_default_frame(task_table+i, ep, arg); + ret = create_default_frame(task_table+i, ep, arg, user); // add task in the readyqueues spinlock_irqsave_lock(&readyqueues.lock); @@ -208,7 +227,15 @@ 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); + return create_task(id, ep, args, prio, 0); +} + +int create_user_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, 1); } /** @brief Wakeup a blocked task @@ -247,7 +274,7 @@ int wakeup_task(tid_t id) task->next = NULL; readyqueues.queue[prio-1].last->next = task; readyqueues.queue[prio-1].last = task; - } + } spinlock_irqsave_unlock(&readyqueues.lock); } @@ -358,7 +385,7 @@ get_task_out: spinlock_irqsave_unlock(&readyqueues.lock); if (current_task != orig_task) { - //kprintf("schedule from %u to %u with prio %u\n", orig_task->id, current_task->id, (uint32_t)current_task->prio); + kprintf("schedule from %u to %u with prio %u\n", orig_task->id, current_task->id, (uint32_t)current_task->prio); return (size_t**) &(orig_task->last_stack_pointer); }