Import kern/ subdirectory.
authorbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Sun, 23 May 2004 17:27:00 +0000 (17:27 +0000)
committerbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Sun, 23 May 2004 17:27:00 +0000 (17:27 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@2 38d2e660-2303-0410-9eaa-f027e97ec537

16 files changed:
kern/event.h [new file with mode: 0755]
kern/file.h [new file with mode: 0755]
kern/heap.c [new file with mode: 0755]
kern/heap.h [new file with mode: 0755]
kern/proc.c [new file with mode: 0755]
kern/proc.h [new file with mode: 0755]
kern/proc_p.h [new file with mode: 0755]
kern/sem.c [new file with mode: 0755]
kern/sem.h [new file with mode: 0755]
kern/signal.c [new file with mode: 0755]
kern/signal.h [new file with mode: 0755]
kern/switch_avr.S [new file with mode: 0755]
kern/switch_dsp56k.c [new file with mode: 0755]
kern/switch_i196.s32 [new file with mode: 0755]
kern/switch_i386.s [new file with mode: 0755]
kern/switch_win32.s [new file with mode: 0755]

diff --git a/kern/event.h b/kern/event.h
new file mode 100755 (executable)
index 0000000..23d3e52
--- /dev/null
@@ -0,0 +1,123 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2001,2003 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Events handling
+ *
+ * This module implements a common system for executing
+ * a user defined action calling a hook function.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+#ifndef KERN_EVENT_H
+#define KERN_EVENT_H
+
+#include "config.h"
+
+#ifdef CONFIG_KERNEL
+       #include "config_kern.h"
+       #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
+               #include "signal.h"
+       #endif
+#endif
+
+
+/* Forward decl */
+struct Process;
+
+
+/*! Event types */
+enum EventAction
+{
+       EVENT_IGNORE,   /*!< No-op event */
+#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
+       EVENT_SIGNAL,   /*!< Send a signal to a process */
+#endif
+       EVENT_SOFTINT   /*!< Trigger a software interrupt (i.e.: call user hook) */
+};
+
+//! User defined callback type
+typedef void (*Hook)(void *);
+
+typedef struct Event
+{
+       enum EventAction action;
+       union
+       {
+#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
+               struct
+               {
+                       struct Process *sig_proc;  /* Process to be signalled */
+                       sig_t           sig_bit;   /* Signal to send */
+               } Sig;
+#endif
+               struct
+               {
+                       Hook  func;         /* Pointer to softint hook */
+                       void *user_data;    /* Data to be passed back to user hook */
+               } Int;
+       } Ev;
+} Event;
+
+
+/*! Initialize an event with a softint */
+#define INITEVENT_INT(e,f,u) \
+       ((e)->action = EVENT_SOFTINT,(e)->Ev.Int.func = (f), (e)->Ev.Int.user_data = (u))
+
+
+#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
+
+/*! Initialize an event with a signal */
+#define INITEVENT_SIG(e,p,s) \
+       ((e)->action = EVENT_SIGNAL,(e)->Ev.Sig.sig_proc = (p), (e)->Ev.Sig.sig_bit = (s))
+
+/*! Trigger an event */
+#define DOEVENT(e) \
+do { \
+       if ((e)->action == EVENT_SIGNAL) \
+               sig_signal((e)->Ev.Sig.sig_proc, (e)->Sig.sig_bit); \
+       else if ((e)->action == EVENT_SOFTINT) \
+               (e)->Ev.Int.func((e)->Ev.Int.user_data); \
+} while (0)
+
+/*! Trigger an event (to be used inside interrupts) */
+#define DOEVENT_INTR(e) \
+do { \
+       if ((e)->action == EVENT_SIGNAL) \
+               _sig_signal((e)->Ev.Sig.sig_proc, (e)->Ev.Sig.sig_bit); \
+       else if ((e)->action == EVENT_SOFTINT) \
+               (e)->Ev.Int.func((e)->Ev.Int.user_data); \
+} while (0)
+
+#else /* !CONFIG_KERN_SIGNALS */
+
+/*! Trigger an event */
+#define DOEVENT(e) \
+do { \
+       if ((e)->action == EVENT_SOFTINT) \
+               (e)->Ev.Int.func((e)->Ev.Int.user_data); \
+} while (0)
+
+/*! Trigger an event (to be used inside interrupts) */
+#define DOEVENT_INTR(e) \
+do { \
+       if ((e)->action == EVENT_SOFTINT) \
+               (e)->Ev.Int.func((e)->Ev.Int.user_data); \
+} while (0)
+
+#endif
+
+#endif /* KERN_EVENT_H */
diff --git a/kern/file.h b/kern/file.h
new file mode 100755 (executable)
index 0000000..e39fae6
--- /dev/null
@@ -0,0 +1,55 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2001,2003 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Interface to KFile virtual class
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ *     $Log$
+ *     Revision 1.1  2004/05/23 17:27:00  bernie
+ *     Import kern/ subdirectory.
+ *
+ */
+#ifndef KERN_KFILE_H
+#define KERN_KFILE_H
+
+#ifndef COMPILER_H
+#include <compiler.h>
+#endif
+
+struct _KFile;
+
+typedef size_t (*ReadFunc_t)   (struct _KFile *fd, char *buf, size_t size);
+typedef size_t (*WriteFunc_t)  (struct _KFile *fd, const char *buf, size_t size);
+typedef        bool    (*SeekFunc_t)   (struct _KFile *fd, int32_t offset);
+typedef bool   (*CloseFunc_t)  (struct _KFile *fd);
+typedef bool   (*OpenFunc_t)   (struct _KFile *fd, const char *name, int mode);
+
+
+/* Context data for callback functions which operate on
+ * pseudo files.
+ */
+typedef struct _KFile
+{
+       ReadFunc_t              Read;
+       WriteFunc_t             Write;
+       SeekFunc_t              Seek;
+/*     OpenFunc_t              Open;   unused */
+       CloseFunc_t             Close;
+
+       /* NOTE: these must _NOT_ be size_t on 16bit CPUs! */
+       uint32_t                SeekPos;
+       uint32_t                Size;
+} KFile;
+
+
+#endif /* KERN_KFILE_H */
diff --git a/kern/heap.c b/kern/heap.c
new file mode 100755 (executable)
index 0000000..b836cab
--- /dev/null
@@ -0,0 +1,178 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Heap subsystem (public interface).
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+#include "heap.h"
+
+/* NOTE: struct size must be a 2's power! */
+typedef struct _MemChunk
+{
+       struct _MemChunk *next;
+       size_t size;
+} MemChunk;
+
+static REGISTER MemChunk *FreeList;    /* Head of the free list */
+static uint8_t Heap[HEAP_SIZE];                /* Heap memory block */
+
+
+
+void heap_init(void)
+{
+#ifdef _DEBUG
+       int i;
+
+       /* Fill the heap with a "DEAD" code to help debugging */
+       for (i = 0; i < HEAP_SIZE / sizeof (uint16_t); i++)
+               ((uint16_t *)Heap)[i] = MEM_FILL_CODE;
+#endif
+
+       /* Initialize heap with a single big chunk */
+       FreeList = (MemChunk *)Heap;
+       FreeList->next = NULL;
+       FreeList->size = sizeof(Heap);
+}
+
+
+void *heap_alloc(size_t size)
+{
+       MemChunk *chunk, *prev;
+
+       /* Round size up to the allocation granularity */
+       size = ROUND2(size, sizeof(MemChunk));
+
+       /* Walk on the free list looking for any chunk big enough to
+        * fit the requested block size.
+        */
+       for (prev = (MemChunk *)&FreeList, chunk = FreeList;
+               chunk;
+               prev = chunk, chunk = chunk->next)
+       {
+               if (chunk->size <= size)
+               {
+                       if (chunk->size == size)
+                       {
+                               /* Just remove this chunk from the free list */
+                               prev->next = chunk->next;
+                               return (void *)chunk;
+                       }
+                       else
+                       {
+                               /* Allocate from the END of an existing chunk */
+                               prev->size -= size;
+                               return (void *)(((uint8_t *)prev) + prev->size);
+                       }
+               }
+       }
+
+       return NULL; /* fail */
+}
+
+
+void heap_free(void *mem, size_t size)
+{
+       MemChunk *prev;
+
+       /* Round size up to the allocation granularity */
+       size = ROUND2(size, sizeof(MemChunk));
+
+       /* Special case: first chunk in the free list */
+       if (((uint8_t *)mem) < ((uint8_t *)FreeList))
+       {
+               /* Insert memory block before the current free list head */
+               prev = (MemChunk *)mem;
+               prev->next = FreeList;
+               prev->size = size;
+               FreeList = prev;
+       }
+       else /* Normal case: not the first chunk in the free list */
+       {
+               /* Walk on the free list. Stop at the insertion point */
+               prev = FreeList;
+               while ((prev->next >= ((MemChunk *)mem)) || (!prev->next))
+                       prev = prev->next;
+
+               /* Should it be merged with previous block? */
+               if (((uint8_t *)prev) + prev->Size == ((uint8_t *)mem))
+               {
+                       /* Yes */
+                       prev->size += size;
+               }
+               else /* not merged with previous chunk */
+               {
+                       /* insert it after the previous node
+                        * and move the 'prev' pointer forward
+                        * for the following operations
+                        */
+                       ((MemChunk *)mem)->next = prev->next;
+                       prev->next = (MemChunk *)mem;
+                       prev = (MemChunk *)mem;
+               }
+       }
+
+       /* Also merge with next chunk? */
+       if (((uint8_t *)prev) + prev->size == ((uint8_t *)prev->next))
+       {
+               prev->size += prev->next->size;
+               prev->next = prev->next->next;
+       }
+}
+
+#ifdef __POSIX__
+
+/*! ANSI/POSIX-like malloc() implementation based on heap_alloc()/heap_free() */
+void *malloc(size_t size)
+{
+       void *mem;
+
+       size += sizeof(size_t);
+
+       if (mem = heap_alloc(size))
+               *((size_t *)mem)++ = size;
+
+       return mem;
+}
+
+
+/*! ANSI/POSIX-like calloc() implementation based on heap_alloc()/heap_free() */
+void *calloc(size_t nelem, size_t size)
+{
+       void *mem, *tmp;
+
+       size *= nelem;
+
+       if (mem = malloc(size))
+       {
+               tmp = mem;
+               while (size--)
+                       ((uint8_t *)tmp++) = 0;
+       }
+
+       return mem;
+}
+
+/*! ANSI/POSIX-like free() implementation based on heap_alloc()/heap_free() */
+void free(void *mem)
+{
+       ((size_t *)mem)--;
+       heap_free(mem, *((size_t *)mem));
+}
+
+#endif /* __POSIX__ */
diff --git a/kern/heap.h b/kern/heap.h
new file mode 100755 (executable)
index 0000000..54174e6
--- /dev/null
@@ -0,0 +1,41 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Heap subsystem (public interface).
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+#ifndef KERN_HEAP_H
+#define KERN_HEAP_H
+
+#include "compiler.h"
+
+
+/* Memory allocation services */
+void heap_init(void);
+void *heap_alloc(size_t size);
+void heap_free(void *mem, size_t size);
+
+#ifdef __POSIX__ /* unused */
+void *malloc(size_t size);
+void *calloc(unsigned int nelem, size_t size);
+void free(void * mem);
+#endif /* __POSIX__ */
+
+#endif /* KERN_HEAP_H */
+
diff --git a/kern/proc.c b/kern/proc.c
new file mode 100755 (executable)
index 0000000..a11e498
--- /dev/null
@@ -0,0 +1,355 @@
+/**
+ * \file
+ * <!--
+ * Copyright 2001,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Simple realtime multitasking scheduler.
+ *        Context switching is only done cooperatively.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+#include "cpu.h"
+#include "proc_p.h"
+#include "proc.h"
+#include "event.h"
+#include "hw.h"
+#include <drv/kdebug.h>
+
+#include <string.h> /* memset() */
+
+/* CPU dependent context switching routines */
+extern void asm_switch_context(cpustack_t **new_sp, cpustack_t **save_sp);
+
+/*
+ * The scheduer tracks ready and waiting processes
+ * by enqueuing them in these lists. A pointer to the currently
+ * running process is stored in the CurrentProcess pointer.
+ *
+ * NOTE: these variables are protected by DI/EI locking
+ */
+REGISTER Process *CurrentProcess;
+REGISTER List     ProcReadyList;
+
+#if CONFIG_KERN_PREEMPTIVE
+/*
+ * The time sharing scheduler forces a task switch when
+ * the current process has consumed its quantum.
+ */
+uint16_t Quantum;
+#endif
+
+
+/* In Win32 we must emulate stack on the real process stack */
+#if (ARCH & ARCH_EMUL)
+extern List StackFreeList;
+#endif
+
+/* The main process (the one that executes main()) */
+struct Process MainProcess;
+
+static void proc_init_struct(Process* proc)
+{
+#if CONFIG_KERN_TIMER
+       INITEVENT_SIG(&proc->proc_timer.expire, proc, SIG_SINGLE);
+#endif
+
+#if CONFIG_KERN_SIGNALS
+       proc->sig_recv = 0;
+#endif
+
+#if CONFIG_KERN_HEAP
+       proc->flags = 0;
+#endif
+}
+
+void proc_init(void)
+{
+       INITLIST(&ProcReadyList);
+
+       /* We "promote" the current context into a real process. The only thing we have
+          to do is create a PCB and make it current. We don't need to setup the stack
+          pointer because it will be written the first time we switch to another process. */
+       proc_init_struct(&MainProcess);
+       CurrentProcess = &MainProcess;
+}
+
+
+/*!
+ * Create a new process, starting at the provided entry point.
+ *
+ * \return Process structure of new created process
+ *         if successful, NULL otherwise.
+ */
+Process *proc_new(void (*entry)(void), size_t stacksize, cpustack_t *stack_base)
+{
+       Process *proc;
+       size_t i;
+       size_t proc_size_words = ROUND2(sizeof(Process), sizeof(cpustack_t)) / sizeof(cpustack_t);
+#if CONFIG_KERN_HEAP
+       bool free_stack = false;
+#endif
+
+#if (ARCH & ARCH_EMUL)
+       /* Ignore stack provided by caller
+       * and use the large enough default instead
+       */
+       stack_base = (cpustack_t *)StackFreeList.head;
+       REMOVE((Node *)stack_base);
+       stacksize = DEF_STACKSIZE;
+#elif CONFIG_KERN_HEAP
+       /* Did the caller provide a stack for us? */
+       if (!stack_base)
+       {
+               /* Did the caller specify the desired stack size? */
+               if (!stacksize)
+                       stacksize = CONFIG_KERN_DEFSTACKSIZE + sizeof(Process);
+
+               /* Allocate stack dinamically */
+               if (!(stack_base = heap_alloc(stacksize)))
+                       return NULL;
+
+               free_stack = true;
+       }
+#else
+       /* Stack must have been provided by the user */
+       ASSERT(stack_base);
+       ASSERT(stacksize);
+#endif
+
+#ifdef _DEBUG
+       /* Fill-in the stack with a special marker to help debugging */
+       memset(stack_base, CONFIG_KERN_STACKFILLCODE, stacksize / sizeof(cpustack_t));
+#endif /* _DEBUG */
+
+       /* Initialize the process control block */
+       if (CPU_STACK_GROWS_UPWARD)
+       {
+               proc = (Process*)stack_base;
+               proc->stack = stack_base + proc_size_words;
+               if (CPU_SP_ON_EMPTY_SLOT)
+                       proc->stack++;
+       }
+       else
+       {
+               proc = (Process*)(stack_base + stacksize / sizeof(cpustack_t) - proc_size_words);
+               proc->stack = (cpustack_t*)proc;
+               if (CPU_SP_ON_EMPTY_SLOT)
+                       proc->stack--;
+       }
+
+       proc_init_struct(proc);
+
+#if CONFIG_KERN_HEAP
+       proc->stack_base = stack_base;
+       proc->stack_size = stack_size;
+       if (free_stack)
+               proc->flags |= PF_FREESTACK;
+#endif
+
+       /* Initialize process stack frame */
+       CPU_PUSH_CALL_CONTEXT(proc->stack, proc_exit);
+       CPU_PUSH_CALL_CONTEXT(proc->stack, entry);
+
+       /* Push a clean set of CPU registers for asm_switch_context() */
+       for (i = 0; i < CPU_SAVED_REGS_CNT; i++)
+               CPU_PUSH_WORD(proc->stack, CPU_REG_INIT_VALUE(i));
+
+       /* Add to ready list */
+       DISABLE_INTS;
+       SCHED_ENQUEUE(proc);
+       ENABLE_INTS;
+
+       return proc;
+}
+
+
+/*!
+ * System scheduler: pass CPU control to the next process in
+ * the ready queue.
+ *
+ * Saving and restoring the context on the stack is done
+ * by a CPU-dependent support routine which must usually be
+ * written in assembly.
+ */
+void proc_schedule(void)
+{
+       /* This function must not have any "auto" variables, otherwise
+        * the compiler might put them on the stack of the process
+        * being switched out.
+        */
+       static Process *old_process;
+
+       /* Remember old process to save its context later */
+       old_process = CurrentProcess;
+       CurrentProcess = NULL;
+
+       /* Poll on the ready queue for the first ready process
+        */
+       for(;;) /* forever */
+       {
+               /* Do CPU specific idle processing (ARGH, should be moved to the end of the loop!) */
+               SCHEDULER_IDLE;
+
+               DISABLE_INTS;
+               if (!ISLISTEMPTY(&ProcReadyList))
+               {
+                       /* Get process from ready list */
+                       CurrentProcess = (Process *)ProcReadyList.head;
+                       REMOVE((Node *)CurrentProcess);
+                       ENABLE_INTS;
+                       break;
+               }
+               ENABLE_INTS;
+       }
+
+       /* Optimization: don't switch contexts when the active
+        * process has not changed.
+        */
+       if (CurrentProcess != old_process)
+       {
+               static cpustack_t* dummy;
+
+#if CONFIG_KERN_PREEMPTIVE
+               /* Reset quantum for this process */
+               Quantum = CONFIG_KERN_QUANTUM;
+#endif
+
+               /* Save context of old process and switch to new process. If there is no
+                * old process, we save the old stack pointer into a dummy variable that
+                * we ignore. In fact, this happens only when the old process has just
+                * exited.
+                * TODO: Instead of physically clearing the process at exit time, a zombie
+                * list should be created.
+                */
+               asm_switch_context(&CurrentProcess->stack, old_process ? &old_process->stack : &dummy);
+       }
+
+       /* This RET resumes the execution on the new process */
+}
+
+
+/*!
+ * Terminate the current process
+ */
+void proc_exit(void)
+{
+#if CONFIG_KERN_HEAP
+       /* The following code is BROKEN.
+        * We are freeing our own stack before entering proc_schedule()
+        * BAJO: A correct fix would be to rearrange the scheduler with
+        *  an additional parameter which frees the old stack/process
+        *  after a context switch.
+        */
+       if (CurrentProcess->flags & PF_FREESTACK)
+               heap_free(CurrentProcess->stack_base, CurrentProcess->stack_size);
+       heap_free(CurrentProcess);
+#endif
+
+#if (ARCH & ARCH_EMUL)
+#error This is wrong
+       /* Reinsert process stack in free list */
+       ADDHEAD(&StackFreeList, (Node *)(CurrentProcess->stack
+               - (DEF_STACKSIZE / sizeof(cpustack_t))));
+
+       /* NOTE: At this point the first two words of what used
+        * to be our stack contain a list node. From now on, we
+        * rely on the compiler not reading/writing the stack.
+        */
+#endif /* ARCH_EMUL */
+
+       CurrentProcess = NULL;
+       proc_schedule();
+       /* not reached */
+}
+
+
+/*!
+ * Co-operative context switch
+ */
+void proc_switch(void)
+{
+       DISABLE_INTS;
+       SCHED_ENQUEUE(CurrentProcess);
+       ENABLE_INTS;
+       proc_schedule();
+}
+
+
+/*!
+ * Get the pointer to the current process
+ */
+struct Process *proc_current(void)
+{
+       return CurrentProcess;
+}
+
+
+#if 0 /* Simple testcase for the scheduler */
+
+/*!
+ * Proc scheduling test subthread 1
+ */
+static void NORETURN proc_test_thread1(void)
+{
+       for (;;)
+       {
+               kputs(">task 1\n");
+               timer_delay(50);
+               proc_switch();
+       }
+}
+
+/*!
+ * Proc scheduling test subthread 2
+ */
+static void NORETURN proc_test_thread2(void)
+{
+       for (;;)
+       {
+               kputs(">task 2\n");
+               timer_delay(75);
+               proc_switch();
+       }
+}
+
+static cpustack_t proc_test_stack1[CONFIG_KERN_DEFSTACKSIZE/sizeof(cpustack_t)];
+static cpustack_t proc_test_stack2[CONFIG_KERN_DEFSTACKSIZE/sizeof(cpustack_t)];
+
+/*!
+ * Proc scheduling test
+ */
+void NORETURN proc_test(void)
+{
+       proc_new(proc_test_thread1, sizeof(proc_test_stack1), proc_test_stack1);
+       proc_new(proc_test_thread2, sizeof(proc_test_stack2), proc_test_stack2);
+       kputs("Created tasks\n");
+
+       kputs("stack1:\n");
+       kdump(proc_test_stack1+sizeof(proc_test_stack1)-64, 64);
+       kputs("stack2:\n");
+       kdump(proc_test_stack2+sizeof(proc_test_stack1)-64, 64);
+
+       for (;;)
+       {
+               kputs(">main task\n");
+               timer_delay(93);
+               proc_switch();
+       }
+
+       ASSERT(false);
+}
+#endif
diff --git a/kern/proc.h b/kern/proc.h
new file mode 100755 (executable)
index 0000000..d586699
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * \file
+ * <!--
+ * Copyright 2001,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Process scheduler (public interface).
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+#ifndef KERN_PROC_H
+#define KERN_PROC_H
+
+#include "compiler.h"
+#include "cpu.h"
+#include "config_kern.h"
+
+/* Fwd decl */
+struct Process;
+
+/* Task scheduling services */
+void proc_init(void);
+struct Process *proc_new(void (*entry)(void), size_t stacksize, cpustack_t *stack);
+void proc_exit(void);
+void proc_switch(void);
+void proc_test(void);
+struct Process* proc_current(void);
+
+#if CONFIG_KERN_PREEMPTIVE
+       #define FORBID proc_forbid()
+       #define PERMIT proc_permit()
+#else
+       #define FORBID
+       #define PERMIT
+#endif
+
+#endif /* KERN_PROC_H */
+
diff --git a/kern/proc_p.h b/kern/proc_p.h
new file mode 100755 (executable)
index 0000000..5cd44a9
--- /dev/null
@@ -0,0 +1,91 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2001,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Internal scheduler structures and definitions for processes.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ * Revision 1.3  2004/05/14 12:52:13  rasky
+ * Importato supporto kernel per AVR da Stefano
+ *
+ * Revision 1.2  2004/04/28 16:13:49  rasky
+ * proc_schedule() is now semi-private (used only within the kernel)
+ *
+ * Revision 1.1  2004/04/26 18:02:40  rasky
+ * Importato microkernel
+ *
+ * Revision 1.1  2004/04/04 17:40:26  aleph
+ * Add multithreading kernel
+ *
+ */
+
+#ifndef KERN_PROC_P_H
+#define KERN_PROC_P_H
+
+#include "compiler.h"
+#include "config.h"
+#include "config_kern.h"
+#include <mware/list.h>
+#include <drv/timer.h>
+
+
+typedef struct Process
+{
+       Node         link;        /*!< Link Process into scheduler lists */
+       cpustack_t  *stack;       /*!< Per-process SP */
+
+#if CONFIG_KERN_SIGNALS
+       sigset_t     sig_wait;    /*!< Signals the process is waiting for */
+       sigset_t     sig_recv;    /*!< Received signals */
+#endif
+
+#if CONFIG_KERN_TIMER
+       struct Timer proc_timer;  /*!< Process own timer */
+#endif
+
+#if CONFIG_KERN_HEAP
+       uint16_t     flags;       /*!< Flags */
+       cpustack_t  *stack_base;  /*!< Base of process stack */
+       size_t       stack_size;  /*!< Size of process stack */
+#endif
+} Process;
+
+
+/*!
+ * \name Flags for Process.flags
+ * \{
+ */
+#define PF_FREESTACK  BV(0)  /*!< Free the stack when process dies */
+/*\}*/
+
+
+/*! Track running processes */
+extern REGISTER Process        *CurrentProcess;
+
+/*! Track ready processes */
+extern REGISTER List     ProcReadyList;
+
+
+/*!
+ * Enqueue a task in the ready list
+ */
+#define SCHED_ENQUEUE(proc)  ADDTAIL(&ProcReadyList, &(proc)->link)
+
+/*! Schedule to another process *without* adding the current to the ready list */
+void proc_schedule(void);
+
+#endif /* KERN_PROC_P_H */
+
diff --git a/kern/sem.c b/kern/sem.c
new file mode 100755 (executable)
index 0000000..98646e9
--- /dev/null
@@ -0,0 +1,144 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2001,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Semaphore based synchronization services.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+#include "sem.h"
+#include "proc.h"
+#include "proc_p.h"
+#include "signal.h"
+#include "hw.h"
+
+
+/*!
+ * \brief Initialize a Semaphore structure
+ */
+void sem_init(struct Semaphore *s)
+{
+       INITLIST(&s->wait_queue);
+       s->owner = NULL;
+       s->nest_count = 0;
+}
+
+
+/*!
+ * \brief Attempt to lock a semaphore without waiting.
+ *
+ * \return true in case of success, false if the semaphore
+ *         was already locked by someone else.
+ *
+ * \note   each call to sem_attempt() must be matched by a
+ *         call to sem_release().
+ */
+bool sem_attempt(struct Semaphore *s)
+{
+       DISABLE_INTS;
+       if ((!s->owner) || (s->owner == CurrentProcess))
+       {
+               s->owner = CurrentProcess;
+               s->nest_count++;
+               ENABLE_INTS;
+               return true;
+       }
+       ENABLE_INTS;
+       return false;
+}
+
+
+/*!
+ * \brief Lock a semaphore.
+ *
+ * If the semaphore is already owned by another process, the caller
+ * process will be enqueued into the waiting list and sleep until
+ * the semaphore is available.
+ *
+ * \note Each call to sem_obtain() must be matched by a
+ *       call to sem_release().
+ *
+ * \note This routine is optimized for highest speed in
+ *       the most common case: the semaphore is free or locked
+ *       by the calling process itself. Rearranging this code
+ *       is probably a bad idea.
+ */
+void sem_obtain(struct Semaphore *s)
+{
+       DISABLE_INTS;
+
+       /* Is the semaphore already locked by another process? */
+       if (s->owner && (s->owner != CurrentProcess))
+       {
+               /* Append calling process to the wait queue */
+               ADDTAIL(&s->wait_queue, (Node *)CurrentProcess);
+               ENABLE_INTS;
+
+               /* We will awake only when the current owner calls
+                * ReleaseSemaphore(). Then, the semaphore will already
+                * be locked for us.
+                */
+               proc_schedule();
+       }
+       else
+       {
+               /* The semaphore is free: lock it */
+               s->owner = CurrentProcess;
+               s->nest_count++;
+               ENABLE_INTS;
+       }
+}
+
+
+/*!
+ * \brief Releases a lock on a previously locked semaphore.
+ *
+ * If the nesting count of the semaphore reaches zero,
+ * the next process waiting for it will be awaken.
+ *
+ * \note This routine is optimized for highest speed in
+ *       the most common case: the semaphore has been locked just
+ *       once and nobody else was waiting for it. Rearranging
+ *       this code is probably a bad idea.
+ */
+void sem_release(struct Semaphore *s)
+{
+       DISABLE_INTS;
+
+       /* Decremement nesting count and check if the semaphore
+        * has been fully unlocked
+        */
+       if (--s->nest_count == 0)
+       {
+               /* Disown semaphore */
+               s->owner = NULL;
+
+               /* Anybody still waiting for this semaphore? */
+               if (!ISLISTEMPTY(&s->wait_queue))
+               {
+                       /* Give semaphore to the first applicant */
+                       Process *proc = (Process *)s->wait_queue.head;
+                       REMOVE((Node *)proc);
+                       s->nest_count = 1;
+                       s->owner = proc;
+                       SCHED_ENQUEUE(proc);
+               }
+       }
+
+       ENABLE_INTS;
+}
+
diff --git a/kern/sem.h b/kern/sem.h
new file mode 100755 (executable)
index 0000000..91b5615
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * \file
+ * <!--
+ * Copyright 2001,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Mutually exclusive semaphores.
+ *        Shared locking not supported in this implementation.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+#ifndef KERN_SEM_H
+#define KERN_SEM_H
+
+#include "compiler.h"
+#include <mware/list.h>
+
+/* Fwd decl */
+struct Process;
+
+
+struct Semaphore
+{
+       struct Process *owner;
+       List            wait_queue;
+       int             nest_count;
+};
+
+/*!
+ * \name Process synchronization services
+ * \{
+ */
+void sem_init(struct Semaphore *s);
+bool sem_attempt(struct Semaphore *s);
+void sem_obtain(struct Semaphore *s);
+void sem_release(struct Semaphore *s);
+/* \} */
+
+#endif /* KERN_SEM_H */
diff --git a/kern/signal.c b/kern/signal.c
new file mode 100755 (executable)
index 0000000..3bc9aab
--- /dev/null
@@ -0,0 +1,125 @@
+/**
+ * \file
+ * <!--
+ * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief IPC signals implementation.
+ *
+ * Each process can wait for just one signal.
+ * Multiple processes can wait for the same signal. In this
+ * case, each signal will wake-up one of them.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+#include "signal.h"
+#include "proc.h"
+#include "proc_p.h"
+#include "hw.h"
+
+// FIXME
+#if CONFIG_KERN_SIGNALS
+
+/*!
+ * Check if any of the signals in \a sigs has occurred and clear them.
+ * Return the signals that have occurred.
+ */
+sigset_t sig_check(sigset_t sigs)
+{
+       sigset_t result;
+
+       DISABLE_INTS;
+       result = CurrentProcess->sig_recv & sigs;
+       CurrentProcess->sig_recv &= ~sigs;
+       ENABLE_INTS;
+       return result;
+}
+
+
+/*!
+ * Sleep until any of the signals in \a sigs occurs.
+ * Return the signal(s) that have awaked the process.
+ */
+sigset_t sig_wait(sigset_t sigs)
+{
+       sigset_t result;
+
+       DISABLE_INTS;
+
+       for(;;)
+       {
+               /* Check if we got at least one of the signals */
+               if ((result = CurrentProcess->sig_recv & sigs))
+               {
+                       /* Yes, clear signals and return */
+                       CurrentProcess->sig_recv &= ~sigs;
+                       ENABLE_INTS;
+                       return result;
+               }
+
+               /* No, go to sleep and proc_schedule() another process */
+               CurrentProcess->sig_wait = sigs;
+               proc_schedule();
+       }
+}
+
+
+/*!
+ * Send the signals \a sigs to the process \a proc.
+ * The process will be awaken if it was waiting for any of them.
+ *
+ * This call is interrupt safe (no \c DISABLE_INTS/ENABLE_INTS protection)
+ */
+void _sig_signal(Process *proc, sigset_t sigs)
+{
+       /* Set the signals */
+       proc->sig_recv |= sigs;
+
+       /* Check if process needs to be awaken */
+       if (proc->sig_recv & proc->sig_wait)
+       {
+               /* Wake up process and enqueue in ready list */
+               proc->sig_wait = 0;
+               SCHED_ENQUEUE(proc);
+       }
+}
+
+
+/*!
+ * Same as _sig_signal() with interrupt protection.
+ *
+ * \note Inlined manually because some compilers are too
+ *       stupid to it automatically.
+ */
+void sig_signal(Process *proc, sigset_t sigs)
+{
+       DISABLE_INTS;
+
+       /* Set the signals */
+       proc->sig_recv |= sigs;
+
+       /* Check if process needs to be awaken */
+       if (proc->sig_recv & proc->sig_wait)
+       {
+               /* Wake up process and enqueue in ready list */
+               proc->sig_wait = 0;
+               SCHED_ENQUEUE(proc);
+       }
+
+       ENABLE_INTS;
+}
+
+#endif /* CONFIG_KERN_SIGNALS */
+
diff --git a/kern/signal.h b/kern/signal.h
new file mode 100755 (executable)
index 0000000..27a821a
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * \file
+ * <!--
+ * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Signal module (public interface).
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+#ifndef KERN_SIGNAL_H
+#define KERN_SIGNAL_H
+
+#include "compiler.h"
+
+
+/* Fwd decl */
+struct Process;
+
+/* Inter-process Communication services */
+sigset_t sig_check(sigset_t sigs);
+void sig_signal(struct Process *proc, sigset_t sig);
+void _sig_signal(struct Process *proc, sigset_t sig);
+sigset_t sig_wait(sigset_t sigs);
+
+
+/*!
+ * \name Signal definitions
+ *
+ * \{
+ */
+#define SIG_USER0    BV(0)  /*!< Free for user usage */
+#define SIG_USER1    BV(1)  /*!< Free for user usage */
+#define SIG_USER2    BV(2)  /*!< Free for user usage */
+#define SIG_USER3    BV(3)  /*!< Free for user usage */
+#define SIG_SYSTEM4  BV(4)  /*!< Reserved for system use */
+#define SIG_SYSTEM5  BV(5)  /*!< Reserved for system use */
+#define SIG_SYSTEM6  BV(6)  /*!< Reserved for system use */
+#define SIG_SINGLE   BV(7)  /*!< Used to wait for a single event */
+/*\}*/
+
+#endif /* KERN_SIGNAL_H */
diff --git a/kern/switch_avr.S b/kern/switch_avr.S
new file mode 100755 (executable)
index 0000000..266a77e
--- /dev/null
@@ -0,0 +1,102 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief AVR context switch
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+
+#include <avr/io.h>
+
+/* void asm_switch_context(void **new_sp, void **save_sp) */
+.globl asm_switch_context
+asm_switch_context:
+
+;      push    r0      caller-save
+;      push    r1      caller-save
+       push    r2
+       push    r3
+       push    r4
+       push    r5
+       push    r6
+       push    r7
+       push    r8
+       push    r9
+       push    r10
+       push    r11
+       push    r12
+       push    r13
+       push    r14
+       push    r15
+       push    r16
+       push    r17
+;      push    r18     caller-save
+;      push    r19     caller-save
+;      push    r20     caller-save
+;      push    r21     caller-save
+;      push    r22     caller-save
+;      push    r23     caller-save
+;      push    r24     caller-save
+;      push    r25     caller-save
+;      push    r26     caller-save
+;      push    r27     caller-save
+       push    r28
+       push    r29
+;      push    r30     caller-save
+;      push    r31     caller-save
+
+; First parameter (new_sp) is in r24:r25, second (save_sp) in r22:r23
+
+       in      r0,SPL-__SFR_OFFSET     ; r0:r1 = SP
+       in      r1,SPH-__SFR_OFFSET
+       movw    r26,r22                 ; X = save_sp
+       st      X+,r0                   ; *save_sp = SP
+       st      X,r1
+       movw    r26,r24                 ; X = new_sp
+       ld      r0,X+
+       ld      r1,X
+       out     SPL-__SFR_OFFSET,r0     ; SP = *new_sp
+       out     SPH-__SFR_OFFSET,r1
+
+;      pop     r31     caller-save
+;      pop     r30     caller-save
+       pop     r29
+       pop     r28
+;      pop     r27     caller-save
+;      pop     r26     caller-save
+;      pop     r25     caller-save
+;      pop     r24     caller-save
+;      pop     r23     caller-save
+;      pop     r22     caller-save
+;      pop     r21     caller-save
+;      pop     r20     caller-save
+;      pop     r19     caller-save
+;      pop     r18     caller-save
+       pop     r17
+       pop     r16
+       pop     r15
+       pop     r14
+       pop     r13
+       pop     r12
+       pop     r11
+       pop     r10
+       pop     r9
+       pop     r8
+       pop     r7
+       pop     r6
+       pop     r5
+       pop     r4
+       pop     r3
+       pop     r2
+;      pop     r1      caller-save
+;      pop     r0      caller-save
+
+       ret
diff --git a/kern/switch_dsp56k.c b/kern/switch_dsp56k.c
new file mode 100755 (executable)
index 0000000..e10216c
--- /dev/null
@@ -0,0 +1,136 @@
+/*!
+ * \file
+ * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ *
+ * \version $Id$
+ *
+ * \author Giovanni Bajo <rasky@develer.com>
+ *
+ * \brief DSP5680x task switching support
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+void asm_switch_context(void ** new_sp/*R2*/, void ** save_sp/*R3*/);
+asm void asm_switch_context(void ** new_sp, void ** save_sp)
+{
+       lea   (SP)+
+       move  n,x:(SP)+
+       move  x0,x:(SP)+
+       move  y0,x:(SP)+
+       move  y1,x:(SP)+
+       move  a0,x:(SP)+
+       move  a1,x:(SP)+
+       move  a2,x:(SP)+
+       move  b0,x:(SP)+
+       move  b1,x:(SP)+
+       move  b2,x:(SP)+
+       move  r0,x:(SP)+
+       move  r1,x:(SP)+
+       move  r2,x:(SP)+
+       move  r3,x:(SP)+
+
+       move  omr,x:(SP)+
+       move  la,x:(SP)+
+       move  m01,x:(SP)+
+       move  lc,x:(SP)+
+
+       ;
+       ; save hardware stack
+       ;
+       move  hws,x:(SP)+
+       move  hws,x:(SP)+
+
+       ; From the manual:
+       ; The compiler uses page 0 address locations X: 0x0030 - 0x003F as register
+       ; variables. Frequently accessed local variables are assigned to the page 0
+       ; registers instead of to stack locations so that load and store instructions
+       ; are shortened. Addresses X: 0x0030 - 0x0037 (page 0 registers MR0-MR7) are
+       ; volatile registers and can be overwritten. The remaining registers (page 0
+       ; registers MR8-MR15) are treated as non-volatile and, if used by a routine,
+       ; must be saved on entry and restored on exit.
+       ;
+       ; So, register 0x30-0x37 are caller-save, while 0x38-0x3F are callee-save.
+       move  x:<$38,y1
+       move  y1,x:(SP)+
+       move  x:<$39,y1
+       move  y1,x:(SP)+
+       move  x:<$3A,y1
+       move  y1,x:(SP)+
+       move  x:<$3B,y1
+       move  y1,x:(SP)+
+       move  x:<$3C,y1
+       move  y1,x:(SP)+
+       move  x:<$3D,y1
+       move  y1,x:(SP)+
+       move  x:<$3E,y1
+       move  y1,x:(SP)+
+       move  x:<$3F,y1
+       move  y1,x:(SP)
+       
+       ; 
+       ; 28 words have been pushed on the stack.
+       nop
+       move SP, x:(R3)
+       nop
+       move x:(R2), SP
+       nop
+
+       pop   y1
+       move  y1,x:<$3F
+       pop   y1
+       move  y1,x:<$3E
+       pop   y1
+       move  y1,x:<$3D
+       pop   y1
+       move  y1,x:<$3C
+       pop   y1
+       move  y1,x:<$3B
+       pop   y1
+       move  y1,x:<$3A
+       pop   y1
+       move  y1,x:<$39
+       pop   y1
+       move  y1,x:<$38
+
+       ;
+       ; restore hardware stack
+       ;
+       move  hws,la  ; Clear HWS to ensure proper reload
+       move  hws,la
+       pop   HWS
+       pop   HWS
+       
+       ;
+       ; restore all saved registers
+       ;
+       pop   lc
+       pop   m01
+       pop   la
+       pop   omr
+
+       pop   r3
+       pop   r2
+       pop   r1
+       pop   r0
+       pop   b2
+       pop   b1
+       pop   b0
+       pop   a2
+       pop   a1
+       pop   a0
+
+       pop   y1
+       pop   y0
+       pop   x0
+
+       pop   n
+       
+       rts
+}
diff --git a/kern/switch_i196.s32 b/kern/switch_i196.s32
new file mode 100755 (executable)
index 0000000..6b9d6af
--- /dev/null
@@ -0,0 +1,88 @@
+;* Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+;* Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+;*
+;* \version $Id$
+;*
+;* \author Bernardo Innocenti <bernie@develer.com>
+;*
+
+;* $Log$
+;* Revision 1.1  2004/05/23 17:27:00  bernie
+;* Import kern/ subdirectory.
+;*
+;*
+
+!!!!!! THIS FILE HAS NOT BEEN REVISED FOR THE NEW SCHEDULER API !!!!!!
+
+
+
+       NAME    AsmSwitch
+       RSEG    CODE
+
+       EXTERN  ?LR
+       EXTERN  ?GR
+       PUBLIC  AsmSwitchContext
+       PUBLIC  AsmReplaceContext
+
+
+;* Perform low-level process context switching
+;*
+;*     void AsmSwitchContext(cpustack_t *new_sp, cpustack_t **save_sp)
+;*                                        GR+0                 SP+2
+;*
+;* Replace current context with new process
+;*
+;*     void AsmReplaceContext(cpustack_t *new_sp, cpustack_t **dummy)
+;*                                         GR+0                 SP+2
+;*
+
+AsmSwitchContext:
+
+; pop 2nd parameter from the stack
+       ld      ?GR+2,2[SP]
+
+; save all registers
+       push    ?LR+0
+       push    ?LR+2
+       push    ?LR+4
+       push    ?LR+6
+       push    ?LR+8
+       push    ?LR+10
+       push    ?LR+12
+       push    ?LR+14
+       push    ?LR+16
+       push    ?LR+18
+       push    ?LR+20
+       push    ?LR+22
+       push    ?LR+24
+       push    ?LR+26
+       push    ?LR+28
+       push    ?LR+30
+       st      SP,[?GR+2]              ; save old stack pointer
+       ; fall-thru
+
+AsmReplaceContext:
+       ld      SP,?GR+0                ; load new stack pointer
+
+; restore all registers
+       pop     ?LR+30
+       pop     ?LR+28
+       pop     ?LR+26
+       pop     ?LR+24
+       pop     ?LR+22
+       pop     ?LR+20
+       pop     ?LR+18
+       pop     ?LR+16
+       pop     ?LR+14
+       pop     ?LR+12
+       pop     ?LR+10
+       pop     ?LR+8
+       pop     ?LR+6
+       pop     ?LR+4
+       pop     ?LR+2
+       pop     ?LR+0
+
+; restore execution in new context
+       ret
+
+       END
diff --git a/kern/switch_i386.s b/kern/switch_i386.s
new file mode 100755 (executable)
index 0000000..c4a23da
--- /dev/null
@@ -0,0 +1,62 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief i386 context switch
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+ *
+ * $Log$
+ * Revision 1.1  2004/05/23 17:27:00  bernie
+ * Import kern/ subdirectory.
+ *
+ */
+
+!!!!!! THIS FILE HAS NOT BEEN REVISED FOR THE NEW SCHEDULER API !!!!!!
+
+/* I know it's ugly... */
+#.intel_syntax
+
+/* void AsmSwitchContext(void * new_sp, void ** save_sp) */
+.globl AsmSwitchContext
+AsmSwitchContext:
+       pushl   %eax
+       pushl   %ebx
+       pushl   %ecx
+       pushl   %edx
+       pushl   %esi
+       pushl   %edi
+       pushl   %ebp
+       movl    0x24(%esp),%ebp         /* ebp = save_sp */
+       movl    %esp,(%ebp)                     /* *save_sp = esp */
+       movl    0x20(%esp),%esp         /* esp = new_sp */
+       popl    %ebp
+       popl    %edi
+       popl    %esi
+       popl    %edx
+       popl    %ecx
+       popl    %ebx
+       popl    %eax
+       ret
+
+/* void AsmReplaceContext(void * new_sp, void ** dummy) */
+.globl AsmReplaceContext
+AsmReplaceContext:
+       movl    4(%esp),%esp            /* esp = new_sp */
+       popl    %ebp
+       popl    %edi
+       popl    %esi
+       popl    %edx
+       popl    %ecx
+       popl    %ebx
+       popl    %eax
+       ret
+
diff --git a/kern/switch_win32.s b/kern/switch_win32.s
new file mode 100755 (executable)
index 0000000..3e5ce54
--- /dev/null
@@ -0,0 +1,56 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999,2000,2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief i386 context switch for WIN32
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+__declspec(naked) void AsmSwitchContext(void * new_sp, void ** save_sp)
+{
+       __asm
+       {
+               push    eax
+               push    ebx
+               push    ecx
+               push    edx
+               push    esi
+               push    edi
+               push    ebp
+               mov             ebp,dword ptr [esp+24h] ; ebp <- save_sp
+               mov             dword ptr [ebp],esp             ; *save_sp = esp
+               mov             esp,dword ptr [esp+20h] ; new_sp
+               pop             ebp
+               pop             edi
+               pop             esi
+               pop             edx
+               pop             ecx
+               pop             ebx
+               pop             eax
+               ret
+       }
+}
+
+__declspec(naked) void AsmReplaceContext(void * new_sp, void ** dummy)
+{
+       __asm
+       {
+               mov             esp,dword ptr [esp + 4] ; new_sp
+               pop             ebp
+               pop             edi
+               pop             esi
+               pop             edx
+               pop             ecx
+               pop             ebx
+               pop             eax
+               ret
+       }
+}
+