add first steps to support user-level tasks
This commit is contained in:
parent
aed7b1ce8d
commit
b83bc1d261
15 changed files with 415 additions and 28 deletions
|
@ -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))
|
||||
|
|
99
arch/x86/include/asm/syscall.h
Normal file
99
arch/x86/include/asm/syscall.h
Normal file
|
@ -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 <eduos/stddef.h>
|
||||
|
||||
#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
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -36,9 +36,9 @@
|
|||
#include <asm/tss.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <eduos/errno.h>
|
||||
#include <eduos/processor.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
84
include/eduos/syscall.h
Normal file
84
include/eduos/syscall.h
Normal file
|
@ -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 <eduos/stddef.h>
|
||||
#include <asm/syscall.h>
|
||||
|
||||
#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
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
C_source := main.c tasks.c
|
||||
C_source := main.c tasks.c syscall.c
|
||||
MODULE := kernel
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <eduos/tasks.h>
|
||||
#include <eduos/processor.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <eduos/semaphore.h>
|
||||
#include <eduos/syscall.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irqflags.h>
|
||||
|
||||
|
@ -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;
|
||||
|
|
67
kernel/syscall.c
Normal file
67
kernel/syscall.c
Normal file
|
@ -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 <eduos/stddef.h>
|
||||
#include <eduos/stdio.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <eduos/errno.h>
|
||||
#include <eduos/syscall.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -28,10 +28,12 @@
|
|||
#include <eduos/stddef.h>
|
||||
#include <eduos/stdlib.h>
|
||||
#include <eduos/stdio.h>
|
||||
#include <eduos/string.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <eduos/tasks_types.h>
|
||||
#include <eduos/spinlock.h>
|
||||
#include <eduos/errno.h>
|
||||
#include <eduos/syscall.h>
|
||||
|
||||
/** @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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue